pop-os / cosmic-comp

Compositor for the COSMIC desktop environment
GNU General Public License v3.0
489 stars 93 forks source link

Window on workspace moved back to hotplugged monitor not getting frame callbacks #985

Closed ids1024 closed 4 days ago

ids1024 commented 1 week ago

Reproduction:

This can result in a state where the (vkgears) window on the second monitor is frozen.

When the window is like this, it updates at 1fps when the cursor is moved, but even the 1 fps throttled frame callbacks don't occur when there isn't input. Opening another window on the same workspace causes it to update at 1 fps if the other window is redrawing.

Switching to a different workspace and back on the affected monitor fixes the issue. Going through the code that's called in that case, it surprisingly seems to be related to animations. If animate is set to false in WorkspaceSet::activate, switching the workspace and back does not make the window start drawing at a normal frame rate. So somehow setting previously_active triggers some later code that fixes the state, but it's unclear how...

Related issues:

ids1024 commented 1 week ago

Okay, even weirder: instead of setting animate to false, setting previous_idx to None in src/backend/kms/surface/mod.rs also makes switching workspaces not fix this. So somehow calling workspace_elements is what's fixing the state of the surface?

ids1024 commented 1 week ago

In render_input_order_internal, this seems to be related to the offset of the Stage::Workspace.

So when it renders the window with a different/non-zero offset, somehow that fixes the rate at which it gets frame callbacks.

ids1024 commented 1 week ago

(I was assuming activate ended up calling or setting something that the code moving workspaces to a different output didn't, and it would be simple to add that there once it was identified. This is stranger than I expected, but hopefully useful context, though I'm not sure what to make of it or where to go from here...)

ids1024 commented 1 week ago

COSMIC_DISABLE_DIRECT_SCANOUT=1 doesn't seem to change things, so this isn't related to direct scanout.

But somehow relates to the offset used with RescaleRenderElement.

ids1024 commented 1 week ago

Looks like the reason offset impacts this is that default_primary_scanout_output_compare compares how much area of the surface appears on an output. So shrinking that area then growing it again triggers switching to the new output as the scanout output.

The issue where workspaces aren't always moved back is probably because this laptop dynamically adds DRM connectors, and the numbering isn't entirely consistent. Maybe we could do better to identity the "same monitor", though that's inherently imperfect.