Instead of handling both cases in a single function, split the work of
populating the atomic request in two new functions, and keep the common
bits in drm_prepare.
Shouldn't have any functional change.
drm_can_avoid_composite doesn't merely checks whether we can avoid
composition: it also prepares a pending atomic request. It's always
necessary to call this function before drm_atomic_commit.
Rename the function to make this clearer.
Before the window is mapped, the client can set the initial NET_WM_STATE
directly in the window property. After the window is mapped, the client
must use a client message and shouldn't touch the property anymore.
Sometimes we hide our window and show it again after some time.
SDL_SetRelativeMouseMode doesn't seem to properly cope with this, at
least on my setup.
VUID-VkSwapchainCreateInfoKHR-surface-01270(ERROR / SPEC): msgNum: -1585220531 - Validation Error: [ VUID-VkSwapchainCreateInfoKHR-surface-01270 ] Object 0: handle = 0x628000040100, type = VK_OBJECT_TYPE_DEVICE; | MessageID = 0xa183744d | vkCreateSwapchainKHR(): pCreateInfo->surface is not known at this time to be supported for presentation by this device. The vkGetPhysicalDeviceSurfaceSupportKHR() must be called beforehand, and it must return VK_TRUE support with this surface for at least one queue family of this device. The Vulkan spec states: surface must be a surface that is supported by the device as determined using vkGetPhysicalDeviceSurfaceSupportKHR (https://www.khronos.org/registry/vulkan/specs/1.2-extensions/html/vkspec.html#VUID-VkSwapchainCreateInfoKHR-surface-01270)
VUID-vkCreateInstance-ppEnabledExtensionNames-01388(ERROR / SPEC): msgNum: -437968512 - Validation Error: [ VUID-vkCreateInstance-ppEnabledExtensionNames-01388 ] Object 0: VK_NULL_HANDLE, type = VK_OBJECT_TYPE_INSTANCE; | MessageID = 0xe5e52180 | Missing extension required by the instance extension VK_KHR_external_memory_capabilities: VK_KHR_get_physical_device_properties2. The Vulkan spec states: All required extensions for each extension in the VkInstanceCreateInfo::ppEnabledExtensionNames list must also be present in that list (https://www.khronos.org/registry/vulkan/specs/1.2-extensions/html/vkspec.html#VUID-vkCreateInstance-ppEnabledExtensionNames-01388)
In file included from ../src/steamcompmgr.cpp:74:
src/steamcompmgr.hpp:75:7: warning: private field 'm_hasPlane' is not used [-Wunused-private-field]
bool m_hasPlane;
^
src/steamcompmgr.cpp: In function 'void statsThreadMain()':
src/steamcompmgr.cpp:357:62: error: 'O_WRONLY' was not declared in this scope
357 | statsPipeFD = open( statsThreadPath.c_str(), O_WRONLY );
| ^~~~~~~~
src/steamcompmgr.cpp:357:31: error: 'open' was not declared in this scope; did you mean 'popen'?
357 | statsPipeFD = open( statsThreadPath.c_str(), O_WRONLY );
| ^~~~
| popen
src/steamcompmgr.cpp: In function 'void steamcompmgr_main(int, char**)':
src/steamcompmgr.cpp:2559:61: error: 'O_WRONLY' was not declared in this scope
2559 | readyPipeFD = open( optarg, O_WRONLY );
| ^~~~~~~~
src/steamcompmgr.cpp:2559:47: error: 'open' was not declared in this scope; did you mean 'popen'?
2559 | readyPipeFD = open( optarg, O_WRONLY );
| ^~~~
| popen
Should let people run against Intel and other non-AMD Mesa GPUs.
Also force compute+graphics if vkBasalt is enabled, as it won't support
compute-only rings. Also always composite if vkBasalt is enabled, so it
applies always in embedded.
Calling nice() in the very beginning ensures that Mesa worker threads in
gamescope and Xwayland can properly reduce their priority without us stomping
it later.
Move away from posix_spawn, since there's no easy way (that seems to work)
to keep priority normal for the spawned process and get the right behaviour
for gamescope and Xwayland.
The intermediate fork() lets us simplify the logic for LD_PRELOAD rewriting.
Avoid setting it for our children processes, by spawning them in a new
thread group and setting group-wide priority, which also conveniently
gets Xwayland.
If running through Steam, we want the overlay hooked into gamescope and
not the underlying game, or we'll get double overlay, and one with wrong
scaling.
This strips any token containing gameoverlayrenderer.so from LD_PRELOAD.
The new-ish code to listen for destroy on surfaces on the wlserver side
installs a dynamic listener. We need to remove it from the list before
freeing it, or wayland will try to do it when the signal gets destroyed,
which involves updating the link member in the freed memory.
Some xcb protocol allocations would often get allocated there in that
short time window and get scribbled on.
https://github.com/Plagman/gamescope/issues/7
Ironic. 064d132c could save others from use-after-free, but not itself.
wlr_texture_to_dmabuf involves issuing EGL commands to get a DMA-BUF out
of an EGLImage.
When the client submits a DMA-BUF via the linux-dmabuf protocol, there's
no need to go through EGL. We can directly import the client's DMA-BUF
into Vulkan.
The old code is still retained as a fallback in case the client uses
wl_drm (old Xwayland) or wl_shm. Removing it would involve creating a
Vulkan-based wlr_renderer.
References: https://github.com/Plagman/gamescope/issues/16
Avoid override redirect windows.
Raise new windows, don't focus tiny windows. If we only raised windows
that want to be activated, we probably wouldn't need the hack to filter
out small windows. TBD.
When directly scanning out game buffers, we need to make sure the game
buffer is suitable for scanout. If that's not the case, we need to
fallback to composition.
The fallback path was implemented, but we never checked whether scan-out
is possible in drm_can_avoid_composite. Perform an atomic test-only
commit to fix this.
wlroots headers can mostly be included with extern "C" blocks. Two
exceptions are the use of `static` for array args and `class` as a
struct field. These can be #define'ed to avoid C++ build errors.
This allows the whole project to be built as a single C++ codebase,
without having to maintain hybrid header files.
This commit fixes two issues.
A first issue is that fbids_in_req was previously populated
drm_can_avoid_composite and read from in page_flip_handler. As a
result, calling drm_can_avoid_composite then page_flip_handler would
prevent drm_atomic_commit from referencing the right FBs
(page_flip_handler runs in a separate thread and clears fbids_in_req).
To fix this, add a new fbids_queued vector filled by drm_atomic_commit.
Make page_flip_handler read from this new vector instead of
fbids_in_req. As a bonus, this fixes a data race since fbids_queued is
now protected by flip_lock.
The second issue is that drm_can_avoid_composite assumes all layers made
it into a hw plane when liftoff_output_apply succeeds. That's not the
case because libliftoff supports mixed hw plane + composition (where
some layers make it into a hw plane and the others get composited).
To fix this, make drm_can_avoid_composite fail if some but not all
layers make it into a hw plane. In the future, we'll want to support the
mixed mode too.
Closes: https://github.com/Plagman/gamescope/issues/65
References: https://github.com/Plagman/gamescope/issues/41
Only works when switching to fbcon for now. We need to stop
page-flipping when the DRM FD is paused to support switching to another
compositor.
References: https://github.com/Plagman/gamescope/issues/6
win objects are allocated with `new`, so they need to be de-allocated
with `delete` instead of `free`.
==589398==ERROR: AddressSanitizer: alloc-dealloc-mismatch (operator new vs free) on 0x61200017f140
(EE) failed to read Wayland events: Broken pipe
X connection to :1 broken (explicit kill or server shutdown).
#0 0x7f5468ae4720 in __interceptor_free /build/gcc/src/gcc/libsanitizer/asan/asan_malloc_linux.cc:122
#1 0x559820f5c9a0 in finish_destroy_win ../src/steamcompmgr.cpp:1743
#2 0x559820f5ca6d in destroy_win ../src/steamcompmgr.cpp:1759
#3 0x559820f6163e in steamcompmgr_main ../src/steamcompmgr.cpp:2288
#4 0x559820f8e977 in steamCompMgrThreadRun() ../src/main.cpp:121
#5 0x559820f8e3e9 in void std::__invoke_impl<void, void (*)()>(std::__invoke_other, void (*&&)()) /usr/include/c++/9.3.0/bits/invoke.h:60
#6 0x559820f8e24f in std::__invoke_result<void (*)()>::type std::__invoke<void (*)()>(void (*&&)()) /usr/include/c++/9.3.0/bits/invoke.h:95
#7 0x559820f8e0b3 in void std:🧵:_Invoker<std::tuple<void (*)()> >::_M_invoke<0ul>(std::_Index_tuple<0ul>) /usr/include/c++/9.3.0/thread:244
#8 0x559820f8dfae in std:🧵:_Invoker<std::tuple<void (*)()> >::operator()() /usr/include/c++/9.3.0/thread:251
#9 0x559820f8d7ba in std:🧵:_State_impl<std:🧵:_Invoker<std::tuple<void (*)()> > >::_M_run() /usr/include/c++/9.3.0/thread:195
#10 0x7f5468006b23 in execute_native_thread_routine /build/gcc/src/gcc/libstdc++-v3/src/c++11/thread.cc:80
#11 0x7f546745346e in start_thread (/usr/lib/libpthread.so.0+0x946e)
#12 0x7f54673833d2 in clone (/usr/lib/libc.so.6+0xff3d2)
0x61200017f140 is located 0 bytes inside of 296-byte region [0x61200017f140,0x61200017f268)
allocated by thread T40 here:
#0 0x7f5468ae6968 in operator new(unsigned long) /build/gcc/src/gcc/libsanitizer/asan/asan_new_delete.cc:104
#1 0x559820f595fe in add_win ../src/steamcompmgr.cpp:1548
#2 0x559820f614e8 in steamcompmgr_main ../src/steamcompmgr.cpp:2278
#3 0x559820f8e977 in steamCompMgrThreadRun() ../src/main.cpp:121
#4 0x559820f8e3e9 in void std::__invoke_impl<void, void (*)()>(std::__invoke_other, void (*&&)()) /usr/include/c++/9.3.0/bits/invoke.h:60
#5 0x559820f8e24f in std::__invoke_result<void (*)()>::type std::__invoke<void (*)()>(void (*&&)()) /usr/include/c++/9.3.0/bits/invoke.h:95
#6 0x559820f8e0b3 in void std:🧵:_Invoker<std::tuple<void (*)()> >::_M_invoke<0ul>(std::_Index_tuple<0ul>) /usr/include/c++/9.3.0/thread:244
#7 0x559820f8dfae in std:🧵:_Invoker<std::tuple<void (*)()> >::operator()() /usr/include/c++/9.3.0/thread:251
#8 0x559820f8d7ba in std:🧵:_State_impl<std:🧵:_Invoker<std::tuple<void (*)()> > >::_M_run() /usr/include/c++/9.3.0/thread:195
#9 0x7f5468006b23 in execute_native_thread_routine /build/gcc/src/gcc/libstdc++-v3/src/c++11/thread.cc:80
Thread T40 created by T0 here:
#0 0x7f5468a0e377 in __interceptor_pthread_create /build/gcc/src/gcc/libsanitizer/asan/asan_interceptors.cc:208
#1 0x7f5468006df9 in __gthread_create /build/gcc/src/gcc-build/x86_64-pc-linux-gnu/libstdc++-v3/include/x86_64-pc-linux-gnu/bits/gthr-default.h:663
#2 0x7f5468006df9 in std:🧵:_M_start_thread(std::unique_ptr<std:🧵:_State, std::default_delete<std:🧵:_State> >, void (*)()) /build/gcc/src/gcc/libstdc++-v3/src/c++11/thread.cc:135
#3 0x559820f8ea10 in startSteamCompMgr ../src/main.cpp:126
#4 0x559820f95cfb in xwayland_ready ../src/wlserver.c:119
#5 0x5598210de191 in wlr_signal_emit_safe ../subprojects/wlroots/util/signal.c:29
#6 0x559820ff596b in xserver_handle_ready ../subprojects/wlroots/xwayland/xwayland.c:251
#7 0x7f5468744434 (/usr/lib/libwayland-server.so.0+0xa434)
#8 0x7ffc9796869f ([stack]+0x1f69f)
Activate libliftoff's internal log when layers are enabled and the parameter
'd' is provided.
Note: this needs some patches to libliftoff to make the debug readable that I
have proposed upstream.
Trying to layer onto planes should be continued when fb ids are set and
not the other way around. Here the assert also failed when only having
one layer.
It is enough to get the global cursor location when repainting it. So we do not
need to query the relative position. If later on we find this is not right we
should be still able to get the relative position from the surface position
instead of calling into XWayland.
Also it is not expected and apparently unnecessary to move the cursor in the
paint function. Therefore remove this call too.
With cursor position going through global variables we do not need to query the
global position anymore. Remove the MouseCursor function for that.
Furtheron the relative position getter is also not necessary, but let's remove
this one in a separate commit.
This commit also adds a debug line for debugging flaky focus changing.
Many code editiors remove trailing whitespace automatically making patches
difficult since often unrelated lines get changed with the same commit.
So remove the whitespace in the steamcompmgr file all at once in this separate
commit.
For now just mark one repaint per refresh interval without any particular
alignment, as that can be hard to get in nested. We'll use the display
timing extensions for that later.
We'll have it align properly in embedded mode soon.
- Add a commit wait thread that just waits for the work associated with
an in-bound dma-buff is done. We'd like to be getting a fence directly
from Wayland, but in the absence of that we'll make our own by tapping
into implicit-sync, DX11-style. gpuvis logging of the outcome of the
waits in the thread are consistent with the end of GPU work.
- Rework wayland commit handoff between wlserver and steamcompmgr to let
steamcompmgr have full access to the commit queue, letting it remove
elements in the middle and still keep going, compared to the previous
interface. This lets steamcompmgr get one commit per window per loop,
for now. We should be able to kick off waits and ref/unref resources
for all pending commits soon, with some work on the accounting first.
This should also fix an issue introduced recently where the overlay
could get really starved in embedded mode, as we were just getting
the first commit in the queue for a single frame.
It's a requirement of wlroots, since it uses it to get notified of
Xwayland readiness.
Having our threads use SIG_IGN would mean that they could still get
selected to get the signal and would just discard it, as opposed to
not being in the running at all. So the more threads we added, the
least chance we had of the notify function running consistently at
startup.
Now seems to consistently agree that XWayland is up every startup.
Add the concept of a cursor coordinate when that initializes when focusing
a surface.
Put some super primitive tap to left-click emulation in there for now.
If a window already has a buffer attached by the time we figure out it
exists and sets its role, we missed the initial commit and will never
get it. For windows that animate interactively, that's fine, as we'll
get another one soon enough, but 2D apps like launchers repaint on
demand, so it's not fine there.
If the base game is stuck before having rendered anything, we still want
to show overlay layers when they animate so the user can get out.
Let us composite and the empty texture should take care of it.
It's non-fatal, presumably we messed up source coordinates for that flip
but needs root-causing. Can happen in the very early loading of MGSV:TPP.
Fix a bug with the new flip lock where non-fatal flip errors would hang.
If we only take the first commit, we leave a bunch in the queue, which
makes us that much more likely to run out of FDs when importing the
myriad of buffer referenced coming from a non-vsynced client. Fixes
crashes with vblank_mode=0 glxgears after the recent changes.
We were always subject to such crashes, just getting lucky/fast before.
Use an empty dummy texture for unbound slots, as the driver can't know
what the shader will sample from.
Also remove any sort of implicit attempts at compaction of slots.
Import libliftoff as subproject and plumb our planes through it.
Wait for a flip to complete immediately after queuing it for now.
Also immediately wait for cursor image uploads, as we don't have to
do Vulkan rendering anymore after queuing an upload.
Cursor shows up with format hack, but is badly corrupt. We might need
to use a DRM dumb_fb rather than going through the same Vulkan image.
Alpha bits of surfaces are ignored again, need to make Steam select
an ARGB visual for overlay windows, probably.
Setting up the "alpha" plane property somehow makes overlays not
show up at all despite liftoff happily letting us go with scanout.
Only set implicit_sync on in-bound buffers, we'll sync our scanout image
ourselves by exporting the fence and passing to DRM, and flushing.
The fence export actually fails, so leave it commented our for now.
Flushing also doesn't do anything, the bottom of our scanout image is still
corrupt when scanning out to DRM.
So we can easily test single-app scenarios by generating placeholder
ones. Will also make it more robust by using Xres1.2, which should
remove the need for Alkazar's patch for Dead Cells and other apps that
don't get tagged right by the current overlay.
It worked well enough with the Big Picture cursor, and seeing it change
scales between Steam and a game was sometimes jarring, but it doesn't
compute hotspot offset right, and scaling cursors doesn't come out great
a lot of the time.
We're in sole control of the cursor now, there's no "fake" cursor anymore.
Don't attempt to hide it in X, it doesn't matter.
Also Vulkan rendering of a texture populated from arbitrary bits.
Also add the third layer to the shader... Badly needs clean-up.
This should make steamcompmgr messages actually go when we send them.
We're pulling too many frames out of "vsynced" clients now, need to instill
a real frame cadence based on vblank and notify based on that.
The WL_SURFACE_ID messages force us to register SubstructureRedirectMask,
which means we have to participate in a bunch more stuff before windows
will resize and reconfigure properly. This fixes a bunch of problems with
real games.
Main motivation was to have a clean-ish spot to add a ping-pong
command-buffer instead of allocating one every frame. Leaking
significantly less GTT now.
Also add some more leading whitespace courtesy of Kate.
Doesn't help running out right now, as the DMA-BUFs from a new app
frame get imported as different Vulkan textures. Not sure how to
ensure continuity across several sightings of the original swapchain
images yet.
As Bas points out, their original WSI allocated them expecting them to
get scanned out, so this has a better chance of describing their memory
layout in the absence of full modifiers. This fixes corruption for me
on Vega at least, but glxgears colors are swapped still.
Lower half is getting eaten by something, presumably underflow as it's black.
Make EGL and DRM coexist; make ensure_win_resources safe to call regardless
of what resources we want, so outer code doesn't have to care.
frames out of thin air.
Also use dummy ClientMessage events to nudge steamcompmgr's event loop,
Expose events have a meaning and we don't want to confuse some clients.
And remove rootston's output render path. This seems like it was the only
strictly needed thing, frames seem to time out without that. Will probably
find bugs later.
That should help setting it up on a machine that might want to use normal
wlroots for other things. Resolve a GL symbol conflict now that we're
colocated with wlroots' dynamic loading code.
Get steamcompmgr's GL context from EGL and rip out GLX, as we need EGL to
import dma-bufs.
When new buffers are committed to surfaces, push their information to
steamcompmgr (without any feedback for now, fire-and-forget).
Can render games now.
Enable C++ for bits of the code, but nothing that includes wlroots as that
doesn't want to build as C++.
Enable SubstructureRedirectMask mode and handle MapRequest for now; this lets
us get the WL_SURFACE_ID ClientMessages.
This uses a build of wlroots that has its internal XWM ripped out.
steamos-compositor (1.32) brewmaster; urgency=medium
* Fix a bug where cursor would be auto-hidden even when buttons held
* Show cursor if a button gets clicked while it's hidden
steamos-compositor (1.30) brewmaster; urgency=medium
* Added preliminary support for screen magnification.
* Increase cursor hiding time to 10 seconds.
* Fix bug while cursor would hide even when moving the mouse if a button was
held.
steamos-compositor (1.29) brewmaster; urgency=medium
* Tweaking focus and display logic in steamcompmgr to avoid event storms on newer
X servers. It looks like Damage semantics changed on Xserver 1.16 and we were
getting unexpected events after XDamageSubtract().
SteamOS modeswitch-inhibitor 1.7
Changelogs:
steamos-compositor (1.8) alchemist; urgency=low
* Rearm ignore warp count when hiding cursor to prevent spurious appearances.
* Work around X server bug 69198 by warping the cursor back into our window
if it escapes.
* Disable DPMS and the X screensaver for now in the SteamOS session.
steamos-modeswitch-inhibitor (1.7) alchemist; urgency=low
* Correct interposer open location to account for new library name.
- add support for global overscan compensation, controlled with a root window property; pending tenfoot wizard to set it up
- present the cursor with the same visible size as in Steam or the overlay, no matter what scale ratio is being applied to the game