Skip to content

Commit 1879f4e

Browse files
committed
fix(linux/glad): add EGL_IMG_context_priority & EGL_NV_context_priority_realtime
Resolves encoding throttling: * Try to create EGL context with realtime or high priority if supported. * Set CAP_SYS_NICE capability (needed for AMDGPU priority queues above NORMAL). Currently has no effect on AMDGPU with Flatpak, AppImage and/or with Portal capture. Other GPUs may behave differently.
1 parent 2a5901b commit 1879f4e

9 files changed

Lines changed: 79 additions & 23 deletions

File tree

cmake/dependencies/glad.cmake

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -179,10 +179,12 @@ glad_add_library(glad_egl
179179
EGL_EXT_platform_base
180180
EGL_EXT_platform_wayland
181181
EGL_EXT_platform_x11
182+
EGL_IMG_context_priority
182183
EGL_KHR_create_context
183184
EGL_KHR_image_base
184185
EGL_KHR_surfaceless_context
185186
EGL_MESA_platform_gbm
187+
EGL_NV_context_priority_realtime
186188
)
187189

188190
# GL compatibility=4.6 --loader --mx

cmake/packaging/linux.cmake

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@ endif()
6464

6565
# Apply setcap for RPM
6666
# https://github.com/coreos/rpm-ostree/discussions/5036#discussioncomment-10291071
67-
set(CPACK_RPM_USER_FILELIST "%caps(cap_sys_admin+p) ${SUNSHINE_EXECUTABLE_PATH}")
67+
set(CPACK_RPM_USER_FILELIST "%caps(cap_sys_admin,cap_sys_nice+p) ${SUNSHINE_EXECUTABLE_PATH}")
6868

6969
# Dependencies
7070
set(CPACK_DEB_COMPONENT_INSTALL ON)

docs/building.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ from source and using the binary directly, this will also work:
5959

6060
```bash
6161
sudo cp build/sunshine /tmp
62-
sudo setcap cap_sys_admin+p /tmp/sunshine
62+
sudo setcap cap_sys_admin,cap_sys_nice+p /tmp/sunshine
6363
sudo getcap /tmp/sunshine
6464
sudo mv /tmp/sunshine build/sunshine
6565
```

packaging/linux/AppImage/AppRun

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ function install() {
6060
sed -i -e "s#$SUNSHINE_PATH#$(readlink -f $ARGV0)#g" ~/.config/systemd/user/app-dev.lizardbyte.app.Sunshine.service
6161

6262
# setcap
63-
sudo setcap cap_sys_admin+p "$(readlink -f "$SUNSHINE_BIN_HERE")"
63+
sudo setcap cap_sys_admin,cap_sys_nice+p "$(readlink -f "$SUNSHINE_BIN_HERE")"
6464
}
6565

