in src/common/util/navigator_gpu.ts [67:168]
export function getGPU(recorder: TestCaseRecorder | null): GPU {
if (impl) {
return impl;
}
impl = gpuProvider();
if (globalTestConfig.enforceDefaultLimits) {
// eslint-disable-next-line @typescript-eslint/unbound-method
const origRequestAdapterFn = impl.requestAdapter;
// eslint-disable-next-line @typescript-eslint/unbound-method
const origRequestDeviceFn = GPUAdapter.prototype.requestDevice;
impl.requestAdapter = async function (options?: GPURequestAdapterOptions) {
if (!s_defaultLimits) {
const tempAdapter = await origRequestAdapterFn.call(this, {
...defaultRequestAdapterOptions,
...options,
});
// eslint-disable-next-line no-restricted-syntax
const tempDevice = await tempAdapter?.requestDevice();
s_defaultLimits = copyLimits(tempDevice!.limits);
tempDevice?.destroy();
}
const adapter = await origRequestAdapterFn.call(this, {
...defaultRequestAdapterOptions,
...options,
});
if (adapter) {
const limits = Object.fromEntries(
Object.entries(s_defaultLimits).map(([key, v]) => [key, v])
);
Object.defineProperty(adapter, 'limits', {
get() {
return limits;
},
});
}
return adapter;
};
const enforceDefaultLimits = (adapter: GPUAdapter, desc: GPUDeviceDescriptor | undefined) => {
if (desc?.requiredLimits) {
for (const [key, value] of Object.entries(desc.requiredLimits)) {
const limit = s_defaultLimits![key];
if (limit !== undefined && value !== undefined) {
const [beyondLimit, condition] = key.startsWith('max')
? [value > limit, 'greater']
: [value < limit, 'less'];
if (beyondLimit) {
throw new DOMException(
`requestedLimit ${value} for ${key} is ${condition} than adapter limit ${limit}`,
'OperationError'
);
}
}
}
}
};
GPUAdapter.prototype.requestDevice = async function (
this: GPUAdapter,
desc?: GPUDeviceDescriptor | undefined
) {
// We need to enforce the default limits because even though we patched the adapter to
// show defaults for adapter.limits, there are tests that test we throw when we request more than the max.
// In other words.
//
// adapter.requestDevice({ requiredLimits: {
// maxXXX: addapter.limits.maxXXX + 1, // should throw
// });
//
// But unless we enforce this manually, it won't actual through if the adapter's
// true limits are higher than we patched above.
enforceDefaultLimits(this, desc);
return await origRequestDeviceFn.call(this, desc);
};
}
if (defaultRequestAdapterOptions) {
// eslint-disable-next-line @typescript-eslint/unbound-method
const oldFn = impl.requestAdapter;
impl.requestAdapter = function (
options?: GPURequestAdapterOptions
): Promise<GPUAdapter | null> {
const promise = oldFn.call(this, { ...defaultRequestAdapterOptions, ...options });
if (recorder) {
void promise.then(adapter => {
if (adapter) {
const adapterInfo = adapter.info;
const infoString = `Adapter: ${adapterInfo.vendor} / ${adapterInfo.architecture} / ${adapterInfo.device}`;
recorder.debug(new ErrorWithExtra(infoString, () => ({ adapterInfo })));
}
});
}
return promise;
};
}
return impl;
}