mirror of
https://github.com/ilya-zlobintsev/LACT.git
synced 2025-02-25 18:55:26 -06:00
Merge pull request #108 from ilya-zlobintsev/rx-6000-fixes
feat: voltage offset support, fixes for rx 6000 series format
This commit is contained in:
commit
b9f8f1cc86
4
Cargo.lock
generated
4
Cargo.lock
generated
@ -25,9 +25,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "amdgpu-sysfs"
|
name = "amdgpu-sysfs"
|
||||||
version = "0.9.5"
|
version = "0.9.7"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "ae160ad9551e11cf5aa19fc78b590ee5f8ccfe07f983a99bead7a6680907da30"
|
checksum = "6667682d11c8face0277986d0cfc0862399febf666e0d9a9d8b12fa0362373ba"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"enum_dispatch",
|
"enum_dispatch",
|
||||||
"serde",
|
"serde",
|
||||||
|
@ -6,7 +6,7 @@ edition = "2021"
|
|||||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
amdgpu-sysfs = { version = "0.9.5", features = ["serde"] }
|
amdgpu-sysfs = { version = "0.9.7", features = ["serde"] }
|
||||||
anyhow = "1.0"
|
anyhow = "1.0"
|
||||||
bincode = "1.3"
|
bincode = "1.3"
|
||||||
nix = "0.26"
|
nix = "0.26"
|
||||||
|
@ -41,6 +41,7 @@ pub struct Gpu {
|
|||||||
pub max_core_clock: Option<u32>,
|
pub max_core_clock: Option<u32>,
|
||||||
pub max_memory_clock: Option<u32>,
|
pub max_memory_clock: Option<u32>,
|
||||||
pub max_voltage: Option<u32>,
|
pub max_voltage: Option<u32>,
|
||||||
|
pub voltage_offset: Option<i32>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
|
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
|
||||||
|
@ -11,8 +11,8 @@ use amdgpu_sysfs::{
|
|||||||
};
|
};
|
||||||
use anyhow::{anyhow, Context};
|
use anyhow::{anyhow, Context};
|
||||||
use lact_schema::{
|
use lact_schema::{
|
||||||
ClocksInfo, ClocksTable, ClockspeedStats, DeviceInfo, DeviceStats, FanStats, GpuPciInfo,
|
ClocksInfo, ClocksTable, ClocksTableGen, ClockspeedStats, DeviceInfo, DeviceStats, FanStats,
|
||||||
LinkInfo, PciInfo, PerformanceLevel, PowerStats, VoltageStats, VramStats,
|
GpuPciInfo, LinkInfo, PciInfo, PerformanceLevel, PowerStats, VoltageStats, VramStats,
|
||||||
};
|
};
|
||||||
use pciid_parser::Database;
|
use pciid_parser::Database;
|
||||||
use std::{
|
use std::{
|
||||||
@ -347,6 +347,15 @@ impl GpuController {
|
|||||||
{
|
{
|
||||||
let mut table = self.handle.get_clocks_table()?;
|
let mut table = self.handle.get_clocks_table()?;
|
||||||
|
|
||||||
|
if let ClocksTableGen::Vega20(ref mut table) = table {
|
||||||
|
// Avoid writing settings to the clocks table except the user-specified ones
|
||||||
|
// There is an issue on some GPU models where the default values are actually outside of the allowed range
|
||||||
|
// See https://github.com/sibradzic/amdgpu-clocks/issues/32#issuecomment-829953519 (part 2) for an example
|
||||||
|
table.clear();
|
||||||
|
|
||||||
|
table.voltage_offset = config.voltage_offset;
|
||||||
|
}
|
||||||
|
|
||||||
if let Some(clockspeed) = config.max_core_clock {
|
if let Some(clockspeed) = config.max_core_clock {
|
||||||
table.set_max_sclk(clockspeed)?;
|
table.set_max_sclk(clockspeed)?;
|
||||||
}
|
}
|
||||||
|
@ -214,6 +214,7 @@ impl<'a> Handler {
|
|||||||
SetClocksCommand::MaxCoreClock(clock) => gpu_config.max_core_clock = Some(clock),
|
SetClocksCommand::MaxCoreClock(clock) => gpu_config.max_core_clock = Some(clock),
|
||||||
SetClocksCommand::MaxMemoryClock(clock) => gpu_config.max_memory_clock = Some(clock),
|
SetClocksCommand::MaxMemoryClock(clock) => gpu_config.max_memory_clock = Some(clock),
|
||||||
SetClocksCommand::MaxVoltage(voltage) => gpu_config.max_voltage = Some(voltage),
|
SetClocksCommand::MaxVoltage(voltage) => gpu_config.max_voltage = Some(voltage),
|
||||||
|
SetClocksCommand::VoltageOffset(offset) => gpu_config.voltage_offset = Some(offset),
|
||||||
SetClocksCommand::Reset => {
|
SetClocksCommand::Reset => {
|
||||||
gpu_config.max_core_clock = None;
|
gpu_config.max_core_clock = None;
|
||||||
gpu_config.max_memory_clock = None;
|
gpu_config.max_memory_clock = None;
|
||||||
|
@ -297,6 +297,12 @@ impl App {
|
|||||||
.context("Could not set the maximum voltage")?;
|
.context("Could not set the maximum voltage")?;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if let Some(offset) = clocks_settings.voltage_offset {
|
||||||
|
self.daemon_client
|
||||||
|
.set_clocks_value(&gpu_id, SetClocksCommand::VoltageOffset(offset))
|
||||||
|
.context("Could not set the voltage offset")?;
|
||||||
|
}
|
||||||
|
|
||||||
self.set_initial(&gpu_id);
|
self.set_initial(&gpu_id);
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
|
@ -34,7 +34,7 @@ impl InformationPage {
|
|||||||
let gpu_name_label = label_row("GPU Model:", &values_grid, 0, 0, true);
|
let gpu_name_label = label_row("GPU Model:", &values_grid, 0, 0, true);
|
||||||
let gpu_manufacturer_label = label_row("GPU Manufacturer:", &values_grid, 1, 0, true);
|
let gpu_manufacturer_label = label_row("GPU Manufacturer:", &values_grid, 1, 0, true);
|
||||||
let vbios_version_label = label_row("VBIOS Version:", &values_grid, 2, 0, true);
|
let vbios_version_label = label_row("VBIOS Version:", &values_grid, 2, 0, true);
|
||||||
let driver_label = label_row("Driver Version:", &values_grid, 3, 0, true);
|
let driver_label = label_row("Driver Used:", &values_grid, 3, 0, true);
|
||||||
let vram_size_label = label_row("VRAM Size:", &values_grid, 4, 0, true);
|
let vram_size_label = label_row("VRAM Size:", &values_grid, 4, 0, true);
|
||||||
let link_speed_label = label_row("Link Speed:", &values_grid, 5, 0, true);
|
let link_speed_label = label_row("Link Speed:", &values_grid, 5, 0, true);
|
||||||
|
|
||||||
|
@ -4,6 +4,9 @@ use gtk::prelude::*;
|
|||||||
use gtk::*;
|
use gtk::*;
|
||||||
use lact_client::schema::{ClocksTable, ClocksTableGen};
|
use lact_client::schema::{ClocksTable, ClocksTableGen};
|
||||||
|
|
||||||
|
const VOLTAGE_OFFSET_RANGE: f64 = 250.0;
|
||||||
|
const WARNING_TEXT: &str = "Warning: changing these values may lead to system instability and potentially damage your hardware!";
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct ClocksFrame {
|
pub struct ClocksFrame {
|
||||||
pub container: Box,
|
pub container: Box,
|
||||||
@ -11,6 +14,7 @@ pub struct ClocksFrame {
|
|||||||
max_sclk_adjustment: Adjustment,
|
max_sclk_adjustment: Adjustment,
|
||||||
max_mclk_adjustment: Adjustment,
|
max_mclk_adjustment: Adjustment,
|
||||||
max_voltage_adjustment: Adjustment,
|
max_voltage_adjustment: Adjustment,
|
||||||
|
voltage_offset_adjustment: Adjustment,
|
||||||
reset_button: Button,
|
reset_button: Button,
|
||||||
clocks_data_unavailable_label: Label,
|
clocks_data_unavailable_label: Label,
|
||||||
}
|
}
|
||||||
@ -20,15 +24,29 @@ impl ClocksFrame {
|
|||||||
let container = section_box("Maximum Clocks");
|
let container = section_box("Maximum Clocks");
|
||||||
|
|
||||||
let tweaking_grid = Grid::builder().row_spacing(5).build();
|
let tweaking_grid = Grid::builder().row_spacing(5).build();
|
||||||
let max_sclk_adjustment = oc_adjustment("GPU Clock (MHz)", &tweaking_grid, 0);
|
|
||||||
let max_voltage_adjustment = oc_adjustment("GPU voltage (mV)", &tweaking_grid, 1);
|
let warning_label = Label::builder()
|
||||||
let max_mclk_adjustment = oc_adjustment("VRAM Clock (MHz)", &tweaking_grid, 2);
|
.label(WARNING_TEXT)
|
||||||
|
.wrap_mode(pango::WrapMode::Word)
|
||||||
|
.halign(Align::Start)
|
||||||
|
.hexpand(true)
|
||||||
|
.margin_top(5)
|
||||||
|
.margin_bottom(5)
|
||||||
|
.build();
|
||||||
|
tweaking_grid.attach(&warning_label, 0, 0, 7, 1);
|
||||||
|
|
||||||
|
let max_sclk_adjustment = oc_adjustment("GPU Clock (MHz)", &tweaking_grid, 1);
|
||||||
|
let max_voltage_adjustment = oc_adjustment("GPU voltage (mV)", &tweaking_grid, 2);
|
||||||
|
let max_mclk_adjustment = oc_adjustment("VRAM Clock (MHz)", &tweaking_grid, 3);
|
||||||
|
let voltage_offset_adjustment = oc_adjustment("GPU voltage offset (mV)", &tweaking_grid, 4);
|
||||||
|
|
||||||
let reset_button = Button::builder()
|
let reset_button = Button::builder()
|
||||||
.label("Defaults")
|
.label("Reset")
|
||||||
.halign(Align::End)
|
.halign(Align::End)
|
||||||
|
.tooltip_text("Warning: this resets all clock settings to defaults!")
|
||||||
|
.css_classes(["destructive-action"])
|
||||||
.build();
|
.build();
|
||||||
tweaking_grid.attach(&reset_button, 6, 3, 1, 1);
|
tweaking_grid.attach(&reset_button, 6, 5, 1, 1);
|
||||||
|
|
||||||
let clocks_data_unavailable_label = Label::new(Some("No clocks data available"));
|
let clocks_data_unavailable_label = Label::new(Some("No clocks data available"));
|
||||||
|
|
||||||
@ -43,10 +61,12 @@ impl ClocksFrame {
|
|||||||
max_voltage_adjustment,
|
max_voltage_adjustment,
|
||||||
reset_button,
|
reset_button,
|
||||||
clocks_data_unavailable_label,
|
clocks_data_unavailable_label,
|
||||||
|
voltage_offset_adjustment,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_table(&self, table: ClocksTableGen) -> anyhow::Result<()> {
|
pub fn set_table(&self, table: ClocksTableGen) -> anyhow::Result<()> {
|
||||||
|
// The upper value "0.0" is used to hide the adjustment when info is not available
|
||||||
if let Some((current_sclk_max, sclk_min, sclk_max)) =
|
if let Some((current_sclk_max, sclk_min, sclk_max)) =
|
||||||
extract_value_and_range(&table, |table| {
|
extract_value_and_range(&table, |table| {
|
||||||
(table.get_max_sclk(), table.get_max_sclk_range())
|
(table.get_max_sclk(), table.get_max_sclk_range())
|
||||||
@ -55,6 +75,8 @@ impl ClocksFrame {
|
|||||||
self.max_sclk_adjustment.set_lower(sclk_min.into());
|
self.max_sclk_adjustment.set_lower(sclk_min.into());
|
||||||
self.max_sclk_adjustment.set_upper(sclk_max.into());
|
self.max_sclk_adjustment.set_upper(sclk_max.into());
|
||||||
self.max_sclk_adjustment.set_value(current_sclk_max.into());
|
self.max_sclk_adjustment.set_value(current_sclk_max.into());
|
||||||
|
} else {
|
||||||
|
self.max_sclk_adjustment.set_upper(0.0);
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some((current_mclk_max, mclk_min, mclk_max)) =
|
if let Some((current_mclk_max, mclk_min, mclk_max)) =
|
||||||
@ -65,6 +87,8 @@ impl ClocksFrame {
|
|||||||
self.max_mclk_adjustment.set_lower(mclk_min.into());
|
self.max_mclk_adjustment.set_lower(mclk_min.into());
|
||||||
self.max_mclk_adjustment.set_upper(mclk_max.into());
|
self.max_mclk_adjustment.set_upper(mclk_max.into());
|
||||||
self.max_mclk_adjustment.set_value(current_mclk_max.into());
|
self.max_mclk_adjustment.set_value(current_mclk_max.into());
|
||||||
|
} else {
|
||||||
|
self.max_mclk_adjustment.set_upper(0.0);
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some((current_voltage_max, voltage_min, voltage_max)) =
|
if let Some((current_voltage_max, voltage_min, voltage_max)) =
|
||||||
@ -76,8 +100,30 @@ impl ClocksFrame {
|
|||||||
self.max_voltage_adjustment.set_upper(voltage_max.into());
|
self.max_voltage_adjustment.set_upper(voltage_max.into());
|
||||||
self.max_voltage_adjustment
|
self.max_voltage_adjustment
|
||||||
.set_value(current_voltage_max.into());
|
.set_value(current_voltage_max.into());
|
||||||
|
} else {
|
||||||
|
self.max_voltage_adjustment.set_upper(0.0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if let ClocksTableGen::Vega20(table) = table {
|
||||||
|
if let Some(offset) = table.voltage_offset {
|
||||||
|
// TODO: check this
|
||||||
|
self.voltage_offset_adjustment
|
||||||
|
.set_lower(VOLTAGE_OFFSET_RANGE * -1.0);
|
||||||
|
self.voltage_offset_adjustment
|
||||||
|
.set_upper(VOLTAGE_OFFSET_RANGE);
|
||||||
|
self.voltage_offset_adjustment.set_value(offset.into());
|
||||||
|
} else {
|
||||||
|
self.voltage_offset_adjustment.set_upper(0.0);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
self.voltage_offset_adjustment.set_upper(0.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
emit_changed(&self.max_sclk_adjustment);
|
||||||
|
emit_changed(&self.max_mclk_adjustment);
|
||||||
|
emit_changed(&self.max_voltage_adjustment);
|
||||||
|
emit_changed(&self.voltage_offset_adjustment);
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -95,7 +141,8 @@ impl ClocksFrame {
|
|||||||
let f = clone!(@strong f => move |_: &Adjustment| f());
|
let f = clone!(@strong f => move |_: &Adjustment| f());
|
||||||
self.max_sclk_adjustment.connect_value_changed(f.clone());
|
self.max_sclk_adjustment.connect_value_changed(f.clone());
|
||||||
self.max_mclk_adjustment.connect_value_changed(f.clone());
|
self.max_mclk_adjustment.connect_value_changed(f.clone());
|
||||||
self.max_voltage_adjustment.connect_value_changed(f);
|
self.max_voltage_adjustment.connect_value_changed(f.clone());
|
||||||
|
self.voltage_offset_adjustment.connect_value_changed(f);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn connect_clocks_reset<F: Fn() + 'static + Clone>(&self, f: F) {
|
pub fn connect_clocks_reset<F: Fn() + 'static + Clone>(&self, f: F) {
|
||||||
@ -108,10 +155,17 @@ impl ClocksFrame {
|
|||||||
let max_memory_clock = zero_to_option(self.max_mclk_adjustment.value());
|
let max_memory_clock = zero_to_option(self.max_mclk_adjustment.value());
|
||||||
let max_voltage = zero_to_option(self.max_voltage_adjustment.value());
|
let max_voltage = zero_to_option(self.max_voltage_adjustment.value());
|
||||||
|
|
||||||
|
let voltage_offset = if self.voltage_offset_adjustment.upper() == 0.0 {
|
||||||
|
None
|
||||||
|
} else {
|
||||||
|
Some(self.voltage_offset_adjustment.value() as i32)
|
||||||
|
};
|
||||||
|
|
||||||
ClocksSettings {
|
ClocksSettings {
|
||||||
max_core_clock,
|
max_core_clock,
|
||||||
max_memory_clock,
|
max_memory_clock,
|
||||||
max_voltage,
|
max_voltage,
|
||||||
|
voltage_offset,
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
ClocksSettings::default()
|
ClocksSettings::default()
|
||||||
@ -130,7 +184,7 @@ fn extract_value_and_range(
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn oc_adjustment(title: &'static str, grid: &Grid, row: i32) -> Adjustment {
|
fn oc_adjustment(title: &'static str, grid: &Grid, row: i32) -> Adjustment {
|
||||||
let label = Label::new(Some(title));
|
let label = Label::builder().label(title).halign(Align::Start).build();
|
||||||
|
|
||||||
let adjustment = Adjustment::new(0.0, 0.0, 0.0, 1.0, 10.0, 0.0);
|
let adjustment = Adjustment::new(0.0, 0.0, 0.0, 1.0, 10.0, 0.0);
|
||||||
|
|
||||||
@ -148,17 +202,36 @@ fn oc_adjustment(title: &'static str, grid: &Grid, row: i32) -> Adjustment {
|
|||||||
let value_selector = SpinButton::new(Some(&adjustment), 1.0, 0);
|
let value_selector = SpinButton::new(Some(&adjustment), 1.0, 0);
|
||||||
let value_label = Label::new(None);
|
let value_label = Label::new(None);
|
||||||
|
|
||||||
adjustment.connect_value_changed(clone!(@strong value_label => move |adjustment| {
|
|
||||||
let value = adjustment.value();
|
|
||||||
value_label.set_text(&value.to_string());
|
|
||||||
}));
|
|
||||||
|
|
||||||
let popover = Popover::builder().child(&value_selector).build();
|
let popover = Popover::builder().child(&value_selector).build();
|
||||||
let value_button = MenuButton::builder()
|
let value_button = MenuButton::builder()
|
||||||
.popover(&popover)
|
.popover(&popover)
|
||||||
.child(&value_label)
|
.child(&value_label)
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
|
adjustment.connect_value_changed(clone!(@strong value_label => move |adjustment| {
|
||||||
|
let value = adjustment.value();
|
||||||
|
value_label.set_text(&value.to_string());
|
||||||
|
}));
|
||||||
|
|
||||||
|
adjustment.connect_changed(
|
||||||
|
clone!(@strong label, @strong value_label, @strong scale, @strong value_button => move |adjustment| {
|
||||||
|
let value = adjustment.value();
|
||||||
|
value_label.set_text(&value.to_string());
|
||||||
|
|
||||||
|
if adjustment.upper() == 0.0 {
|
||||||
|
label.hide();
|
||||||
|
value_label.hide();
|
||||||
|
scale.hide();
|
||||||
|
value_button.hide();
|
||||||
|
} else {
|
||||||
|
label.show();
|
||||||
|
value_label.show();
|
||||||
|
scale.show();
|
||||||
|
value_button.show();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
));
|
||||||
|
|
||||||
grid.attach(&label, 0, row, 1, 1);
|
grid.attach(&label, 0, row, 1, 1);
|
||||||
grid.attach(&scale, 1, row, 4, 1);
|
grid.attach(&scale, 1, row, 4, 1);
|
||||||
grid.attach(&value_button, 6, row, 4, 1);
|
grid.attach(&value_button, 6, row, 4, 1);
|
||||||
@ -171,6 +244,7 @@ pub struct ClocksSettings {
|
|||||||
pub max_core_clock: Option<u32>,
|
pub max_core_clock: Option<u32>,
|
||||||
pub max_memory_clock: Option<u32>,
|
pub max_memory_clock: Option<u32>,
|
||||||
pub max_voltage: Option<u32>,
|
pub max_voltage: Option<u32>,
|
||||||
|
pub voltage_offset: Option<i32>,
|
||||||
}
|
}
|
||||||
|
|
||||||
fn zero_to_option(value: f64) -> Option<u32> {
|
fn zero_to_option(value: f64) -> Option<u32> {
|
||||||
@ -180,3 +254,7 @@ fn zero_to_option(value: f64) -> Option<u32> {
|
|||||||
Some(value as u32)
|
Some(value as u32)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn emit_changed(adjustment: &Adjustment) {
|
||||||
|
adjustment.emit_by_name::<()>("changed", &[]);
|
||||||
|
}
|
||||||
|
@ -4,7 +4,7 @@ version = "0.2.2"
|
|||||||
edition = "2021"
|
edition = "2021"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
amdgpu-sysfs = { version = "0.9.5", features = ["serde"] }
|
amdgpu-sysfs = { version = "0.9.7", features = ["serde"] }
|
||||||
serde = { version = "1.0", features = ["derive"] }
|
serde = { version = "1.0", features = ["derive"] }
|
||||||
indexmap = { version = "*", features = ["serde"] }
|
indexmap = { version = "*", features = ["serde"] }
|
||||||
|
|
||||||
|
@ -42,5 +42,6 @@ pub enum SetClocksCommand {
|
|||||||
MaxCoreClock(u32),
|
MaxCoreClock(u32),
|
||||||
MaxMemoryClock(u32),
|
MaxMemoryClock(u32),
|
||||||
MaxVoltage(u32),
|
MaxVoltage(u32),
|
||||||
|
VoltageOffset(i32),
|
||||||
Reset,
|
Reset,
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user