Present extension based scheduler doesn't work well on NVIDIA drivers.
GLX_SGI_video_sync is less accurate, but is rumoured to work. See
[kwin's usage](https://invent.kde.org/plasma/kwin/-/blob/master/src/
backends/x11/standalone/x11_standalone_sgivideosyncvsyncmonitor.cpp)
Signed-off-by: Yuxuan Shui <yshuiv7@gmail.com>
It's kind of dumb anyway. If we get damage event right after a vblank
event, we would waste the whole vblank.
Instead improve the frame scheduling logic to target the right vblank
interval. This only affects smart_frame_pacing anyway.
Signed-off-by: Yuxuan Shui <yshuiv7@gmail.com>
Right now we rely on `reschedule_render_at_vblank` being scheduled for
the render finish check. Which means we will only know if a frame has
finished rendering the next time we queue a render. And we only check at
vblank boundary, which means when a render is queued we have to wait for
the next vblank, when had we checked earlier, we will be able to start
rendering immediately
Signed-off-by: Yuxuan Shui <yshuiv7@gmail.com>
Also, vblank event callback should call schedule_render to queue renders
instead of starting the draw timer directly, so that the CPU time
calculation will be correct.
Signed-off-by: Yuxuan Shui <yshuiv7@gmail.com>
Disable timing estimation based pacing by default, as it might not work
well across drivers, and might have subtle bugs.
You can try setting `PICOM_DEBUG=smart_frame_pacing` if you want to try
it out.
Signed-off-by: Yuxuan Shui <yshuiv7@gmail.com>
Factored out vblank event generation, add abstraction over how vblank
events are generated. The goal is so we can request vblank events in
different ways based on the driver we are running on.
Tried to simplify the frame scheduling logic, we will see if I succeeded
or not.
Also, the logic to exclude vblank events for vblank interval estimation
when the screen off is dropped. It's too hard to get right, we need to
find something robust.
Signed-off-by: Yuxuan Shui <yshuiv7@gmail.com>
We unredirect because we receive bad vblank events, and also vblank
events at a different interval compared to when the screen is on. But it
is enough to just not record the vblank interval statistics when the
screen is off.
Although, unredirecting when display is off can also fix the problem
where use-damage causes the screen to flicker when the display is turned
off then back on. So we need something else for that.
Signed-off-by: Yuxuan Shui <yshuiv7@gmail.com>
Previously everytime we receive a vblank event, we always request a new
one. This made the logic somewhat simpler. But this generated many
useless vblank events, and wasted power. We only need vblank events for
two things:
1. after we rendered a frame, we need to know when it has been displayed
on the screen.
2. estimating the refresh rate.
This commit makes sure we only request vblank events when it's actually
needed.
Fixes#1079
Signed-off-by: Yuxuan Shui <yshuiv7@gmail.com>
Make it simpler to stop requesting PresentCompleteNotify when there is
nothing to render.
Related: #1079
Signed-off-by: Yuxuan Shui <yshuiv7@gmail.com>
I mistakenly assumed that PresentCompleteNotify event signifies the end
of a vblank (or the start of scanout). But actually this event can in
theory in sent at any point during a vblank, with its timestamp pointing
to when the end of vblank is. (that's why we often find the timestamp to
be in the future).
Add a delay so schedule_render is actually called at the end of vblank,
so it doesn't mistakenly think the render is too slow to complete.
Signed-off-by: Yuxuan Shui <yshuiv7@gmail.com>
paint_process would return NULL for both of these cases, but we should exit in
the failure case, and continue going in the other.
Signed-off-by: Yuxuan Shui <yshuiv7@gmail.com>
This usually means there is another compositor running. If we don't do
this picom will spin forever.
Fixes#1104
Signed-off-by: Yuxuan Shui <yshuiv7@gmail.com>
One annoying thing is C23 still defines auto as a storage class despite
it now being used for type inference. As a consequence we must write
"auto const" instead of the more natural "const auto".
Signed-off-by: Yuxuan Shui <yshuiv7@gmail.com>
Part of the long running effort to reduce the prevalence of `session_t`.
After this, functions that communicate with X can make use of the error
handling machinary (set_ignore_cookie, set_cant_fail_cookie) without
needing to take a `session_t` parameter.
This commit converts everything to use the new struct `x_connection`,
most of the conversions are mechanical.
Signed-off-by: Yuxuan Shui <yshuiv7@gmail.com>
Don't use pthread_{set,get}schedparam, which requires -lpthread. Use
sched_setscheduler/sched_getparam instead, which is provided by libc.
Signed-off-by: Yuxuan Shui <yshuiv7@gmail.com>
FreeBSD doesn't have RLIMIT_RTPRIO. So instead we skip this check and
just always try to set our priority to the lowest SCHED_RR priority
available.
Fixes#1082
Signed-off-by: Yuxuan Shui <yshuiv7@gmail.com>
Sometimes a scheduled render can end up doing nothing, e.g. if the
damage region is empty. In that case we don't have valid data to
collect and thus shouldn't update the statistics.
Signed-off-by: Yuxuan Shui <yshuiv7@gmail.com>
Add a render_statistics type to encapsulate all the statistics done on
rendering times. And use that to estimate the time budget for rendering
and frame pacing.
Tweak the rolling window utilities a bit so we can reuse one rolling
window for multiple statistics.
Signed-off-by: Yuxuan Shui <yshuiv7@gmail.com>
We only checked render time. If we don't have frame time estimates, we
would divide by zero and end up with wild scheduling delays.
Signed-off-by: Yuxuan Shui <yshuiv7@gmail.com>
So when the screen is off, we calls queue_redraw, hoping draw_callback
will be called and unredirects the screen. However, queue_redraw doesn't
queue another redraw when one is already queued. Redraws can be queued
in two ways: one is timer based, which is fine, because it will be
triggered no matter what; the other is frame based, which is triggered
by Present events.
When the screen is off, X server, depends on the driver, could send
abnormal Present events, which we ignore. But that also means queued
frame based redraw will stop being triggered.
Those two factors combined means sometimes unredirection does not happen
when the screen is off. Which means we aren't going to free the GL
context, which are still receiving Present events, but can't handle
them, because we are not rendering anything with GL. In the end all
these causes memory usage to balloon, until the screen is turned on and
we start rendering again.
And all these is not caught by leak checkers because this technically is
not a leak, as everything is eventually freed.
Signed-off-by: Yuxuan Shui <yshuiv7@gmail.com>
Sometimes X sends bogus complete notifies with invalid msc number.
Instead use a saved msc number to get the next complete notify.
Signed-off-by: Yuxuan Shui <yshuiv7@gmail.com>
Timer can sometimes drift randomly, like when the system is suspended.
we don't want to disable frame pacing for that
Signed-off-by: Yuxuan Shui <yshuiv7@gmail.com>
When the screen turns off, X sometimes sends present complete notify for
the same frame multiple times, or even events with invalid msc/ust
number.
This will cause us to ignore it and not send a subsequent NotifyMsc
request, causing the complete notify to stop.
Now we send NotifyMsc regardless to keep the events going.
Also detect when the complete notifies skip frames, divide the interval
by frame count to estimate frame time in that case.
Upstream bug report:
https://gitlab.freedesktop.org/xorg/xserver/-/issues/1418
Signed-off-by: Yuxuan Shui <yshuiv7@gmail.com>
Use frame timing and render time statistic to pace frames.
Right now the criteria are simple:
* Don't render multiple frames in one vblank cycle. Otherwise the
rendered frame will be delay multiple cycles, which isn't ideal.
* Start rendering as late as possible while still hitting vblank.
Refresh rate is estimated from a rolling average of frame timing. Render
time is predicted from the rolling maximum of past 128 frames. The
window size still needs to be investigated.
Remove glFinish calls and GL_MaxFramesAllowed=1, frame pacing superseeds
them.
Professionals might laugh at how rudimentary this is, but hopefully this
is better than what we had before. Which is absolutely nothing at all.
Signed-off-by: Yuxuan Shui <yshuiv7@gmail.com>
there are two x extensions for working with monitors (especially
multiple): xinerama and randr. xinerama is old, feature-poor and in
general isn't used anymore compared to the randr: new, feature-rich and
widely-used. for some reason we were using both of them, so let's drop
xinerama to keep things simple, clean and small. and to be modern.
the drop was done in three steps:
* first step was to replace all the xinerama-based code with the
randr-based one and to replace or remove all the xinerama mentions;
* second step was to replace the xinerama's terminology with the
randr's one. xinerama was referring only to the word "screen", while
randr refers to multiple words and i think the word "monitor" is the
most suitable for us and, hopefully, clear both to a contributor and
to an end user;
* third step was to refactor the new randr-based code if needed and to
address related todo's (mostly about moving related functions
elsewhere).
all the steps were done well except addressing a leftover todo about
moving the win_update_monitor function to the x.c which wasn't done.
the xinerama-shadow-crop option was renamed to crop-shadow-to-monitor,
but it's previous name is still accepted, has effect and the
deprecation message is printed to preserve backwards-compatibility.
Use the DPMS extension to detect if screen is turned off, and unredirect
if it is. This also helps working around the problem where OpenGL
buffers lose data when screen is turned off, causing screen to flicker
later when it turns back on if use-damage is enabled.
Unfortunately the DPMS extension doesn't define an event, so we have to
periodically poll the screen state.
Signed-off-by: Yuxuan Shui <yshuiv7@gmail.com>
We used to have a list of X errors we should ignore in case they do
occur. This commit expands that functionality to also allow us aborting
on certain errors.
Signed-off-by: Yuxuan Shui <yshuiv7@gmail.com>
Transparent clipping interacts poorly with programs whose transparent
interface elements must show windows below them for functionality,
for example screenshot utilities.
This needs the EGL_KHR_image_pixmap and the GL_EXT_EGL_image_storage
extensions, which unfortunately aren't available on NVIDIA cards.
Don't add documentation for these, for now.
Signed-off-by: Yuxuan Shui <yshuiv7@gmail.com>