If presentation events start arriving late (by whole frame intervals!) due to the GPU being overwhelmed then it's already too late to fix it and we would get stuck in a negative feedback loop of dropping frames and staying at a low GPU frequency. Because frame rate decimation increases GPU idle time, which makes the driver think the current frequency is adequate.
To avoid that problem we now plan ahead what the ideal next dispatch time after the current one would be. And we stick to that time (the native refresh rate) regardless of whether the previous frame is finished. This triple buffering allows mutter to reach 100% GPU utilization (if required) which then encourages the GPU to scale up frequency (if required).
Performance measurements at 4K 60Hz, on an i7-7700 with GPU base frequency of 350MHz, max frequency 1150MHz:
|Test||FPS Before||MHz Before||FPS After||MHz After|
|1 small window||60||350||60||350|
|1 big window||59||364||60||364|
|1 big window overview||30||363||60||474|
|2 big windows overview||30||930||60||1150|
|4 big windows overview||20||1150||30||1150|
This shows frame rates now only drop after the maximum GPU frequency is reached.
More test cases.
Add support in the native backend, since the feature is only enabled on Xorg right now.