How to eliminate tearing from animation? - c#

I'm running an animation in a WinForms app at 18.66666... frames per second (it's synced with music at 140 BPM, which is why the frame rate is weird). Each cel of the animation is pre-calculated, and the animation is driven by a high-resolution multimedia timer. The animation itself is smooth, but I am seeing a significant amount of "tearing", or artifacts that result from cels being caught partway through a screen refresh.
When I take the set of cels rendered by my program and write them out to an AVI file, and then play the AVI file in Windows Media Player, I do not see any tearing at all. I assume that WMP plays the file smoothly because it uses DirectX (or something else) and is able to synchronize the rendering with the screen's refresh activity. It's not changing the frame rate, as the animation stays in sync with the audio.
Is this why WMP is able to render the animation without tearing, or am I missing something? Is there any way I can use DirectX (or something else) in order to enable my program to be aware of where the current scan line is, and if so, is there any way I can use that information to eliminate tearing without actually using DirectX for displaying the cels? Or do I have to fully use DirectX for rendering in order to deal with this problem?
Update: forgot a detail. My app renders each cell onto a PictureBox using Graphics.DrawImage. Is this significantly slower than using BitBlt, such that I might eliminate at least some of the tearing by using BitBlt?
Update 2: the effect I'm seeing is definitely not flicker (which is different from tearing). My panel is double-buffered, sets the control styles for AllPaintingInWmPaint, UserPaint, OptimizedDoubleBuffer etc., overrides onPaintBackGround and so on. All these are necessary to eliminate flicker, but the tearing problem remains. It is especially pronounced when the animation has very fast-moving objects or objects that change from light to dark very quickly. When objects are slow-moving and don't change color rapidly, the tearing effect is much less noticeable (because consecutive cels are always very similar to each other).

Tearing occurs when your image update is not in sync with the refresh rate of the monitor. The monitor shows part of the previous image, part of the new image. When the objects in the image move fast, the effect is quite noticeable.
It isn't fixable in Windows Forms, you can't get to the video adapter's v-sync signal. You can in a DirectX app.

I tried the double buffering idea on the project I'm working on at the moment, but I didn't get very good results with it. In the end, I created the following:
A System.Drawing.Bitmap for my offscreen buffer. Decode the animation into this bitmap.
A UserControl the same size as the image in (1) and where the OnPaintBackground method was empty (no drawing, no call to base class) and the OnPaint did a Graphics.DrawImage to copy the offscreen image to the screen.
Now, you've got a weird animation rate so the tearing is almost certainly to do with a mismatch between screen update rate and screen refresh rate. You are updating the screen midway through the screen's refresh so the screen is drawing the old frame at the top of the screen and the new frame at the bottom of the screen. If you can synchronise the frame rate with the display refresh rate, the tearing should disappear.

You would better to use directx (or opengl) for such tasks. But if you want to use only winforms use DoubleBuffered property.

Double buffer it.
You can enable double buffering using windows styles or, whats probably easier, is to draw to a picture from offscreen and then swap them.
If this doesnt work then the best thing to do is bitblit and double buffer.
Essentially its the same.
Have a reference to two bitmaps, one is the screen, the other is the buffer.
You draw to the buffer first, then blit that entire thing to the screen.
This way you only ever write live data to the buffer. The sceen simply shows something you made earlier (blue peter style)

Tearing is an artifact from a frame being drawn on top of another. The only safe ways of avoiding it is to a) wait from vsync or b) draw behind the beam (this is rather tricky). Double buffer alone doesn't guarantee against tearing since you can have double buffer but still draw having the vsync off. Some cards might also have vsync wait option "forced off". You need to check the documentation regarding vsync and how to check where it is. This is the only safe way to do it. Also, keep in mind that this will lock your framerate.

Related

C# PictureBox control flickering / performance issues

