fleeting-garden/src/utils/graphics/initialize-gpu.test.ts
Andras Schmelczer 7f628180f0
All checks were successful
Check & deploy / build (pull_request) Successful in 1m9s
Check & deploy / build (push) Successful in 1m39s
Improve settings
2026-05-24 15:24:33 +01:00

100 lines
3 KiB
TypeScript

import { afterEach, describe, expect, it, vi } from 'vitest';
import { initializeGpu } from './initialize-gpu';
const limits = {
maxBufferSize: 1024,
maxComputeWorkgroupsPerDimension: 16,
maxStorageBufferBindingSize: 1024,
} as unknown as GPUSupportedLimits;
const createDevice = (): GPUDevice =>
({
addEventListener: vi.fn(),
lost: new Promise(() => undefined),
}) as unknown as GPUDevice;
const createAdapter = (features: Array<GPUFeatureName> = []): GPUAdapter => {
const device = createDevice();
return {
features: new Set(features),
info: {},
limits,
requestDevice: vi.fn().mockResolvedValue(device),
} as unknown as GPUAdapter;
};
const stubSecureWebGpu = (requestAdapter: GPU['requestAdapter']): void => {
vi.stubGlobal('window', { isSecureContext: true });
vi.stubGlobal('navigator', {
gpu: {
requestAdapter,
},
});
};
describe('initializeGpu', () => {
afterEach(() => {
vi.unstubAllGlobals();
});
it('starts with the least demanding compatibility adapter request', async () => {
const adapter = createAdapter();
const requestAdapter = vi.fn().mockResolvedValue(adapter);
stubSecureWebGpu(requestAdapter as GPU['requestAdapter']);
await initializeGpu();
expect(requestAdapter).toHaveBeenNthCalledWith(1, {
featureLevel: 'compatibility',
});
expect(requestAdapter).toHaveBeenCalledTimes(1);
expect(adapter.requestDevice).toHaveBeenCalled();
});
it('continues trying adapters if one request throws', async () => {
const adapter = createAdapter();
const requestAdapter = vi
.fn()
.mockRejectedValueOnce(new Error('adapter request failed'))
.mockResolvedValueOnce(adapter);
stubSecureWebGpu(requestAdapter as GPU['requestAdapter']);
await expect(initializeGpu()).resolves.toBeDefined();
expect(requestAdapter).toHaveBeenCalledTimes(2);
});
it('falls back through core and high-performance adapter requests', async () => {
const adapter = createAdapter();
const requestAdapter = vi
.fn()
.mockResolvedValueOnce(null)
.mockResolvedValueOnce(null)
.mockResolvedValueOnce(adapter);
stubSecureWebGpu(requestAdapter as GPU['requestAdapter']);
await initializeGpu();
expect(requestAdapter).toHaveBeenNthCalledWith(1, {
featureLevel: 'compatibility',
});
expect(requestAdapter).toHaveBeenNthCalledWith(2, undefined);
expect(requestAdapter).toHaveBeenNthCalledWith(3, {
featureLevel: 'compatibility',
powerPreference: 'high-performance',
});
expect(adapter.requestDevice).toHaveBeenCalled();
});
it('requests only the core feature when the adapter exposes optional features', async () => {
const adapter = createAdapter(['core-features-and-limits', 'timestamp-query']);
const requestAdapter = vi.fn().mockResolvedValue(adapter);
stubSecureWebGpu(requestAdapter as GPU['requestAdapter']);
await initializeGpu();
expect(adapter.requestDevice).toHaveBeenCalledWith({
requiredFeatures: ['core-features-and-limits'],
});
});
});