diff --git a/Cargo.lock b/Cargo.lock index 00097a13..c993100b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -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", diff --git a/Cargo.toml b/Cargo.toml index 23c71cae..74046326 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -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 = [ diff --git a/docs/CONFIG.md b/docs/CONFIG.md index 52d253cb..4a4ac153 100644 --- a/docs/CONFIG.md +++ b/docs/CONFIG.md @@ -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 diff --git a/flatpak/generated-sources.json b/flatpak/generated-sources.json index b5206bf9..4fec31d7 100644 --- a/flatpak/generated-sources.json +++ b/flatpak/generated-sources.json @@ -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 \",]\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" } diff --git a/lact-daemon/src/config.rs b/lact-daemon/src/config.rs index eb7b4d17..b6e56063 100644 --- a/lact-daemon/src/config.rs +++ b/lact-daemon/src/config.rs @@ -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()); diff --git a/lact-daemon/src/server/gpu_controller/amd.rs b/lact-daemon/src/server/gpu_controller/amd.rs index 1124ecd1..e3e669ec 100644 --- a/lact-daemon/src/server/gpu_controller/amd.rs +++ b/lact-daemon/src/server/gpu_controller/amd.rs @@ -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(()) }) } diff --git a/lact-daemon/src/server/gpu_controller/amd/drm.rs b/lact-daemon/src/server/gpu_controller/amd/drm.rs index 6c891887..4b2bcad6 100644 --- a/lact-daemon/src/server/gpu_controller/amd/drm.rs +++ b/lact-daemon/src/server/gpu_controller/amd/drm.rs @@ -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) -> Option; + fn get_drm_info( + &self, + handle: &GpuHandle, + cache_info: Option, + uma_carveout: Option, + ) -> Option; fn get_device_type(&self) -> Option; diff --git a/lact-daemon/src/server/gpu_controller/amd/drm/amdgpu.rs b/lact-daemon/src/server/gpu_controller/amd/drm/amdgpu.rs index 53f5dc2d..d3d820a5 100644 --- a/lact-daemon/src/server/gpu_controller/amd/drm/amdgpu.rs +++ b/lact-daemon/src/server/gpu_controller/amd/drm/amdgpu.rs @@ -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) -> Option { + fn get_drm_info( + &self, + handle: &GpuHandle, + cache_info: Option, + amd_uma_carveout: Option, + ) -> Option { 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() }) } diff --git a/lact-daemon/src/server/gpu_controller/amd/drm/mock.rs b/lact-daemon/src/server/gpu_controller/amd/drm/mock.rs index 89bb6f70..21756c7f 100644 --- a/lact-daemon/src/server/gpu_controller/amd/drm/mock.rs +++ b/lact-daemon/src/server/gpu_controller/amd/drm/mock.rs @@ -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, + amd_uma_carveout: Option, ) -> Option { - 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 { diff --git a/lact-daemon/src/server/gpu_controller/nvidia.rs b/lact-daemon/src/server/gpu_controller/nvidia.rs index f3b97e00..f7f27b63 100644 --- a/lact-daemon/src/server/gpu_controller/nvidia.rs +++ b/lact-daemon/src/server/gpu_controller/nvidia.rs @@ -860,6 +860,7 @@ impl GpuController for NvidiaGpuController { .ok(), amd_ip_info: vec![], intel: IntelDrmInfo::default(), + ..Default::default() }), flags: vec![ DeviceFlag::ConfigurableFanControl, diff --git a/lact-daemon/src/snapshots/lact_daemon__config__tests__parse_doc.snap b/lact-daemon/src/snapshots/lact_daemon__config__tests__parse_doc.snap index 852f0c3d..5364f798 100644 --- a/lact-daemon/src/snapshots/lact_daemon__config__tests__parse_doc.snap +++ b/lact-daemon/src/snapshots/lact_daemon__config__tests__parse_doc.snap @@ -103,6 +103,7 @@ gpus: memory_clock: - 0 - 1 + uma_carveout: 1 profiles: vkcube: rule: diff --git a/lact-daemon/src/tests/snapshots/lact_daemon__tests__amd__strixpoint.snap b/lact-daemon/src/tests/snapshots/lact_daemon__tests__amd__strixpoint.snap index 2b58407c..ce028004 100644 --- a/lact-daemon/src/tests/snapshots/lact_daemon__tests__amd__strixpoint.snap +++ b/lact-daemon/src/tests/snapshots/lact_daemon__tests__amd__strixpoint.snap @@ -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": [ [ diff --git a/lact-gui/i18n/en/lact_gui.ftl b/lact-gui/i18n/en/lact_gui.ftl index 8438453d..d067eefa 100644 --- a/lact-gui/i18n/en/lact_gui.ftl +++ b/lact-gui/i18n/en/lact_gui.ftl @@ -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 diff --git a/lact-gui/src/app.rs b/lact-gui/src/app.rs index 4e89505c..8dc7edc6 100644 --- a/lact-gui/src/app.rs +++ b/lact-gui/src/app.rs @@ -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) diff --git a/lact-gui/src/app/pages/oc_page.rs b/lact-gui/src/app/pages/oc_page.rs index 97c2871c..c6894df0 100644 --- a/lact-gui/src/app/pages/oc_page.rs +++ b/lact-gui/src/app/pages/oc_page.rs @@ -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, gpu_clocks_frame: relm4::Controller, vram_clocks_frame: relm4::Controller, + igpu_frame: relm4::Controller, vf_curve_editor: relm4::Controller, } @@ -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 { + self.igpu_frame.model().get_uma_carveout() + } } diff --git a/lact-gui/src/app/pages/oc_page/igpu_frame.rs b/lact-gui/src/app/pages/oc_page/igpu_frame.rs new file mode 100644 index 00000000..b7884fe2 --- /dev/null +++ b/lact-gui/src/app/pages/oc_page/igpu_frame.rs @@ -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, + // combo_row: relm4::Controller>, + uma_options: gtk::StringList, + uma_current: u32, + uma_selected: u32, +} + +#[derive(Debug)] +pub enum IGpuFrameMsg { + UmaCarveout(Option), + 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, + ) -> ComponentParts { + 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, _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 { + if self.uma_current != self.uma_selected { + Some(self.uma_selected) + } else { + None + } + } +} diff --git a/lact-schema/src/config.rs b/lact-schema/src/config.rs index 8c3859ae..be509cc2 100644 --- a/lact-schema/src/config.rs +++ b/lact-schema/src/config.rs @@ -53,6 +53,7 @@ pub struct GpuConfig { pub custom_power_profile_mode_hueristics: Vec>>, #[serde(default, skip_serializing_if = "IndexMap::is_empty")] pub power_states: IndexMap>, + pub uma_carveout: Option, } #[skip_serializing_none] diff --git a/lact-schema/src/lib.rs b/lact-schema/src/lib.rs index 89b83479..a981c693 100644 --- a/lact-schema/src/lib.rs +++ b/lact-schema/src/lib.rs @@ -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, #[serde(default, skip_serializing_if = "Vec::is_empty")] pub amd_ip_info: Vec, + pub amd_uma_carveout: Option, #[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, + pub current: usize, +} + #[derive(Serialize, Deserialize, Debug, Clone, Default)] pub struct AmdIpInfo { pub ip_type: String, diff --git a/tests/snapshots/amd/strixpoint/card1/device/uma/carveout b/tests/snapshots/amd/strixpoint/card1/device/uma/carveout new file mode 100644 index 00000000..573541ac --- /dev/null +++ b/tests/snapshots/amd/strixpoint/card1/device/uma/carveout @@ -0,0 +1 @@ +0 diff --git a/tests/snapshots/amd/strixpoint/card1/device/uma/carveout_options b/tests/snapshots/amd/strixpoint/card1/device/uma/carveout_options new file mode 100644 index 00000000..425bfbda --- /dev/null +++ b/tests/snapshots/amd/strixpoint/card1/device/uma/carveout_options @@ -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)