🔒 Locked
responsive HUD
Advertisement
Original Post
I have a game which requires fast keyboard input from the user. In order for the user to not be hindered by slower frame rates, I need to HUD to update at a rate faster than the rate my 3d scene updates. I am guessing that until DX11 comes out that any way of accomplishing this is highly untrivial, but I just wanted to hear if anybody has any ideas. My one idea involves compositing the 3d portion of the scene into a render target(A) on a separate thread and then copying that render target to another render target(B) when it is finished. The main thread renders B as a full screen quad and then the HUD to the backbuffer. This solution however would entail massive amounts of thread synchonization and would not be simple.
How fast are we talking about? There is no point re-rendering the HUD faster than the refresh rate of the monitor, which limits you to at most 120 Hz, and more likely 90 Hz for a decent CRT, or 60 Hz for an LCD. I often manage to get frame rates in the low 100's on commercial games, so you may not have to do much beyond optimisation.
I think you will have to do something like cheking each fram, if you wants to draw the 3D secene. (maybe you will only draw it when something has changed, or only after some amount of time)
Let us say that we are running on some particularly bad hardware and only get 20 fps. I would like to keep rendering the 3d scene around 15-20 fps so that I can render the HUD at a good 60 fps.
Since this implies rendering the backbuffer at a constant 60 fps, I think the only way to get around this would involve rendering the 3d scene into an offscreen render target on a separate thread.
In my game, the 3d scene is purely auxiliary and does not provide any information needed to actually play the game. For instance think of the 3d dancers shown in the background of the game 'Dance Dance Revolution'. Technically the player only needs to see the HUD (arrows), but the dancers still function as cool avatars.
The situation is the same in my game and so it would be excusable in my case if the 3d scene rendered slowly as long as the information on the HUD and my event processing responded quickly.
Since this implies rendering the backbuffer at a constant 60 fps, I think the only way to get around this would involve rendering the 3d scene into an offscreen render target on a separate thread.
In my game, the 3d scene is purely auxiliary and does not provide any information needed to actually play the game. For instance think of the 3d dancers shown in the background of the game 'Dance Dance Revolution'. Technically the player only needs to see the HUD (arrows), but the dancers still function as cool avatars.
The situation is the same in my game and so it would be excusable in my case if the 3d scene rendered slowly as long as the information on the HUD and my event processing responded quickly.
Quote:In that case, I am afraid that you are pretty much out of luck until multi-threaded rendering hits mainstream.
Original post by Khaos Dragon
Since this implies rendering the backbuffer at a constant 60 fps, I think the only way to get around this would involve rendering the 3d scene into an offscreen render target on a separate thread.
Quote:
Original post by swiftcoder Quote:In that case, I am afraid that you are pretty much out of luck until multi-threaded rendering hits mainstream.
Original post by Khaos Dragon
Since this implies rendering the backbuffer at a constant 60 fps, I think the only way to get around this would involve rendering the 3d scene into an offscreen render target on a separate thread.
Well for concept's sake, is the solution I posited in my original post theoretically possible with D3D9, even if it would require an insane amount of work to implement?
A very basic test of the concept could for instance, break up the 3d scene rendering into 3 serial phases. If this could be shown to work, then one could proceed to break up the 3d scene rendering into 5-10 phases
Here is some pseudo code:
//render portion of main thread game looplock(L)setBackBufferRenderTargetclearScenebeginScenerenderFullScreenQuad( RenderTargetB)renderHUDendSceneunlock(L)//3d scene rendering thread, (doPhase(0) + doPhase(1) + doPhase(2) = a complete 3d scenebool renderCompleted = falselock(L)setRenderTargetA as render target//doPhase makes no assumptions about the current render state settings and explicitly sets all render target states it needs doPhase( currentPhase++ )if( currentPhase == 3 ){//render has completedcopy RenderTargetA to RenderTargetBcurrentPhase = 0}unlock(L)My expectation with an implementation like this is that the 3d scene would render slower than it originally did using a single threaded approach, but that the HUD would render and respond to input faster.
[Edited by - Khaos Dragon on March 21, 2009 10:45:31 AM]
You want stable 60 fps for rendering; which means that both your GPU and render thread frame time have to be <= 16.6 ms.
The only way to bound GPU frame time is to manually split the work you're trying to do - i.e. render half of the visible batches in first frame (to offscreen RT), render another half in second one, copy offscreen RT contents to back buffer. This is not going to change with D3D11. Also, this is a lot of work, given the asynchronous nature of CPU-GPU interaction. There is a GPU packet scheduler in Vista, which can make the task possible - I don't know enough details though (it will require two D3D devices for certain, possibly two processes?).
If you're certain that the GPU time will always be within adequate limits, the only concern is render thread and driver CPU time - if D3D Runtime + driver overhead is below 16 ms, you can put that in a separate thread, move all other render-related calculations in some other thread and enjoy the results. Otherwise you'll again have to split your render-related work in batches.
Overall, the only two remotely practical solutions I see is either split the render work in medium-sized batches by hand, dynamically adjusting the amount of batches you can push per frame according to framerate, or do it more or less automatically using a stub device which captures D3D commands and does splitting behind the scenes - http://www.emergent.net/en/About/Resources/Microsoft-XNA-GameFest-2008/ contains the relevant details on capturing/replaying commands (you're on your own with splitting, which will involve problems with maintaining state between batch boundaries).
Oh, and you can optimize your game to achieve target framerate even on slower machines (perhaps with some non gameplay related features disabled).
The only way to bound GPU frame time is to manually split the work you're trying to do - i.e. render half of the visible batches in first frame (to offscreen RT), render another half in second one, copy offscreen RT contents to back buffer. This is not going to change with D3D11. Also, this is a lot of work, given the asynchronous nature of CPU-GPU interaction. There is a GPU packet scheduler in Vista, which can make the task possible - I don't know enough details though (it will require two D3D devices for certain, possibly two processes?).
If you're certain that the GPU time will always be within adequate limits, the only concern is render thread and driver CPU time - if D3D Runtime + driver overhead is below 16 ms, you can put that in a separate thread, move all other render-related calculations in some other thread and enjoy the results. Otherwise you'll again have to split your render-related work in batches.
Overall, the only two remotely practical solutions I see is either split the render work in medium-sized batches by hand, dynamically adjusting the amount of batches you can push per frame according to framerate, or do it more or less automatically using a stub device which captures D3D commands and does splitting behind the scenes - http://www.emergent.net/en/About/Resources/Microsoft-XNA-GameFest-2008/ contains the relevant details on capturing/replaying commands (you're on your own with splitting, which will involve problems with maintaining state between batch boundaries).
Oh, and you can optimize your game to achieve target framerate even on slower machines (perhaps with some non gameplay related features disabled).
Can you not just do it a single thread?
offcourse this is extremely simplfied, but it gives the general idea. You would only call Render3D if there is enough time to do so and still hit the 60fps.
offcourse this is extremely simplfied, but it gives the general idea. You would only call Render3D if there is enough time to do so and still hit the 60fps.
void Render(){ Start(); if(ReRender3D) Render3D();//render to offscreen target 3DRenderSurface->Draw(); RenderHud(); End(); Present();}
youre just trying to create extra work for yourself
if the user finds the game framerate to slow, give them options
A/ decrease framebuffer size
B/ turn off effects
the user is king, let them decide.
you could give them the option to enable dynamic toggle of certian things eg if framerate drops below Xhz then render next frame particles at 1/4size etc
if the user finds the game framerate to slow, give them options
A/ decrease framebuffer size
B/ turn off effects
the user is king, let them decide.
you could give them the option to enable dynamic toggle of certian things eg if framerate drops below Xhz then render next frame particles at 1/4size etc
Topic Locked
This topic has been locked by a moderator. New replies are not allowed.
Sign in to reply to this topic.
Advertisement