6666
function remove() {

packaging/linux/Arch/sunshine.install

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
do_setcap() {
2-
setcap cap_sys_admin+p $(readlink -f usr/bin/sunshine)
2+
setcap cap_sys_admin,cap_sys_nice+p $(readlink -f usr/bin/sunshine)
33
}
44

55
do_udev_reload() {

packaging/linux/copr/Sunshine.spec

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -387,8 +387,8 @@ fi
387387

388388
%files
389389
# Executables
390-
%caps(cap_sys_admin+p) %{_bindir}/sunshine
391-
%caps(cap_sys_admin+p) %{_bindir}/sunshine-*
390+
%caps(cap_sys_admin,cap_sys_nice+p) %{_bindir}/sunshine
391+
%caps(cap_sys_admin,cap_sys_nice+p) %{_bindir}/sunshine-*
392392

393393
# Systemd unit files for user services
394394
%{_userunitdir}/*.service

src/platform/linux/graphics.cpp

Lines changed: 62 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,11 @@
1111
#include "src/logging.h"
1212
#include "src/video.h"
1313

14+
// platform includes
15+
#if !defined(__FreeBSD__)
16+
#include <sys/capability.h>
17+
#endif
18+
1419
extern "C" {
1520
#include <libavutil/pixdesc.h>
1621
}
@@ -387,6 +392,18 @@ namespace egl {
387392
}
388393

389394
std::optional<ctx_t> make_ctx(display_t::pointer display) {
395+
bool nice_warning = false;
396+
#if !defined(__FreeBSD__)
397+
cap_t caps = cap_get_proc();
398+
399+
cap_value_t sys_nice = CAP_SYS_NICE;
400+
if (cap_set_flag(caps, CAP_EFFECTIVE, 1, &sys_nice, CAP_SET) || cap_set_proc(caps)) {
401+
BOOST_LOG(debug) << "Failed to gain CAP_SYS_NICE"sv;
402+
nice_warning = true;
403+
}
404+
cap_free(caps);
405+
#endif
406+
390407
constexpr int conf_attr[] {
391408
EGL_RENDERABLE_TYPE,
392409
EGL_OPENGL_BIT,
@@ -405,20 +422,48 @@ namespace egl {
405422
return std::nullopt;
406423
}
407424

408-
constexpr int attr[] {
409-
EGL_CONTEXT_CLIENT_VERSION,
410-
3,
411-
EGL_NONE
412-
};
425+
const char *extension_st = eglQueryString(display, EGL_EXTENSIONS);
426+
427+
std::vector<EGLint> attr;
428+
attr.push_back(EGL_CONTEXT_CLIENT_VERSION);
429+
attr.push_back(3);
430+
431+
// Only add the realtime/high priority attribute if the driver explicitly supports it
432+
if (extension_st && std::string_view(extension_st).contains("EGL_NV_context_priority_realtime"sv)) {
433+
BOOST_LOG(debug) << "EGL: Realtime priority context supported"sv;
434+
attr.push_back(EGL_CONTEXT_PRIORITY_LEVEL_IMG);
435+
attr.push_back(EGL_CONTEXT_PRIORITY_REALTIME_NV);
436+
} else if (extension_st && std::string_view(extension_st).contains("EGL_IMG_context_priority"sv)) {
437+
BOOST_LOG(debug) << "EGL: High priority context supported"sv;
438+
attr.push_back(EGL_CONTEXT_PRIORITY_LEVEL_IMG);
439+
attr.push_back(EGL_CONTEXT_PRIORITY_HIGH_IMG);
440+
}
441+
attr.push_back(EGL_NONE);
413442

414-
ctx_t ctx {display, eglCreateContext(display, conf, EGL_NO_CONTEXT, attr)};
415-
if (fail()) {
443+
EGLContext raw_ctx = eglCreateContext(display, conf, EGL_NO_CONTEXT, attr.data());
444+
if (raw_ctx == EGL_NO_CONTEXT) {
416445
BOOST_LOG(error) << "Couldn't create EGL context: ["sv << util::hex(eglGetError()).to_string_view() << ']';
417446
return std::nullopt;
418447
}
419448

420-
TUPLE_EL_REF(ctx_p, 1, ctx.el);
421-
if (!eglMakeCurrent(display, EGL_NO_SURFACE, EGL_NO_SURFACE, ctx_p)) {
449+
ctx_t ctx {display, raw_ctx};
450+
451+
EGLint actual_priority = EGL_CONTEXT_PRIORITY_MEDIUM_IMG;
452+
std::string actual_priority_str = "MEDIUM";
453+
if (eglQueryContext(display, raw_ctx, EGL_CONTEXT_PRIORITY_LEVEL_IMG, &actual_priority)) {
454+
if (actual_priority == EGL_CONTEXT_PRIORITY_REALTIME_NV) {
455+
actual_priority_str = "REALTIME";
456+
} else if (actual_priority == EGL_CONTEXT_PRIORITY_HIGH_IMG) {
457+
actual_priority_str = "HIGH";
458+
}
459+
if (nice_warning) {
460+
BOOST_LOG(warning) << "EGL: Context Priority set to "sv << actual_priority_str << " but CAP_SYS_NICE capability is missing"sv;
461+
} else {
462+
BOOST_LOG(info) << "EGL: Context Priority set to "sv << actual_priority_str;
463+
}
464+
}
465+
466+
if (!eglMakeCurrent(display, EGL_NO_SURFACE, EGL_NO_SURFACE, raw_ctx)) {
422467
BOOST_LOG(error) << "Couldn't make current display"sv;
423468
return std::nullopt;
424469
}
@@ -453,6 +498,14 @@ namespace egl {
453498

454499
gl::ctx.PixelStorei(GL_UNPACK_ALIGNMENT, 1);
455500

501+
#if !defined(__FreeBSD__)
502+
caps = cap_get_proc();
503+
if (cap_set_flag(caps, CAP_EFFECTIVE, 1, &sys_nice, CAP_CLEAR) || cap_set_proc(caps)) {
504+
BOOST_LOG(debug) << "Failed to drop CAP_SYS_NICE"sv;
505+
}
506+
cap_free(caps);
507+
#endif
508+
456509
return ctx;
457510
}
458511

src/platform/linux/portalgrab.cpp

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -231,18 +231,19 @@ namespace portal {
231231

232232
void finalize_portal_security() {
233233
#if !defined(__FreeBSD__)
234-
BOOST_LOG(debug) << "Finalizing Portal security: dropping CAP_SYS_ADMIN and resetting dumpable"sv;
234+
BOOST_LOG(debug) << "Finalizing Portal security: dropping capabilities and resetting dumpable"sv;
235235

236236
cap_t caps = cap_get_proc();
237237
if (!caps) {
238238
BOOST_LOG(error) << "Failed to get process capabilities"sv;
239239
return;
240240
}
241241

242-
std::array<cap_value_t, 1> remove_list {CAP_SYS_ADMIN};
242+
std::array<cap_value_t, 2> effective_list {CAP_SYS_ADMIN, CAP_SYS_NICE};
243+
std::array<cap_value_t, 2> permitted_list {CAP_SYS_ADMIN, CAP_SYS_NICE};
243244

244-
cap_set_flag(caps, CAP_PERMITTED, remove_list.size(), remove_list.data(), CAP_CLEAR);
245-
cap_set_flag(caps, CAP_EFFECTIVE, remove_list.size(), remove_list.data(), CAP_CLEAR);
245+
cap_set_flag(caps, CAP_EFFECTIVE, effective_list.size(), effective_list.data(), CAP_CLEAR);
246+
cap_set_flag(caps, CAP_PERMITTED, permitted_list.size(), permitted_list.data(), CAP_CLEAR);
246247

247248
if (cap_set_proc(caps) != 0) {
248249
BOOST_LOG(error) << "Failed to prune capabilities: "sv << std::strerror(errno);

src_assets/linux/misc/postinst

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,10 +12,10 @@ if [ ! -x "$(command -v rpm-ostree)" ]; then
1212
path_to_setcap=$(which setcap)
1313
path_to_sunshine=$(readlink -f "$(which sunshine)")
1414
if [ -x "$path_to_setcap" ] ; then
15-
echo "Setting CAP_SYS_ADMIN capability on Sunshine binary."
16-
echo "$path_to_setcap cap_sys_admin+p $path_to_sunshine"
17-
$path_to_setcap cap_sys_admin+p $path_to_sunshine
18-
echo "CAP_SYS_ADMIN capability set on Sunshine binary."
15+
echo "Setting CAP_SYS_ADMIN, CAP_SYS_NICE capabilities on Sunshine binary."
16+
echo "$path_to_setcap cap_sys_admin,cap_sys_nice+p $path_to_sunshine"
17+
$path_to_setcap cap_sys_admin,cap_sys_nice+p $path_to_sunshine
18+
echo "CAP_SYS_ADMIN, CAP_SYS_NICE capabilities set on Sunshine binary."
1919
else
2020
echo "error: setcap not found or not executable."
2121
fi

0 commit comments

Comments
 (0)