jingwood / d2dlib

A .NET library for hardware-accelerated, high performance, immediate mode rendering via Direct2D.
MIT License
244 stars 45 forks source link

Only 60fps ? Vsync issue ? #124

Open dorlip07 opened 3 weeks ago

dorlip07 commented 3 weeks ago

Hello, thank you for this excellent project! I've noticed a problem, I never go over 60fps on the projects I've done with d2dlib. Is this a Direct2D limit, a d2dlib limit, or a problem with vertical synchronization enabled (vsync)? Thanks in advance for your feedback.

Bobbar commented 2 weeks ago

See: https://github.com/jingwood/d2dlib/blob/35feb92a86b5d692cd3aba77133e9aebe8f35978/src/d2dlib/Context.cpp#L73

D2D1_PRESENT_OPTIONS are not specified and not exposed in the API, so it defaults to D2D1_PRESENT_OPTIONS_NONE which means EndRender()/EndDraw() will always block until next v-sync.

It's a limit of d2dlib currently. But it's trivial to expose it.

drewnoakes commented 2 weeks ago

Thanks @Bobbar,

D2D1_PRESENT_OPTIONS_IMMEDIATELY The render target does not wait until the display refreshes to present.

Does this mean that a 60fps limit implies that's the displays max refresh rate? If so, what benefit would there be to rendering more often than that?

Bobbar commented 2 weeks ago

@drewnoakes

Does this mean that a 60fps limit implies that's the displays max refresh rate?

I assume it would be whatever your current refresh rate is set to. If you had a 120hz display and 120hz set in the driver, it would limit to 120 FPS. (Assuming the D2D pipeline, GPU and the managed code stuff can finish in time)

If so, what benefit would there be to rendering more often than that?

Say you want to test your game/simulation//UI/whatever at a higher than available refresh rate, or want to speed up some visualization at a constant time delta without having to roll your own deferred rendering and syncing of threads. Basically, it gives you the option to make your main advance & render loop run as fast as possible.

Perhaps a little niche, but that's been my use cases. I'm imagine there's others.

Bobbar commented 2 weeks ago

Added a quick little PR to expose the present options.

jingwood commented 2 weeks ago

Thanks, @Bobbar! PR merged.

I tested setting D2D1PresentOptions to Immediately and adjusted the redraw timer interval to 1 (meaning virtually no delay between redraws). However, the FPS remained around 60-65.

I also tried lowering the display refresh rate to 30Hz, but there was no change; the FPS stayed between 60-65. It seems something else might be limiting frequent redraws—perhaps a restriction within the Windows Desktop Management, like the handling of window messages.

Additionally, I noticed that when continuously resizing the window by dragging, Windows keeps sending redraw messages, and the FPS can spike up to 150 in those instances.

Bobbar commented 2 weeks ago

@jingwood

I tested setting D2D1PresentOptions to Immediately and adjusted the redraw timer interval to 1 (meaning virtually no delay between redraws). However, the FPS remained around 60-65.

I think you are just seeing the resolution limit of the Timer class. I just tested Timer by itself, with no rendering inside of Tick(), and with the interval set to 1 it was still only firing at 60Hz (16000 ticks). In my projects I'm using a tight while loop running on another thread to fire the rendering events, and it will hit 1000FPS+ if I let it.

I also tried lowering the display refresh rate to 30Hz, but there was no change; the FPS stayed between 60-65. It seems something else might be limiting frequent redraws—perhaps a restriction within the Windows Desktop Management, like the handling of window messages.

Likely the same issue as the first part if it was still set to Immediately. Does it still do 60 if it's set to None?

Additionally, I noticed that when continuously resizing the window by dragging, Windows keeps sending redraw messages, and the FPS can spike up to 150 in those instances.

I've noticed this too. It seems to be something with the resizing the context. It causes the next several EndRender calls to not block. It's mystery to me.