mirror of
https://github.com/LizardByte/Sunshine.git
synced 2026-05-06 13:40:23 +08:00
feat(linux/glad): implement EGL_IMG_context_priority (#4857)
This commit is contained in:
@@ -179,6 +179,7 @@ glad_add_library(glad_egl
|
||||
EGL_EXT_platform_base
|
||||
EGL_EXT_platform_wayland
|
||||
EGL_EXT_platform_x11
|
||||
EGL_IMG_context_priority
|
||||
EGL_KHR_create_context
|
||||
EGL_KHR_image_base
|
||||
EGL_KHR_surfaceless_context
|
||||
|
||||
@@ -64,7 +64,7 @@ endif()
|
||||
|
||||
# Apply setcap for RPM
|
||||
# https://github.com/coreos/rpm-ostree/discussions/5036#discussioncomment-10291071
|
||||
set(CPACK_RPM_USER_FILELIST "%caps(cap_sys_admin+p) ${SUNSHINE_EXECUTABLE_PATH}")
|
||||
set(CPACK_RPM_USER_FILELIST "%caps(cap_sys_admin,cap_sys_nice+p) ${SUNSHINE_EXECUTABLE_PATH}")
|
||||
|
||||
# Dependencies
|
||||
set(CPACK_DEB_COMPONENT_INSTALL ON)
|
||||
|
||||
@@ -59,7 +59,7 @@ from source and using the binary directly, this will also work:
|
||||
|
||||
```bash
|
||||
sudo cp build/sunshine /tmp
|
||||
sudo setcap cap_sys_admin+p /tmp/sunshine
|
||||
sudo setcap cap_sys_admin,cap_sys_nice+p /tmp/sunshine
|
||||
sudo getcap /tmp/sunshine
|
||||
sudo mv /tmp/sunshine build/sunshine
|
||||
```
|
||||
|
||||
@@ -60,7 +60,7 @@ function install() {
|
||||
sed -i -e "s#$SUNSHINE_PATH#$(readlink -f $ARGV0)#g" ~/.config/systemd/user/app-dev.lizardbyte.app.Sunshine.service
|
||||
|
||||
# setcap
|
||||
sudo setcap cap_sys_admin+p "$(readlink -f "$SUNSHINE_BIN_HERE")"
|
||||
sudo setcap cap_sys_admin,cap_sys_nice+p "$(readlink -f "$SUNSHINE_BIN_HERE")"
|
||||
}
|
||||
|
||||
function remove() {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
do_setcap() {
|
||||
setcap cap_sys_admin+p $(readlink -f usr/bin/sunshine)
|
||||
setcap cap_sys_admin,cap_sys_nice+p $(readlink -f usr/bin/sunshine)
|
||||
}
|
||||
|
||||
do_udev_reload() {
|
||||
|
||||
@@ -387,8 +387,8 @@ fi
|
||||
|
||||
%files
|
||||
# Executables
|
||||
%caps(cap_sys_admin+p) %{_bindir}/sunshine
|
||||
%caps(cap_sys_admin+p) %{_bindir}/sunshine-*
|
||||
%caps(cap_sys_admin,cap_sys_nice+p) %{_bindir}/sunshine
|
||||
%caps(cap_sys_admin,cap_sys_nice+p) %{_bindir}/sunshine-*
|
||||
|
||||
# Systemd unit files for user services
|
||||
%{_userunitdir}/*.service
|
||||
|
||||
@@ -11,6 +11,11 @@
|
||||
#include "src/logging.h"
|
||||
#include "src/video.h"
|
||||
|
||||
// platform includes
|
||||
#if !defined(__FreeBSD__)
|
||||
#include <sys/capability.h>
|
||||
#endif
|
||||
|
||||
extern "C" {
|
||||
#include <libavutil/pixdesc.h>
|
||||
}
|
||||
@@ -387,6 +392,18 @@ namespace egl {
|
||||
}
|
||||
|
||||
std::optional<ctx_t> make_ctx(display_t::pointer display) {
|
||||
bool nice_warning = false;
|
||||
#if !defined(__FreeBSD__)
|
||||
cap_t caps = cap_get_proc();
|
||||
|
||||
cap_value_t sys_nice = CAP_SYS_NICE;
|
||||
if (cap_set_flag(caps, CAP_EFFECTIVE, 1, &sys_nice, CAP_SET) || cap_set_proc(caps)) {
|
||||
BOOST_LOG(debug) << "Failed to gain CAP_SYS_NICE"sv;
|
||||
nice_warning = true;
|
||||
}
|
||||
cap_free(caps);
|
||||
#endif
|
||||
|
||||
constexpr int conf_attr[] {
|
||||
EGL_RENDERABLE_TYPE,
|
||||
EGL_OPENGL_BIT,
|
||||
@@ -405,20 +422,42 @@ namespace egl {
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
constexpr int attr[] {
|
||||
EGL_CONTEXT_CLIENT_VERSION,
|
||||
3,
|
||||
EGL_NONE
|
||||
};
|
||||
const char *extension_st = eglQueryString(display, EGL_EXTENSIONS);
|
||||
|
||||
ctx_t ctx {display, eglCreateContext(display, conf, EGL_NO_CONTEXT, attr)};
|
||||
if (fail()) {
|
||||
std::vector<EGLint> attr;
|
||||
attr.push_back(EGL_CONTEXT_CLIENT_VERSION);
|
||||
attr.push_back(3);
|
||||
|
||||
// Only add the high priority attribute if the driver explicitly supports it
|
||||
if (extension_st && std::string_view(extension_st).contains("EGL_IMG_context_priority"sv)) {
|
||||
BOOST_LOG(debug) << "EGL: High priority context supported"sv;
|
||||
attr.push_back(EGL_CONTEXT_PRIORITY_LEVEL_IMG);
|
||||
attr.push_back(EGL_CONTEXT_PRIORITY_HIGH_IMG);
|
||||
}
|
||||
attr.push_back(EGL_NONE);
|
||||
|
||||
EGLContext raw_ctx = eglCreateContext(display, conf, EGL_NO_CONTEXT, attr.data());
|
||||
if (raw_ctx == EGL_NO_CONTEXT) {
|
||||
BOOST_LOG(error) << "Couldn't create EGL context: ["sv << util::hex(eglGetError()).to_string_view() << ']';
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
TUPLE_EL_REF(ctx_p, 1, ctx.el);
|
||||
if (!eglMakeCurrent(display, EGL_NO_SURFACE, EGL_NO_SURFACE, ctx_p)) {
|
||||
ctx_t ctx {display, raw_ctx};
|
||||
|
||||
EGLint actual_priority = EGL_CONTEXT_PRIORITY_MEDIUM_IMG;
|
||||
std::string actual_priority_str = "MEDIUM";
|
||||
if (eglQueryContext(display, raw_ctx, EGL_CONTEXT_PRIORITY_LEVEL_IMG, &actual_priority)) {
|
||||
if (actual_priority == EGL_CONTEXT_PRIORITY_HIGH_IMG) {
|
||||
actual_priority_str = "HIGH";
|
||||
}
|
||||
if (nice_warning) {
|
||||
BOOST_LOG(warning) << "EGL: context priority set to "sv << actual_priority_str << " but CAP_SYS_NICE capability is missing"sv;
|
||||
} else {
|
||||
BOOST_LOG(info) << "EGL: context priority set to "sv << actual_priority_str;
|
||||
}
|
||||
}
|
||||
|
||||
if (!eglMakeCurrent(display, EGL_NO_SURFACE, EGL_NO_SURFACE, raw_ctx)) {
|
||||
BOOST_LOG(error) << "Couldn't make current display"sv;
|
||||
return std::nullopt;
|
||||
}
|
||||
@@ -453,6 +492,14 @@ namespace egl {
|
||||
|
||||
gl::ctx.PixelStorei(GL_UNPACK_ALIGNMENT, 1);
|
||||
|
||||
#if !defined(__FreeBSD__)
|
||||
caps = cap_get_proc();
|
||||
if (cap_set_flag(caps, CAP_EFFECTIVE, 1, &sys_nice, CAP_CLEAR) || cap_set_proc(caps)) {
|
||||
BOOST_LOG(debug) << "Failed to drop CAP_SYS_NICE"sv;
|
||||
}
|
||||
cap_free(caps);
|
||||
#endif
|
||||
|
||||
return ctx;
|
||||
}
|
||||
|
||||
|
||||
@@ -236,7 +236,7 @@ namespace portal {
|
||||
|
||||
void finalize_portal_security() {
|
||||
#if !defined(__FreeBSD__)
|
||||
BOOST_LOG(debug) << "Finalizing Portal security: dropping CAP_SYS_ADMIN and resetting dumpable"sv;
|
||||
BOOST_LOG(debug) << "Finalizing Portal security: dropping capabilities and resetting dumpable"sv;
|
||||
|
||||
cap_t caps = cap_get_proc();
|
||||
if (!caps) {
|
||||
@@ -244,10 +244,11 @@ namespace portal {
|
||||
return;
|
||||
}
|
||||
|
||||
std::array<cap_value_t, 1> remove_list {CAP_SYS_ADMIN};
|
||||
std::array<cap_value_t, 2> effective_list {CAP_SYS_ADMIN, CAP_SYS_NICE};
|
||||
std::array<cap_value_t, 2> permitted_list {CAP_SYS_ADMIN, CAP_SYS_NICE};
|
||||
|
||||
cap_set_flag(caps, CAP_PERMITTED, remove_list.size(), remove_list.data(), CAP_CLEAR);
|
||||
cap_set_flag(caps, CAP_EFFECTIVE, remove_list.size(), remove_list.data(), CAP_CLEAR);
|
||||
cap_set_flag(caps, CAP_EFFECTIVE, effective_list.size(), effective_list.data(), CAP_CLEAR);
|
||||
cap_set_flag(caps, CAP_PERMITTED, permitted_list.size(), permitted_list.data(), CAP_CLEAR);
|
||||
|
||||
if (cap_set_proc(caps) != 0) {
|
||||
BOOST_LOG(error) << "Failed to prune capabilities: "sv << std::strerror(errno);
|
||||
|
||||
@@ -12,10 +12,10 @@ if [ ! -x "$(command -v rpm-ostree)" ]; then
|
||||
path_to_setcap=$(which setcap)
|
||||
path_to_sunshine=$(readlink -f "$(which sunshine)")
|
||||
if [ -x "$path_to_setcap" ] ; then
|
||||
echo "Setting CAP_SYS_ADMIN capability on Sunshine binary."
|
||||
echo "$path_to_setcap cap_sys_admin+p $path_to_sunshine"
|
||||
$path_to_setcap cap_sys_admin+p $path_to_sunshine
|
||||
echo "CAP_SYS_ADMIN capability set on Sunshine binary."
|
||||
echo "Setting CAP_SYS_ADMIN, CAP_SYS_NICE capabilities on Sunshine binary."
|
||||
echo "$path_to_setcap cap_sys_admin,cap_sys_nice+p $path_to_sunshine"
|
||||
$path_to_setcap cap_sys_admin,cap_sys_nice+p $path_to_sunshine
|
||||
echo "CAP_SYS_ADMIN, CAP_SYS_NICE capabilities set on Sunshine binary."
|
||||
else
|
||||
echo "error: setcap not found or not executable."
|
||||
fi
|
||||
|
||||
Reference in New Issue
Block a user