I am currently working in Windows Form Apps and am making what will essentially be a map editor for a game. The way i have gone about this is by having a central TabControl where each TabPage contains a custom PictureBox control and all the other UI controls are around this central TabControl. The PictureBox uses its Paint event to draw everything that is placed on the map, and therefore draws multiple images of many sizes, rotations and scales etc to the single PictureBox. This has all gone well so far. The TabPage is essentially used as a view window for the PictureBox and is of size (1280x720).
The problem is with the scale to which the maps are being produced. The avg (and also maximum) map size on screen is around 19200x10800px and can be made up of hundreds of items at any one point. When drawing just a backdrop image of size 19200x10800px the PictureBox starts to flicker when it redraws and makes the program unusable. As the map is so big you are able to pan around them and this is where the flickering really shows. Also i do not want to use a 19200x10800px image source if possible for the sake of file sizes and the scaled image quality isn't an issue at all.
I have done heaps of reading on why this might be and feel like I have tried everything up until this point. So far ive tried:
Having the background image only 1920x1080 and scaling it up by 10x
Starting with a 1920x1080 image, programatically resizing it and drawing this image
Slicing the background into multiple segments (i tried many different amounts) and drawing only the ones that the view window can see (tried this for both a small(1080p) and large(10800p) images)
Using graphics clipping so that only the things on screen would be drawn
Used Double Buffering on both the picturebox and the form that the picturebox is on
Converting the image at initialisation to an "optimised bitmap" with faster formatting and then drawing the bitmap
I've probably tried a couple other things along with minor optimisations but its taken me so long ive forgotten the rest. From what i've read its most likely something to do with the control redrawing too slowly for some sort of performance reason or a limitation with picturebox's, however exactly what is going on i cannot tell due to lack of experience with form apps controls.
Currently to draw the background in the Paint event i have either:
g.DrawImage(image, new Rectangle(0, 0, (int)(image.Size.Width * levelScale), (int)(image.Size.Height * levelScale)));
or
g.ScaleTransform(levelScale, levelScale);
g.DrawImage(image, new Rectangle(0, 0, (int)(image.Size.Width), (int)(image.Size.Height)));
Where g is the Graphics object.
Have I hit the limit of Win form apps capabilities or is there something i may be missing?
Any and all help appreciated,
Thanks in advance.
Just for formality I though id answer my own question just in case anyone else would like to know the outcome.
Based off the overwhelming consensus that winforms was just not made to do the things I was trying to do with it I decided I had to move to some other platform. Suggested to me was WPF, DirectX and OpenGL but after some extensive searching around I found what I think is the optimal solution.
In order to utilise the power of DirectX hardware acceleration MS has made it so that you can embed XNA graphics devices into a winforms application. Essentially you can create custom controls that run in the normal winform style that have access to a much higher caliber of graphics control. In this manner (with a bit of extra work) I have replaced the picturebox I was using with a custom graphics control which handles all of the drawing. This has worked very well, and on the up side i havent had to take too much of a hit to my development time.
For those looking for more info refer to this question which has further links that should help. Once again thanks to all those who gave their advice!
This is a quoted answer from the URL at the bottom. There are code examples at the link at the bottom. Hope this is helpful; not sure if you tried this yet and maybe it'll help you get a little more juice out of the existing picturebox control. As explain in the other answers, it sounds like you will be forced to a more powerful solution in the near future regardless (DirectX/OpenGL or WPF)
** Partial quote from http://social.msdn.microsoft.com/Forums/en-US/68ecd1f6-2eeb-45ce-a881-24c62145ab0e/c-picturebox-problems
"I'd guess the real problem is that it takes too long to redraw the images. GDI+ is pretty slow, it doesn't use any video hardware acceleration. To speed it up, be sure to avoid rescaling the drawing and to use the Format32PArgb format. It is about 10 times faster than any other format. Load the images into a Bitmap with the right format first."
If you have a LOT of items (Maybe realized as controls), forget about the standard event mechanism of Windows Forms. Some time ago, i've written a logic gate editor/simulator which supported lots of thousands of gates in the editor and was really fast. There, I've used the canvas and draw the gates as custom "images" instead of putting them as controls. You'll have to write a custom GetUnderlyingGate function which resolves the current gate / tile (Is your editor a tilemap editor?) from a coordinate array. Also, there were some visible area optimizations.
Maybe, when i'm back home, I'll upload some sourcecode and notify you.

Why does one SpriteBatch.Draw causes frame rate to drop 23 fps?

