Separate interface and world rendering.

Started by szoltomi, August 04, 2011, 21:02:32

Previous topic - Next topic

szoltomi

Hello!

I'll keep it short:
Is it possible to render the game world, and the UI separately, so that even if the world causes an FPS drop, the UI is still fast and responsive?


Fool Running

No, that is not possible. Your FPS is a measure of how fast the screen is being redrawn. You can't render faster then your FPS (without keeping the user from seeing what you rendered).
You might be able to do some magic with stencil buffers or something to draw half of the world each frame which would keep your FPS higher. :P
Usually an FPS of 15 is plenty for a fairly responsive UI as long as the mouse is not affected by the FPS (i.e. you are using the native cursor and not drawing it yourself).

That being said... how much of a FPS drop are you expecting. It might be better to keep the FPS from dropping then try to figure out how to keep the UI responsive.
Programmers will, one day, rule the world... and the world won't notice until its too late.Just testing the marquee option ;D

CodeBunny

Actually, you can do something like that if you render to framebuffers instead of straight to the screen. It'd be limited, though.

Consider:

Have two separate off-screen framebuffers, one for the world and one for the gui. Simply update the world-framebuffer every other frame.

So, you basically do the following:

public void render()
{
    // render world to framebuffer A.
    // render gui to framebuffer B.
    // Render both framebuffers in order (A beneath B)
    // Update display, your game can be shown.
    // render gui to framebuffer B.
    // Render both framebuffers in order again. Note that A remains the same but B can be updated.
    // Update display, your game can be shown.
    // Wash, rinse, and repeat.
}


There are problems with this. Your rendering will be uneven, because it's not divided into two separate threads; basically, you have one render pass that's heavy-duty, and one render pass that is much more lightweight. If you drop below the target framerate it's going to look weirdly choppy. In this case it would probably be better and simpler to just render them both at the same rate.

However, if you can work out a fast way to share textures between contexts, you use textures as your framebuffers, render to them in separate contexts in different threads (to steady the rendering), then have your main thread simply render them on top of each other as described above.

CodeBunny

However, in all honesty, there is NO WAY your UI should need to be rendered more often than your game world. In virtually all circumstances, the game world will be changing far more rapidly than the info being shown to the user. Really, you should be asking the opposite question: "How can I render my UI less so as to give my game-world rendering more time to process?"

Consider Swing. Components normally only need repainting when their state changes and they are marked as "dirty." When that happens, Swing does its best to
render only the components that need repainting, reaching a minimum-render solution that works very well in practice.

And what type of GUI do you need? There are plenty of LWJGL GUI-libraries (TWL, Nifty, etc) that can get the job done for you.

szoltomi

Currently I am making a 2D game, writing every system by myself, apart from LWJGL and Slick-util. In many games it bothered me that if the world rendering is slow, the use of the UI becomes slow and clunky to use as well. I am currently experimenting with solving this out of curiosity, but it's likely  won't be needed at all.

I use an FBO to render the world to a texture. Then I use this texture as the background of an UI component. If I do it in one loop it goes like this:

[Loop at 60 FPS]{
updateWorld();
drawWorldToTexture();
drawUiComponents();
Display.Update;
}


The second step which I'm trying to figure out is calling updateWorld(); in a separate thread, and using a buffer to pass the data to the drawing. Or would a volatile data structure be better/faster? I still have to figure this out.
This step worked more-or-less, the drawing thread could run at any speed, while the world ran at a steady 60 FPS, but the drawing was a bit jerky. Not low FPS jerky, but something I messed up with the buffer caused data from previous frames to show up.

While I was working on the above, I wondered about freeing the UI from the world render's speed. Swifty put it into a separate thread, and of course was causing problems. Obviously openGL calls were happening in the wrong order, and without severe synchronization, or some feature I don't know about causes issues. I decided to ask because of the latter one.

One last thing I thought about: since everything in the world is rendered as AABB sprites, I can do a pseudo-interrupt on the world render thread when drawUi(); is called, a variable change which I check before every sprite draw or so. If it happens, I change state, manage the UI, then switch back to the texture rendering and continue. The state change is pretty much only a FBO bind, and a modelview matrix change.

What do you think about this approach?


Edit: The reason for the jerkiness was that I didn't copy the entities into the buffer, just put their reference into one. Then their position was modified by the world thread mid-rendering. I have to see if copying the necessary data every tick is a feasible solution.