refactor: use blueprint for the info page (#273)

* feat: use blueprint for hardware info

* chore: unify padding

* fix: opensuse libadwaita build
This commit is contained in:
Ilya Zlobintsev 2024-02-24 16:07:42 +02:00 committed by GitHub
parent e91bc46a0f
commit 54370e9b22
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
6 changed files with 294 additions and 183 deletions

View File

@ -52,7 +52,7 @@ impl App {
let window = ApplicationWindow::builder()
.title("LACT")
.default_width(600)
.default_height(820)
.default_height(830)
.icon_name(APP_ID)
.build();

View File

@ -0,0 +1,174 @@
use gtk::glib::{self, object::ObjectExt, subclass::object::DerivedObjectProperties, Object};
use lact_client::schema::{DeviceInfo, DeviceStats};
glib::wrapper! {
pub struct HardwareInfoSection(ObjectSubclass<imp::HardwareInfoSection>)
@extends gtk::Box, gtk::Widget,
@implements gtk::Orientable, gtk::Accessible, gtk::Buildable;
}
impl HardwareInfoSection {
pub fn new() -> Self {
Self::default()
}
pub fn set_info(&self, info: &DeviceInfo) {
self.reset();
if let Some(pci_info) = &info.pci_info {
if let Some(name) = pci_info
.subsystem_pci_info
.model
.as_deref()
.or(pci_info.device_pci_info.model.as_deref())
{
self.set_gpu_model(name);
}
if let Some(manufacturer_name) = info.pci_info.as_ref().and_then(|pci_info| {
pci_info
.subsystem_pci_info
.vendor
.as_deref()
.or(pci_info.device_pci_info.model.as_deref())
}) {
self.set_gpu_manufacturer(manufacturer_name);
}
}
if let Some(drm_info) = &info.drm_info {
self.set_gpu_family(drm_info.family_name.clone());
self.set_asic_name(drm_info.asic_name.clone());
self.set_compute_units(drm_info.compute_units.to_string());
self.set_vram_type(drm_info.vram_type.clone());
self.set_peak_vram_bandwidth(format!("{} GiB/s", drm_info.vram_max_bw));
self.set_l1_cache(format!("{} KiB", drm_info.l1_cache_per_cu / 1024));
self.set_l2_cache(format!("{} KiB", drm_info.l2_cache / 1024));
self.set_l3_cache(format!("{} MiB", drm_info.l3_cache_mb));
if let Some(memory_info) = &drm_info.memory_info {
let rebar = if memory_info.resizeable_bar {
"Enabled"
} else {
"Disabled"
};
self.set_rebar(rebar);
self.set_cpu_accessible_vram(format!(
"{} MiB",
memory_info.cpu_accessible_total / 1024 / 1024
));
}
}
self.set_driver_used(info.driver);
if let Some(vbios) = &info.vbios_version {
self.set_vbios_version(vbios.clone());
}
if let (Some(link_speed), Some(link_width)) =
(&info.link_info.current_speed, &info.link_info.current_width)
{
self.set_link_speed(format!("{link_speed} x{link_width}",));
}
}
pub fn set_stats(&self, stats: &DeviceStats) {
if let Some(total_vram) = stats.vram.total {
self.set_vram_size(format!("{} MiB", total_vram / 1024 / 1024));
}
}
fn reset(&self) {
let properties = imp::HardwareInfoSection::derived_properties();
for property in properties {
self.set_property(property.name(), "Unknown");
}
}
}
impl Default for HardwareInfoSection {
fn default() -> Self {
Object::builder().build()
}
}
mod imp {
#![allow(clippy::enum_variant_names)]
use crate::app::{info_row::InfoRow, page_section::PageSection};
use glib::Properties;
use gtk::{
glib::{self, subclass::InitializingObject},
prelude::*,
subclass::{
prelude::*,
widget::{CompositeTemplateClass, WidgetImpl},
},
CompositeTemplate,
};
use std::cell::RefCell;
#[derive(CompositeTemplate, Default, Properties)]
#[properties(wrapper_type = super::HardwareInfoSection)]
#[template(file = "ui/info_page/hardware_info_section.blp")]
pub struct HardwareInfoSection {
#[property(get, set)]
gpu_model: RefCell<String>,
#[property(get, set)]
gpu_manufacturer: RefCell<String>,
#[property(get, set)]
gpu_family: RefCell<String>,
#[property(get, set)]
asic_name: RefCell<String>,
#[property(get, set)]
compute_units: RefCell<String>,
#[property(get, set)]
vbios_version: RefCell<String>,
#[property(get, set)]
driver_used: RefCell<String>,
#[property(get, set)]
vram_size: RefCell<String>,
#[property(get, set)]
vram_type: RefCell<String>,
#[property(get, set)]
peak_vram_bandwidth: RefCell<String>,
#[property(get, set)]
l1_cache: RefCell<String>,
#[property(get, set)]
l2_cache: RefCell<String>,
#[property(get, set)]
l3_cache: RefCell<String>,
#[property(get, set)]
rebar: RefCell<String>,
#[property(get, set)]
cpu_accessible_vram: RefCell<String>,
#[property(get, set)]
link_speed: RefCell<String>,
}
#[glib::object_subclass]
impl ObjectSubclass for HardwareInfoSection {
const NAME: &'static str = "HardwareInfoSection";
type Type = super::HardwareInfoSection;
type ParentType = PageSection;
fn class_init(class: &mut Self::Class) {
InfoRow::ensure_type();
PageSection::ensure_type();
class.bind_template();
}
fn instance_init(obj: &InitializingObject<Self>) {
obj.init_template();
}
}
#[glib::derived_properties]
impl ObjectImpl for HardwareInfoSection {}
impl WidgetImpl for HardwareInfoSection {}
impl BoxImpl for HardwareInfoSection {}
}

View File

@ -1,6 +1,9 @@
mod hardware_info;
mod vulkan_info;
use super::{label_row, values_grid};
use self::hardware_info::HardwareInfoSection;
use super::values_grid;
use crate::app::page_section::PageSection;
use gtk::prelude::*;
use gtk::*;
@ -10,22 +13,7 @@ use vulkan_info::VulkanInfoFrame;
#[derive(Clone)]
pub struct InformationPage {
pub container: ScrolledWindow,
gpu_name_label: Label,
gpu_manufacturer_label: Label,
family_name: Label,
asic_name: Label,
vbios_version_label: Label,
driver_label: Label,
vram_size_label: Label,
vram_type_label: Label,
vram_peak_bw_label: Label,
compute_units_label: Label,
l1_cache_label: Label,
l2_cache_label: Label,
l3_cache_label: Label,
resizable_bar_enabled: Label,
cpu_accessible_vram_label: Label,
link_speed_label: Label,
hardware_info: HardwareInfoSection,
vulkan_info_frame: VulkanInfoFrame,
vulkan_unavailable_label: Label,
}
@ -39,42 +27,12 @@ impl InformationPage {
.margin_end(20)
.build();
let info_container = PageSection::new("Hardware Information");
let values_grid = values_grid();
// Dummy label to prevent the gpu name label from stealing focus
let dummy_label = Label::builder().selectable(true).halign(Align::End).build();
values_grid.attach(&dummy_label, 0, 0, 1, 1);
let mut row = 0;
let gpu_name_label = sequential_label_row("GPU Model:", &values_grid, &mut row);
let gpu_manufacturer_label =
sequential_label_row("GPU Manufacturer:", &values_grid, &mut row);
let family_name = sequential_label_row("GPU Family:", &values_grid, &mut row);
let asic_name = sequential_label_row("ASIC Name:", &values_grid, &mut row);
let compute_units_label = sequential_label_row("Compute Units:", &values_grid, &mut row);
let vbios_version_label = sequential_label_row("VBIOS Version:", &values_grid, &mut row);
let driver_label = sequential_label_row("Driver Used:", &values_grid, &mut row);
let vram_size_label = sequential_label_row("VRAM Size:", &values_grid, &mut row);
let vram_type_label = sequential_label_row("VRAM Type:", &values_grid, &mut row);
let vram_peak_bw_label =
sequential_label_row("Peak VRAM Bandwidth:", &values_grid, &mut row);
let l1_cache_label = sequential_label_row("L1 Cache (Per CU):", &values_grid, &mut row);
let l2_cache_label = sequential_label_row("L2 Cache:", &values_grid, &mut row);
let l3_cache_label = sequential_label_row("L3 Cache:", &values_grid, &mut row);
let resizable_bar_enabled = sequential_label_row("Resizeable BAR:", &values_grid, &mut row);
let cpu_accessible_vram_label =
sequential_label_row("CPU Accessible VRAM:", &values_grid, &mut row);
let link_speed_label = sequential_label_row("Link Speed:", &values_grid, &mut row);
info_container.append(&values_grid);
vbox.append(&info_container);
let hardware_info = HardwareInfoSection::new();
vbox.append(&hardware_info);
let vulkan_container = PageSection::new("Vulkan Information");
vulkan_container.set_spacing(10);
vulkan_container.set_margin_start(15);
let vulkan_info_frame = VulkanInfoFrame::new();
vulkan_container.append(&vulkan_info_frame.container);
@ -97,129 +55,14 @@ impl InformationPage {
Self {
container,
gpu_name_label,
gpu_manufacturer_label,
vbios_version_label,
driver_label,
vram_size_label,
link_speed_label,
hardware_info,
vulkan_info_frame,
family_name,
asic_name,
vram_type_label,
resizable_bar_enabled,
cpu_accessible_vram_label,
compute_units_label,
vram_peak_bw_label,
l1_cache_label,
l2_cache_label,
l3_cache_label,
vulkan_unavailable_label,
}
}
pub fn set_info(&self, gpu_info: &DeviceInfo) {
let gpu_name = gpu_info
.pci_info
.as_ref()
.and_then(|pci_info| {
pci_info
.subsystem_pci_info
.model
.as_deref()
.or(pci_info.device_pci_info.model.as_deref())
})
.unwrap_or_default();
self.gpu_name_label
.set_markup(&format!("<b>{gpu_name}</b>"));
let gpu_manufacturer = gpu_info
.pci_info
.as_ref()
.and_then(|pci_info| {
pci_info
.subsystem_pci_info
.vendor
.as_deref()
.or(pci_info.device_pci_info.model.as_deref())
})
.unwrap_or_default();
self.gpu_manufacturer_label
.set_markup(&format!("<b>{gpu_manufacturer}</b>"));
let mut family_name = "Unknown";
let mut asic_name = "Unknown";
let mut compute_units = "Unknown".to_owned();
let mut vram_type = "Unknown";
let mut vram_max_bw = "Unknown";
let mut cpu_accessible_vram = "Unknown".to_owned();
let mut resizeable_bar_enabled = "Unknown";
let mut l1_cache = "Unknown".to_owned();
let mut l2_cache = "Unknown".to_owned();
let mut l3_cache = "Unknown".to_owned();
if let Some(drm_info) = &gpu_info.drm_info {
family_name = &drm_info.family_name;
asic_name = &drm_info.asic_name;
compute_units = drm_info.compute_units.to_string();
vram_type = &drm_info.vram_type;
vram_max_bw = &drm_info.vram_max_bw;
l1_cache = format!("{} KiB", drm_info.l1_cache_per_cu / 1024);
l2_cache = format!("{} KiB", drm_info.l2_cache / 1024);
l3_cache = format!("{} MiB", drm_info.l3_cache_mb);
if let Some(memory_info) = &drm_info.memory_info {
resizeable_bar_enabled = if memory_info.resizeable_bar {
"Enabled"
} else {
"Disabled"
};
cpu_accessible_vram = (memory_info.cpu_accessible_total / 1024 / 1024).to_string();
}
}
self.family_name
.set_markup(&format!("<b>{family_name}</b>"));
self.asic_name.set_markup(&format!("<b>{asic_name}</b>"));
self.compute_units_label
.set_markup(&format!("<b>{compute_units}</b>"));
self.vram_type_label
.set_markup(&format!("<b>{vram_type}</b>"));
self.vram_peak_bw_label
.set_markup(&format!("<b>{vram_max_bw} GiB/s</b>"));
self.l1_cache_label
.set_markup(&format!("<b>{l1_cache}</b>"));
self.l2_cache_label
.set_markup(&format!("<b>{l2_cache}</b>"));
self.l3_cache_label
.set_markup(&format!("<b>{l3_cache}</b>"));
self.resizable_bar_enabled
.set_markup(&format!("<b>{resizeable_bar_enabled}</b>"));
self.cpu_accessible_vram_label
.set_markup(&format!("<b>{cpu_accessible_vram} MiB</b>"));
let vbios_version = gpu_info.vbios_version.as_deref().unwrap_or("Unknown");
self.vbios_version_label
.set_markup(&format!("<b>{vbios_version}</b>"));
self.driver_label
.set_markup(&format!("<b>{}</b>", gpu_info.driver));
let link_speed = gpu_info
.link_info
.current_speed
.as_deref()
.unwrap_or("Unknown");
let link_width = gpu_info
.link_info
.current_width
.as_deref()
.unwrap_or("Unknown");
self.link_speed_label
.set_markup(&format!("<b>{link_speed} x{link_width}</b>",));
self.hardware_info.set_info(gpu_info);
if let Some(vulkan_info) = &gpu_info.vulkan_info {
self.vulkan_info_frame.set_info(vulkan_info);
@ -232,17 +75,6 @@ impl InformationPage {
}
pub fn set_stats(&self, stats: &DeviceStats) {
let vram_size = stats.vram.total.map_or_else(
|| "Unknown".to_owned(),
|size| (size / 1024 / 1024).to_string(),
);
self.vram_size_label
.set_markup(&format!("<b>{vram_size} MiB</b>"));
self.hardware_info.set_stats(stats);
}
}
fn sequential_label_row(title: &str, parent: &Grid, row: &mut i32) -> Label {
let label = label_row(title, parent, *row, 0, true);
*row += 1;
label
}

View File

@ -30,6 +30,8 @@ impl VulkanInfoFrame {
let extensions_model = gio::ListStore::new::<VulkanFeature>();
let grid = values_grid();
grid.set_margin_start(0);
grid.set_margin_end(0);
let device_name_label = label_row("Device name", &grid, 0, 0, true);
let version_label = label_row("Vulkan version:", &grid, 1, 0, true);

View File

@ -0,0 +1,103 @@
using Gtk 4.0;
template $HardwareInfoSection: $PageSection {
name: "Hardware Information";
spacing: 10;
margin-start: 15;
$InfoRow {
name: "GPU Model:";
value: bind template.gpu_model;
selectable: true;
}
$InfoRow {
name: "GPU Manufacturer:";
value: bind template.gpu_manufacturer;
selectable: true;
}
$InfoRow {
name: "GPU Family:";
value: bind template.gpu_family;
selectable: true;
}
$InfoRow {
name: "ASIC Name:";
value: bind template.asic_name;
selectable: true;
}
$InfoRow {
name: "Compute Units:";
value: bind template.compute_units;
selectable: true;
}
$InfoRow {
name: "VBIOS Version:";
value: bind template.vbios_version;
selectable: true;
}
$InfoRow {
name: "Driver Used:";
value: bind template.driver_used;
selectable: true;
}
$InfoRow {
name: "VRAM Size:";
value: bind template.vram_size;
selectable: true;
}
$InfoRow {
name: "VRAM Type:";
value: bind template.vram_type;
selectable: true;
}
$InfoRow {
name: "Peak VRAM Bandwidth:";
value: bind template.peak_vram_bandwidth;
selectable: true;
}
$InfoRow {
name: "L1 Cache (Per CU):";
value: bind template.l1_cache;
selectable: true;
}
$InfoRow {
name: "L2 Cache:";
value: bind template.l2_cache;
selectable: true;
}
$InfoRow {
name: "L3 Cache:";
value: bind template.l3_cache;
selectable: true;
}
$InfoRow {
name: "Resizeable BAR:";
value: bind template.rebar;
selectable: true;
}
$InfoRow {
name: "CPU Accessible VRAM:";
value: bind template.cpu_accessible_vram;
selectable: true;
}
$InfoRow {
name: "Link Speed:";
value: bind template.link_speed;
selectable: true;
}
}

View File

@ -14,12 +14,12 @@ metadata:
all: [ hwdata ]
fedora-39: [ gtk4, libdrm, libadwaita ]
arch: [ gtk4, libadwaita ]
opensuse-tumbleweed: [ gtk4, libdrm, libadwaita ]
opensuse-tumbleweed: [ libdrm, libadwaita ]
build_depends:
all: [ curl, make, clang ]
fedora-39: [ gtk4-devel, gcc, libdrm-devel, blueprint-compiler, libadwaita-devel, dbus ]
arch: [ gtk4, blueprint-compiler, libadwaita, dbus ]
opensuse-tumbleweed: [ gtk4-devel, libdrm-devel, blueprint-compiler, libadwaita-devel ]
opensuse-tumbleweed: [ libdrm-devel, blueprint-compiler, libadwaita-devel ]
all_images: true
env:
RUSTUP_URL: https://sh.rustup.rs