Compare commits

..

No commits in common. "master" and "1.8.1" have entirely different histories.

58 changed files with 197 additions and 840 deletions

View File

@ -19,6 +19,7 @@ AlwaysBreakTemplateDeclarations: false
BinPackArguments: false
BinPackParameters: true
BreakBeforeBinaryOperators: None
BreakBeforeBinaryOperators: None
BreakBeforeBraces: Linux
BreakBeforeTernaryOperators: true
BreakConstructorInitializersBeforeComma: false

View File

@ -1,18 +1,15 @@
name: Build and test
on: [push, pull_request]
permissions:
contents: read
actions: write
jobs:
build-and-test:
runs-on: ubuntu-latest
runs-on: ubuntu-20.04
steps:
- name: Checkout
uses: actions/checkout@v2
- name: Install dependencies
run: |
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
sudo apt install build-essential meson appstream clang clang-format clang-tools libdbus-1-dev libinih-dev libsystemd-dev
- name: Check format
env:
CI: "true"
@ -34,7 +31,7 @@ jobs:
./scripts/static-analyser-check.sh
- name: Upload logs
if: ${{ always() }}
uses: actions/upload-artifact@v4
uses: actions/upload-artifact@v2
with:
name: logs
path: |

1
.gitignore vendored
View File

@ -1,3 +1,2 @@
/builddir
/subprojects/packagecache/
/subprojects/inih-r*

View File

