diff --git a/.github/release-nest-v3 b/.github/release-nest-v3 index e440e5c..56a6051 100644 --- a/.github/release-nest-v3 +++ b/.github/release-nest-v3 @@ -1 +1 @@ -3 \ No newline at end of file +1 \ No newline at end of file diff --git a/pikafetch/debian/changelog b/pikafetch/debian/changelog index 67ef038..26c0731 100644 --- a/pikafetch/debian/changelog +++ b/pikafetch/debian/changelog @@ -1,4 +1,4 @@ -pikafetch (0.1.0-101pika3) pika; urgency=medium +pikafetch (0.1.0-101pika4) pika; urgency=medium * Initial release. diff --git a/pikafetch/src/system/hardware/gpu.zig b/pikafetch/src/system/hardware/gpu.zig index e4d4534..451db0c 100644 --- a/pikafetch/src/system/hardware/gpu.zig +++ b/pikafetch/src/system/hardware/gpu.zig @@ -96,7 +96,7 @@ pub fn getGPUInfo(allocator: mem.Allocator) ![][]const u8 { } }, VendorId.AMD, VendorId.AMD_2 => { - if (try detectAMDGPU(allocator, entry.name)) |gpu| { + if (try detectAMDGPU(allocator, entry.name, vendor_id)) |gpu| { try gpus.append(gpu); continue; } @@ -124,67 +124,128 @@ pub fn getGPUInfo(allocator: mem.Allocator) ![][]const u8 { } fn detectNvidiaGPU(allocator: mem.Allocator, card_name: []const u8) !?[]const u8 { + // First try to get device ID for PCI lookup + const device_path = try allocPrint(allocator, "/sys/class/drm/{s}/device/device", .{card_name}); + defer allocator.free(device_path); + + const device_file = fs.openFileAbsolute(device_path, .{}) catch return null; + defer device_file.close(); + + var device_buf: [32]u8 = undefined; + const device_len = device_file.readAll(&device_buf) catch return null; + const device_str = mem.trim(u8, device_buf[0..device_len], "\n\r \t0x"); + + const device_id = std.fmt.parseInt(u32, device_str, 16) catch return null; + + // Try /proc/driver/nvidia first const proc_path = try allocPrint(allocator, "/proc/driver/nvidia/gpus/{s}/information", .{card_name}); defer allocator.free(proc_path); - const info_file = fs.openFileAbsolute(proc_path, .{}) catch return null; - defer info_file.close(); - - var buf: [1024]u8 = undefined; - const bytes_read = info_file.readAll(&buf) catch return null; - const content = buf[0..bytes_read]; - var model_name: ?[]const u8 = null; var vbios_version: ?[]const u8 = null; var memory_size: ?u64 = null; - var lines = mem.split(u8, content, "\n"); - while (lines.next()) |line| { - if (mem.indexOf(u8, line, "Model:")) |_| { - const start = mem.indexOf(u8, line, ":").? + 1; - model_name = mem.trim(u8, line[start..], " \t\r\n"); - } else if (mem.indexOf(u8, line, "Video BIOS:")) |_| { - const start = mem.indexOf(u8, line, ":").? + 1; - vbios_version = mem.trim(u8, line[start..], " \t\r\n"); - } else if (mem.indexOf(u8, line, "Video Memory:")) |_| { - const start = mem.indexOf(u8, line, ":").? + 1; - const mem_str = mem.trim(u8, line[start..], " \t\r\nMB"); - memory_size = std.fmt.parseInt(u64, mem_str, 10) catch null; + // Try to read from nvidia proc + const info_file = fs.openFileAbsolute(proc_path, .{}) catch null; + if (info_file) |file| { + defer file.close(); + var buf: [1024]u8 = undefined; + const bytes_read = file.readAll(&buf) catch 0; + if (bytes_read > 0) { + const content = buf[0..bytes_read]; + + var lines = mem.split(u8, content, "\n"); + while (lines.next()) |line| { + if (mem.indexOf(u8, line, "Model:")) |_| { + const start = mem.indexOf(u8, line, ":").? + 1; + model_name = mem.trim(u8, line[start..], " \t\r\n"); + } else if (mem.indexOf(u8, line, "Video BIOS:")) |_| { + const start = mem.indexOf(u8, line, ":").? + 1; + vbios_version = mem.trim(u8, line[start..], " \t\r\n"); + } else if (mem.indexOf(u8, line, "Video Memory:")) |_| { + const start = mem.indexOf(u8, line, ":").? + 1; + const mem_str = mem.trim(u8, line[start..], " \t\r\nMB"); + memory_size = std.fmt.parseInt(u64, mem_str, 10) catch null; + } + } } } - if (model_name) |model| { - const gpu_info = GPUInfo{ - .vendor = "NVIDIA", - .model = model, - .driver = vbios_version, - .memory = memory_size, - }; - const formatted = try gpu_info.format(allocator); - return formatted; + // If we couldn't get model name from nvidia proc, try product name + if (model_name == null) { + const product_path = try allocPrint(allocator, "/sys/class/drm/{s}/device/product_name", .{card_name}); + defer allocator.free(product_path); + + const product_file = fs.openFileAbsolute(product_path, .{}) catch null; + if (product_file) |file| { + defer file.close(); + var product_buf: [256]u8 = undefined; + const len = file.readAll(&product_buf) catch 0; + if (len > 0) { + model_name = mem.trim(u8, product_buf[0..len], "\n\r \t"); + } + } } - return null; + // If still no model name, try PCI lookup + if (model_name == null) { + model_name = if (findPCIName(VendorId.NVIDIA, device_id)) |name| + name + else + try allocPrint(allocator, "NVIDIA GPU (0x{x:0>4})", .{device_id}); + } + + // Get driver info if not already found from nvidia proc + if (vbios_version == null) { + const driver_path = try allocPrint(allocator, "/sys/class/drm/{s}/device/driver", .{card_name}); + defer allocator.free(driver_path); + + vbios_version = blk: { + var dir_handle = fs.openDirAbsolute(driver_path, .{}) catch break :blk null; + defer dir_handle.close(); + + var path_buf: [256]u8 = undefined; + const path = dir_handle.readLink("driver", &path_buf) catch break :blk null; + break :blk std.fs.path.basename(path); + }; + } + + const gpu_info = GPUInfo{ + .vendor = "NVIDIA", + .model = model_name.?, // Safe because we always set it above + .driver = vbios_version, + .memory = memory_size, + }; + + const formatted = try gpu_info.format(allocator); + return formatted; } -fn detectAMDGPU(allocator: mem.Allocator, card_name: []const u8) !?[]const u8 { - const product_path = try allocPrint(allocator, "/sys/class/drm/{s}/device/product_name", .{card_name}); - defer allocator.free(product_path); +fn detectAMDGPU(allocator: mem.Allocator, card_name: []const u8, vendor_id: u32) !?[]const u8 { + // Get device ID + const device_path = try allocPrint(allocator, "/sys/class/drm/{s}/device/device", .{card_name}); + defer allocator.free(device_path); - var product_name: []const u8 = undefined; - if (fs.openFileAbsolute(product_path, .{})) |product_file| { - defer product_file.close(); - var product_buf: [256]u8 = undefined; - const product_len = product_file.readAll(&product_buf) catch return null; - product_name = mem.trim(u8, product_buf[0..product_len], "\n\r \t"); - } else |_| { - return null; - } + const device_file = fs.openFileAbsolute(device_path, .{}) catch return null; + defer device_file.close(); - const driver_path = try allocPrint(allocator, "/sys/class/drm/{s}/device/driver", .{card_name}); - defer allocator.free(driver_path); + var device_buf: [32]u8 = undefined; + const device_len = device_file.readAll(&device_buf) catch return null; + const device_str = mem.trim(u8, device_buf[0..device_len], "\n\r \t0x"); + const device_id = std.fmt.parseInt(u32, device_str, 16) catch return null; + + // Get model name from PCI database + const model_name = if (findPCIName(vendor_id, device_id)) |name| + name + else + try allocPrint(allocator, "GPU (0x{x:0>4})", .{device_id}); + + // Get driver info const driver = blk: { + const driver_path = try allocPrint(allocator, "/sys/class/drm/{s}/device/driver", .{card_name}); + defer allocator.free(driver_path); + var dir_handle = fs.openDirAbsolute(driver_path, .{}) catch break :blk null; defer dir_handle.close(); @@ -193,11 +254,27 @@ fn detectAMDGPU(allocator: mem.Allocator, card_name: []const u8) !?[]const u8 { break :blk std.fs.path.basename(path); }; + // Get VRAM info + var memory: ?u64 = null; + const vram_path = try allocPrint(allocator, "/sys/class/drm/{s}/device/mem_info_vram_total", .{card_name}); + defer allocator.free(vram_path); + + if (fs.openFileAbsolute(vram_path, .{})) |vram_file| { + defer vram_file.close(); + var vram_buf: [32]u8 = undefined; + if (vram_file.readAll(&vram_buf)) |len| { + const vram_str = mem.trim(u8, vram_buf[0..len], "\n\r \t"); + if (std.fmt.parseInt(u64, vram_str, 10)) |vram_bytes| { + memory = vram_bytes / (1024 * 1024); // Convert to MB + } else |_| {} + } else |_| {} + } else |_| {} + const gpu_info = GPUInfo{ .vendor = "AMD", - .model = product_name, + .model = model_name, .driver = driver, - .memory = null, + .memory = memory, }; const formatted = try gpu_info.format(allocator); @@ -247,26 +324,25 @@ fn findPCIName(vendor_id: u32, device_id: u32) ?[]const u8 { var current_vendor: ?u32 = null; while (lines.next()) |line| { - const trimmed = mem.trim(u8, line, " \t\r"); + const trimmed = mem.trim(u8, line, " \r\n"); if (trimmed.len == 0 or trimmed[0] == '#') continue; - // Check if this is a vendor line (no tabs at start) - if (trimmed[0] != '\t') { - // Parse vendor ID + // Count leading tabs + const tab_count = for (trimmed, 0..) |c, i| { + if (c != '\t') break @as(usize, @intCast(i)); + } else trimmed.len; + + // No tabs = vendor line + if (tab_count == 0) { const space_idx = mem.indexOf(u8, trimmed, " ") orelse continue; const vendor_str = trimmed[0..space_idx]; current_vendor = std.fmt.parseInt(u32, vendor_str, 16) catch continue; continue; } - // If we found our vendor, look for the device - if (current_vendor) |vendor| { - if (vendor != vendor_id) continue; - - // Device lines have one tab - if (trimmed[0] != '\t' or trimmed.len < 2) continue; - const device_line = mem.trim(u8, trimmed[1..], " \t"); - + // One tab = device line + if (tab_count == 1 and current_vendor != null and current_vendor.? == vendor_id) { + const device_line = trimmed[tab_count..]; const space_idx = mem.indexOf(u8, device_line, " ") orelse continue; const device_str = device_line[0..space_idx]; const found_device = std.fmt.parseInt(u32, device_str, 16) catch continue;