Sign in to follow this  
reaperrar

DX9 Rendering - Present issues

Recommended Posts

I think the wait during the IDirect3DDevice9::Present call is causing issues with my program. I'm currently using a timer to manage how often my physics update. It is important the physics is updated a fixed number of times per second. I have it currently set to 60 and am in the middle of testing.

When running my application (rendering a single sprite atm) with no vertical sync / frame limit the physics will receive its 60 updates per second (and the fps is 9000+).

When having either vertical sync or a frame limit enabled the physics will receives less updates per second (45-49, it is not very consistent).

I beleive the wait/sleep time resulting from the present call is the cause.

I split the rendering onto a seperate thread for testing and that resolved the problem, 60 physics updates / second with vertical sync/frame limit enabled or disabled. Though since I do not want to make all my transformations thread safe this multithreaded rendering isn't viable for me.

I did a little research for a simpler approach and found that I could use the IDirect3DSwapChain9::Present method with a D3DPRESENT_DONOTWAIT flag instead. So I store the swap chain (m_poDevice->GetSwapChain(0, &poSwapChain);) and tried that. Problem is it didn't change a thing and D3DERR_WASSTILLDRAWING is never returned.

Anyone able to help me with my problem?

Share this post


Link to post
Share on other sites
Ok, so when you Present with VSync enabled, you're effectively telling D3D that you're done for the frame, and it can hold up your thread for the rest of the frame if it feels like it. You get your thread back 16ms later, having missed out on a whole bunch of physics processing, so your [font=courier new,courier,monospace]if[/font] condition triggers and you do a single physics update ([i]before presenting and going to sleep for too long again[/i]).
Instead of going back to sleep (Presenting) after each single physics update, you could try performing as many updates as are required to catch up -- i.e. change your [font=courier new,courier,monospace]if[/font] statement to a [font=courier new,courier,monospace]while[/font] statement.

Share this post


Link to post
Share on other sites
I understand this, though shouldn't I be able to avoid that 16ms altogether? Through research I was led to believe IDirect3DSwapChain9::Present + D3DPRESENT_DONOTWAIT would achieve what I want (though it does not seem to be working).

Share this post


Link to post
Share on other sites
[quote name='Seabolt' timestamp='1347574879' post='4979863']
You should be able to create your device with D3DPRESENT_INTERVAL_IMMEDIATE
[/quote]
I do if I do not want vsync enabled...

Just had a thought, is it threadsafe to have present called on a seperate thread (while making sure not to make any rendering calls until it is finished)?

Share this post


Link to post
Share on other sites
[quote name='reaperrar' timestamp='1347531583' post='4979656']I understand this, though shouldn't I be able to avoid that 16ms altogether?[/quote]In order to vsync, your display thread has to wait until the monitor has finished displaying the previous frame, and is about to request a new frame. If you have a 60Hz monitor, this will occur every 16.66ms.
Lets say that right after Presenting, your game does 1.66ms of work, and then calls Present again -- this means that Present will sleep for 15ms. If you want to avoid Present sleeping for long periods, then you mustn't call it until the end of the frame.
In other words, make sure that you do ~16ms worth of work in between every call to Present.
[quote]Through research I was led to believe IDirect3DSwapChain9::Present + D3DPRESENT_DONOTWAIT would achieve what I want (though it does not seem to be working).[/quote]"[font=courier new,courier,monospace]DONOTWAIT[/font]" is a hint ([i]many drivers ignore the hint[/i]) to D3D meaning "[i]if you're going to sleep until a vsync, I'd rather that you instead did nothing at all (don't present) and returned [font=courier new,courier,monospace]D3DERR_WASSTILLDRAWING[/font][/i]". If you use that mode, you've got to repeatedly call Present over an over again until it doesn't return that error code -- and if you don't call it often enough, you can miss the vblank which results in your game not being vsync'ed any more.[quote name='reaperrar' timestamp='1347579402' post='4979889']is it threadsafe to have present called on a seperate thread[/quote]No, it must be called from the thread that created your window ([i]and all other DX9 calls should also be made on this thread[/i]). Edited by Hodgman

Share this post


Link to post
Share on other sites
This is disappointing, is it only a dx9 issue?

Also, are their any articles on how to efficiently structure a dx9 app to work with this sleep time. I'm guessing we calculate the sleep time based on refreshrate / max frames, continue updating until we've almost exceeded that time then do the render / present?

Share this post


Link to post
Share on other sites
It doesn't have to be that much of an issue -
* if you're targeting 60FPS, then your game loop already needs to execute faster than 16.6ms every time ([i]and running more often that that isn't required[/i]).
* if you're vsync'ing, then any unused time (16.6 - frame time) will be used by vsync, meaning that your frame-times are padded out to 16.6ms.

Maybe check out [url="http://gafferongames.com/game-physics/fix-your-timestep/"]fix your timestep[/url] and/or post your game-loop/timing code? Edited by Hodgman

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this