@ -1,24 +1,3 @@
## 1.8.2
### Changes
* Fix idle inhibitor closing bus connection too early (#466)
* Fix hybrid CPU core pinning (#455)
* Fix unreadable process maps in gamemodelist (#463)
* Fixed crash if dbus is not accesible (#458)
* Various bugfixes and improvements to documentation
### Contributors
* @notpeelz
* @patatahooligan
* Reilly Brogan @ReillyBrogan
* Alexandru Ionut Tripon @Trial97
* Kostadin @kostadinsh
* Daniel Martinez @Calandracas606
[View the full list of contributors](https://github.com/FeralInteractive/gamemode/graphs/contributors?from=2023-12-13&to=2024-08-19&type=c)
## 1.8.1
### Changes

View File

@ -1,4 +1,4 @@
Copyright (c) 2017-2025, Feral Interactive and the GameMode contributors
Copyright (c) 2017-2023, Feral Interactive
All rights reserved.
Redistribution and use in source and binary forms, with or without

View File

@ -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, simply running the game will automatically activate GameMode.
For games/launchers which integrate GameMode support (see list later on), 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,6 +58,29 @@ 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 ([via extension](https://github.com/gicmo/gamemode-extension)) - indicates when GameMode is active in the top panel.
* Lutris - 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) - is a frontend for emulators, game engines and media players.
---
## Development [![Build and test](https://github.com/FeralInteractive/gamemode/actions/workflows/build-and-test.yml/badge.svg)](https://github.com/FeralInteractive/gamemode/actions/workflows/build-and-test.yml)
@ -66,16 +89,15 @@ 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. These instructions all assume that you
already have a C development environment (gcc or clang, libc-devel, etc) installed.
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`)
#### Ubuntu/Debian
Note: Debian 13 and Ubuntu 25.04 (and later) need to install `systemd-dev` in addition to the dependencies below.
```bash
apt update && apt install meson libsystemd-dev pkg-config ninja-build git dbus-user-session libdbus-1-dev libinih-dev build-essential
apt install meson libsystemd-dev pkg-config ninja-build git libdbus-1-dev libinih-dev build-essential
```
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`.
On Ubuntu 18.04, you'll need to install `python3` package and install the latest meson version from `pip`.
```bash
python3 -m venv .venv
@ -92,28 +114,12 @@ rm -rf .venv
#### Arch
```bash
pacman -S meson systemd git dbus libinih gcc pkgconf
pacman -S meson systemd git dbus libinih
```
#### 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 inih-devel
dnf install meson systemd-devel pkg-config git dbus-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
@ -124,19 +130,13 @@ 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:
Then clone, build and install a release version of GameMode at 1.8.1:
```bash
git clone https://github.com/FeralInteractive/gamemode.git
cd gamemode
git checkout 1.8.2 # omit to build the master branch
git checkout 1.8.1 # omit to build the master branch
./bootstrap.sh
```
To test GameMode installed and will run correctly:
@ -164,7 +164,7 @@ See the [contributors](https://github.com/FeralInteractive/gamemode/graphs/contr
---
## License
Copyright © 2017-2025 Feral Interactive and the GameMode contributors
Copyright © 2017-2023 Feral Interactive
GameMode is available under the terms of the BSD 3-Clause License (Revised)

View File

@ -1,6 +1,6 @@
/*
Copyright (c) 2017-2025, Feral Interactive and the GameMode contributors
Copyright (c) 2017-2019, Feral Interactive
All rights reserved.
Redistribution and use in source and binary forms, with or without

View File

@ -1,6 +1,6 @@
/*
Copyright (c) 2017-2025, Feral Interactive and the GameMode contributors
Copyright (c) 2017-2019, Feral Interactive
All rights reserved.
Redistribution and use in source and binary forms, with or without
@ -31,8 +31,6 @@ POSSIBILITY OF SUCH DAMAGE.
#pragma once
#define _GNU_SOURCE
#include <sched.h>
#include <stdlib.h>

View File

@ -1,6 +1,6 @@
/*
Copyright (c) 2017-2025, Feral Interactive and the GameMode contributors
Copyright (c) 2017-2019, Feral Interactive
All rights reserved.
Redistribution and use in source and binary forms, with or without

View File

@ -1,6 +1,6 @@
/*
Copyright (c) 2017-2025, Feral Interactive and the GameMode contributors
Copyright (c) 2017-2019, Feral Interactive
All rights reserved.
Redistribution and use in source and binary forms, with or without

View File

@ -1,6 +1,6 @@
/*
Copyright (c) 2017-2025, Feral Interactive and the GameMode contributors
Copyright (c) 2017-2019, Feral Interactive
All rights reserved.
Redistribution and use in source and binary forms, with or without

View File

@ -1,6 +1,6 @@
/*
Copyright (c) 2017-2025, Feral Interactive and the GameMode contributors
Copyright (c) 2017-2019, Feral Interactive
All rights reserved.
Redistribution and use in source and binary forms, with or without

View File

@ -1,6 +1,6 @@
/*
Copyright (c) 2017-2025, Feral Interactive and the GameMode contributors
Copyright (c) 2017-2019, Feral Interactive
All rights reserved.
Redistribution and use in source and binary forms, with or without

View File

@ -1,6 +1,6 @@
/*
Copyright (c) 2017-2025, Feral Interactive and the GameMode contributors
Copyright (c) 2017-2019, Feral Interactive
All rights reserved.
Redistribution and use in source and binary forms, with or without

View File

@ -1,6 +1,6 @@
/*
Copyright (c) 2017-2025, Feral Interactive and the GameMode contributors
Copyright (c) 2017-2019, Feral Interactive
Copyright (c) 2019, Red Hat
All rights reserved.

View File

@ -1,6 +1,6 @@
/*
Copyright (c) 2017-2025, Feral Interactive and the GameMode contributors
Copyright (c) 2017-2019, Feral Interactive
All rights reserved.
Redistribution and use in source and binary forms, with or without

View File

@ -1,6 +1,6 @@
/*
Copyright (c) 2017-2025, Feral Interactive and the GameMode contributors
Copyright (c) 2017-2019, Feral Interactive
All rights reserved.
Redistribution and use in source and binary forms, with or without

View File

@ -1,6 +1,6 @@
/*
Copyright (c) 2017-2025, Feral Interactive and the GameMode contributors
Copyright (c) 2017-2019, Feral Interactive
All rights reserved.
Redistribution and use in source and binary forms, with or without

View File

@ -1,6 +1,6 @@
/*
Copyright (c) 2017-2025, Feral Interactive and the GameMode contributors
Copyright (c) 2017-2019, Feral Interactive
Copyright (c) 2019, Red Hat
All rights reserved.

View File

@ -1,6 +1,6 @@
/*
Copyright (c) 2017-2025, Feral Interactive and the GameMode contributors
Copyright (c) 2017-2019, Feral Interactive
Copyright (c) 2019, Red Hat
All rights reserved.

View File

@ -1,6 +1,6 @@
/*
Copyright (c) 2017-2025, Feral Interactive and the GameMode contributors
Copyright (c) 2017-2019, Feral Interactive
Copyright (c) 2019, Intel Corporation
All rights reserved.

View File

@ -1,6 +1,6 @@
/*
Copyright (c) 2017-2025, Feral Interactive and the GameMode contributors
Copyright (c) 2017-2019, Feral Interactive
All rights reserved.
Redistribution and use in source and binary forms, with or without

View File

@ -1,86 +0,0 @@
/*
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;
}

View File

@ -1,50 +0,0 @@
/*
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);

View File

@ -1,64 +0,0 @@
/*
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;
}

View File

@ -1,44 +0,0 @@
/*
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);

View File

@ -2,8 +2,6 @@
common_sources = [
'common-logging.c',
'common-governors.c',
'common-profile.c',
'common-splitlock.c',
'common-external.c',
'common-helpers.c',
'common-gpu.c',

View File

@ -1,6 +1,6 @@
/*
Copyright (c) 2017-2025, Feral Interactive and the GameMode contributors
Copyright (c) 2017-2019, Feral Interactive
All rights reserved.
Redistribution and use in source and binary forms, with or without
@ -41,7 +41,6 @@ POSSIBILITY OF SUCH DAMAGE.
#include <ini.h>
#include <dirent.h>
#include <libgen.h>
#include <math.h>
#include <pthread.h>
#include <pwd.h>
@ -88,9 +87,6 @@ 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;
@ -268,10 +264,6 @@ 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) {
@ -698,29 +690,13 @@ void config_get_default_governor(GameModeConfig *self, char governor[CONFIG_VALU
}
/*
* Get the chosen desired platform profile
* Get the chosen desired governor
*/
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
*/

View File

@ -1,6 +1,6 @@
/*
Copyright (c) 2017-2025, Feral Interactive and the GameMode contributors
Copyright (c) 2017-2019, Feral Interactive
All rights reserved.
Redistribution and use in source and binary forms, with or without
@ -102,8 +102,6 @@ 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]);

View File

@ -1,6 +1,6 @@
/*
Copyright (c) 2017-2025, Feral Interactive and the GameMode contributors
Copyright (c) 2017-2019, Feral Interactive
All rights reserved.
Redistribution and use in source and binary forms, with or without
@ -36,8 +36,6 @@ 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"
@ -73,11 +71,6 @@ 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 */
@ -89,16 +82,11 @@ 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 */
struct GameModeCPUInfo *cpu; /**<Stored CPU info for the current CPU */
GameModeIdleInhibitor *idle_inhibitor;
bool igpu_optimization_enabled;
uint32_t last_cpu_energy_uj;
uint32_t last_igpu_energy_uj;
@ -219,13 +207,6 @@ 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))
@ -234,9 +215,31 @@ static int game_mode_disable_splitlock(GameModeContext *self, bool disable)
long value_num = self->initial_split_lock_mitigate;
char value_str[40];
if (disable && value_num == 0)
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 (value_num == -1)
return 0;
@ -256,26 +259,25 @@ 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) {
@ -315,65 +317,6 @@ 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);
@ -461,15 +404,6 @@ 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.
*
@ -481,14 +415,6 @@ 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.
@ -497,10 +423,8 @@ static void game_mode_context_enter(GameModeContext *self)
}
/* Inhibit the screensaver */
if (config_get_inhibit_screensaver(self->config)) {
game_mode_destroy_idle_inhibitor(self->idle_inhibitor);
self->idle_inhibitor = game_mode_create_idle_inhibitor();
}
if (config_get_inhibit_screensaver(self->config))
game_mode_inhibit_screensaver(true);
game_mode_disable_splitlock(self, true);
@ -530,21 +454,14 @@ 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);
game_mode_unpark_cpu(self->cpu);
/* UnInhibit the screensaver */
if (config_get_inhibit_screensaver(self->config)) {
game_mode_destroy_idle_inhibitor(self->idle_inhibitor);
self->idle_inhibitor = NULL;
}
if (config_get_inhibit_screensaver(self->config))
game_mode_inhibit_screensaver(false);
game_mode_disable_splitlock(self, false);

View File

@ -1,7 +1,7 @@
/*
Copyright (c) 2017-2025, Feral Interactive and the GameMode contributors
Copyright (c) 2017-2019, Feral Interactive
All rights reserved.
Redistribution and use in source and binary forms, with or without
@ -73,38 +73,6 @@ 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];
@ -116,6 +84,8 @@ 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);
@ -155,7 +125,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 * 10) / 100;
unsigned long long cutoff = (freq * 5) / 100;
if (freq > max_freq) {
if (max_freq < freq - cutoff)
@ -164,7 +134,7 @@ static int walk_sysfs(char *cpulist, char **buf, size_t *buflen, GameModeCPUInfo
max_freq = freq;
}
if (freq + cutoff >= max_freq)
if (freq - cutoff >= max_freq)
CPU_SET_S((size_t)cpu, CPU_ALLOC_SIZE(info->num_cpu), freq_cores);
}
}
@ -308,14 +278,9 @@ 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 {
set_online_from_list(buf, new_info);
if (!check_pe_cores(&buf2, &buf2len, new_info)) {
if (!walk_sysfs(buf, &buf2, &buf2len, new_info))
} else if (!walk_sysfs(buf, &buf2, &buf2len, new_info)) {
goto error_exit;
}
}
if (park_or_pin == IS_CPU_PARK &&
CPU_EQUAL_S(CPU_ALLOC_SIZE(new_info->num_cpu), new_info->online, new_info->to_keep)) {

View File

@ -1,6 +1,6 @@
/*
Copyright (c) 2017-2025, Feral Interactive and the GameMode contributors
Copyright (c) 2017-2019, Feral Interactive
All rights reserved.
Redistribution and use in source and binary forms, with or without
@ -708,106 +708,81 @@ void game_mode_context_loop(GameModeContext *context)
}
}
struct GameModeIdleInhibitor {
sd_bus *bus;
unsigned int cookie;
};
/**
* Attempts to inhibit the screensaver
* Uses the "org.freedesktop.ScreenSaver" interface
*/
GameModeIdleInhibitor *game_mode_create_idle_inhibitor(void)
static unsigned int screensaver_inhibit_cookie = 0;
int game_mode_inhibit_screensaver(bool inhibit)
{
const char *service = "org.freedesktop.ScreenSaver";
const char *object_path = "/org/freedesktop/ScreenSaver";
const char *interface = "org.freedesktop.ScreenSaver";
const char *function = inhibit ? "Inhibit" : "UnInhibit";
sd_bus_message *msg = NULL;
sd_bus *bus_local = NULL;
sd_bus_error err = SD_BUS_ERROR_NULL;
sd_bus_error err;
memset(&err, 0, sizeof(sd_bus_error));
int result = -1;
// Open the user bus
int ret = sd_bus_open_user(&bus_local);
if (ret < 0) {
LOG_ERROR("Could not connect to user bus: %s\n", strerror(-ret));
return NULL;
return -1;
}
if (inhibit) {
ret = sd_bus_call_method(bus_local,
"org.freedesktop.ScreenSaver",
"/org/freedesktop/ScreenSaver",
"org.freedesktop.ScreenSaver",
"Inhibit",
service,
object_path,
interface,
function,
&err,
&msg,
"ss",
"com.feralinteractive.GameMode",
"GameMode Activated");
if (ret < 0) {
LOG_ERROR(
"Failed to call Inhibit on org.freedesktop.ScreenSaver: %s\n"
"\t%s\n"
"\t%s\n",
strerror(-ret),
err.name,
err.message);
sd_bus_close(bus_local);
sd_bus_unrefp(&bus_local);
return NULL;
}
// Read the reply
unsigned int cookie = 0;
ret = sd_bus_message_read(msg, "u", &cookie);
if (ret < 0) {
LOG_ERROR("Invalid response from Inhibit on org.freedesktop.ScreenSaver: %s\n",
strerror(-ret));
sd_bus_close(bus_local);
sd_bus_unrefp(&bus_local);
return NULL;
}
GameModeIdleInhibitor *inhibitor = malloc(sizeof(GameModeIdleInhibitor));
if (inhibitor == NULL) {
sd_bus_close(bus_local);
sd_bus_unrefp(&bus_local);
return NULL;
}
inhibitor->bus = bus_local;
inhibitor->cookie = cookie;
return inhibitor;
}
void game_mode_destroy_idle_inhibitor(GameModeIdleInhibitor *inhibitor)
{
sd_bus_message *msg = NULL;
sd_bus_error err = SD_BUS_ERROR_NULL;
if (inhibitor == NULL) {
return;
}
int ret = sd_bus_call_method(inhibitor->bus,
"org.freedesktop.ScreenSaver",
"/org/freedesktop/ScreenSaver",
"org.freedesktop.ScreenSaver",
"UnInhibit",
} else {
ret = sd_bus_call_method(bus_local,
service,
object_path,
interface,
function,
&err,
&msg,
"u",
inhibitor->cookie);
screensaver_inhibit_cookie);
}
if (ret < 0) {
LOG_ERROR(
"Failed to call UnInhibit on org.freedesktop.ScreenSaver: %s\n"
"Could not call %s on %s: %s\n"
"\t%s\n"
"\t%s\n",
function,
service,
strerror(-ret),
err.name,
err.message);
} else if (inhibit) {
// Read the reply
ret = sd_bus_message_read(msg, "u", &screensaver_inhibit_cookie);
if (ret < 0) {
LOG_ERROR("Failure to parse response from %s on %s: %s\n",
function,
service,
strerror(-ret));
} else {
result = 0;
}
} else {
result = 0;
}
sd_bus_close(inhibitor->bus);
sd_bus_unrefp(&inhibitor->bus);
free(inhibitor);
sd_bus_unref(bus_local);
return result;
}

View File

@ -1,7 +1,7 @@
/*
Copyright (c) 2017-2025, Feral Interactive and the GameMode contributors
Copyright (c) 2017-2019, Feral Interactive
All rights reserved.
Redistribution and use in source and binary forms, with or without

View File

@ -1,6 +1,6 @@
/*
Copyright (c) 2017-2025, Feral Interactive and the GameMode contributors
Copyright (c) 2017-2019, Feral Interactive
All rights reserved.
Redistribution and use in source and binary forms, with or without

View File

@ -1,6 +1,6 @@
/*
Copyright (c) 2017-2025, Feral Interactive and the GameMode contributors
Copyright (c) 2017-2019, Feral Interactive
All rights reserved.
Redistribution and use in source and binary forms, with or without

View File

@ -1,6 +1,6 @@
/*
Copyright (c) 2017-2025, Feral Interactive and the GameMode contributors
Copyright (c) 2017-2019, Feral Interactive
All rights reserved.
Redistribution and use in source and binary forms, with or without
@ -36,7 +36,6 @@ 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"
@ -358,62 +357,6 @@ 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;
@ -858,32 +801,11 @@ 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");

View File

@ -1,6 +1,6 @@
/*
Copyright (c) 2017-2025, Feral Interactive and the GameMode contributors
Copyright (c) 2017-2019, Feral Interactive
All rights reserved.
Redistribution and use in source and binary forms, with or without

View File

@ -1,6 +1,6 @@
/*
Copyright (c) 2017-2025, Feral Interactive and the GameMode contributors
Copyright (c) 2017-2019, Feral Interactive
All rights reserved.
Redistribution and use in source and binary forms, with or without
@ -219,9 +219,7 @@ void game_mode_undo_core_pinning(const GameModeCPUInfo *info, const pid_t client
/** gamemode-dbus.c
* Provides an API interface for using dbus
*/
typedef struct GameModeIdleInhibitor GameModeIdleInhibitor;
void game_mode_context_loop(GameModeContext *context) __attribute__((noreturn));
GameModeIdleInhibitor *game_mode_create_idle_inhibitor(void);
void game_mode_destroy_idle_inhibitor(GameModeIdleInhibitor *inhibitor);
int game_mode_inhibit_screensaver(bool inhibit);
void game_mode_client_registered(pid_t);
void game_mode_client_unregistered(pid_t);

View File

@ -1,6 +1,6 @@
/*
Copyright (c) 2017-2025, Feral Interactive and the GameMode contributors
Copyright (c) 2017-2019, Feral Interactive
All rights reserved.
Redistribution and use in source and binary forms, with or without

View File

@ -28,5 +28,5 @@ if [ ! -d /proc ]; then
fi
find /proc -maxdepth 2 -type f -user "${USER}" -readable -name maps -exec \
awk -- 'BEGINFILE { if (ERRNO) nextfile } $0 ~ /libgamemodeauto\.so\.0/ {pid=FILENAME; gsub("[^0-9]", "", pid); print pid;nextfile}' {} + \
awk -- '$0 ~ /libgamemodeauto\.so\.0/ {pid=FILENAME; gsub("[^0-9]", "", pid); print pid;nextfile}' {} + \
| xargs | xargs -I{} -- ps -o pid,ppid,user,ni,psr,comm --pid '{}'

View File

@ -36,6 +36,4 @@
<category>Utility</category>
<category>Game</category>
</categories>
<url type="homepage">https://feralinteractive.github.io/gamemode</url>
</component>

View File

@ -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.project_source_root(), 'example', 'gamemode.ini'),
join_paths(meson.source_root(), 'example', 'gamemode.ini'),
check: true,
).stdout().strip()
data_conf.set('GAMEMODE_EXAMPLE_CONFIG', config_example)

View File

@ -5,7 +5,7 @@
<policyconfig>
<!--
Copyright (c) 2017-2025, Feral Interactive and the GameMode contributors
Copyright (c) 2017-2019, Feral Interactive
All rights reserved.
-->
@ -58,16 +58,4 @@
<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>

View File

@ -6,8 +6,7 @@ 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.profile-helper") &&
action.id == "com.feralinteractive.GameMode.procsys-helper") &&
subject.isInGroup("@GAMEMODE_PRIVILEGED_GROUP@"))
{
return polkit.Result.YES;

View File

@ -7,11 +7,6 @@ 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.
@ -92,8 +87,6 @@ disable_splitlock=1
; a range. E.g "park_cores=1,8-15" would park cores 1 and 8 to 15.
; The default is uncommented is to disable parking but enable pinning. If either is enabled the code will
; currently only properly autodetect Ryzen 7900x3d, 7950x3d and Intel CPU:s with E- and P-cores.
; For Core Parking, user must be added to the gamemode group (not required for Core Pinning):
; sudo usermod -aG gamemode $(whoami)
;park_cores=no
;pin_cores=yes

View File

@ -1,6 +1,6 @@
/*
Copyright (c) 2017-2025, Feral Interactive and the GameMode contributors
Copyright (c) 2017-2019, Feral Interactive
All rights reserved.
Redistribution and use in source and binary forms, with or without

View File

@ -1,6 +1,6 @@
/*
Copyright (c) 2017-2025, Feral Interactive and the GameMode contributors
Copyright (c) 2017-2019, Feral Interactive
All rights reserved.
Redistribution and use in source and binary forms, with or without
@ -150,7 +150,7 @@ static int log_error(const char *fmt, ...)
static void hop_off_the_bus(DBusConnection **bus)
{
if (bus == NULL || *bus == NULL)
if (bus == NULL)
return;
dbus_connection_unref(*bus);

View File

@ -1,6 +1,6 @@
/*
Copyright (c) 2017-2025, Feral Interactive and the GameMode contributors
Copyright (c) 2017-2019, Feral Interactive
All rights reserved.
Redistribution and use in source and binary forms, with or without

View File

@ -1,6 +1,6 @@
/*
Copyright (c) 2017-2025, Feral Interactive and the GameMode contributors
Copyright (c) 2017-2019, Feral Interactive
All rights reserved.
Redistribution and use in source and binary forms, with or without

View File

@ -2,9 +2,8 @@ project(
'gamemode',
'c',
default_options : ['c_std=c11', 'warning_level=3'],
version: '1.8.2',
version: '1.8.1',
license: 'BSD',
meson_version: '>= 1.3.1',
)
am_cflags = [
@ -113,7 +112,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_variable(pkgconfig: 'systemduserunitdir')
path_systemd_unit_dir = pkgconfig_systemd.get_pkgconfig_variable('systemduserunitdir')
endif
endif
if with_privileged_group != ''
@ -123,7 +122,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_variable(pkgconfig: 'sysusersdir')
path_systemd_group_dir = pkgconfig_systemd.get_pkgconfig_variable('sysusersdir')
endif
endif
else

View File

@ -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')

View File

@ -1,9 +1,10 @@
[wrap-file]
directory = inih-r60
source_url = https://github.com/benhoyt/inih/archive/r60.tar.gz
source_filename = inih-r60.tar.gz
source_hash = 706aa05c888b53bd170e5d8aa8f8a9d9ccf5449dfed262d5103d1f292af26774
directory = inih-r54
source_url = https://github.com/benhoyt/inih/archive/r54.tar.gz
source_filename = inih-r54.tar.gz
source_hash = b5566af5203f8a49fda27f1b864c0c157987678ffbd183280e16124012869869
[provide]
inih = inih_dep
inireader = INIReader_dep

View File

@ -1,6 +1,6 @@
/*
Copyright (c) 2017-2025, Feral Interactive and the GameMode contributors
Copyright (c) 2017-2019, Feral Interactive
All rights reserved.
Redistribution and use in source and binary forms, with or without

View File

@ -1,6 +1,6 @@
/*
Copyright (c) 2017-2025, Feral Interactive and the GameMode contributors
Copyright (c) 2017-2019, Feral Interactive
All rights reserved.
Redistribution and use in source and binary forms, with or without

View File

@ -1,6 +1,6 @@
/*
Copyright (c) 2017-2025, Feral Interactive and the GameMode contributors
Copyright (c) 2017-2019, Feral Interactive
All rights reserved.
Redistribution and use in source and binary forms, with or without

View File

@ -58,18 +58,3 @@ 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,
)

View File

@ -1,84 +0,0 @@
/*
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;
}

View File

@ -1,5 +1,5 @@
/*
Copyright (c) 2017-2025, Feral Interactive and the GameMode contributors
Copyright (c) 2017-2023, Feral Interactive
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,9 +27,8 @@ POSSIBILITY OF SUCH DAMAGE.
#define _GNU_SOURCE
#include <unistd.h>
#include "common-logging.h"
#include "common-splitlock.h"
static bool write_value(const char *key, const char *value)
static bool write_value(char *key, char *value)
{
FILE *f = fopen(key, "w");
@ -59,7 +58,7 @@ int main(int argc, char *argv[])
if (argc == 3) {
if (strcmp(argv[1], "split_lock_mitigate") == 0) {
if (!write_value(splitlock_path, argv[2]))
if (!write_value("/proc/sys/kernel/split_lock_mitigate", argv[2]))
return EXIT_FAILURE;
return EXIT_SUCCESS;