Browse Source

Preliminary (empty) implementation of GPU optimisations

Marc Di Luzio 6 years ago
parent
commit
aeaef7377d
4 changed files with 162 additions and 0 deletions
  1. 139 0
      daemon/gamemode-gpu.c
  2. 14 0
      daemon/gamemode.c
  3. 8 0
      daemon/gamemode.h
  4. 1 0
      daemon/meson.build

+ 139 - 0
daemon/gamemode-gpu.c

@@ -0,0 +1,139 @@
+
+/*
+
+Copyright (c) 2017-2018, 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:
+
+ * 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 "gamemode.h"
+#include "helpers.h"
+#include "logging.h"
+
+// TODO
+// Gather GPU type and information
+// Allow configuration file specifying of gpu info
+// Apply Nvidia GPU settings (CoolBits will be needed)
+// Apply AMD GPU settings (Will need user changing pwm1_enable)
+// Intel?
+// Provide documentation on optimisations
+
+/* Enums for GPU vendors */
+enum GPUVendor {
+	Vendor_Invalid = 0,
+	Vendor_NVIDIA = 0x10de,
+	Vendor_AMD = 0x1002,
+	Vendor_Intel = 0x8086
+};
+
+/* Storage for static GPU info gathered at start */
+struct GameModeGPUInfo {
+	enum GPUVendor vendor;
+	int device; /* path to device, ie. /sys/class/drm/card#/ */
+};
+
+/**
+ * Applies or removes Nvidia optimisations
+ */
+static int apply_gpu_nvidia(bool apply)
+{
+	// Running these commands:
+	// nvidia-settings -a '[gpu:0]/GPUMemoryTransferRateOffset[3]=1400'
+	// nvidia-settings -a '[gpu:0]/GPUGraphicsClockOffset[3]=50'
+	if (apply) {
+	} else {
+	}
+
+	return 0;
+}
+
+/**
+ * Applies or removes AMD optimisations
+ */
+static int apply_gpu_amd(bool apply)
+{
+	// We'll want to set both the following:
+	// core: device/pp_sclk_od (0%+ additional)
+	// mem: device/pp_mclk_od (0%+ additional)
+	// Guide from https://www.maketecheasier.com/overclock-amd-gpu-linux/
+	if (apply) {
+	} else {
+	}
+
+	return 0;
+}
+
+/**
+ * Attempts to identify the current in use GPU information
+ */
+int game_mode_identify_gpu(GameModeGPUInfo **info)
+{
+	int status = 0;
+
+	/* Verify input, this is programmer error */
+	if (!info || *info)
+		FATAL_ERROR("Invalid GameModeGPUInfo passed to %s", __func__);
+
+	/* Create the context */
+	GameModeGPUInfo *new_info = malloc(sizeof(GameModeGPUInfo));
+	memset(new_info, 0, sizeof(GameModeGPUInfo));
+
+	// TODO: Fill in the GPU info
+
+	/* Give back the new gpu info */
+	*info = new_info;
+
+	return status;
+}
+
+/* Simply used to free the GPU info object */
+void game_mode_free_gpu(GameModeGPUInfo **info)
+{
+	/* Simply free the object */
+	free(*info);
+	*info = NULL;
+}
+
+/**
+ * Applies GPU optimisations when gamemode is active and removes them after
+ */
+int game_mode_apply_gpu(const GameModeGPUInfo *info, bool apply)
+{
+	switch (info->vendor) {
+	case Vendor_NVIDIA:
+		return apply_gpu_nvidia(apply);
+	case Vendor_AMD:
+		return apply_gpu_amd(apply);
+	default:
+		break;
+	}
+
+	/* Unsupported GPU vendor, do nothing */
+	return 0;
+}

+ 14 - 0
daemon/gamemode.c

@@ -63,6 +63,8 @@ struct GameModeContext {
 
 	char initial_cpu_mode[64]; /**<Only updates when we can */
 
+	struct GameModeGPUInfo *gpu_info; /**<Stored GPU info for the current GPU */
+
 	/* Reaper control */
 	struct {
 		pthread_t thread;
@@ -107,6 +109,9 @@ void game_mode_context_init(GameModeContext *self)
 	self->config = config_create();
 	config_init(self->config);
 
+	/* Grab the current GPU */
+	game_mode_identify_gpu(&self->gpu_info);
+
 	pthread_rwlock_init(&self->rwlock, NULL);
 	pthread_mutex_init(&self->reaper.mutex, NULL);
 	pthread_cond_init(&self->reaper.condition, NULL);
@@ -144,6 +149,9 @@ void game_mode_context_destroy(GameModeContext *self)
 	pthread_cond_destroy(&self->reaper.condition);
 	pthread_mutex_destroy(&self->reaper.mutex);
 
+	/* Destroy the gpu object */
+	game_mode_free_gpu(&self->gpu_info);
+
 	/* Destroy the config object */
 	config_destroy(self->config);
 
@@ -200,6 +208,9 @@ static void game_mode_context_enter(GameModeContext *self)
 	/* Inhibit the screensaver */
 	if (config_get_inhibit_screensaver(self->config))
 		game_mode_inhibit_screensaver(true);
+
+	/* Apply GPU optimisations */
+	game_mode_apply_gpu(self->gpu_info, true);
 }
 
 /**
@@ -213,6 +224,9 @@ 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");
 
+	/* Remove GPU optimisations */
+	game_mode_apply_gpu(self->gpu_info, false);
+
 	/* UnInhibit the screensaver */
 	if (config_get_inhibit_screensaver(self->config))
 		game_mode_inhibit_screensaver(false);

+ 8 - 0
daemon/gamemode.h

@@ -136,3 +136,11 @@ char *game_mode_resolve_wine_preloader(const pid_t pid);
  * Provides a test suite to verify gamemode behaviour
  */
 int game_mode_run_client_tests(void);
+
+/** gamemode-gpu.c
+ * Provides internal APU functions to apply optimisations to gpus
+ */
+typedef struct GameModeGPUInfo GameModeGPUInfo;
+int game_mode_identify_gpu(GameModeGPUInfo **info);
+void game_mode_free_gpu(GameModeGPUInfo **info);
+int game_mode_apply_gpu(const GameModeGPUInfo *info, bool apply);

+ 1 - 0
daemon/meson.build

@@ -24,6 +24,7 @@ daemon_sources = [
     'gamemode-sched.c',
     'gamemode-wine.c',
     'gamemode-tests.c',
+    'gamemode-gpu.c',
     'daemonize.c',
     'dbus_messaging.c',
     'governors.c',