Files
makelore/electron/main/gpu-fallback.ts

66 lines
1.9 KiB
TypeScript

import { mkdirSync, readFileSync, renameSync, writeFileSync } from 'node:fs';
import { dirname } from 'node:path';
export const GPU_CRASH_WINDOW_MS = 10 * 60 * 1000;
export const GPU_CRASH_THRESHOLD = 2;
export type GpuFallbackState = {
crashCount: number;
lastCrashAt: number;
reason: string;
};
function isState(value: unknown): value is GpuFallbackState {
if (!value || typeof value !== 'object') return false;
const record = value as Record<string, unknown>;
return Number.isFinite(record.crashCount)
&& Number.isFinite(record.lastCrashAt)
&& typeof record.reason === 'string';
}
export function readGpuFallbackState(
filePath: string,
now = Date.now(),
): GpuFallbackState | null {
try {
const parsed: unknown = JSON.parse(readFileSync(filePath, 'utf8'));
if (!isState(parsed)) return null;
if (now - parsed.lastCrashAt > GPU_CRASH_WINDOW_MS) return null;
return parsed;
} catch {
return null;
}
}
export function shouldUseSoftwareRendering(input: {
envDisabled?: boolean;
cliDisabled?: boolean;
state?: GpuFallbackState | null;
now?: number;
}): boolean {
if (input.envDisabled || input.cliDisabled) return true;
const state = input.state;
if (!state) return false;
const now = input.now ?? Date.now();
return now - state.lastCrashAt <= GPU_CRASH_WINDOW_MS
&& state.crashCount >= GPU_CRASH_THRESHOLD;
}
export function recordGpuCrash(
filePath: string,
reason: string,
now = Date.now(),
): GpuFallbackState {
const previous = readGpuFallbackState(filePath, now);
const next: GpuFallbackState = {
crashCount: previous ? previous.crashCount + 1 : 1,
lastCrashAt: now,
reason,
};
mkdirSync(dirname(filePath), { recursive: true });
const temporaryPath = `${filePath}.${process.pid}.tmp`;
writeFileSync(temporaryPath, `${JSON.stringify(next)}\n`, 'utf8');
renameSync(temporaryPath, filePath);
return next;
}