mirror of
https://github.com/lone-cloud/gerbil
synced 2026-06-03 19:54:44 -07:00
windows hardware detection improvements, hide integrated gpus for the clblast backend, dont try to detect avx/avx2 flags in the CPU as it's unreliable, use --usecpu flag when CPU backend is selected
This commit is contained in:
parent
3652ce4686
commit
48338b9904
11 changed files with 219 additions and 183 deletions
|
|
@ -7,31 +7,51 @@ export const BackendSelectItem = ({
|
|||
label,
|
||||
devices,
|
||||
disabled = false,
|
||||
}: BackendSelectItemProps) => (
|
||||
<Group justify="space-between" wrap="nowrap">
|
||||
<Box w={!disabled ? '3rem' : 'auto'}>
|
||||
<Text size="sm" truncate>
|
||||
{label}
|
||||
{disabled && (
|
||||
<Text component="span" size="xs" ml="xs">
|
||||
(Compatible devices not found)
|
||||
</Text>
|
||||
)}
|
||||
</Text>
|
||||
</Box>
|
||||
{devices && devices.length > 0 && (
|
||||
<Group gap={4}>
|
||||
{devices.slice(0, 2).map((device, index) => (
|
||||
<Badge key={index} size="md" variant="light" color="blue">
|
||||
{device.length > 25 ? `${device.slice(0, 25)}...` : device}
|
||||
</Badge>
|
||||
))}
|
||||
{devices.length > 2 && (
|
||||
<Badge size="md" variant="light" color="gray">
|
||||
+{devices.length - 2}
|
||||
</Badge>
|
||||
)}
|
||||
</Group>
|
||||
)}
|
||||
</Group>
|
||||
);
|
||||
}: BackendSelectItemProps) => {
|
||||
const renderDeviceName = (
|
||||
device: string | { name: string; isIntegrated: boolean }
|
||||
) => {
|
||||
const deviceName = typeof device === 'string' ? device : device.name;
|
||||
return deviceName.length > 25
|
||||
? `${deviceName.slice(0, 25)}...`
|
||||
: deviceName;
|
||||
};
|
||||
|
||||
return (
|
||||
<Group justify="space-between" wrap="nowrap">
|
||||
<Box w={!disabled ? '3.5rem' : 'auto'}>
|
||||
<Text size="sm" truncate>
|
||||
{label}
|
||||
{disabled && (
|
||||
<Text component="span" size="xs" ml="xs">
|
||||
(Compatible devices not found)
|
||||
</Text>
|
||||
)}
|
||||
</Text>
|
||||
</Box>
|
||||
{devices &&
|
||||
devices.length > 0 &&
|
||||
(() => {
|
||||
const discreteDevices = devices.filter(
|
||||
(device) => typeof device === 'string' || !device.isIntegrated
|
||||
);
|
||||
return (
|
||||
discreteDevices.length > 0 && (
|
||||
<Group gap={4}>
|
||||
{discreteDevices.slice(0, 2).map((device, index) => (
|
||||
<Badge key={index} size="md" variant="light" color="blue">
|
||||
{renderDeviceName(device)}
|
||||
</Badge>
|
||||
))}
|
||||
{discreteDevices.length > 2 && (
|
||||
<Badge size="md" variant="light" color="gray">
|
||||
+{discreteDevices.length - 2}
|
||||
</Badge>
|
||||
)}
|
||||
</Group>
|
||||
)
|
||||
);
|
||||
})()}
|
||||
</Group>
|
||||
);
|
||||
};
|
||||
|
|
|
|||
|
|
@ -25,8 +25,18 @@ export const GpuDeviceSelector = ({
|
|||
backend === 'rocm' ||
|
||||
backend === 'vulkan' ||
|
||||
backend === 'clblast';
|
||||
const hasMultipleDevices =
|
||||
selectedBackend?.devices && selectedBackend.devices.length > 1;
|
||||
|
||||
const getDiscreteDeviceCount = () => {
|
||||
if (!selectedBackend?.devices) return 0;
|
||||
if (backend === 'clblast') {
|
||||
return selectedBackend.devices.filter(
|
||||
(device) => typeof device === 'string' || !device.isIntegrated
|
||||
).length;
|
||||
}
|
||||
return selectedBackend.devices.length;
|
||||
};
|
||||
|
||||
const hasMultipleDevices = getDiscreteDeviceCount() > 1;
|
||||
const showTensorSplit =
|
||||
(backend === 'cuda' || backend === 'rocm' || backend === 'vulkan') &&
|
||||
hasMultipleDevices &&
|
||||
|
|
@ -36,19 +46,42 @@ export const GpuDeviceSelector = ({
|
|||
return null;
|
||||
}
|
||||
|
||||
const deviceOptions =
|
||||
backend === 'clblast'
|
||||
? selectedBackend.devices!.map((device, index) => ({
|
||||
value: index.toString(),
|
||||
label: `GPU ${index}: ${device}`,
|
||||
}))
|
||||
: [
|
||||
{ value: 'all', label: 'All GPUs' },
|
||||
...selectedBackend.devices!.map((device, index) => ({
|
||||
const deviceOptions = (() => {
|
||||
if (!selectedBackend?.devices) return [];
|
||||
|
||||
if (backend === 'clblast') {
|
||||
return selectedBackend.devices
|
||||
.map((device, index) => {
|
||||
if (typeof device === 'object' && device.isIntegrated) {
|
||||
return null;
|
||||
}
|
||||
const deviceName = typeof device === 'string' ? device : device.name;
|
||||
return {
|
||||
value: index.toString(),
|
||||
label: `GPU ${index}: ${device}`,
|
||||
})),
|
||||
];
|
||||
label: `GPU ${index}: ${deviceName}`,
|
||||
};
|
||||
})
|
||||
.filter(
|
||||
(option): option is NonNullable<typeof option> => option !== null
|
||||
);
|
||||
}
|
||||
|
||||
return [
|
||||
{ value: 'all', label: 'All GPUs' },
|
||||
...selectedBackend.devices.map((device, index) => {
|
||||
const deviceName =
|
||||
typeof device === 'string'
|
||||
? device
|
||||
: typeof device === 'object' && 'name' in device
|
||||
? device.name
|
||||
: String(device);
|
||||
return {
|
||||
value: index.toString(),
|
||||
label: `GPU ${index}: ${deviceName}`,
|
||||
};
|
||||
}),
|
||||
];
|
||||
})();
|
||||
|
||||
return (
|
||||
<div>
|
||||
|
|
|
|||
|
|
@ -75,8 +75,6 @@ export const LaunchScreen = ({ onLaunch }: LaunchScreenProps) => {
|
|||
model,
|
||||
sdmodel,
|
||||
backend,
|
||||
noavx2,
|
||||
failsafe,
|
||||
configLoaded,
|
||||
});
|
||||
|
||||
|
|
|
|||
|
|
@ -85,10 +85,14 @@ const buildModelArgs = (
|
|||
const buildConfigArgs = (isImageMode: boolean, launchArgs: LaunchArgs) => {
|
||||
const args: string[] = [];
|
||||
|
||||
if (launchArgs.autoGpuLayers) {
|
||||
args.push('--gpulayers', '-1');
|
||||
} else if (launchArgs.gpuLayers > 0) {
|
||||
args.push('--gpulayers', launchArgs.gpuLayers.toString());
|
||||
const isGpuBackend = launchArgs.backend && launchArgs.backend !== 'cpu';
|
||||
|
||||
if (isGpuBackend) {
|
||||
if (launchArgs.autoGpuLayers) {
|
||||
args.push('--gpulayers', '-1');
|
||||
} else if (launchArgs.gpuLayers > 0) {
|
||||
args.push('--gpulayers', launchArgs.gpuLayers.toString());
|
||||
}
|
||||
}
|
||||
|
||||
if (launchArgs.contextSize) {
|
||||
|
|
@ -193,6 +197,9 @@ const buildBackendArgs = (launchArgs: LaunchArgs) => {
|
|||
const args: string[] = [];
|
||||
|
||||
if (!launchArgs.backend || launchArgs.backend === 'cpu') {
|
||||
if (launchArgs.backend === 'cpu') {
|
||||
args.push('--usecpu');
|
||||
}
|
||||
return args;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -10,8 +10,6 @@ interface UseWarningsProps {
|
|||
model: string;
|
||||
sdmodel: string;
|
||||
backend?: string;
|
||||
noavx2?: boolean;
|
||||
failsafe?: boolean;
|
||||
configLoaded?: boolean;
|
||||
}
|
||||
|
||||
|
|
@ -133,9 +131,6 @@ const checkVramWarnings = async (backend: string): Promise<Warning[]> => {
|
|||
|
||||
const checkCpuWarnings = (
|
||||
backend: string,
|
||||
cpuCapabilities: { avx: boolean; avx2: boolean },
|
||||
noavx2: boolean,
|
||||
failsafe: boolean,
|
||||
availableBackends: BackendOption[]
|
||||
) => {
|
||||
const warnings: Warning[] = [];
|
||||
|
|
@ -144,22 +139,6 @@ const checkCpuWarnings = (
|
|||
return warnings;
|
||||
}
|
||||
|
||||
if (!cpuCapabilities.avx2 && !noavx2) {
|
||||
warnings.push({
|
||||
type: 'warning',
|
||||
message:
|
||||
'Your CPU does not support AVX2. Enable the "Disable AVX2" option on the Advanced tab to avoid crashes.',
|
||||
});
|
||||
}
|
||||
|
||||
if (!cpuCapabilities.avx && !cpuCapabilities.avx2 && !failsafe) {
|
||||
warnings.push({
|
||||
type: 'warning',
|
||||
message:
|
||||
'Your CPU does not support AVX or AVX2. Enable the "Failsafe" option on the Advanced tab to avoid crashes.',
|
||||
});
|
||||
}
|
||||
|
||||
if (
|
||||
availableBackends.length > 0 &&
|
||||
availableBackends.some((b) => b.value === 'cpu')
|
||||
|
|
@ -177,11 +156,8 @@ const checkCpuWarnings = (
|
|||
const checkBackendWarnings = async (params?: {
|
||||
backend: string;
|
||||
cpuCapabilities: {
|
||||
avx: boolean;
|
||||
avx2: boolean;
|
||||
devices: string[];
|
||||
} | null;
|
||||
noavx2: boolean;
|
||||
failsafe: boolean;
|
||||
availableBackends: BackendOption[];
|
||||
}): Promise<Warning[]> => {
|
||||
const warnings: Warning[] = [];
|
||||
|
|
@ -204,20 +180,13 @@ const checkBackendWarnings = async (params?: {
|
|||
warnings.push(...gpuWarnings);
|
||||
|
||||
if (params) {
|
||||
const { backend, cpuCapabilities, noavx2, failsafe, availableBackends } =
|
||||
params;
|
||||
const { backend, cpuCapabilities, availableBackends } = params;
|
||||
|
||||
const vramWarnings = await checkVramWarnings(backend);
|
||||
warnings.push(...vramWarnings);
|
||||
|
||||
if (cpuCapabilities) {
|
||||
const cpuWarnings = checkCpuWarnings(
|
||||
backend,
|
||||
cpuCapabilities,
|
||||
noavx2,
|
||||
failsafe,
|
||||
availableBackends
|
||||
);
|
||||
const cpuWarnings = checkCpuWarnings(backend, availableBackends);
|
||||
warnings.push(...cpuWarnings);
|
||||
}
|
||||
}
|
||||
|
|
@ -229,8 +198,6 @@ export const useWarnings = ({
|
|||
model,
|
||||
sdmodel,
|
||||
backend,
|
||||
noavx2 = false,
|
||||
failsafe = false,
|
||||
configLoaded = false,
|
||||
}: UseWarningsProps) => {
|
||||
const [backendWarnings, setBackendWarnings] = useState<Warning[]>([]);
|
||||
|
|
@ -251,21 +218,14 @@ export const useWarnings = ({
|
|||
window.electronAPI.kobold.getAvailableBackends(),
|
||||
]);
|
||||
|
||||
const cpuCapabilities = {
|
||||
avx: cpuCapabilitiesResult.avx,
|
||||
avx2: cpuCapabilitiesResult.avx2,
|
||||
};
|
||||
|
||||
const result = await checkBackendWarnings({
|
||||
backend,
|
||||
cpuCapabilities,
|
||||
noavx2,
|
||||
failsafe,
|
||||
cpuCapabilities: cpuCapabilitiesResult,
|
||||
availableBackends,
|
||||
});
|
||||
|
||||
setBackendWarnings(result);
|
||||
}, [backend, noavx2, failsafe]);
|
||||
}, [backend]);
|
||||
|
||||
useEffect(() => {
|
||||
updateBackendWarnings();
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
/* eslint-disable no-comments/disallowComments */
|
||||
import {
|
||||
cpu as siCpu,
|
||||
cpuFlags,
|
||||
mem as siMem,
|
||||
memLayout as siMemLayout,
|
||||
} from 'systeminformation';
|
||||
|
|
@ -16,7 +15,11 @@ import type {
|
|||
import { execa } from 'execa';
|
||||
import { formatDeviceName } from '@/utils/format';
|
||||
import { platform } from 'process';
|
||||
import { getVulkanInfo, detectLinuxGPUViaVulkan } from '@/utils/node/vulkan';
|
||||
import {
|
||||
getVulkanInfo,
|
||||
detectLinuxGPUViaVulkan,
|
||||
detectVulkan,
|
||||
} from '@/utils/node/vulkan';
|
||||
|
||||
const COMMON_EXEC_OPTIONS = {
|
||||
timeout: 3000,
|
||||
|
|
@ -34,7 +37,7 @@ export async function detectCPU() {
|
|||
}
|
||||
|
||||
const result = await safeExecute(async () => {
|
||||
const [cpu, flags] = await Promise.all([siCpu(), cpuFlags()]);
|
||||
const cpu = await siCpu();
|
||||
|
||||
const devices: string[] = [];
|
||||
if (cpu.brand) {
|
||||
|
|
@ -43,12 +46,7 @@ export async function detectCPU() {
|
|||
);
|
||||
}
|
||||
|
||||
const avx = flags.includes('avx') || flags.includes('AVX');
|
||||
const avx2 = flags.includes('avx2') || flags.includes('AVX2');
|
||||
|
||||
const capabilities = {
|
||||
avx,
|
||||
avx2,
|
||||
devices,
|
||||
};
|
||||
|
||||
|
|
@ -57,8 +55,6 @@ export async function detectCPU() {
|
|||
}, 'CPU detection failed');
|
||||
|
||||
const fallbackCapabilities = {
|
||||
avx: false,
|
||||
avx2: false,
|
||||
devices: [],
|
||||
};
|
||||
|
||||
|
|
@ -74,15 +70,15 @@ export async function detectGPU() {
|
|||
const result = await safeExecute(async () => {
|
||||
if (platform === 'linux') {
|
||||
return detectLinuxGPUViaVulkan();
|
||||
} else {
|
||||
return detectGPUViaSI();
|
||||
}
|
||||
|
||||
return detectGPUViaSI();
|
||||
}, 'GPU detection failed');
|
||||
|
||||
const fallbackGPUInfo = {
|
||||
hasAMD: false,
|
||||
hasNVIDIA: false,
|
||||
gpuInfo: ['GPU detection failed'],
|
||||
gpuInfo: [],
|
||||
};
|
||||
|
||||
basicGPUInfoCache = result || fallbackGPUInfo;
|
||||
|
|
@ -317,28 +313,8 @@ export async function detectROCm() {
|
|||
}
|
||||
}
|
||||
|
||||
async function detectVulkan() {
|
||||
try {
|
||||
const vulkanInfo = await getVulkanInfo();
|
||||
|
||||
const devices: string[] = [];
|
||||
|
||||
for (const gpu of vulkanInfo.discreteGPUs) {
|
||||
devices.push(formatDeviceName(gpu.deviceName));
|
||||
}
|
||||
|
||||
return {
|
||||
supported: devices.length > 0,
|
||||
devices,
|
||||
version: vulkanInfo.apiVersion || 'Unknown',
|
||||
};
|
||||
} catch {
|
||||
return { supported: false, devices: [], version: 'Unknown' };
|
||||
}
|
||||
}
|
||||
|
||||
function parseClInfoOutput(output: string) {
|
||||
const devices: string[] = [];
|
||||
const devices: { name: string; isIntegrated: boolean }[] = [];
|
||||
const lines = output.split('\n');
|
||||
|
||||
let currentPlatform = '';
|
||||
|
|
@ -353,9 +329,13 @@ function parseClInfoOutput(output: string) {
|
|||
|
||||
if (line.includes('Device Type:') && line.includes('GPU')) {
|
||||
const deviceName = findDeviceNameInClInfo(lines, i);
|
||||
const computeUnits = findComputeUnitsInClInfo(lines, i);
|
||||
|
||||
if (deviceName && currentPlatform) {
|
||||
devices.push(formatDeviceName(deviceName));
|
||||
devices.push({
|
||||
name: formatDeviceName(deviceName),
|
||||
isIntegrated: !isDiscreteGPU(deviceName, computeUnits),
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -389,6 +369,38 @@ function findDeviceNameInClInfo(lines: string[], startIndex: number) {
|
|||
return '';
|
||||
}
|
||||
|
||||
function findComputeUnitsInClInfo(lines: string[], startIndex: number) {
|
||||
for (
|
||||
let j = startIndex + 1;
|
||||
j < Math.min(startIndex + 50, lines.length);
|
||||
j++
|
||||
) {
|
||||
const nextLine = lines[j].trim();
|
||||
if (nextLine.includes('Max compute units:')) {
|
||||
const units = nextLine.split('Max compute units:')[1]?.trim();
|
||||
return units ? parseInt(units, 10) : 0;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
function isDiscreteGPU(deviceName: string, computeUnits: number) {
|
||||
const lowerName = deviceName.toLowerCase();
|
||||
|
||||
if (
|
||||
lowerName.includes('radeon(tm) graphics') ||
|
||||
lowerName.includes('intel')
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (computeUnits <= 2) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
async function detectCLBlast() {
|
||||
try {
|
||||
const { stdout } = await execa('clinfo', [], COMMON_EXEC_OPTIONS);
|
||||
|
|
|
|||
9
src/types/hardware.d.ts
vendored
9
src/types/hardware.d.ts
vendored
|
|
@ -1,6 +1,4 @@
|
|||
export interface CPUCapabilities {
|
||||
avx: boolean;
|
||||
avx2: boolean;
|
||||
devices: string[];
|
||||
}
|
||||
|
||||
|
|
@ -34,7 +32,7 @@ export interface GPUCapabilities {
|
|||
};
|
||||
clblast: {
|
||||
readonly supported: boolean;
|
||||
readonly devices: readonly string[];
|
||||
readonly devices: readonly CLBlastDevice[];
|
||||
readonly version?: string;
|
||||
};
|
||||
}
|
||||
|
|
@ -45,6 +43,11 @@ export interface BasicGPUInfo {
|
|||
gpuInfo: string[];
|
||||
}
|
||||
|
||||
export interface CLBlastDevice {
|
||||
readonly name: string;
|
||||
readonly isIntegrated: boolean;
|
||||
}
|
||||
|
||||
export interface HardwareDetectionResult {
|
||||
readonly supported: boolean;
|
||||
readonly devices: readonly string[];
|
||||
|
|
|
|||
5
src/types/index.d.ts
vendored
5
src/types/index.d.ts
vendored
|
|
@ -72,7 +72,10 @@ export interface SelectOption {
|
|||
}
|
||||
|
||||
export interface BackendOption extends SelectOption {
|
||||
readonly devices?: readonly string[];
|
||||
readonly devices?: readonly (
|
||||
| string
|
||||
| { name: string; isIntegrated: boolean }
|
||||
)[];
|
||||
readonly disabled?: boolean;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,8 +1,8 @@
|
|||
import { readFile, readdir } from 'fs/promises';
|
||||
import { join } from 'path';
|
||||
import { platform } from 'process';
|
||||
import { execa } from 'execa';
|
||||
import { graphics as siGraphics } from 'systeminformation';
|
||||
import { formatDeviceName } from '../format';
|
||||
|
||||
interface CachedGPUInfo {
|
||||
devicePath: string;
|
||||
|
|
@ -167,50 +167,23 @@ async function getLinuxGPUData() {
|
|||
|
||||
async function getWindowsGPUData() {
|
||||
try {
|
||||
const { stdout } = await execa(
|
||||
'powershell',
|
||||
[
|
||||
'-Command',
|
||||
`$activeGpus = Get-CimInstance -ClassName Win32_VideoController | Where-Object { $_.Status -eq 'OK' -and $_.Name -notlike '*Intel*UHD*' -and $_.Name -notlike '*Intel*Iris*' -and $_.Name -notlike '*Basic Display*' } | Select-Object -ExpandProperty Name;
|
||||
$gpuKeys = Get-ChildItem 'HKLM:\\SYSTEM\\CurrentControlSet\\Control\\Class\\{4d36e968-e325-11ce-bfc1-08002be10318}' | Where-Object { $_.PSChildName -match '^\\d{4}$' };
|
||||
foreach($key in $gpuKeys) {
|
||||
$props = Get-ItemProperty $key.PSPath -ErrorAction SilentlyContinue;
|
||||
if($props.DriverDesc -and $props.'HardwareInformation.qwMemorySize' -and $activeGpus -contains $props.DriverDesc) {
|
||||
$vramBytes = $props.'HardwareInformation.qwMemorySize';
|
||||
$vramGB = [math]::Round($vramBytes/1GB, 2);
|
||||
if($vramGB -ge 1) {
|
||||
Write-Output "$($props.DriverDesc)|$vramGB";
|
||||
}
|
||||
}
|
||||
}`,
|
||||
],
|
||||
{
|
||||
timeout: 10000,
|
||||
reject: false,
|
||||
}
|
||||
const graphics = await siGraphics();
|
||||
|
||||
const discreteControllers = graphics.controllers.filter(
|
||||
(controller) => controller.vram && controller.vram >= 1024
|
||||
);
|
||||
|
||||
if (!stdout.trim()) {
|
||||
return [];
|
||||
}
|
||||
|
||||
const gpus: GPUData[] = [];
|
||||
const lines = stdout.trim().split('\n');
|
||||
const seenVram = new Set<number>();
|
||||
|
||||
for (const line of lines) {
|
||||
const parts = line.trim().split('|');
|
||||
if (parts.length === 2) {
|
||||
const vramGB = parseFloat(parts[1]);
|
||||
if (vramGB > 0 && !seenVram.has(vramGB)) {
|
||||
seenVram.add(vramGB);
|
||||
gpus.push({
|
||||
usage: 0,
|
||||
memoryUsed: 0,
|
||||
memoryTotal: vramGB,
|
||||
temperature: undefined,
|
||||
});
|
||||
}
|
||||
for (const controller of discreteControllers) {
|
||||
if (controller.vram) {
|
||||
const vramGB = parseFloat((controller.vram / 1024).toFixed(2));
|
||||
gpus.push({
|
||||
usage: 0,
|
||||
memoryUsed: 0,
|
||||
memoryTotal: vramGB,
|
||||
temperature: undefined,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -250,10 +223,17 @@ export async function detectGPUViaSI() {
|
|||
let hasNVIDIA = false;
|
||||
const gpuInfo: string[] = [];
|
||||
|
||||
const discreteControllers = graphics.controllers.filter(
|
||||
(controller) =>
|
||||
controller.busAddress && isDiscreteBusAddress(controller.busAddress)
|
||||
);
|
||||
const discreteControllers = graphics.controllers.filter((controller) => {
|
||||
if (platform === 'linux' && controller.busAddress) {
|
||||
return isDiscreteBusAddress(controller.busAddress);
|
||||
}
|
||||
|
||||
if (platform === 'win32') {
|
||||
return controller.vram && controller.vram >= 1024;
|
||||
}
|
||||
|
||||
return false;
|
||||
});
|
||||
|
||||
for (const controller of discreteControllers) {
|
||||
if (
|
||||
|
|
@ -268,13 +248,13 @@ export async function detectGPUViaSI() {
|
|||
}
|
||||
|
||||
if (controller.model) {
|
||||
gpuInfo.push(controller.model);
|
||||
gpuInfo.push(formatDeviceName(controller.model));
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
hasAMD,
|
||||
hasNVIDIA,
|
||||
gpuInfo: gpuInfo.length > 0 ? gpuInfo : ['No GPU information available'],
|
||||
gpuInfo: gpuInfo.length > 0 ? gpuInfo : [],
|
||||
};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -151,13 +151,33 @@ export async function detectLinuxGPUViaVulkan() {
|
|||
return {
|
||||
hasAMD,
|
||||
hasNVIDIA,
|
||||
gpuInfo: gpuInfo.length > 0 ? gpuInfo : ['No GPU information available'],
|
||||
gpuInfo: gpuInfo.length > 0 ? gpuInfo : [],
|
||||
};
|
||||
} catch {
|
||||
return {
|
||||
hasAMD: false,
|
||||
hasNVIDIA: false,
|
||||
gpuInfo: ['GPU detection failed'],
|
||||
gpuInfo: [],
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
export async function detectVulkan() {
|
||||
try {
|
||||
const vulkanInfo = await getVulkanInfo();
|
||||
|
||||
const devices: string[] = [];
|
||||
|
||||
for (const gpu of vulkanInfo.discreteGPUs) {
|
||||
devices.push(formatDeviceName(gpu.deviceName));
|
||||
}
|
||||
|
||||
return {
|
||||
supported: devices.length > 0,
|
||||
devices,
|
||||
version: vulkanInfo.apiVersion || 'Unknown',
|
||||
};
|
||||
} catch {
|
||||
return { supported: false, devices: [], version: 'Unknown' };
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -72,7 +72,7 @@ export const createDriverItems = (hardwareInfo: HardwareInfo) => {
|
|||
|
||||
if (gpuCapabilities.cuda.driverVersion) {
|
||||
items.push({
|
||||
label: 'NVIDIA Driver',
|
||||
label: 'NVIDIA',
|
||||
value: gpuCapabilities.cuda.driverVersion,
|
||||
});
|
||||
}
|
||||
|
|
@ -88,7 +88,7 @@ export const createDriverItems = (hardwareInfo: HardwareInfo) => {
|
|||
|
||||
if (gpuCapabilities.rocm.driverVersion) {
|
||||
items.push({
|
||||
label: 'AMD Driver',
|
||||
label: 'AMD',
|
||||
value: gpuCapabilities.rocm.driverVersion,
|
||||
});
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue