mirror of
https://github.com/FeralInteractive/gamemode.git
synced 2025-06-04 22:57:21 +02:00
Compare commits
16 Commits
Author | SHA1 | Date | |
---|---|---|---|
![]() |
af07e169d5 | ||
![]() |
6e5c950141 | ||
![]() |
499af4c7bb | ||
![]() |
5f691c3171 | ||
![]() |
f5fbdcf014 | ||
![]() |
7c49d6e1db | ||
![]() |
d84c5ded1c | ||
![]() |
2d71be6a94 | ||
![]() |
1e3e55c5d8 | ||
![]() |
e75f2c3942 | ||
![]() |
81d26c79b4 | ||
![]() |
5b3b4ae638 | ||
![]() |
1d9c1e6a72 | ||
![]() |
2eecd513ac | ||
![]() |
086b3fe5b4 | ||
![]() |
2f69f7c023 |
9
.github/workflows/build-and-test.yml
vendored
9
.github/workflows/build-and-test.yml
vendored
@ -1,15 +1,18 @@
|
||||
name: Build and test
|
||||
on: [push, pull_request]
|
||||
permissions:
|
||||
contents: read
|
||||
actions: write
|
||||
|
||||
jobs:
|
||||
build-and-test:
|
||||
runs-on: ubuntu-20.04
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v2
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
sudo apt install build-essential meson appstream clang clang-format clang-tools libdbus-1-dev libinih-dev libsystemd-dev
|
||||
sudo DEBIAN_FRONTEND=noninteractive apt-get install -y build-essential meson appstream clang clang-format clang-tools libdbus-1-dev libinih-dev libsystemd-dev systemd-dev
|
||||
- name: Check format
|
||||
env:
|
||||
CI: "true"
|
||||
@ -31,7 +34,7 @@ jobs:
|
||||
./scripts/static-analyser-check.sh
|
||||
- name: Upload logs
|
||||
if: ${{ always() }}
|
||||
uses: actions/upload-artifact@v2
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: logs
|
||||
path: |
|
||||
|
1
.gitignore
vendored
1
.gitignore
vendored
@ -1,2 +1,3 @@
|
||||
/builddir
|
||||
/subprojects/packagecache/
|
||||
/subprojects/inih-r*
|
||||
|
@ -1,4 +1,4 @@
|
||||
Copyright (c) 2017-2024, Feral Interactive
|
||||
Copyright (c) 2017-2025, Feral Interactive and the GameMode contributors
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
|
65
README.md
65
README.md
@ -20,7 +20,7 @@ Issues with GameMode should be reported here in the issues section, and not repo
|
||||
---
|
||||
## Requesting GameMode
|
||||
|
||||
For games/launchers which integrate GameMode support (see list later on), simply running the game will automatically activate GameMode.
|
||||
For games/launchers which integrate GameMode support, simply running the game will automatically activate GameMode.
|
||||
|
||||
For others, you must manually request GameMode when running the game. This can be done by launching the game through `gamemoderun`:
|
||||
```bash
|
||||
@ -58,30 +58,6 @@ You can do this by setting the environment variable `GAMEMODERUNEXEC` to your wr
|
||||
|
||||
GameMode will not be injected to the wrapper.
|
||||
|
||||
---
|
||||
## Apps with GameMode integration
|
||||
|
||||
### Games
|
||||
The following games are known to integrate GameMode support (meaning they don't require any additional configuration to activate GameMode while running):
|
||||
* DiRT 4
|
||||
* Rise of the Tomb Raider
|
||||
* Shadow of the Tomb Raider
|
||||
* Total War Saga: Thrones of Britannia
|
||||
* Total War: ROME REMASTERED
|
||||
* Total War: Three Kingdoms
|
||||
* Total War: WARHAMMER II
|
||||
* Total War: WARHAMMER III
|
||||
|
||||
### Others
|
||||
Other apps which can integrate with GameMode include:
|
||||
* [ATLauncher](https://atlauncher.com/downloads) Minecraft launcher
|
||||
* [Cemu](https://cemu.info/) Wii U emulator
|
||||
* [GNOME Shell Extension](https://github.com/trsnaqe/gamemode-shell-extension) GameMode status indicator extension for GNOME Shell
|
||||
* [Lutris](https://lutris.net/) Install and play any video game easily
|
||||
* Enables GameMode for all games by default if available (must have both 32- and 64-bit GameMode libraries installed), configurable in preferences.
|
||||
* [Prism Launcher](https://prismlauncher.org/) Minecraft launcher
|
||||
* [RetroArch](https://www.retroarch.com) Frontend for emulators, game engines and media players
|
||||
* [Vinegar](https://vinegarhq.org/) Roblox Player/Studio bootstrapper
|
||||
---
|
||||
## Development [](https://github.com/FeralInteractive/gamemode/actions/workflows/build-and-test.yml)
|
||||
|
||||
@ -90,15 +66,16 @@ The design of GameMode has a clear-cut abstraction between the host daemon and l
|
||||
See repository subdirectories for information on each component.
|
||||
|
||||
### Install Dependencies
|
||||
GameMode depends on `meson` for building and `systemd` for internal communication. This repo contains a `bootstrap.sh` script to allow for quick install to the user bus, but check `meson_options.txt` for custom settings.
|
||||
|
||||
#### Ubuntu/Debian (you may also need `dbus-user-session`)
|
||||
GameMode depends on `meson` for building and `systemd` for internal communication. This repo contains a `bootstrap.sh` script to allow for quick install to the user bus, but check `meson_options.txt` for custom settings. These instructions all assume that you
|
||||
already have a C development environment (gcc or clang, libc-devel, etc) installed.
|
||||
|
||||
#### Ubuntu/Debian
|
||||
Note: Debian 13 and Ubuntu 25.04 (and later) need to install `systemd-dev` in addition to the dependencies below.
|
||||
```bash
|
||||
apt install meson libsystemd-dev pkg-config ninja-build git libdbus-1-dev libinih-dev build-essential
|
||||
apt update && apt install meson libsystemd-dev pkg-config ninja-build git dbus-user-session libdbus-1-dev libinih-dev build-essential
|
||||
```
|
||||
|
||||
On Ubuntu 18.04, you'll need to install `python3` package and install the latest meson version from `pip`.
|
||||
On Debian 12 and Ubuntu 22 (and earlier), you'll need to install `python3` and `python3-venv` packages to install the latest meson version from `pip`.
|
||||
|
||||
```bash
|
||||
python3 -m venv .venv
|
||||
@ -115,12 +92,28 @@ rm -rf .venv
|
||||
|
||||
#### Arch
|
||||
```bash
|
||||
pacman -S meson systemd git dbus libinih
|
||||
pacman -S meson systemd git dbus libinih gcc pkgconf
|
||||
```
|
||||
|
||||
#### RHEL 10 and variants
|
||||
Note: Older versions of RHEL (and variants) cannot build gamemode due to not exposing libdbus-1 to pkg-config.
|
||||
(also - don't try and play games on RHEL, come on)
|
||||
|
||||
You must have [EPEL](https://docs.fedoraproject.org/en-US/epel/getting-started/) enabled to install all dependencies.
|
||||
```bash
|
||||
dnf install meson systemd-devel pkg-config git dbus-devel inih-devel
|
||||
```
|
||||
|
||||
#### Fedora
|
||||
```bash
|
||||
dnf install meson systemd-devel pkg-config git dbus-devel
|
||||
dnf install meson systemd-devel pkg-config git dbus-devel inih-devel
|
||||
```
|
||||
|
||||
#### OpenSUSE Leap/Tumbleweed
|
||||
```bash
|
||||
zypper install meson systemd-devel git dbus-1-devel libgcc_s1 libstdc++-devel libinih-devel
|
||||
```
|
||||
|
||||
#### Gentoo
|
||||
Gentoo has an ebuild which builds a stable release from sources. It will also pull in all the dependencies so you can work on the source code.
|
||||
```bash
|
||||
@ -131,6 +124,12 @@ You can also install using the latest sources from git:
|
||||
ACCEPT_KEYWORDS="**" emerge --ask ~games-util/gamemode-9999
|
||||
```
|
||||
|
||||
#### Nix
|
||||
Similar to Gentoo, nixOS already has a package for gamemode, so we can use that to setup an environment:
|
||||
```bash
|
||||
nix-shell -p pkgs.gamemode.buildInputs pkgs.gamemode.nativeBuildInputs
|
||||
```
|
||||
|
||||
### Build and Install GameMode
|
||||
Then clone, build and install a release version of GameMode at 1.8.2:
|
||||
|
||||
@ -165,7 +164,7 @@ See the [contributors](https://github.com/FeralInteractive/gamemode/graphs/contr
|
||||
---
|
||||
## License
|
||||
|
||||
Copyright © 2017-2024 Feral Interactive
|
||||
Copyright © 2017-2025 Feral Interactive and the GameMode contributors
|
||||
|
||||
GameMode is available under the terms of the BSD 3-Clause License (Revised)
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2017-2019, Feral Interactive
|
||||
Copyright (c) 2017-2025, Feral Interactive and the GameMode contributors
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
|
@ -1,6 +1,6 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2017-2019, Feral Interactive
|
||||
Copyright (c) 2017-2025, Feral Interactive and the GameMode contributors
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
|
@ -1,6 +1,6 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2017-2019, Feral Interactive
|
||||
Copyright (c) 2017-2025, Feral Interactive and the GameMode contributors
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
|
@ -1,6 +1,6 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2017-2019, Feral Interactive
|
||||
Copyright (c) 2017-2025, Feral Interactive and the GameMode contributors
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
|
@ -1,6 +1,6 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2017-2019, Feral Interactive
|
||||
Copyright (c) 2017-2025, Feral Interactive and the GameMode contributors
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
|
@ -1,6 +1,6 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2017-2019, Feral Interactive
|
||||
Copyright (c) 2017-2025, Feral Interactive and the GameMode contributors
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
|
@ -1,6 +1,6 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2017-2019, Feral Interactive
|
||||
Copyright (c) 2017-2025, Feral Interactive and the GameMode contributors
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
|
@ -1,6 +1,6 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2017-2019, Feral Interactive
|
||||
Copyright (c) 2017-2025, Feral Interactive and the GameMode contributors
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
|
@ -1,6 +1,6 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2017-2019, Feral Interactive
|
||||
Copyright (c) 2017-2025, Feral Interactive and the GameMode contributors
|
||||
Copyright (c) 2019, Red Hat
|
||||
All rights reserved.
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2017-2019, Feral Interactive
|
||||
Copyright (c) 2017-2025, Feral Interactive and the GameMode contributors
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
|
@ -1,6 +1,6 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2017-2019, Feral Interactive
|
||||
Copyright (c) 2017-2025, Feral Interactive and the GameMode contributors
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
|
@ -1,6 +1,6 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2017-2019, Feral Interactive
|
||||
Copyright (c) 2017-2025, Feral Interactive and the GameMode contributors
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
|
@ -1,6 +1,6 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2017-2019, Feral Interactive
|
||||
Copyright (c) 2017-2025, Feral Interactive and the GameMode contributors
|
||||
Copyright (c) 2019, Red Hat
|
||||
All rights reserved.
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2017-2019, Feral Interactive
|
||||
Copyright (c) 2017-2025, Feral Interactive and the GameMode contributors
|
||||
Copyright (c) 2019, Red Hat
|
||||
All rights reserved.
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2017-2019, Feral Interactive
|
||||
Copyright (c) 2017-2025, Feral Interactive and the GameMode contributors
|
||||
Copyright (c) 2019, Intel Corporation
|
||||
All rights reserved.
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2017-2019, Feral Interactive
|
||||
Copyright (c) 2017-2025, Feral Interactive and the GameMode contributors
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
|
86
common/common-profile.c
Normal file
86
common/common-profile.c
Normal file
@ -0,0 +1,86 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2025, the GameMode contributors
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright notice,
|
||||
this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
* Neither the name of Feral Interactive nor the names of its contributors
|
||||
may be used to endorse or promote products derived from this software
|
||||
without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
*/
|
||||
|
||||
#define _GNU_SOURCE
|
||||
|
||||
#include "common-profile.h"
|
||||
#include "common-logging.h"
|
||||
|
||||
/**
|
||||
* Path for platform profile
|
||||
*/
|
||||
const char *profile_path = "/sys/firmware/acpi/platform_profile";
|
||||
|
||||
/**
|
||||
* Check if platform profile file exists
|
||||
*/
|
||||
int profile_exists(void)
|
||||
{
|
||||
return !access(profile_path, F_OK);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the current platform profile state
|
||||
*/
|
||||
const char *get_profile_state(void)
|
||||
{
|
||||
/* Persistent profile state */
|
||||
static char profile[64] = { 0 };
|
||||
memset(profile, 0, sizeof(profile));
|
||||
|
||||
FILE *f = fopen(profile_path, "r");
|
||||
if (!f) {
|
||||
LOG_ERROR("Failed to open file for read %s\n", profile_path);
|
||||
return "none";
|
||||
}
|
||||
|
||||
/* Grab the file length */
|
||||
fseek(f, 0, SEEK_END);
|
||||
long length = ftell(f);
|
||||
fseek(f, 0, SEEK_SET);
|
||||
|
||||
if (length == -1) {
|
||||
LOG_ERROR("Failed to seek file %s\n", profile_path);
|
||||
} else {
|
||||
char contents[length + 1];
|
||||
|
||||
if (fread(contents, 1, (size_t)length, f) > 0) {
|
||||
strtok(contents, "\n");
|
||||
strncpy(profile, contents, sizeof(profile) - 1);
|
||||
} else {
|
||||
LOG_ERROR("Failed to read contents of %s\n", profile_path);
|
||||
}
|
||||
}
|
||||
|
||||
fclose(f);
|
||||
|
||||
return profile;
|
||||
}
|
50
common/common-profile.h
Normal file
50
common/common-profile.h
Normal file
@ -0,0 +1,50 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2025, the GameMode contributors
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright notice,
|
||||
this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
* Neither the name of Feral Interactive nor the names of its contributors
|
||||
may be used to endorse or promote products derived from this software
|
||||
without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <linux/limits.h>
|
||||
#include <unistd.h>
|
||||
|
||||
/**
|
||||
* Path for platform profile
|
||||
*/
|
||||
extern const char *profile_path;
|
||||
|
||||
/**
|
||||
* Check if platform profile file exists
|
||||
*/
|
||||
int profile_exists(void);
|
||||
|
||||
/**
|
||||
* Get the current platform profile state
|
||||
*/
|
||||
const char *get_profile_state(void);
|
64
common/common-splitlock.c
Normal file
64
common/common-splitlock.c
Normal file
@ -0,0 +1,64 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2025, the GameMode contributors
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright notice,
|
||||
this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
* Neither the name of Feral Interactive nor the names of its contributors
|
||||
may be used to endorse or promote products derived from this software
|
||||
without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
*/
|
||||
|
||||
#define _GNU_SOURCE
|
||||
|
||||
#include "common-splitlock.h"
|
||||
#include "common-logging.h"
|
||||
|
||||
/**
|
||||
* Path for the split lock mitigation state
|
||||
*/
|
||||
const char *splitlock_path = "/proc/sys/kernel/split_lock_mitigate";
|
||||
|
||||
/**
|
||||
* Return the current split lock mitigation state
|
||||
*/
|
||||
long get_splitlock_state(void)
|
||||
{
|
||||
FILE *f = fopen(splitlock_path, "r");
|
||||
if (!f) {
|
||||
LOG_ERROR("Failed to open file for read %s\n", splitlock_path);
|
||||
return -1;
|
||||
}
|
||||
|
||||
char contents[41] = { 0 };
|
||||
long value = -1;
|
||||
|
||||
if (fread(contents, 1, sizeof contents - 1, f) > 0) {
|
||||
value = strtol(contents, NULL, 10);
|
||||
} else {
|
||||
LOG_ERROR("Failed to read contents of %s\n", splitlock_path);
|
||||
}
|
||||
fclose(f);
|
||||
|
||||
return value;
|
||||
}
|
44
common/common-splitlock.h
Normal file
44
common/common-splitlock.h
Normal file
@ -0,0 +1,44 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2025, the GameMode contributors
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright notice,
|
||||
this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
* Neither the name of Feral Interactive nor the names of its contributors
|
||||
may be used to endorse or promote products derived from this software
|
||||
without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <linux/limits.h>
|
||||
|
||||
/**
|
||||
* Path for the split lock mitagation state
|
||||
*/
|
||||
extern const char *splitlock_path;
|
||||
|
||||
/**
|
||||
* Get the current split lock mitigation state
|
||||
*/
|
||||
long get_splitlock_state(void);
|
@ -2,6 +2,8 @@
|
||||
common_sources = [
|
||||
'common-logging.c',
|
||||
'common-governors.c',
|
||||
'common-profile.c',
|
||||
'common-splitlock.c',
|
||||
'common-external.c',
|
||||
'common-helpers.c',
|
||||
'common-gpu.c',
|
||||
|
@ -1,6 +1,6 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2017-2019, Feral Interactive
|
||||
Copyright (c) 2017-2025, Feral Interactive and the GameMode contributors
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
@ -88,6 +88,9 @@ struct GameModeConfig {
|
||||
char defaultgov[CONFIG_VALUE_MAX];
|
||||
char desiredgov[CONFIG_VALUE_MAX];
|
||||
|
||||
char defaultprof[CONFIG_VALUE_MAX];
|
||||
char desiredprof[CONFIG_VALUE_MAX];
|
||||
|
||||
char igpu_desiredgov[CONFIG_VALUE_MAX];
|
||||
float igpu_power_threshold;
|
||||
|
||||
@ -265,6 +268,10 @@ static int inih_handler(void *user, const char *section, const char *name, const
|
||||
valid = get_string_value(value, self->values.defaultgov);
|
||||
} else if (strcmp(name, "desiredgov") == 0) {
|
||||
valid = get_string_value(value, self->values.desiredgov);
|
||||
} else if (strcmp(name, "defaultprof") == 0) {
|
||||
valid = get_string_value(value, self->values.defaultprof);
|
||||
} else if (strcmp(name, "desiredprof") == 0) {
|
||||
valid = get_string_value(value, self->values.desiredprof);
|
||||
} else if (strcmp(name, "igpu_desiredgov") == 0) {
|
||||
valid = get_string_value(value, self->values.igpu_desiredgov);
|
||||
} else if (strcmp(name, "igpu_power_threshold") == 0) {
|
||||
@ -691,13 +698,29 @@ void config_get_default_governor(GameModeConfig *self, char governor[CONFIG_VALU
|
||||
}
|
||||
|
||||
/*
|
||||
* Get the chosen desired governor
|
||||
* Get the chosen desired platform profile
|
||||
*/
|
||||
void config_get_desired_governor(GameModeConfig *self, char governor[CONFIG_VALUE_MAX])
|
||||
{
|
||||
memcpy_locked_config(self, governor, self->values.desiredgov, sizeof(self->values.desiredgov));
|
||||
}
|
||||
|
||||
/*
|
||||
* Get the chosen default platform profile
|
||||
*/
|
||||
void config_get_default_profile(GameModeConfig *self, char profile[CONFIG_VALUE_MAX])
|
||||
{
|
||||
memcpy_locked_config(self, profile, self->values.defaultprof, sizeof(self->values.defaultprof));
|
||||
}
|
||||
|
||||
/*
|
||||
* Get the chosen desired governor
|
||||
*/
|
||||
void config_get_desired_profile(GameModeConfig *self, char profile[CONFIG_VALUE_MAX])
|
||||
{
|
||||
memcpy_locked_config(self, profile, self->values.desiredprof, sizeof(self->values.desiredprof));
|
||||
}
|
||||
|
||||
/*
|
||||
* Get the chosen iGPU desired governor
|
||||
*/
|
||||
|
@ -1,6 +1,6 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2017-2019, Feral Interactive
|
||||
Copyright (c) 2017-2025, Feral Interactive and the GameMode contributors
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
@ -102,6 +102,8 @@ bool config_get_inhibit_screensaver(GameModeConfig *self);
|
||||
long config_get_script_timeout(GameModeConfig *self);
|
||||
void config_get_default_governor(GameModeConfig *self, char governor[CONFIG_VALUE_MAX]);
|
||||
void config_get_desired_governor(GameModeConfig *self, char governor[CONFIG_VALUE_MAX]);
|
||||
void config_get_default_profile(GameModeConfig *self, char profile[CONFIG_VALUE_MAX]);
|
||||
void config_get_desired_profile(GameModeConfig *self, char profile[CONFIG_VALUE_MAX]);
|
||||
void config_get_igpu_desired_governor(GameModeConfig *self, char governor[CONFIG_VALUE_MAX]);
|
||||
float config_get_igpu_power_threshold(GameModeConfig *self);
|
||||
void config_get_soft_realtime(GameModeConfig *self, char softrealtime[CONFIG_VALUE_MAX]);
|
||||
|
@ -1,6 +1,6 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2017-2019, Feral Interactive
|
||||
Copyright (c) 2017-2025, Feral Interactive and the GameMode contributors
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
@ -36,6 +36,8 @@ POSSIBILITY OF SUCH DAMAGE.
|
||||
#include "common-helpers.h"
|
||||
#include "common-logging.h"
|
||||
#include "common-power.h"
|
||||
#include "common-profile.h"
|
||||
#include "common-splitlock.h"
|
||||
|
||||
#include "gamemode.h"
|
||||
#include "gamemode-config.h"
|
||||
@ -71,6 +73,11 @@ enum GameModeGovernor {
|
||||
GAME_MODE_GOVERNOR_IGPU_DESIRED,
|
||||
};
|
||||
|
||||
enum GameModeProfile {
|
||||
GAME_MODE_PROFILE_DEFAULT,
|
||||
GAME_MODE_PROFILE_DESIRED,
|
||||
};
|
||||
|
||||
struct GameModeContext {
|
||||
pthread_rwlock_t rwlock; /**<Guard access to the client list */
|
||||
_Atomic int refcount; /**<Allow cycling the game mode */
|
||||
@ -82,6 +89,9 @@ struct GameModeContext {
|
||||
|
||||
enum GameModeGovernor current_govenor;
|
||||
|
||||
char initial_profile[64];
|
||||
enum GameModeProfile current_profile;
|
||||
|
||||
struct GameModeGPUInfo *stored_gpu; /**<Stored GPU info for the current GPU */
|
||||
struct GameModeGPUInfo *target_gpu; /**<Target GPU info for the current GPU */
|
||||
|
||||
@ -209,6 +219,13 @@ void game_mode_context_destroy(GameModeContext *self)
|
||||
pthread_rwlock_destroy(&self->rwlock);
|
||||
}
|
||||
|
||||
static void game_mode_store_splitlock(GameModeContext *self)
|
||||
{
|
||||
long initial_state = get_splitlock_state();
|
||||
self->initial_split_lock_mitigate = initial_state;
|
||||
LOG_MSG("split lock mitigation was initially set to [%ld]\n", initial_state);
|
||||
}
|
||||
|
||||
static int game_mode_disable_splitlock(GameModeContext *self, bool disable)
|
||||
{
|
||||
if (!config_get_disable_splitlock(self->config))
|
||||
@ -217,30 +234,8 @@ static int game_mode_disable_splitlock(GameModeContext *self, bool disable)
|
||||
long value_num = self->initial_split_lock_mitigate;
|
||||
char value_str[40];
|
||||
|
||||
if (disable) {
|
||||
FILE *f = fopen("/proc/sys/kernel/split_lock_mitigate", "r");
|
||||
if (f == NULL) {
|
||||
if (errno == ENOENT)
|
||||
return 0;
|
||||
|
||||
LOG_ERROR("Couldn't open /proc/sys/kernel/split_lock_mitigate : %s\n", strerror(errno));
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (fgets(value_str, sizeof value_str, f) == NULL) {
|
||||
LOG_ERROR("Couldn't read from /proc/sys/kernel/split_lock_mitigate : %s\n",
|
||||
strerror(errno));
|
||||
fclose(f);
|
||||
return 1;
|
||||
}
|
||||
|
||||
self->initial_split_lock_mitigate = strtol(value_str, NULL, 10);
|
||||
fclose(f);
|
||||
|
||||
value_num = 0;
|
||||
if (self->initial_split_lock_mitigate == value_num)
|
||||
return 0;
|
||||
}
|
||||
if (disable && value_num == 0)
|
||||
return 0;
|
||||
|
||||
if (value_num == -1)
|
||||
return 0;
|
||||
@ -261,25 +256,26 @@ static int game_mode_disable_splitlock(GameModeContext *self, bool disable)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void game_mode_store_governor(GameModeContext *self)
|
||||
{
|
||||
if (self->current_govenor != GAME_MODE_GOVERNOR_DEFAULT)
|
||||
return;
|
||||
|
||||
const char *initial_state = get_gov_state();
|
||||
if (initial_state == NULL)
|
||||
return;
|
||||
|
||||
strncpy(self->initial_cpu_mode, initial_state, sizeof(self->initial_cpu_mode) - 1);
|
||||
self->initial_cpu_mode[sizeof(self->initial_cpu_mode) - 1] = '\0';
|
||||
LOG_MSG("governor was initially set to [%s]\n", initial_state);
|
||||
}
|
||||
|
||||
static int game_mode_set_governor(GameModeContext *self, enum GameModeGovernor gov)
|
||||
{
|
||||
if (self->current_govenor == gov) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (self->current_govenor == GAME_MODE_GOVERNOR_DEFAULT) {
|
||||
/* Read the initial governor state so we can revert it correctly */
|
||||
const char *initial_state = get_gov_state();
|
||||
if (initial_state == NULL) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* store the initial cpu governor mode */
|
||||
strncpy(self->initial_cpu_mode, initial_state, sizeof(self->initial_cpu_mode) - 1);
|
||||
self->initial_cpu_mode[sizeof(self->initial_cpu_mode) - 1] = '\0';
|
||||
LOG_MSG("governor was initially set to [%s]\n", initial_state);
|
||||
}
|
||||
|
||||
char *gov_str = NULL;
|
||||
char gov_config_str[CONFIG_VALUE_MAX] = { 0 };
|
||||
switch (gov) {
|
||||
@ -319,6 +315,65 @@ static int game_mode_set_governor(GameModeContext *self, enum GameModeGovernor g
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void game_mode_store_profile(GameModeContext *self)
|
||||
{
|
||||
if (!profile_exists() || self->current_profile != GAME_MODE_PROFILE_DEFAULT)
|
||||
return;
|
||||
|
||||
const char *initial_state = get_profile_state();
|
||||
if (initial_state == NULL)
|
||||
return;
|
||||
|
||||
strncpy(self->initial_profile, initial_state, sizeof(self->initial_profile) - 1);
|
||||
self->initial_profile[sizeof(self->initial_profile) - 1] = '\0';
|
||||
LOG_MSG("platform profile was initially set to [%s]\n", initial_state);
|
||||
}
|
||||
|
||||
static int game_mode_set_profile(GameModeContext *self, enum GameModeProfile prof)
|
||||
{
|
||||
if (self->current_profile == prof) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!profile_exists()) {
|
||||
LOG_MSG("Setting platform profile unsupported; skipping\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
const char *prof_str = NULL;
|
||||
char prof_config_str[CONFIG_VALUE_MAX] = { 0 };
|
||||
switch (prof) {
|
||||
case GAME_MODE_PROFILE_DEFAULT:
|
||||
config_get_default_profile(self->config, prof_config_str);
|
||||
prof_str = prof_config_str[0] != '\0' ? prof_config_str : self->initial_profile;
|
||||
break;
|
||||
|
||||
case GAME_MODE_PROFILE_DESIRED:
|
||||
config_get_desired_profile(self->config, prof_config_str);
|
||||
prof_str = prof_config_str[0] != '\0' ? prof_config_str : "performance";
|
||||
break;
|
||||
|
||||
default:
|
||||
assert(!"Invalid platform profile requested");
|
||||
}
|
||||
|
||||
const char *const exec_args[] = {
|
||||
"pkexec", LIBEXECDIR "/platprofctl", "set", prof_str, NULL,
|
||||
};
|
||||
|
||||
LOG_MSG("Requesting update of platform profile to %s\n", prof_str);
|
||||
int ret = run_external_process(exec_args, NULL, -1);
|
||||
if (ret != 0) {
|
||||
LOG_ERROR("Failed to update platform profile\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Update the current govenor only if we succeed at setting govenors. */
|
||||
self->current_profile = prof;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void game_mode_enable_igpu_optimization(GameModeContext *self)
|
||||
{
|
||||
float threshold = config_get_igpu_power_threshold(self->config);
|
||||
@ -406,6 +461,15 @@ unlock:
|
||||
pthread_rwlock_unlock(&self->rwlock);
|
||||
}
|
||||
|
||||
static void game_mode_context_store_defaults(GameModeContext *self)
|
||||
{
|
||||
game_mode_store_profile(self);
|
||||
|
||||
game_mode_store_governor(self);
|
||||
|
||||
game_mode_store_splitlock(self);
|
||||
}
|
||||
|
||||
/**
|
||||
* Pivot into game mode.
|
||||
*
|
||||
@ -417,6 +481,14 @@ static void game_mode_context_enter(GameModeContext *self)
|
||||
LOG_MSG("Entering Game Mode...\n");
|
||||
sd_notifyf(0, "STATUS=%sGameMode is now active.%s\n", "\x1B[1;32m", "\x1B[0m");
|
||||
|
||||
/* Store the default value for everything before anything changes. */
|
||||
game_mode_context_store_defaults(self);
|
||||
|
||||
/* Set the profile before anything else since it can restrict things
|
||||
* like the governor.
|
||||
*/
|
||||
game_mode_set_profile(self, GAME_MODE_PROFILE_DESIRED);
|
||||
|
||||
if (game_mode_set_governor(self, GAME_MODE_GOVERNOR_DESIRED) == 0) {
|
||||
/* We just switched to a non-default governor. Enable the iGPU
|
||||
* optimization.
|
||||
@ -458,6 +530,11 @@ static void game_mode_context_leave(GameModeContext *self)
|
||||
LOG_MSG("Leaving Game Mode...\n");
|
||||
sd_notifyf(0, "STATUS=%sGameMode is currently deactivated.%s\n", "\x1B[1;36m", "\x1B[0m");
|
||||
|
||||
/* Restore profile before anything else since it can restrict things
|
||||
* like the governor.
|
||||
*/
|
||||
game_mode_set_profile(self, GAME_MODE_PROFILE_DEFAULT);
|
||||
|
||||
/* Remove GPU optimisations */
|
||||
game_mode_apply_gpu(self->stored_gpu);
|
||||
|
||||
|
@ -1,7 +1,7 @@
|
||||
|
||||
/*
|
||||
|
||||
Copyright (c) 2017-2019, Feral Interactive
|
||||
Copyright (c) 2017-2025, Feral Interactive and the GameMode contributors
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
@ -73,6 +73,38 @@ static int read_small_file(char *path, char **buf, size_t *buflen)
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void set_online_from_list(char *cpulist, GameModeCPUInfo *info)
|
||||
{
|
||||
long from, to;
|
||||
while ((cpulist = parse_cpulist(cpulist, &from, &to))) {
|
||||
for (long cpu = from; cpu < to + 1; cpu++) {
|
||||
CPU_SET_S((size_t)cpu, CPU_ALLOC_SIZE(info->num_cpu), info->online);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static int check_pe_cores(char **buf, size_t *buflen, GameModeCPUInfo *info)
|
||||
{
|
||||
if (!read_small_file("/sys/devices/cpu_core/cpus", buf, buflen))
|
||||
return 0;
|
||||
|
||||
LOG_MSG("found kernel support for checking P/E-cores\n");
|
||||
|
||||
long from, to;
|
||||
char *list = *buf;
|
||||
while ((list = parse_cpulist(list, &from, &to))) {
|
||||
for (long cpu = from; cpu < to + 1; cpu++) {
|
||||
CPU_SET_S((size_t)cpu, CPU_ALLOC_SIZE(info->num_cpu), info->to_keep);
|
||||
}
|
||||
}
|
||||
|
||||
if (CPU_EQUAL_S(CPU_ALLOC_SIZE(info->num_cpu), info->online, info->to_keep) ||
|
||||
CPU_COUNT_S(CPU_ALLOC_SIZE(info->num_cpu), info->to_keep) == 0)
|
||||
LOG_MSG("kernel did not indicate that this was an P/E-cores system\n");
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int walk_sysfs(char *cpulist, char **buf, size_t *buflen, GameModeCPUInfo *info)
|
||||
{
|
||||
char path[PATH_MAX];
|
||||
@ -84,8 +116,6 @@ static int walk_sysfs(char *cpulist, char **buf, size_t *buflen, GameModeCPUInfo
|
||||
char *list = cpulist;
|
||||
while ((list = parse_cpulist(list, &from, &to))) {
|
||||
for (long cpu = from; cpu < to + 1; cpu++) {
|
||||
CPU_SET_S((size_t)cpu, CPU_ALLOC_SIZE(info->num_cpu), info->online);
|
||||
|
||||
/* check for L3 cache non-uniformity among the cores */
|
||||
int ret =
|
||||
snprintf(path, PATH_MAX, "/sys/devices/system/cpu/cpu%ld/cache/index3/size", cpu);
|
||||
@ -125,7 +155,7 @@ static int walk_sysfs(char *cpulist, char **buf, size_t *buflen, GameModeCPUInfo
|
||||
if (ret > 0 && ret < PATH_MAX) {
|
||||
if (read_small_file(path, buf, buflen)) {
|
||||
unsigned long long freq = strtoull(*buf, NULL, 10);
|
||||
unsigned long long cutoff = (freq * 5) / 100;
|
||||
unsigned long long cutoff = (freq * 10) / 100;
|
||||
|
||||
if (freq > max_freq) {
|
||||
if (max_freq < freq - cutoff)
|
||||
@ -278,8 +308,13 @@ int game_mode_initialise_cpu(GameModeConfig *config, GameModeCPUInfo **info)
|
||||
} else if (park_or_pin == IS_CPU_PIN && pin_cores[0] != '\0') {
|
||||
if (!walk_string(buf, pin_cores, new_info))
|
||||
goto error_exit;
|
||||
} else if (!walk_sysfs(buf, &buf2, &buf2len, new_info)) {
|
||||
goto error_exit;
|
||||
} else {
|
||||
set_online_from_list(buf, new_info);
|
||||
|
||||
if (!check_pe_cores(&buf2, &buf2len, new_info)) {
|
||||
if (!walk_sysfs(buf, &buf2, &buf2len, new_info))
|
||||
goto error_exit;
|
||||
}
|
||||
}
|
||||
|
||||
if (park_or_pin == IS_CPU_PARK &&
|
||||
|
@ -1,6 +1,6 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2017-2019, Feral Interactive
|
||||
Copyright (c) 2017-2025, Feral Interactive and the GameMode contributors
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
|
@ -1,7 +1,7 @@
|
||||
|
||||
/*
|
||||
|
||||
Copyright (c) 2017-2019, Feral Interactive
|
||||
Copyright (c) 2017-2025, Feral Interactive and the GameMode contributors
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
|
@ -1,6 +1,6 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2017-2019, Feral Interactive
|
||||
Copyright (c) 2017-2025, Feral Interactive and the GameMode contributors
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
@ -60,7 +60,7 @@ POSSIBILITY OF SUCH DAMAGE.
|
||||
#endif
|
||||
|
||||
#ifndef IOPRIO_PRIO_DATA
|
||||
#define IOPRIO_PRIO_DATA(mask) ((mask)&IOPRIO_PRIO_MASK)
|
||||
#define IOPRIO_PRIO_DATA(mask) ((mask) & IOPRIO_PRIO_MASK)
|
||||
#endif
|
||||
|
||||
#ifndef IOPRIO_PRIO_VALUE
|
||||
|
@ -1,6 +1,6 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2017-2019, Feral Interactive
|
||||
Copyright (c) 2017-2025, Feral Interactive and the GameMode contributors
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
|
@ -1,6 +1,6 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2017-2019, Feral Interactive
|
||||
Copyright (c) 2017-2025, Feral Interactive and the GameMode contributors
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
@ -36,6 +36,7 @@ POSSIBILITY OF SUCH DAMAGE.
|
||||
#include "common-gpu.h"
|
||||
#include "common-helpers.h"
|
||||
#include "common-logging.h"
|
||||
#include "common-profile.h"
|
||||
|
||||
#include "gamemode.h"
|
||||
#include "gamemode-config.h"
|
||||
@ -357,6 +358,62 @@ static int run_cpu_governor_tests(struct GameModeConfig *config)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Check the platform profile setting works */
|
||||
static int run_platform_profile_tests(struct GameModeConfig *config)
|
||||
{
|
||||
if (!profile_exists())
|
||||
return 1;
|
||||
|
||||
/* get the two config parameters we care about */
|
||||
char desiredprof[CONFIG_VALUE_MAX] = { 0 };
|
||||
config_get_desired_profile(config, desiredprof);
|
||||
|
||||
if (desiredprof[0] == '\0')
|
||||
strcpy(desiredprof, "performance");
|
||||
|
||||
char defaultprof[CONFIG_VALUE_MAX] = { 0 };
|
||||
config_get_default_profile(config, defaultprof);
|
||||
|
||||
if (defaultprof[0] == '\0') {
|
||||
const char *currentprof = get_profile_state();
|
||||
if (currentprof) {
|
||||
strncpy(defaultprof, currentprof, CONFIG_VALUE_MAX - 1);
|
||||
} else {
|
||||
LOG_ERROR(
|
||||
"Could not get current platform profile state, this indicates an error! See rest "
|
||||
"of log.\n");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
/* Start gamemode */
|
||||
gamemode_request_start();
|
||||
|
||||
/* Verify the platform profile is the desired one */
|
||||
const char *currentprof = get_profile_state();
|
||||
if (strncmp(currentprof, desiredprof, CONFIG_VALUE_MAX) != 0) {
|
||||
LOG_ERROR("Platform profile was not set to %s (was actually %s)!\n",
|
||||
desiredprof,
|
||||
currentprof);
|
||||
gamemode_request_end();
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* End gamemode */
|
||||
gamemode_request_end();
|
||||
|
||||
/* Verify the platform profile has been set back */
|
||||
currentprof = get_profile_state();
|
||||
if (strncmp(currentprof, defaultprof, CONFIG_VALUE_MAX) != 0) {
|
||||
LOG_ERROR("Platform profile was not set back to %s (was actually %s)!\n",
|
||||
defaultprof,
|
||||
currentprof);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int run_custom_scripts_tests(struct GameModeConfig *config)
|
||||
{
|
||||
int scriptstatus = 0;
|
||||
@ -801,11 +858,32 @@ static int game_mode_run_feature_tests(struct GameModeConfig *config)
|
||||
LOG_MSG("::: Passed\n");
|
||||
else {
|
||||
LOG_MSG("::: Failed!\n");
|
||||
LOG_MSG(" -- You may need to add your user to the gamemode group:");
|
||||
LOG_MSG(" -- $ sudo usermod -aG gamemode $(whoami)");
|
||||
// Consider the CPU governor feature required
|
||||
status = -1;
|
||||
}
|
||||
}
|
||||
|
||||
/* Does the platform profile get set properly? */
|
||||
{
|
||||
LOG_MSG("::: Verifying platform profile setting\n");
|
||||
|
||||
int profstatus = run_platform_profile_tests(config);
|
||||
|
||||
if (profstatus == 1)
|
||||
LOG_MSG("::: Passed (platform profile not supported)\n");
|
||||
else if (profstatus == 0)
|
||||
LOG_MSG("::: Passed\n");
|
||||
else {
|
||||
LOG_MSG("::: Failed!\n");
|
||||
LOG_MSG(" -- You may need to add your user to the gamemode group:");
|
||||
LOG_MSG(" -- $ sudo usermod -aG gamemode $(whoami)");
|
||||
// If available, setting the platform profile should work
|
||||
status = -1;
|
||||
}
|
||||
}
|
||||
|
||||
/* Do custom scripts run? */
|
||||
{
|
||||
LOG_MSG("::: Verifying Scripts\n");
|
||||
|
@ -1,6 +1,6 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2017-2019, Feral Interactive
|
||||
Copyright (c) 2017-2025, Feral Interactive and the GameMode contributors
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
|
@ -1,6 +1,6 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2017-2019, Feral Interactive
|
||||
Copyright (c) 2017-2025, Feral Interactive and the GameMode contributors
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
|
@ -1,6 +1,6 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2017-2019, Feral Interactive
|
||||
Copyright (c) 2017-2025, Feral Interactive and the GameMode contributors
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
|
@ -9,7 +9,7 @@ data_conf.set('GAMEMODE_PRIVILEGED_GROUP', with_privileged_group)
|
||||
# Pull in the example config
|
||||
config_example = run_command(
|
||||
'cat',
|
||||
join_paths(meson.source_root(), 'example', 'gamemode.ini'),
|
||||
join_paths(meson.project_source_root(), 'example', 'gamemode.ini'),
|
||||
check: true,
|
||||
).stdout().strip()
|
||||
data_conf.set('GAMEMODE_EXAMPLE_CONFIG', config_example)
|
||||
|
@ -5,7 +5,7 @@
|
||||
<policyconfig>
|
||||
|
||||
<!--
|
||||
Copyright (c) 2017-2019, Feral Interactive
|
||||
Copyright (c) 2017-2025, Feral Interactive and the GameMode contributors
|
||||
All rights reserved.
|
||||
-->
|
||||
|
||||
@ -58,4 +58,16 @@
|
||||
<annotate key="org.freedesktop.policykit.exec.path">@LIBEXECDIR@/procsysctl</annotate>
|
||||
<annotate key="org.freedesktop.policykit.exec.allow_gui">true</annotate>
|
||||
</action>
|
||||
|
||||
<action id="com.feralinteractive.GameMode.profile-helper">
|
||||
<description>Modify the platform profile</description>
|
||||
<message>Authentication is required to modify platform profile</message>
|
||||
<defaults>
|
||||
<allow_any>no</allow_any>
|
||||
<allow_inactive>no</allow_inactive>
|
||||
<allow_active>no</allow_active>
|
||||
</defaults>
|
||||
<annotate key="org.freedesktop.policykit.exec.path">@LIBEXECDIR@/platprofctl</annotate>
|
||||
<annotate key="org.freedesktop.policykit.exec.allow_gui">true</annotate>
|
||||
</action>
|
||||
</policyconfig>
|
||||
|
@ -6,7 +6,8 @@ polkit.addRule(function (action, subject) {
|
||||
if ((action.id == "com.feralinteractive.GameMode.governor-helper" ||
|
||||
action.id == "com.feralinteractive.GameMode.gpu-helper" ||
|
||||
action.id == "com.feralinteractive.GameMode.cpu-helper" ||
|
||||
action.id == "com.feralinteractive.GameMode.procsys-helper") &&
|
||||
action.id == "com.feralinteractive.GameMode.procsys-helper" ||
|
||||
action.id == "com.feralinteractive.GameMode.profile-helper") &&
|
||||
subject.isInGroup("@GAMEMODE_PRIVILEGED_GROUP@"))
|
||||
{
|
||||
return polkit.Result.YES;
|
||||
|
@ -7,6 +7,11 @@ desiredgov=performance
|
||||
; The default governor is used when leaving GameMode instead of restoring the original value
|
||||
;defaultgov=powersave
|
||||
|
||||
; The desired platform profile is used when entering GameMode instead of "performance"
|
||||
desiredprof=performance
|
||||
; The default platform profile is used when leaving GameMode instead of restoring the original value
|
||||
;defaultgov=low-power
|
||||
|
||||
; The iGPU desired governor is used when the integrated GPU is under heavy load
|
||||
igpu_desiredgov=powersave
|
||||
; Threshold to use to decide when the integrated GPU is under heavy load.
|
||||
|
@ -1,6 +1,6 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2017-2019, Feral Interactive
|
||||
Copyright (c) 2017-2025, Feral Interactive and the GameMode contributors
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
|
@ -1,6 +1,6 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2017-2019, Feral Interactive
|
||||
Copyright (c) 2017-2025, Feral Interactive and the GameMode contributors
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
|
@ -1,6 +1,6 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2017-2019, Feral Interactive
|
||||
Copyright (c) 2017-2025, Feral Interactive and the GameMode contributors
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
|
@ -1,6 +1,6 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2017-2019, Feral Interactive
|
||||
Copyright (c) 2017-2025, Feral Interactive and the GameMode contributors
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
|
@ -4,6 +4,7 @@ project(
|
||||
default_options : ['c_std=c11', 'warning_level=3'],
|
||||
version: '1.8.2',
|
||||
license: 'BSD',
|
||||
meson_version: '>= 1.3.1',
|
||||
)
|
||||
|
||||
am_cflags = [
|
||||
@ -112,7 +113,7 @@ if sd_bus_provider == 'systemd'
|
||||
if path_systemd_unit_dir == ''
|
||||
message('Asking pkg-config for systemd\'s \'systemduserunitdir\' directory')
|
||||
pkgconfig_systemd = dependency('systemd')
|
||||
path_systemd_unit_dir = pkgconfig_systemd.get_pkgconfig_variable('systemduserunitdir')
|
||||
path_systemd_unit_dir = pkgconfig_systemd.get_variable(pkgconfig: 'systemduserunitdir')
|
||||
endif
|
||||
endif
|
||||
if with_privileged_group != ''
|
||||
@ -122,7 +123,7 @@ if sd_bus_provider == 'systemd'
|
||||
if path_systemd_group_dir == ''
|
||||
message('Asking pkg-config for systemd\'s \'sysusersdir\' directory')
|
||||
pkgconfig_systemd = dependency('systemd')
|
||||
path_systemd_group_dir = pkgconfig_systemd.get_pkgconfig_variable('sysusersdir')
|
||||
path_systemd_group_dir = pkgconfig_systemd.get_variable(pkgconfig: 'sysusersdir')
|
||||
endif
|
||||
endif
|
||||
else
|
||||
|
@ -1,20 +1,20 @@
|
||||
# limits.d
|
||||
option('with-pam-renicing', type: 'boolean', description: 'Install the limits.d configuration file to allow renicing as a user being part of the privileged gamemode group', value: 'true')
|
||||
option('with-pam-renicing', type: 'boolean', description: 'Install the limits.d configuration file to allow renicing as a user being part of the privileged gamemode group', value: true)
|
||||
option('with-pam-limits-dir', type: 'string', description: 'Explicitly set the PAM limits.d directory', value: '/etc/security/limits.d')
|
||||
|
||||
# sd-bus provider
|
||||
option('with-sd-bus-provider', type: 'combo', choices: ['systemd', 'elogind', 'no-daemon'], value: 'systemd')
|
||||
|
||||
# systemd specific
|
||||
option('with-systemd-user-unit', type: 'boolean', description: 'Install systemd user unit', value: 'true')
|
||||
option('with-systemd-user-unit', type: 'boolean', description: 'Install systemd user unit', value: true)
|
||||
option('with-systemd-user-unit-dir', type: 'string', description: 'Explicitly set the systemd user unit directory')
|
||||
option('with-systemd-group', type: 'boolean', description: 'Install privileged gamemode group with systemd', value: 'true')
|
||||
option('with-systemd-group', type: 'boolean', description: 'Install privileged gamemode group with systemd', value: true)
|
||||
option('with-systemd-group-dir', type: 'string', description: 'Explicitly set the systemd group directory')
|
||||
|
||||
# Not using systemd
|
||||
option('with-dbus-service-dir', type: 'string', description: 'Explicitly set the D-BUS session directory')
|
||||
|
||||
# General options
|
||||
option('with-examples', type: 'boolean', description: 'Build sample programs', value: 'true')
|
||||
option('with-util', type: 'boolean', description: 'Build the utilities', value: 'true')
|
||||
option('with-examples', type: 'boolean', description: 'Build sample programs', value: true)
|
||||
option('with-util', type: 'boolean', description: 'Build the utilities', value: true)
|
||||
option('with-privileged-group', type: 'string', description: 'Group that has access to privileged gamemode features', value: 'gamemode')
|
||||
|
@ -1,10 +1,9 @@
|
||||
[wrap-file]
|
||||
directory = inih-r54
|
||||
source_url = https://github.com/benhoyt/inih/archive/r54.tar.gz
|
||||
source_filename = inih-r54.tar.gz
|
||||
source_hash = b5566af5203f8a49fda27f1b864c0c157987678ffbd183280e16124012869869
|
||||
directory = inih-r60
|
||||
source_url = https://github.com/benhoyt/inih/archive/r60.tar.gz
|
||||
source_filename = inih-r60.tar.gz
|
||||
source_hash = 706aa05c888b53bd170e5d8aa8f8a9d9ccf5449dfed262d5103d1f292af26774
|
||||
|
||||
[provide]
|
||||
inih = inih_dep
|
||||
inireader = INIReader_dep
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2017-2019, Feral Interactive
|
||||
Copyright (c) 2017-2025, Feral Interactive and the GameMode contributors
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
|
@ -1,6 +1,6 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2017-2019, Feral Interactive
|
||||
Copyright (c) 2017-2025, Feral Interactive and the GameMode contributors
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
|
@ -1,6 +1,6 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2017-2019, Feral Interactive
|
||||
Copyright (c) 2017-2025, Feral Interactive and the GameMode contributors
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
|
@ -58,3 +58,18 @@ procsysctl = executable(
|
||||
install: true,
|
||||
install_dir: path_libexecdir,
|
||||
)
|
||||
|
||||
# Small target util to get and set platform profile
|
||||
platprofctl_sources = [
|
||||
'platprofctl.c',
|
||||
]
|
||||
|
||||
platprofctl = executable(
|
||||
'platprofctl',
|
||||
sources: platprofctl_sources,
|
||||
dependencies: [
|
||||
link_daemon_common,
|
||||
],
|
||||
install: true,
|
||||
install_dir: path_libexecdir,
|
||||
)
|
||||
|
84
util/platprofctl.c
Normal file
84
util/platprofctl.c
Normal file
@ -0,0 +1,84 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2025, the GameMode contributors
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright notice,
|
||||
this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
* Neither the name of Feral Interactive nor the names of its contributors
|
||||
may be used to endorse or promote products derived from this software
|
||||
without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
*/
|
||||
|
||||
#define _GNU_SOURCE
|
||||
|
||||
#include "common-logging.h"
|
||||
#include "common-profile.h"
|
||||
|
||||
#include <unistd.h>
|
||||
|
||||
/**
|
||||
* Sets platform profile to a value
|
||||
*/
|
||||
static int set_profile_state(const char *value)
|
||||
{
|
||||
int retval = EXIT_SUCCESS;
|
||||
|
||||
FILE *f = fopen(profile_path, "w");
|
||||
if (!f) {
|
||||
LOG_ERROR("Failed to open file for write %s\n", profile_path);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
if (fprintf(f, "%s\n", value) < 0) {
|
||||
LOG_ERROR("Failed to set platform profile to %s: %s", value, strerror(errno));
|
||||
retval = EXIT_FAILURE;
|
||||
}
|
||||
fclose(f);
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
/**
|
||||
* Main entry point, dispatch to the appropriate helper
|
||||
*/
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
if (argc == 2 && strncmp(argv[1], "get", 3) == 0) {
|
||||
printf("%s", get_profile_state());
|
||||
} else if (argc == 3 && strncmp(argv[1], "set", 3) == 0) {
|
||||
const char *value = argv[2];
|
||||
|
||||
/* Must be root to set the state */
|
||||
if (geteuid() != 0) {
|
||||
LOG_ERROR("This program must be run as root\n");
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
return set_profile_state(value);
|
||||
} else {
|
||||
fprintf(stderr, "usage: platprofctl [get] [set VALUE]\n");
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
Copyright (c) 2017-2023, Feral Interactive
|
||||
Copyright (c) 2017-2025, Feral Interactive and the GameMode contributors
|
||||
All rights reserved.
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
@ -27,8 +27,9 @@ POSSIBILITY OF SUCH DAMAGE.
|
||||
#define _GNU_SOURCE
|
||||
#include <unistd.h>
|
||||
#include "common-logging.h"
|
||||
#include "common-splitlock.h"
|
||||
|
||||
static bool write_value(char *key, char *value)
|
||||
static bool write_value(const char *key, const char *value)
|
||||
{
|
||||
FILE *f = fopen(key, "w");
|
||||
|
||||
@ -58,7 +59,7 @@ int main(int argc, char *argv[])
|
||||
|
||||
if (argc == 3) {
|
||||
if (strcmp(argv[1], "split_lock_mitigate") == 0) {
|
||||
if (!write_value("/proc/sys/kernel/split_lock_mitigate", argv[2]))
|
||||
if (!write_value(splitlock_path, argv[2]))
|
||||
return EXIT_FAILURE;
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
|
Loading…
x
Reference in New Issue
Block a user