Thursday, August 12, 2010 5:37 PM
What is the current, up to date opinion on backbuffers in games?
I have a load of object, eg spaceships of different types, and some the same type and they will be flying around a screen. The screen will rotate as well as the spacecraft.
What do I use.
I wrote a small amount of code with a WriteableBitmap and it was soooo slow. There are slight improvements I can make but i really don't think they will be sufficient.
Can you just put stuff on a canvas and will it be fast enough? Do I have two canvases, both having the game state on them - one last turn and one this turn and toggle which is visible or not? I really do not know where to start on this.
Any ideas would be greatly appreciated.
Friday, August 13, 2010 4:17 AM
I wrote a small amount of code with a WriteableBitmap and it was soooo slow
To be honest, using the writeable bitmap probably is the fastest possibility you can use, so I wonder if maybe you added some very inefficient code by accident.
You can take a look at the WriteableBitmapEx project that adds even faster and more comfortable methods to the writeable bitmap (e.g. for Blt). It also has some examples (see the linked blog entries) that gives you an idea of what actually is possible performance-wise.
Double-buffering: if you're using the writeable bitmap, you only need to invalidate the bitmap, which triggers a complete repaint (no flickering etc.).
Friday, August 13, 2010 5:04 PM
Thanks for your reply MisterGoodCat. You were right.
Re: so I wonder if maybe you added some very inefficient code by accident.
lol.....accident.....That is very diplomatic talk. In actuallity I added some very inefficient code because I am pants at programming. But thanks for being kind.
I am a much better mathematician than I am a programmer. All the rotations, scaling and translation are bread and butter to me but I keep on forgetting that while mathematicians get a kick out of using sledge hammer solutions to solving simple problems, when it gets to real-life implementation in programming, it is always the simplest and fastest ideas that work best.
I was using some 3D (4D for translation) vector and matrix mathematics I had written a while ago to solve this very simple 2D problem. So what I did was strip it right down to some very fast 2 lines of code, even limiting the operations involved. Now it works like a charm.
Thanks again for the reply. I'll get used to this programming at sometime...hopefully.
Saturday, August 14, 2010 4:26 PM
Does 10 frames per second for a full sreen rotation sound about right with blending and alpha channels and 15 frames per second for a full screen rotation without blending or alpha channels?
I am getting the full screen and rotating it constantly around and around. (I am rotating about 750,000 pixels)
Sunday, August 15, 2010 6:41 AM
That's really hard to say because it depends on a lot of parameters, like the computing power of your CPU, how complex the calculations are you need to do to set up your scene in each frame, and of course how many blt/blending operations you do.
Framerates can decline pretty fast if you're doing a lot of blending with big bitmaps that have alpha channels, however for a scenario without blending 15 fps sounds rather low. Can you post a simple example of what you're doing?
Also, here are some hints for the blending scenarios. We had an application that used 10-15 images with alpha channels that got drawn onto the screen in the Rendering event handler of the CompositionTarget. Framerates were pretty low on an average office computer (5-6 fps). When I analysed the code I realized that for simplicity the "local" writeable bitmaps of each image had the size of the control, which made the blitting code very simple. I changed that so each image only had a local buffer of its own size, and the positioning was done from the outside (by blitting to the correct position of the "screen" bitmap). That made the rendering routine more complex, however the framerate climbed to ~25 fps. In a second step, I optimized a bit further by checking whether some operations that had been executed in every frame could be pre-rendered and only refreshed if it's really necessary (also details only required a partial update of the bitmaps instead of a full redraw). Again that made the rendering logic more complex, but the framerate climbed to ~40 fps.
So a general advice is, when you're blitting, keep the areas involved as small as possible, try to pre-render and recycle as much as you can, and only make updates when it's really necessary (e.g. maybe it's even worth to think about partial updates of your bitmap, instead of the classic "clear and redraw everything" approach).
But again, without knowing how exactly you're working with the images, it's hard to say what might be a bottleneck, if any, and suggest a good optimization.
Monday, August 16, 2010 9:12 AM
Thanks for the advice. I'll explain exactly what I am doing below. However, first things first some good news. I have just found the Release build option on my Express edition. (For those who are interested you get the Release build option visible by going to Tools|Settings|and ticking Expert Settings, then the release builds will be available.)
With the release build on I am up to 20fps with full alpha blending and 25fps with just pixel setting. (My CPU is 2.1 GHz).
Ok, so what am I doing. I have my world. The background is made up of tiles. These tiles will be perfectly aligned with the x/y axis so I planned to create a large bitmap (which is just big enough to allow for all possible rotations of that background without creating dead space on the screen, in other words it is not the full world just the critical area) and blit these tiles to that background. Since these have perfect alignment with the axis, this blit can be a fast memory Buffer Blit for each row. Static objects, again with perfect axis alignment, can also be blitted in this manner.
Then the characters, who can be rotated at exotic angles to the axis, are blitted with my RotateBlit. Each pixel has to be processed separately for rotations obviously. However, I am using some fast maths tricks to speed this up as much as possible. So far this whole process isn't too bad on speed.
Then the time consuming bit. The background which has been created has to then be rotated onto the final screen bitmap according to the main character's viewpoint. This again uses my RotateBlit function where each pixel has to be processed separately - but this time obviously without blending -just with setting.
So, I don;t really think I can use some of the clever tricks you have suggested as my scene is ultimately dependent on my main charater's viewpoint.
I could (with a bit more clever maths) avoid the final scene rotate by doing a RotateBlit on everything that enters the scene including tiles, statics and main characters, preadjusting for the view area. This obviously avoids the last rotate of the final sceen and also means I will not be adding as many things to my drawing scene (as I don't have to accomadate for the larger area) but that means every entry has to use the slower rotateBlit.
Its tough to know what is best.
One question, how do you make inline function in c#?
Monday, August 16, 2010 12:10 PM
One question, how do you make inline function in c#?
You can't. The JIT compiler decides whether something should be inline, and from what I've read it really makes decent decisions.
Its tough to know what is best.
Ack! I've thought about your scenario some more, and from what I've read now it seems to me like the content itself doesn't really change? What I mean is: until now I was under the impression that you're using highly dynamic content (changes color, shape etc. frequently, where the per-pixel manipulation possibilities of the writable bitmap really is needed). But the more I read the more I think you're simply using sprites which admittedly can be rotated, maybe also scaled etc., but they don't change their own shape or appearance apart from these geometric operations? At least that is true for the background tiles and static objects, right?
The reason I'm asking is Silverlight supports a handful of operations to be hardware accelerated (i.e. executed on the video card), in particular all you can do with a render transform, clipping and changing opacity for whole objects. Maybe you'd better off using the built-in operations for at least some of your objects (render transform can be a RotateTransform or combination of several transformations, like scale, rotate, translate). This has nothing to do (here's the diplomatic talk again :)) with the built-in code being more efficient than your own rotation tricks. It's just that your code executes on the CPU, and GPUs are so much faster with this...
But then again, "it's tough to know what's best". I've sometimes found that active GPU acceleration doesn't help anything and can even slow down applications, and I don't know why. Maybe the transfer to VRAM is too costly sometimes? Anyway, it's probably worth trying. You could use "Image" elements on a canvas, e.g. for the background and static parts, and maybe some more for your sprites. The sources for these can still be your writable bitmaps (rendered once initially), but for rotation, scaling and translation you would populate and manipulate the "RotateTransform" property of the image elements. To enable hardware acceleration, you have to do:
a) Set the "CacheMode" attribute of a framework element to "BitmapCache" (you would do that on the image elements).
b) For the Silverlight object in your HTML site, set the "enableGPUAcceleration" parameter to "true".
For diagnosis, there are additional parameters:
<param name="enableGPUAcceleration" value="true" />
<param name="enableFrameRateCounter" value="true" />
<param name="enableCacheVisualization" value="true" />
The second one shows an fps counter that also gives some information about the number of accelerated surfaces, and how many intermediate surfaces had to be created, details see here. The third one tints everything that is not GPU accelerated red, so you can confirm that GPU acceleration actually is used for the parts you want, details see here.
Monday, August 16, 2010 5:22 PM
Thanks I'll try this.
Tuesday, August 17, 2010 5:45 PM
"What is the current, up to date opinion on backbuffers in games?"
My opinion. I remember games, demo's on the Amiga and Commodore 64 which used backbuffering. The first question is, what problem are you trying to solve? On the Amiga and C64 the problem was quite clear: drawing of the screen takes more time than the real world allows you. Plugged on a Television, both popular home-computers had 60 frames per second. No subject of negociation.
You needed to draw the screen, before it was displayed. So if you think of a television having raster lines, the screen could only be drawn when the raster was between the bottom, outside the monitor, and back to the top again. Too little time, so backbuffers were used to display one screen, while drawing on the other screen. If no backbuffering was used on Amiga or C64, then you would see flickering pixels. So the backbuffering in the old days was used to get a stable picture.
If drawing a screen took too much time, then another trick was used: draw a large screen with level data and draw last-minute changes, ie enemies, in your bottom/top border time, while initializing the backbuffer for a new display, which could take more than 2 frames to draw. Turrican 2 was created like this.
With Silverlight, you have entered a different world. First of all, Frames per second is not stable. As far as I know, the Silverlight engine just gets the data for your screen from your display model and renders it. While this happens, your code does not execute. I could be wrong on this last point, but I've never seen flickering pixels in Silverlight. But maybe that's just because I've got a powerful machine.
Frame rates not being stable is a second and significant part of the equation. Frame rates drop when you do a lot of computing. So let's assume you use backbuffering, because the single frame-cycle is too fast. Then you need extra computing for the backbuffering, which decreases the frame rate. So with a decreased frame rate, you could ask yourself, if you have now more time to draw your screen, do you still need backbuffering? You can set the Silverlight frame rate.
If your project is 2D, then I certainly would try the tips mentioned in the above posting, Silverlight has different transformations which could be sufficient. If your project is 3D, perhaps you could look out for a 3D library, like Balder or Kit3D. And Silverlight has some basic 3D transformations as well.
But that is just my opinion. If anyone can make the case for backbuffering, I'd be ofcourse very interested.
Wednesday, August 18, 2010 1:55 AM
You're right. I don't see the necessity for manual back-buffering in Silverlight at all. Silverlight uses a retained rendering mode (as opposed to immediate mode) and defers all rendering anyway, to do exactly those optimizations (among others). It's desirable to relieve the layout engine with pre-rendered content in complex scenarios (as I mentioned above), but more than that, like drawing everything to a back buffer and flipping it etc. is not necessary.
A good example can be found in another thread recently posted here: http://forums.silverlight.net/forums/p/196610/458052.aspx#458052 (although the original poster couldn't solve the problem yet). Someone wanted to make a smooth animation of a large text block and found that CPU load was through the roof. The reason for this is that layouting the text takes a lot of time. What I did was pre-render the text to an image and animate the image instead, which immediately resulted in a drop to a very low CPU load. With this approach the animation already is extremely smooth and doesn't show any flickering etc. at all. Nothing would be gained when someone tried to optimize this any further, e.g. by using any kind of additional back-buffering.