I am having a major performance problem with a game I'm developing for Windows Phone 7 in C# XNA 4.0.
There's a lot of code going on, like collision, input, animations, physics and so on.
The frame rate has been set to 60fps, but is only running at 32fps. I have tried a lot of things, like disabling though stuff like collision detection, but nothing helped getting higher frame rate. Now randomly I discovered when disabling the drawing of the background, which is just a standard 480x800 sized image (Same as the Windows Phone Resolution), and uses the default method "spriteBatch.Draw(Textures.background, Vector2.Zero, Color.White)" the frame rate goes from 32 to 55 fps. I have also tried changing the texture to a plain white one, but that does not help either, and I have also tried moving the drawing of the background to another place in the code, but nothing changed either. I tried making a new project, and just having the background drawed, but the fps would be at 60 fps then as it should. I'm only having one SpriteBatch.Begin() and SpriteBatch.End(), where all the needed sprites are drawed inside. There's 256 Texture2Ds loaded into the game, which all is loaded at the beginning of the game. The game is a sidescroller, so the background needs to move to the left all the time, but even if I just set it to Vector2.Zero, it would still ruin the fps by -20fps. I hope anyone has a solution to this, or at least an idea of why this is happening.
If you have 256 individual Texture2Ds being used within the same SpriteBatch Begiin/End call it's not surprising that performance isn't optimal unless you are ordering the sprites by texture, which you likely are not for a platformer. All that texture switching within the same batch will cause a decrease in framerate - it's likely that the background image is just the straw that breaks the camels back for your particular game setup.
Have you tried combining those 256 separate images into a smaller number of Texture2Ds (i.e. using spritesheets or a texture atlas)? Here is an older link about how proper sprite sorting can affect performance

Why should I do manual double buffering?

I am working on a game in C# (either 2.0 or 3.5 havn't decided yet). The game will be played on a map with a hexagonal grid. I appreciate that the UI for this map should use double buffering (lots of layers, so slow drawing). I know that I can enable double buffering through a style, or create my own buffer and handle it myself. Most recomendations I find on the web are to handle it yourself. I am wondering why? Obviously this allows me to avoid the assumptions that are inherent in the control double buffering, but I do not know what those assumptions are.
Again, I am not looking for code to explain how to double buffer my control, but rather why I would build this myself instead of using the double buffering style and allowing the CLR/Control class to handle it?
From MS:
For graphically intensive applications
such as animation, you can sometimes
improve performance by using a
dedicated BufferedGraphicsContext
instead of the BufferedGraphicsContext
provided by the
BufferedGraphicsManager. This enables
you to create and manage graphics
buffers individually, without
incurring the performance overhead of
managing all the other buffered
graphics associated with your
application, though the memory
consumed by the application will be
greater.
EDIT: I also found this article from Bob Powell which may be helpful:
Manual double buffering can be useful
if you don't want the system so make
assumptions for you such as whether
the background is opaque or
transparent or perhaps if you want to
create a more complex buffering
system. There are a few simple rules
that you need to follow to get manual
double buffering right.
First, don’t create a new back-buffer
every draw cycle. Only create or
destroy the bitmap when the window's
client size changes. Second, only
create a bitmap of the size you need.
Clearing pixels takes time and so if
there are more pixels than you need,
you're just wasting processor cycles.
Lastly, use the simplest draw method
to copy the bitmap to the screen.
DrawImageUnscaled is the way to go
here.
EDIT: Another reason is that you may want the application to control buffering, not the controls themselves.
Source: Pro .NET 2.0 Windows Forms and custom controls in C#.
In WFA, double-buffering slows performance without completely eliminating flicker in custom graphics areas. For built-in GUI elements, like if you create a game built out of ImageButtons and Labels, the built-in double-buffered mode is great at hiding the redrawing of the control tree. However, there are a couple major problems with using it for a custom drawing area:
The draw buffer created when you just set up the application to draw double-buffered is used to draw the whole window and all child controls, not just your custom drawing area, so you add the overhead of redrawing every GUI element on the back buffer before page-flipping.
If anything invalidates the control, the Paint method is called. You may not be finished drawing when that happens and so you'll get an incomplete image shown to the user (not good in real-time graphics).
By keeping the basic window GUI single-buffered, but creating an area on which you control the buffering, both of these problems are minimized.
Double-buffering methods can be as simple as creating a Bitmap object as a back-buffer and drawing it to the draw area when you're good and ready, or setting up a seperate BufferedGraphicsContext to manage buffering of your custom draw area.

