mirror of
https://github.com/ilya-zlobintsev/LACT.git
synced 2026-11-04 13:16:54 -06:00
feat: add UMA carveout option for AMD iGPUs (#1219)
* feat: UMA carveout daemon option * feat: working UI * chore: switch to released lib
This commit is contained in:
1 parent
6e46792968
commit
bd9aa0c1df
20 files changed
+337
-55
No files matched your search
Generated
+3
-2
@@ -31,8 +31,9 @@ checksum = "683d7910e743518b0e34f1186f92494becacb047c7b6bf616c96772180fef923"
|
||||
|
||||
[[package]]
|
||||
name = "amdgpu-sysfs"
|
||||
version = "0.21.0"
|
||||
source = "git+https://github.com/ilya-zlobintsev/amdgpu-sysfs-rs.git?rev=215eafbcbca0fe28f66f8ba0cbcec0f547baaba1#215eafbcbca0fe28f66f8ba0cbcec0f547baaba1"
|
||||
version = "0.22.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cb53ee2a9c2f4a63b349793a8c247500016e0a23d674226c44f1a6916582e866"
|
||||
dependencies = [
|
||||
"enum_dispatch",
|
||||
"serde",
|
||||
|
||||
+1
-1
@@ -13,7 +13,7 @@ members = [
|
||||
edition = "2024"
|
||||
|
||||
[workspace.dependencies]
|
||||
amdgpu-sysfs = { git = "https://github.com/ilya-zlobintsev/amdgpu-sysfs-rs.git", rev = "215eafbcbca0fe28f66f8ba0cbcec0f547baaba1", features = ["serde"] }
|
||||
amdgpu-sysfs = { version = "0.22.0", features = ["serde"] }
|
||||
nvml-wrapper = { git = "https://github.com/rust-nvml/nvml-wrapper.git", rev = "eb47417eede43443f139053479618e96ad32893d" }
|
||||
serde = { version = "1.0", features = ["derive"] }
|
||||
serde_with = { version = "3.21.0", default-features = false, features = [
|
||||
|
||||
@@ -213,6 +213,10 @@ gpus:
|
||||
mem_clock_offsets:
|
||||
0: 200
|
||||
|
||||
# Index of the UMA (dedicated VRAM) configuration that should be used.
|
||||
# Needs a reboot to actually take effect. Applicable to certain AMD iGPUs.
|
||||
uma_carveout: 1
|
||||
|
||||
# Settings profiles
|
||||
profiles:
|
||||
# Name of the profile
|
||||
|
||||
@@ -1,10 +1,4 @@
|
||||
[
|
||||
{
|
||||
"type": "git",
|
||||
"url": "https://github.com/ilya-zlobintsev/amdgpu-sysfs-rs",
|
||||
"commit": "215eafbcbca0fe28f66f8ba0cbcec0f547baaba1",
|
||||
"dest": "flatpak-cargo/git/amdgpu-sysfs-rs-215eafb"
|
||||
},
|
||||
{
|
||||
"type": "git",
|
||||
"url": "https://github.com/rust-nvml/nvml-wrapper",
|
||||
@@ -64,21 +58,16 @@
|
||||
"dest-filename": ".cargo-checksum.json"
|
||||
},
|
||||
{
|
||||
"type": "shell",
|
||||
"commands": [
|
||||
"cp -r --reflink=auto \"flatpak-cargo/git/amdgpu-sysfs-rs-215eafb/.\" \"cargo/vendor/amdgpu-sysfs\""
|
||||
]
|
||||
"type": "archive",
|
||||
"archive-type": "tar-gzip",
|
||||
"url": "https://static.crates.io/crates/amdgpu-sysfs/amdgpu-sysfs-0.22.0.crate",
|
||||
"sha256": "cb53ee2a9c2f4a63b349793a8c247500016e0a23d674226c44f1a6916582e866",
|
||||
"dest": "cargo/vendor/amdgpu-sysfs-0.22.0"
|
||||
},
|
||||
{
|
||||
"type": "inline",
|
||||
"contents": "[package]\nname = \"amdgpu-sysfs\"\nversion = \"0.21.0\"\nauthors = [ \"Ilya Zlobintsev <ilya.zl@protonmail.com>\",]\nedition = \"2021\"\nlicense = \"LGPL-3.0-or-later\"\nrepository = \"https://github.com/ilya-zlobintsev/amdgpu-sysfs-rs/\"\ndescription = \"Library for interacting with the Linux Kernel SysFS interface for GPUs (mainly targeted at the AMDGPU driver).\"\n\n[features]\ndefault = [ \"overdrive\",]\noverdrive = [ \"enum_dispatch\",]\n\n[dev-dependencies]\npretty_assertions = \"1.4.1\"\nrust-embed = \"8.7.2\"\ntempfile = \"3.22.0\"\n\n[dependencies.enum_dispatch]\nversion = \"0.3.8\"\noptional = true\n\n[dependencies.serde]\nversion = \"1\"\nfeatures = [ \"derive\",]\noptional = true\n\n[dev-dependencies.amdgpu-sysfs]\npath = \".\"\nfeatures = [ \"serde\",]\n\n[dev-dependencies.insta]\nversion = \"1.43.2\"\nfeatures = [ \"yaml\", \"redactions\",]\n",
|
||||
"dest": "cargo/vendor/amdgpu-sysfs",
|
||||
"dest-filename": "Cargo.toml"
|
||||
},
|
||||
{
|
||||
"type": "inline",
|
||||
"contents": "{\"package\": null, \"files\": {}}",
|
||||
"dest": "cargo/vendor/amdgpu-sysfs",
|
||||
"contents": "{\"package\": \"cb53ee2a9c2f4a63b349793a8c247500016e0a23d674226c44f1a6916582e866\", \"files\": {}}",
|
||||
"dest": "cargo/vendor/amdgpu-sysfs-0.22.0",
|
||||
"dest-filename": ".cargo-checksum.json"
|
||||
},
|
||||
{
|
||||
@@ -2663,7 +2652,7 @@
|
||||
},
|
||||
{
|
||||
"type": "inline",
|
||||
"contents": "[package]\nname = \"nvml-wrapper\"\nversion = \"0.12.1\"\nauthors = [ \"Cldfire\",]\ndescription = \"A safe and ergonomic Rust wrapper for the NVIDIA Management Library\"\nreadme = \"../README.md\"\ndocumentation = \"https://docs.rs/nvml-wrapper\"\nrepository = \"https://github.com/Cldfire/nvml-wrapper\"\nlicense = \"MIT OR Apache-2.0\"\nedition = \"2021\"\nrust-version = \"1.60.0\"\nkeywords = [ \"nvidia\", \"gpu\", \"managment\", \"monitoring\", \"hardware\",]\ncategories = [ \"api-bindings\", \"hardware-support\",]\n\n[features]\ndefault = []\nlegacy-functions = [ \"nvml-wrapper-sys/legacy-functions\",]\nserde = [ \"dep:serde\", \"dep:serde_derive\", \"bitflags/serde\",]\n\n[dependencies]\nthiserror = \"1.0\"\nbitflags = \"2.4.0\"\nwrapcenum-derive = \"0.4.1\"\nlibloading = \"0.8.1\"\nstatic_assertions = \"1.1\"\n\n[dev-dependencies]\npretty-bytes = \"0.2\"\n\n[dependencies.serde]\nversion = \"1.0\"\noptional = true\n\n[dependencies.serde_derive]\nversion = \"1.0\"\noptional = true\n\n[dependencies.nvml-wrapper-sys]\nversion = \"0.9.1\"\npath = \"../nvml-wrapper-sys\"\n",
|
||||
"contents": "[package]\nname = \"nvml-wrapper\"\nversion = \"0.12.1\"\nauthors = [\"Cldfire\"]\ndescription = \"A safe and ergonomic Rust wrapper for the NVIDIA Management Library\"\nreadme = \"../README.md\"\ndocumentation = \"https://docs.rs/nvml-wrapper\"\nrepository = \"https://github.com/Cldfire/nvml-wrapper\"\nlicense = \"MIT OR Apache-2.0\"\nedition = \"2021\"\nrust-version = \"1.60.0\"\nkeywords = [\"nvidia\", \"gpu\", \"managment\", \"monitoring\", \"hardware\"]\ncategories = [\"api-bindings\", \"hardware-support\"]\n\n[features]\ndefault = []\nlegacy-functions = [\"nvml-wrapper-sys/legacy-functions\"]\nserde = [\"dep:serde\", \"dep:serde_derive\", \"bitflags/serde\"]\n\n[dependencies]\nthiserror = \"1.0\"\nbitflags = \"2.4.0\"\nwrapcenum-derive = \"0.4.1\"\nlibloading = \"0.8.1\"\nstatic_assertions = \"1.1\"\n\n[dependencies.serde]\nversion = \"1.0\"\noptional = true\n\n[dependencies.serde_derive]\nversion = \"1.0\"\noptional = true\n\n[dependencies.nvml-wrapper-sys]\nversion = \"0.9.1\"\npath = \"../nvml-wrapper-sys\"\n\n[dev-dependencies]\npretty-bytes = \"0.2\"\n",
|
||||
"dest": "cargo/vendor/nvml-wrapper",
|
||||
"dest-filename": "Cargo.toml"
|
||||
},
|
||||
@@ -2681,7 +2670,7 @@
|
||||
},
|
||||
{
|
||||
"type": "inline",
|
||||
"contents": "[package]\nname = \"nvml-wrapper-sys\"\nversion = \"0.9.1\"\nauthors = [ \"Cldfire\",]\ndescription = \"Generated bindings to the NVIDIA Management Library.\"\nreadme = \"README.md\"\ndocumentation = \"https://docs.rs/nvml-wrapper-sys\"\nrepository = \"https://github.com/Cldfire/nvml-wrapper\"\nlicense = \"MIT OR Apache-2.0\"\nedition = \"2021\"\nrust-version = \"1.60.0\"\nkeywords = [ \"nvidia\", \"gpu\", \"managment\", \"monitoring\", \"hardware\",]\ncategories = [ \"external-ffi-bindings\", \"hardware-support\",]\nexclude = [ \"nvml.h\",]\n\n[dependencies]\nlibloading = \"0.8.1\"\n\n[features]\ndefault = []\nlegacy-functions = []\n",
|
||||
"contents": "[package]\nname = \"nvml-wrapper-sys\"\nversion = \"0.9.1\"\nauthors = [\"Cldfire\"]\ndescription = \"Generated bindings to the NVIDIA Management Library.\"\nreadme = \"README.md\"\ndocumentation = \"https://docs.rs/nvml-wrapper-sys\"\nrepository = \"https://github.com/Cldfire/nvml-wrapper\"\nlicense = \"MIT OR Apache-2.0\"\nedition = \"2021\"\nrust-version = \"1.60.0\"\nkeywords = [\"nvidia\", \"gpu\", \"managment\", \"monitoring\", \"hardware\"]\ncategories = [\"external-ffi-bindings\", \"hardware-support\"]\nexclude = [\"nvml.h\"]\n\n[dependencies]\nlibloading = \"0.8.1\"\n\n[features]\ndefault = []\nlegacy-functions = []\n",
|
||||
"dest": "cargo/vendor/nvml-wrapper-sys",
|
||||
"dest-filename": "Cargo.toml"
|
||||
},
|
||||
@@ -5384,7 +5373,7 @@
|
||||
},
|
||||
{
|
||||
"type": "inline",
|
||||
"contents": "[source.vendored-sources]\ndirectory = \"cargo/vendor\"\n\n[source.crates-io]\nreplace-with = \"vendored-sources\"\n\n[source.\"https://github.com/ilya-zlobintsev/amdgpu-sysfs-rs\"]\ngit = \"https://github.com/ilya-zlobintsev/amdgpu-sysfs-rs\"\nreplace-with = \"vendored-sources\"\nrev = \"215eafbcbca0fe28f66f8ba0cbcec0f547baaba1\"\n\n[source.\"https://github.com/rust-nvml/nvml-wrapper\"]\ngit = \"https://github.com/rust-nvml/nvml-wrapper\"\nreplace-with = \"vendored-sources\"\nrev = \"eb47417eede43443f139053479618e96ad32893d\"\n",
|
||||
"contents": "[source.vendored-sources]\ndirectory = \"cargo/vendor\"\n\n[source.crates-io]\nreplace-with = \"vendored-sources\"\n\n[source.\"https://github.com/rust-nvml/nvml-wrapper\"]\ngit = \"https://github.com/rust-nvml/nvml-wrapper\"\nreplace-with = \"vendored-sources\"\nrev = \"eb47417eede43443f139053479618e96ad32893d\"\n",
|
||||
"dest": "cargo",
|
||||
"dest-filename": "config"
|
||||
}
|
||||
|
||||
@@ -495,7 +495,7 @@ mod tests {
|
||||
use indexmap::IndexMap;
|
||||
use insta::assert_yaml_snapshot;
|
||||
use lact_schema::{
|
||||
FanControlMode, NvidiaThermalOptions, NvidiaVfPoint, PmfwOptions,
|
||||
FanControlMode, NvidiaVfPoint, PmfwOptions,
|
||||
config::{
|
||||
ClocksConfiguration, CurvePoint, FanControlSettings, FanCurve, GpuConfig,
|
||||
NvidiaCurvePoint,
|
||||
@@ -601,20 +601,7 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn clocks_configuration_applied() {
|
||||
let mut gpu = GpuConfig {
|
||||
fan_control_enabled: false,
|
||||
fan_control_settings: None,
|
||||
pmfw_options: PmfwOptions::default(),
|
||||
nvidia_thermal_options: NvidiaThermalOptions::default(),
|
||||
power_mizer_mode: None,
|
||||
power_cap: None,
|
||||
performance_level: None,
|
||||
clocks_configuration: ClocksConfiguration::default(),
|
||||
power_profile_mode_index: None,
|
||||
custom_power_profile_mode_hueristics: vec![],
|
||||
power_states: IndexMap::new(),
|
||||
};
|
||||
|
||||
let mut gpu = GpuConfig::default();
|
||||
assert!(!gpu.is_core_clocks_used());
|
||||
gpu.clocks_configuration.voltage_offset = Some(10);
|
||||
assert!(gpu.is_core_clocks_used());
|
||||
|
||||
@@ -23,10 +23,10 @@ use drm::{DrmProvider, amdgpu::AmdGpuDrmProvider};
|
||||
use futures::{FutureExt, future::LocalBoxFuture};
|
||||
use indexmap::IndexMap;
|
||||
use lact_schema::{
|
||||
ActivePowerStates, AmdCacheInstance, CacheInfo, CacheType, ClocksInfo, ClockspeedStats,
|
||||
DeviceApiInfo, DeviceFlag, DeviceInfo, DeviceStats, DeviceType, DrmInfo, FanControlMode,
|
||||
FanStats, LinkInfo, NvidiaThermalInfo, PmfwInfo, PowerState, PowerStates, PowerStats,
|
||||
ProcessList, ProcessUtilizationType, TemperatureEntry, VoltageStats, VramStats,
|
||||
ActivePowerStates, AmdCacheInstance, AmdUmaCarveout, CacheInfo, CacheType, ClocksInfo,
|
||||
ClockspeedStats, DeviceApiInfo, DeviceFlag, DeviceInfo, DeviceStats, DeviceType, DrmInfo,
|
||||
FanControlMode, FanStats, LinkInfo, NvidiaThermalInfo, PmfwInfo, PowerState, PowerStates,
|
||||
PowerStats, ProcessList, ProcessUtilizationType, TemperatureEntry, VoltageStats, VramStats,
|
||||
config::{ClocksConfiguration, FanControlSettings, FanCurve, GpuConfig},
|
||||
};
|
||||
#[cfg(feature = "display-info")]
|
||||
@@ -567,14 +567,27 @@ impl AmdGpuController {
|
||||
.ok()
|
||||
});
|
||||
|
||||
let uma_carveout = self
|
||||
.handle
|
||||
.get_uma_carveout_options()
|
||||
.and_then(|options| {
|
||||
let current = self.handle.get_current_uma_carveout()?;
|
||||
Ok(AmdUmaCarveout {
|
||||
options: options.options,
|
||||
current,
|
||||
})
|
||||
})
|
||||
.ok();
|
||||
|
||||
trace!("Reading DRM info");
|
||||
let drm_handle = self.drm_handle.as_ref();
|
||||
|
||||
match drm_handle {
|
||||
Some(drm_handle) => drm_handle.get_drm_info(&self.handle, cache_info),
|
||||
Some(drm_handle) => drm_handle.get_drm_info(&self.handle, cache_info, uma_carveout),
|
||||
None => Some(DrmInfo {
|
||||
cache_info,
|
||||
vram_clock_ratio: 1.0,
|
||||
amd_uma_carveout: uma_carveout,
|
||||
..Default::default()
|
||||
}),
|
||||
}
|
||||
@@ -1385,6 +1398,19 @@ impl GpuController for AmdGpuController {
|
||||
.with_context(|| format!("Could not set {kind:?} power states"))?;
|
||||
}
|
||||
|
||||
if let Some(uma_carveout) = config.uma_carveout {
|
||||
let current_carveout = self
|
||||
.handle
|
||||
.get_current_uma_carveout()
|
||||
.context("Could not get current UMA carveout")?;
|
||||
|
||||
if uma_carveout != current_carveout {
|
||||
self.handle
|
||||
.set_uma_carveout(uma_carveout)
|
||||
.context("Could not apply UMA carveout")?;
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
})
|
||||
}
|
||||
|
||||
@@ -3,11 +3,16 @@ pub mod amdgpu;
|
||||
pub mod mock;
|
||||
|
||||
use amdgpu_sysfs::gpu_handle::GpuHandle;
|
||||
use lact_schema::{CacheInfo, DeviceType, DrmInfo};
|
||||
use lact_schema::{AmdUmaCarveout, CacheInfo, DeviceType, DrmInfo};
|
||||
use libdrm_amdgpu_sys::AMDGPU::VBIOS::VbiosInfo;
|
||||
|
||||
pub trait DrmProvider {
|
||||
fn get_drm_info(&self, handle: &GpuHandle, cache_info: Option<CacheInfo>) -> Option<DrmInfo>;
|
||||
fn get_drm_info(
|
||||
&self,
|
||||
handle: &GpuHandle,
|
||||
cache_info: Option<CacheInfo>,
|
||||
uma_carveout: Option<AmdUmaCarveout>,
|
||||
) -> Option<DrmInfo>;
|
||||
|
||||
fn get_device_type(&self) -> Option<DeviceType>;
|
||||
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
use super::DrmProvider;
|
||||
use amdgpu_sysfs::gpu_handle::GpuHandle;
|
||||
use anyhow::{Context as _, anyhow};
|
||||
use lact_schema::{AmdIpInfo, CacheInfo, DeviceType, DrmInfo, DrmMemoryInfo, RopInfo};
|
||||
use lact_schema::{
|
||||
AmdIpInfo, AmdUmaCarveout, CacheInfo, DeviceType, DrmInfo, DrmMemoryInfo, RopInfo,
|
||||
};
|
||||
use libdrm_amdgpu_sys::{
|
||||
AMDGPU::{
|
||||
GPU_INFO as _, HW_IP::HW_IP_TYPE, SENSOR_INFO::SENSOR_TYPE, VBIOS::VbiosInfo, VRAM_TYPE,
|
||||
@@ -50,7 +52,12 @@ impl AmdGpuDrmProvider {
|
||||
}
|
||||
|
||||
impl DrmProvider for AmdGpuDrmProvider {
|
||||
fn get_drm_info(&self, handle: &GpuHandle, cache_info: Option<CacheInfo>) -> Option<DrmInfo> {
|
||||
fn get_drm_info(
|
||||
&self,
|
||||
handle: &GpuHandle,
|
||||
cache_info: Option<CacheInfo>,
|
||||
amd_uma_carveout: Option<AmdUmaCarveout>,
|
||||
) -> Option<DrmInfo> {
|
||||
let drm_memory_info = self.0.memory_info().ok().map(|memory_info| DrmMemoryInfo {
|
||||
resizeable_bar: Some(memory_info.check_resizable_bar()),
|
||||
cpu_accessible_used: memory_info.cpu_accessible_vram.heap_usage,
|
||||
@@ -108,6 +115,7 @@ impl DrmProvider for AmdGpuDrmProvider {
|
||||
},
|
||||
operations_count: drm_info.calc_rop_count(),
|
||||
}),
|
||||
amd_uma_carveout,
|
||||
..Default::default()
|
||||
})
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
use super::DrmProvider;
|
||||
use crate::server::{gpu_controller::read_mock_snapshot, handler::SnapshotDeviceInfo};
|
||||
use lact_schema::{DeviceType, DrmInfo};
|
||||
use lact_schema::{AmdUmaCarveout, DeviceType, DrmInfo};
|
||||
use libdrm_amdgpu_sys::AMDGPU::VBIOS::VbiosInfo;
|
||||
use std::path::Path;
|
||||
|
||||
@@ -21,12 +21,13 @@ impl DrmProvider for MockDrmProvider {
|
||||
&self,
|
||||
_handle: &amdgpu_sysfs::gpu_handle::GpuHandle,
|
||||
cache_info: Option<lact_schema::CacheInfo>,
|
||||
amd_uma_carveout: Option<AmdUmaCarveout>,
|
||||
) -> Option<DrmInfo> {
|
||||
self.snapshot
|
||||
.info
|
||||
.drm_info
|
||||
.clone()
|
||||
.map(|info| DrmInfo { cache_info, ..info })
|
||||
self.snapshot.info.drm_info.clone().map(|info| DrmInfo {
|
||||
cache_info,
|
||||
amd_uma_carveout,
|
||||
..info
|
||||
})
|
||||
}
|
||||
|
||||
fn get_device_type(&self) -> Option<DeviceType> {
|
||||
|
||||
@@ -860,6 +860,7 @@ impl GpuController for NvidiaGpuController {
|
||||
.ok(),
|
||||
amd_ip_info: vec![],
|
||||
intel: IntelDrmInfo::default(),
|
||||
..Default::default()
|
||||
}),
|
||||
flags: vec![
|
||||
DeviceFlag::ConfigurableFanControl,
|
||||
|
||||
@@ -103,6 +103,7 @@ gpus:
|
||||
memory_clock:
|
||||
- 0
|
||||
- 1
|
||||
uma_carveout: 1
|
||||
profiles:
|
||||
vkcube:
|
||||
rule:
|
||||
|
||||
@@ -39,6 +39,43 @@ expression: device_info
|
||||
"info": {
|
||||
"driver": "amdgpu",
|
||||
"drm_info": {
|
||||
"amd_uma_carveout": {
|
||||
"current": 0,
|
||||
"options": [
|
||||
{
|
||||
"name": "Minimum",
|
||||
"size_bytes": 536870912
|
||||
},
|
||||
{
|
||||
"name": null,
|
||||
"size_bytes": 1073741824
|
||||
},
|
||||
{
|
||||
"name": null,
|
||||
"size_bytes": 2147483648
|
||||
},
|
||||
{
|
||||
"name": null,
|
||||
"size_bytes": 4294967296
|
||||
},
|
||||
{
|
||||
"name": null,
|
||||
"size_bytes": 6442450944
|
||||
},
|
||||
{
|
||||
"name": "Medium",
|
||||
"size_bytes": 8589934592
|
||||
},
|
||||
{
|
||||
"name": null,
|
||||
"size_bytes": 12884901888
|
||||
},
|
||||
{
|
||||
"name": "High",
|
||||
"size_bytes": 17179869184
|
||||
}
|
||||
]
|
||||
},
|
||||
"cache_info": {
|
||||
"Amd": [
|
||||
[
|
||||
|
||||
@@ -154,6 +154,10 @@ missing-stat = N/A
|
||||
vram-usage = VRAM Usage:
|
||||
gtt-usage = GTT Usage:
|
||||
|
||||
igpu-section = Integrated Graphics
|
||||
uma-carveout = UMA Carveout Size
|
||||
uma-carveout-caption = Amount of memory reserved as dedicated VRAM. Requires a reboot to take effect.
|
||||
|
||||
performance-level-auto = Automatic
|
||||
performance-level-high = Highest Clocks
|
||||
performance-level-low = Lowest Clocks
|
||||
|
||||
@@ -1154,6 +1154,18 @@ impl AppModel {
|
||||
.ok()
|
||||
.flatten();
|
||||
|
||||
let info = self
|
||||
.daemon_client
|
||||
.get_device_info(&gpu_id, Some(false))
|
||||
.await
|
||||
.context("Could not fetch info")?;
|
||||
let info = Arc::new(info);
|
||||
|
||||
self.oc_page.emit(OcPageMsg::Update {
|
||||
update: PageUpdate::Info(info),
|
||||
initial: true,
|
||||
});
|
||||
|
||||
let stats = self
|
||||
.daemon_client
|
||||
.get_device_stats(&gpu_id)
|
||||
@@ -1270,6 +1282,14 @@ impl AppModel {
|
||||
let enabled_power_states = self.oc_page.model().get_enabled_power_states();
|
||||
gpu_config.power_states = enabled_power_states;
|
||||
|
||||
// Avoids applying the setting if it's the default but doesn't wipe it if it's unchanged in the UI
|
||||
gpu_config.uma_carveout = self
|
||||
.oc_page
|
||||
.model()
|
||||
.get_uma_carveout()
|
||||
.map(|value| value as usize)
|
||||
.or(gpu_config.uma_carveout);
|
||||
|
||||
let delay = self
|
||||
.daemon_client
|
||||
.set_gpu_config(&gpu_id, gpu_config)
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
mod card_layout;
|
||||
mod clocks_frame;
|
||||
mod igpu_frame;
|
||||
mod performance_frame;
|
||||
mod power_frame;
|
||||
mod power_states;
|
||||
@@ -10,6 +11,7 @@ use crate::app::components::gpu_stats_section::{
|
||||
GpuStat, GpuStatsSection, GpuStatsSectionConfig, GpuStatsSectionMsg,
|
||||
};
|
||||
use crate::app::pages::PageUpdate;
|
||||
use crate::app::pages::oc_page::igpu_frame::{IGpuFrame, IGpuFrameMsg};
|
||||
use crate::app::utils::ext::RelmLaunchable as _;
|
||||
use crate::app::{msg::AppMsg, utils::ext::RelmDefaultLauchable};
|
||||
use adw::prelude::*;
|
||||
@@ -40,6 +42,7 @@ pub struct OcPage {
|
||||
power_states_dialog: relm4::Controller<PowerStatesDialog>,
|
||||
gpu_clocks_frame: relm4::Controller<ClocksFrame>,
|
||||
vram_clocks_frame: relm4::Controller<ClocksFrame>,
|
||||
igpu_frame: relm4::Controller<IGpuFrame>,
|
||||
|
||||
vf_curve_editor: relm4::Controller<VfCurveEditor>,
|
||||
}
|
||||
@@ -88,6 +91,8 @@ impl relm4::Component for OcPage {
|
||||
ColumnBias::Left, // Core
|
||||
ColumnBias::Right, // VRAM
|
||||
ColumnBias::Left, // Power
|
||||
ColumnBias::Right, // Integrated Graphics
|
||||
|
||||
])),
|
||||
set_valign: gtk::Align::Start,
|
||||
|
||||
@@ -102,6 +107,10 @@ impl relm4::Component for OcPage {
|
||||
model.power_frame.widget() {
|
||||
add_css_class: "oc-page-section",
|
||||
},
|
||||
|
||||
model.igpu_frame.widget() {
|
||||
add_css_class: "oc-page-section",
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -143,6 +152,7 @@ impl relm4::Component for OcPage {
|
||||
let power_states_dialog =
|
||||
PowerStatesDialog::launch_default().forward(sender.input_sender(), |msg| msg);
|
||||
let power_frame = PowerFrame::launch_default().forward(sender.input_sender(), |msg| msg);
|
||||
let igpu_frame = IGpuFrame::launch_default().forward(sender.input_sender(), |msg| msg);
|
||||
|
||||
let vf_curve_editor = VfCurveEditor::detach(VfCurveEditorInit {
|
||||
global_settings_changed: settings_changed,
|
||||
@@ -156,6 +166,7 @@ impl relm4::Component for OcPage {
|
||||
power_states_dialog,
|
||||
gpu_clocks_frame,
|
||||
vram_clocks_frame,
|
||||
igpu_frame,
|
||||
vf_curve_editor,
|
||||
};
|
||||
|
||||
@@ -211,6 +222,13 @@ impl relm4::Component for OcPage {
|
||||
.emit(PowerStatesDialogMsg::VramClockRatio(vram_clock_ratio));
|
||||
self.vram_clocks_frame
|
||||
.emit(ClocksFrameMsg::VramRatio(vram_clock_ratio));
|
||||
|
||||
let uma_carveout = info
|
||||
.drm_info
|
||||
.as_ref()
|
||||
.and_then(|info| info.amd_uma_carveout.clone());
|
||||
self.igpu_frame
|
||||
.emit(IGpuFrameMsg::UmaCarveout(uma_carveout));
|
||||
}
|
||||
},
|
||||
OcPageMsg::ClocksTable {
|
||||
@@ -347,4 +365,8 @@ impl OcPage {
|
||||
IndexMap::new()
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_uma_carveout(&self) -> Option<u32> {
|
||||
self.igpu_frame.model().get_uma_carveout()
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,157 @@
|
||||
use super::OcPageMsg;
|
||||
use crate::I18N;
|
||||
use crate::app::APP_BROKER;
|
||||
use crate::app::components::{adjustment_card::AdjustmentCard, page_section::PageSection};
|
||||
use crate::app::msg::AppMsg;
|
||||
use crate::app::utils::formatting;
|
||||
use gtk::gio::prelude::ListModelExt as _;
|
||||
use gtk::prelude::{BoxExt as _, ListBoxRowExt as _, OrientableExt as _, WidgetExt as _};
|
||||
use i18n_embed_fl::fl;
|
||||
use lact_schema::AmdUmaCarveout;
|
||||
use relm4::{ComponentParts, ComponentSender, WidgetTemplate as _, css};
|
||||
|
||||
pub struct IGpuFrame {
|
||||
// options: Option<UmaCarveoutOptions>,
|
||||
// combo_row: relm4::Controller<SimpleComboRow<String>>,
|
||||
uma_options: gtk::StringList,
|
||||
uma_current: u32,
|
||||
uma_selected: u32,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum IGpuFrameMsg {
|
||||
UmaCarveout(Option<AmdUmaCarveout>),
|
||||
UmaSelected(u32),
|
||||
}
|
||||
|
||||
#[relm4::component(pub)]
|
||||
impl relm4::Component for IGpuFrame {
|
||||
type Init = ();
|
||||
type Input = IGpuFrameMsg;
|
||||
type Output = OcPageMsg;
|
||||
type CommandOutput = ();
|
||||
|
||||
view! {
|
||||
PageSection {
|
||||
set_hide_visible_container: true,
|
||||
#[watch]
|
||||
set_name: fl!(I18N, "igpu-section"),
|
||||
#[watch]
|
||||
set_visible: model.uma_options.n_items() != 0,
|
||||
|
||||
#[template]
|
||||
#[local]
|
||||
append_child = &card -> AdjustmentCard {
|
||||
#[template_child]
|
||||
content {
|
||||
gtk::Box {
|
||||
set_orientation: gtk::Orientation::Horizontal,
|
||||
set_spacing: 10,
|
||||
|
||||
gtk::Box {
|
||||
set_orientation: gtk::Orientation::Vertical,
|
||||
set_hexpand: true,
|
||||
set_valign: gtk::Align::Center,
|
||||
|
||||
gtk::Label {
|
||||
set_label: &fl!(I18N, "uma-carveout"),
|
||||
set_halign: gtk::Align::Start,
|
||||
},
|
||||
|
||||
gtk::Label {
|
||||
set_label: &fl!(I18N, "uma-carveout-caption"),
|
||||
set_halign: gtk::Align::Start,
|
||||
set_xalign: 0.0,
|
||||
set_wrap: true,
|
||||
add_css_class: css::DIM_LABEL,
|
||||
add_css_class: css::CAPTION,
|
||||
},
|
||||
},
|
||||
|
||||
gtk::ListBoxRow {
|
||||
set_activatable: false,
|
||||
set_selectable: false,
|
||||
|
||||
#[name = "uma_dropdown"]
|
||||
gtk::DropDown {
|
||||
set_valign: gtk::Align::Center,
|
||||
#[watch]
|
||||
#[block_signal(uma_mode_select_handler)]
|
||||
set_model: Some(&model.uma_options),
|
||||
#[watch]
|
||||
#[block_signal(uma_mode_select_handler)]
|
||||
set_selected: model.uma_selected,
|
||||
|
||||
connect_selected_notify[sender] => move |dropdown| {
|
||||
sender.input(IGpuFrameMsg::UmaSelected(dropdown.selected()));
|
||||
} @ uma_mode_select_handler,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
fn init(
|
||||
_: Self::Init,
|
||||
root: Self::Root,
|
||||
sender: ComponentSender<Self>,
|
||||
) -> ComponentParts<Self> {
|
||||
let card = AdjustmentCard::init(());
|
||||
let model = Self {
|
||||
uma_options: gtk::StringList::default(),
|
||||
uma_selected: 0,
|
||||
uma_current: 0,
|
||||
};
|
||||
|
||||
let widgets = view_output!();
|
||||
|
||||
ComponentParts { model, widgets }
|
||||
}
|
||||
|
||||
fn update(&mut self, msg: Self::Input, _sender: ComponentSender<Self>, _root: &Self::Root) {
|
||||
match msg {
|
||||
IGpuFrameMsg::UmaCarveout(carveout) => {
|
||||
let uma_options = gtk::StringList::default();
|
||||
|
||||
match carveout {
|
||||
Some(carveout) => {
|
||||
for option in carveout.options {
|
||||
let size = formatting::fmt_human_bytes(option.size_bytes, None);
|
||||
let text = if let Some(name) = option.name {
|
||||
format!("{size} ({name})")
|
||||
} else {
|
||||
size
|
||||
};
|
||||
uma_options.append(&text);
|
||||
}
|
||||
|
||||
self.uma_current = carveout.current as u32;
|
||||
self.uma_selected = self.uma_current;
|
||||
}
|
||||
None => {
|
||||
self.uma_current = 0;
|
||||
self.uma_selected = 0;
|
||||
}
|
||||
}
|
||||
|
||||
self.uma_options = uma_options;
|
||||
}
|
||||
IGpuFrameMsg::UmaSelected(selected) => {
|
||||
self.uma_selected = selected;
|
||||
APP_BROKER.send(AppMsg::SettingsChanged);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl IGpuFrame {
|
||||
pub fn get_uma_carveout(&self) -> Option<u32> {
|
||||
if self.uma_current != self.uma_selected {
|
||||
Some(self.uma_selected)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -53,6 +53,7 @@ pub struct GpuConfig {
|
||||
pub custom_power_profile_mode_hueristics: Vec<Vec<Option<i32>>>,
|
||||
#[serde(default, skip_serializing_if = "IndexMap::is_empty")]
|
||||
pub power_states: IndexMap<PowerLevelKind, Vec<u8>>,
|
||||
pub uma_carveout: Option<usize>,
|
||||
}
|
||||
|
||||
#[skip_serializing_none]
|
||||
|
||||
+10
-1
@@ -15,7 +15,7 @@ pub use response::Response;
|
||||
|
||||
use amdgpu_sysfs::{
|
||||
gpu_handle::{
|
||||
PerformanceLevel, PowerLevelId,
|
||||
PerformanceLevel, PowerLevelId, UmaCarveoutOption,
|
||||
fan_control::FanInfo,
|
||||
overdrive::{ClocksTable as _, ClocksTableGen as AmdClocksTableGen},
|
||||
},
|
||||
@@ -415,10 +415,19 @@ pub struct DrmInfo {
|
||||
pub memory_info: Option<DrmMemoryInfo>,
|
||||
#[serde(default, skip_serializing_if = "Vec::is_empty")]
|
||||
pub amd_ip_info: Vec<AmdIpInfo>,
|
||||
pub amd_uma_carveout: Option<AmdUmaCarveout>,
|
||||
#[serde(flatten)]
|
||||
pub intel: IntelDrmInfo,
|
||||
}
|
||||
|
||||
/// Options for iGPU UMA allocation
|
||||
#[skip_serializing_none]
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, Default)]
|
||||
pub struct AmdUmaCarveout {
|
||||
pub options: Vec<UmaCarveoutOption>,
|
||||
pub current: usize,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, Default)]
|
||||
pub struct AmdIpInfo {
|
||||
pub ip_type: String,
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
0
|
||||
@@ -0,0 +1,8 @@
|
||||
0: Minimum (512 MB)
|
||||
1: (1 GB)
|
||||
2: (2 GB)
|
||||
3: (4 GB)
|
||||
4: (6 GB)
|
||||
5: Medium (8 GB)
|
||||
6: (12 GB)
|
||||
7: High (16 GB)
|
||||
Reference in new issue
Block a user