Reliable and efficient busy-waiting?
Posted: 14 Dec 2020, 03:56
I made a small OpenGL program from scratch that does little but alternate between black and white frames with some control of V-sync and frame rate using QueryPerformanceCounter spinning.
When it works, it works surprisingly well. Using a refresh rate set to exactly 60Hz, the tear line manifesting in an arbitrary position on the screen remains static with virtually no drifting. However, once in a while, it can suddenly jump, either a few hundred lines, or in some cases a whole frame. Considering that I am just checking whether enough time has passed since the last frame began, it's no surprise that it will miss the mark ever so slightly occasionally, but the amount it sometimes misses is concerning. In addition, this is occupying an entire CPU core's worth of resources despite being a lightweight workload in principle. It wouldn't surprise me if some internal thread scheduler then causes the aforementioned hitches in part due to the busy-waiting being a hog. Some further observation is that, while the tear line's base position remains static, there is some rather major jitter between every frame that is significantly affected by keyboard and mouse input. Holding down the ctrl key while moving the mouse can push the line almost a quarter of the screen down.
Using the Sleep function before entering the loop mitigates some of the high CPU utilization, but it's far too inaccurate for something this sensitive, especially so at 120Hz where it never stabilizes. I've also tried using YieldProcessor (_mm_pause instruction), but it had no impact I could detect.
What are some further steps that could be taken to, most importantly, ensure that the frame always begins on schedule, but also not unnecessarily leech off CPU cycles?
When it works, it works surprisingly well. Using a refresh rate set to exactly 60Hz, the tear line manifesting in an arbitrary position on the screen remains static with virtually no drifting. However, once in a while, it can suddenly jump, either a few hundred lines, or in some cases a whole frame. Considering that I am just checking whether enough time has passed since the last frame began, it's no surprise that it will miss the mark ever so slightly occasionally, but the amount it sometimes misses is concerning. In addition, this is occupying an entire CPU core's worth of resources despite being a lightweight workload in principle. It wouldn't surprise me if some internal thread scheduler then causes the aforementioned hitches in part due to the busy-waiting being a hog. Some further observation is that, while the tear line's base position remains static, there is some rather major jitter between every frame that is significantly affected by keyboard and mouse input. Holding down the ctrl key while moving the mouse can push the line almost a quarter of the screen down.
Using the Sleep function before entering the loop mitigates some of the high CPU utilization, but it's far too inaccurate for something this sensitive, especially so at 120Hz where it never stabilizes. I've also tried using YieldProcessor (_mm_pause instruction), but it had no impact I could detect.
What are some further steps that could be taken to, most importantly, ensure that the frame always begins on schedule, but also not unnecessarily leech off CPU cycles?