How does Windows Media Player deal with monitor refresh rates?

I'm writing an animation app in C#/WinForms (see this question). Basically, the animation in my application is smooth but shows tearing effects; when I take the same animation and render it to an AVI file and play it with Windows Media Player, the animation shows no tearing effects at all. I know WMP is not changing the frame rate because the animation is synchronized with music.
I assume WMP uses DirectX or some other technology that is aware of the monitor's refresh rate and scanline position etc., but I always assumed that programming to the refresh rate would constrain the frame rate. Obviously this isn't the case with WMP.
Does anyone know anything about how WMP (or other video players) renders video internally? I've searched but I can't seem to find any details about this.
It's been a while since I did any DirectX programming, so this may be out of date.
From what I remember, with DirectX you could set up a flipping chain of buffers, usually three buffers: the buffer being displayed, the buffer to be displayed and the buffer being written to. On an update, DirectX will wait for a V-sync before updating the displayed buffer. Now, this will cause a discrepency between the displayed image and the image that should be displayed, but this will be, at most, one refresh, about 1/60th of a second, so you're unlikely to notice.
Some ASCII art to show what I mean:
|-|-|-|-|-|-|-|-|-|-|-|-|-|-| - screen refresh
|----|----|----|----|----|--- - animation
|-----|---|-----|---|-----|-- - displayed
Are you painting each frame of your animation to a memory bitmap first, and then blitting the bitmap to your window? If not, this might be the solution for you.
(this is, of course, in addition to double-buffering)

.NET C# drawing slowly

I have a problem drawing something quickly in .NET. I don't think that any thing in particular should take much time, but on every machine I've tried it on, I get serious issues. This is implemented in vs2008 .NET, using C# (with some stuff in C++, but nothing relevant to the drawing).
I have three screens, and the user should be able to toggle between them with no lag. On the first screen, there are four buttons, eight user controls consisting of two buttons and 6 labels each, a text field, and a dropdown box. I don't think of it as being that much.
On the second screen, I have four labels, six buttons, and two controls that have six buttons, one opengl drawing context, and about ten labels each.
On the third screen, I have one opengl context and 10 buttons.
Flipping from any screen to any screen takes literally about a second. For instance, if I flip from the second screen to the first, the entire application blanks out, showing the background screen, and then the first screen is drawn. Many times, a screen is drawn piecemeal, as if the machine were deliberately handcrafting delicate and delicious letters in a factory in Sweden and then shipping each one individually to my screen. I exaggerate, and I want to make that clear, because I don't think Swedes are as slow as this redraw.
The first and second screen are drawn in memory, and stored there, with just a '.Hide()' and '.Show()' to make them appear and disappear. Double buffering doesn't seem to matter. The third screen is drawn anew each time, and appears to take the same amount of time to draw as the first and second.
Any thoughts? What could be going on? How can I track it down?
Thanks!
Edit: I should add that any C++ processing and the like happens in its own thread. There is the occasional MethodInvoke to draw the results of the operation to the screen, but this problem happens without calling any functions, just by pressing buttons to go from one screen to the next.
In addition to the profiler that was mentioned, you might also turn off your OpenGL contexts. If you notice a speed-up, then you'll know it's your graphics stuff, and you can focus your optimisations accordingly.
Points awarded for Swedish humour.
How can I track it down?
dotTrace - http://www.jetbrains.com/profiler/
Are you doing any other processing during the "screen flip" event? other than just letting the form be redrawn? If you are processing something between flips (maybe your c++ addition?), and you are not multi-threading, you get that white out effect. The form is probably waiting for CPU time to redraw itself.
I have never used OpenGL in such a way myself, but you might want to look at the way in that the OpenGL contexts are flipped. When switching from one page to another you might be getting a device reset (in DirectX terms), which could be causing the delay.
If at all possible have a device draw to a back System.Drawing.Bitmap, and use that bitmap on the screens. Make your OpenGL code aware of the current page the user is on, and you might get the speed up you seek.
To test this before making huge changes, try removing the OpenGL displays on your form.
This is all a whim.

Categories

Resources