Jump to content
  • Advertisement
Sign in to follow this  
Decept

optimizing 2D rendering

This topic is 4408 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

I have a 2D engine that I have made myself, which uses DX8 for rendering. I'm currently looking for ways to increase the rendering performance. I'm pretty familiar with DirectX (been using it for many years) and I know I should batch as much as possible, which I do. But the there is one thing that keeps breaking up my batching attempts and that's the rendering order. I need to render most objects in the correct order, reason 1: to get the objects in the correct Z order (e.g objects over background). Reason 2: almost every object uses alpha blending. I forgot to mention that I'm using TL vertices (maybe obvious). For batching I have 1 static index buffer and 1 dynamic vertex buffer with triangle list. I thought about using the Z value in the vertices so that I can render in any order but that would mess with the alpha blending. Currently I create "virtual layers" to which I'm rendering. It's actually just lists of objects to render that I use for batching and rendering in the correct Z order. Within a layer I put objects that don't care if they overlapp. For example all explosions in one layer and all gunshots in another. To really understand the problem you must now how the engine works. Each frame of each animation is in a seperate image file. I then have a utility (that I've made) that takes every little image file and puts them in a couple of combined image files (with nice dimensions as 256x256 or whatever you select). This means that there is no guaranty that every frame of an animation is in the same combined file. Which creates problems when trying to batch objects according to texture and in the correct Z order. So if I let all the explosions render without any z-order (within their layer) it looks awful. Because depending on which frame an explosions is it may need a different texture which in turn constantly changes the render order between explosions. So in one screen-frame explosion A gets rendered on top of B and in another frame B is rendered over A. Can you see the problem here? So I must sort them in their Z-order. I can't use the Z-buffer to solve this because then the alpha-blending would screw up. sigh. puh, this post got pretty long, sorry, I just hope I described the problem enough. Any ideas how to optimize this? When sending an indexed tri-list for rendering is there a guaranty that the triangles gets rendered in the order of the list? That could be useful. thank you

Share this post


Link to post
Share on other sites
Advertisement
I've been struggling with this for a while, unfortunately as you say 2d stuff can't use the zbuffer, and so drawing order is heavily dictated by where on screen things are. It's worse with something like a platform game where not only do you have to draw back-to-front, but also top-to-bottom to get correct overlapping behaviour.

It gets worse when you add shaders into the mix, as they're typically more expensive than texture switches and also tend to be scattered all over the sprites.

I have yet to find a good solution to this, and I'm not even sure how much affect it really has on performance. Most of the sorting is actually redundant (because although a sprite might have a different z depth, if they don't overlap then actually they can be rendered in any order), but I can't see a good way to exploit that.

Share this post


Link to post
Share on other sites
Ok, so what we've got is to conflicting demands: (1) visually we need to draw in a specific order to get correct results, but (2) for performance we want to draw in a different order. Somehow we've got to gain some slack so we can re-order one or the other.

Gaining slack for (2) isn't too hard conceptually, we just want to find ways of increasing the size of the batches we can submit. For this the only methods I know are texture atlases and combining multiple shaders into fewer, 'uber' shaders. Unfortunately as soon as we add animation then texture atlases get pretty big pretty fast, so it's not as useful as you'd hope.

(1) probably has much more potential. Most sprites only overlap a few others, but they'd still be ordered quite strictly. Instead perhaps each sprite could calculate a dependancy list - all the sprites which need to be rendered before it for it to be visually correct. Other than the background, most sprites would probably only have one or two different dependant sprites. Each frame, we could then use the dependancy graph to choose the best ordering based on performance (ie. keeping state switching to a minimum) while not breaking the visual depenancies.

However I suspect that finding the most optimal ordering with a given dependancy graph is going to be an NP problem, so you'd need some kind of heristic. Scanning all 'available' sprites (ie ones with no current dependancies) and picking the one with the smallest current state change might work well though.

Building the graph isn't going to be cheap though - you'd need to compare every sprite's bounds against every other sprite's bounds to create the dependancies for itself, and you'd probably have to recreate it every frame. I'm not sure that the GPU time gained would be enough to compensate for the heavy CPU use it'd require.

Share this post


Link to post
Share on other sites
Interesting discussion.

Been encountering some of these problems with my current 2D game project for the past few years. In my experience, there really hasn't been a great solution. Even batching seems largely a waste. I experimented with it, and got very little performance benefit -- wish I hadn't bothered. The biggest bottleneck seems to be the sheer number of texture changes.

I looked at texture atlases, but the extra work maintaining and building large sheets of textures didn't seem worth it at all.

Now, I have a sorted collection of graphics (in depth order, sorted only when depth changes), and I minimze settextures and state changes that way. For sprites that change frequently, I utilize dynamic buffers. For sprites that don't, I use static.

Maybe someone here has a few clever suggestions.

Share this post


Link to post
Share on other sites
You all say that you use alpha blending a lot, but alpha blending is only required for translucent (i.e., semi-transparent) objects. I don't really have a lot of experience with this sort of thing, but it looks to me like most sprites have completely transparent ares (usually surrounding a character or something), and you can use alpha testing to render them, which is cheaper than alpha blending and doesn't require back-to-front sorting.

You probably knew about this already, but I thought I should still mention it.

Share this post


Link to post
Share on other sites
1. 2D games usually have *lots* of semi-transparent objects (particles, lights flares, glows) which wouldn't be suitable for alpha-testing.

2. For best quality you want to use blending to get nice anti-aliased edges, rather than harsh bitmask transparency. All sprites tend to look much better, and fonts will look terrible if they're not blended.

The Frugal Gourmet: What was it about texture atlases that was too much work? The way I've got things currently I have a data process step that happens at compile time which packs up a directory of images into as few atlases as possible. This is nice because I don't actually have to maintain the atlases by hand at all.

Share this post


Link to post
Share on other sites
I also create the texture atlases automatically and it's a great thing to have.

Batched rendering makes a huge difference for my current game is nothing I would consider dropping. Just the opposite, I'm looking for ways to increase batching.

OrangyTang: Creating a dependency graph of overlapping objects sounds interresting. But so far I haven't been able to think out a way to do that without a big cpu hit. Just as you said.

Share this post


Link to post
Share on other sites
Quote:
Original post by Gage64
You all say that you use alpha blending a lot, but alpha blending is only required for translucent (i.e., semi-transparent) objects. I don't really have a lot of experience with this sort of thing, but it looks to me like most sprites have completely transparent ares (usually surrounding a character or something), and you can use alpha testing to render them, which is cheaper than alpha blending and doesn't require back-to-front sorting.


I think a large number of my graphics depend upon alpha blending. Most sprites and fonts need nice anti-aliased edges to really look good.

Share this post


Link to post
Share on other sites
Quote:
Original post by OrangyTang
The Frugal Gourmet: What was it about texture atlases that was too much work? The way I've got things currently I have a data process step that happens at compile time which packs up a directory of images into as few atlases as possible. This is nice because I don't actually have to maintain the atlases by hand at all.


That sounds reasonable. Is it a big performance benefit? How large should the textures in the atlas be, typically?

Share this post


Link to post
Share on other sites
I'm not sure on the exact performance gains, but it certainly makes batching much easier. I generally tend to use 256x256 or 512x512 textures, but one of the things I need to look into is the best size for them.

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

GameDev.net is your game development community. Create an account for your GameDev Portfolio and participate in the largest developer community in the games industry.

Sign me up!