Updated to version 6.0.0.0. See OP.
Printable View
Updated to version 6.0.0.0. See OP.
Hi Niya. Just downloaded the project and took a look. Nice work, and nice code, too. This is a very cool accomplishment for VB.Net!
I'm not particularly familiar with XNA, so I may not have anything useful to share, but off the top of my head, here are some easy ways to improve performance of generic GDI+ functions. (It's entirely possible you are already doing these things, so disregard as necessary!)
- Make sure all images are forced to premultiplied alpha (PARGB). It's not always obvious if GDI+ is loading assets in ARGB or PARGB format, but maybe test to see if ARGB is being used.
- Experiment with the target graphics container settings. Things like wrap mode, compositing quality, and pixel offset mode can impact performance in unpredictable ways, and if switching to high-speed options doesn't cause any graphical issues, this can be a "free" gain.
- When caching bitmaps, look at using GdipCreateCachedBitmap specifically. (Sorry, I'm not sure of the managed names for some of these functions.) GdipCreateCachedBitmap takes a Bitmap and Graphics input, and returns a new "CachedBitmap" optimized for that specific Graphics object. This allows you to use GdipDrawCachedBitmap for a nice performance gain.
- Another alternative to cached bitmaps is to dynamically switch to GDI's AlphaBlend for rendering. I'm not sure of the easiest way to accomplish this with your current rendering model, but basically, instead of using .DrawImage, you would use .GetHdc to return a DC to the graphics container. Then use GDI's AlphaBlend (which is hardware-accelerated) to perform the draw, and of course .ReleaseHdc when you are done. You lose the benefit of sub-pixel positioning (because AlphaBlend takes integer inputs) but GDI's AlphaBlend is several times faster than GDI+'s DrawImage. The problem with this approach in managed code is easily pointing a DC at the source System.Bitmap object... I'm not sure the easiest way to do that.
Those are some of the simpler ways to improve performance. It's possible XNA does some of this for you, but if not, maybe there's an easy performance bump in there...? (Apologies if you're already doing all this - I haven't looked too closely at the code yet!)
I also have an older one written in VB6. That one works but the code is one huge mess. Not VB6's fault though. I was learning as I wrote it so undoing the many mistakes I made during development meant I had to do a lot of nasty patch work.
Since I moved to .Net, I've always wanted to re-write it. To my surprise it was much easier. I wrote the basic engine(Version 1.0.0.0) in only a couple days. This is one of the projects where I saw massive productivity boosts from the new Visual Studio IDE and the .Net Framework. To be fair though, the fact that I had done this before also helped. I already knew what to do.
I actually did quite a bit of experimentation with GDI+. I even made a thread when I was working on the GDI+ renderer. I never wanted to use XNA because of the extra hassle to install it but GDI+, no matter how much I try to optimize can never give me the performance I need. Alpha blending in particular was taxing the GDI+ renderer.
I could have used this suggestion. How much of a performance gain would I get ?
I actually implemented a plain GDI renderer after I gave up on GDI+. It was abandoned of course but you can still see the remnants of the GDI renderer in the code. AlphaBlend was the main API being used. I had read that GDI's blitting was hardware accelerated on Windows 7. To my surprise though, the GDI renderer was only marginally faster than the GDI+ renderer. I wasn't satisfied so I reverted back to the GDI+ renderer since it was less cumbersome as GDI+ is the native API for WinForms. Then I started working on the XNA renderer which gave me a massive performance boost. It was exactly what I needed.
XNA is built on top of DirectX so I really can't get a better renderer. I was thinking about Cairo as a replacement because of easier deployment(It's a single DLL is it not ?) but the fact that it's not hardware accelerated means I would probably have the same performance that I did with GDI and GDI+.
My current performance problems no longer have anything to do with the renderer. It has to do with other aspects of the engine. For instance the current version performs too many removals from lists. Removing an item from a list is very costly since there is a LOT of copying going on and the engine does this several times each tick! There's quite a bit of refactoring that needs to be done along these lines. Another performance killer is collision detection. I have a solution but it can't be implemented without some major refactoring of the code that deals with targeting.
I was trying to come up with ways to improve performance without making massive changes but it seems that is all I can do now. I can't shortcut this. My last attempt at a shortcut, which involved using an IList implemented as a linked list so I can get O(1) removal was a massive failure. It gave me the O(1) removal but caused a host of other problems. This is what inspired by comments about using C/C++ in the other thread.