WebGL/WebGPU feature detection 체크리스트
브라우저 이름으로 renderer를 고르면 금방 깨집니다. 실제 API가 있는지, context/device를 만들 수 있는지, 필요한 capability가 있는지 확인해야 합니다.
capability report를 만드는 코드
브라우저 이름 대신 실제 만들 수 있는 renderer와 제한을 report로 남깁니다.
async function detectGpuCapabilities(canvas) {
const report = {
webgpu: false,
webgl2: false,
maxTextureSize: 0,
renderer: "none"
};
if ("gpu" in navigator) {
const adapter = await navigator.gpu.requestAdapter();
if (adapter) {
report.webgpu = true;
report.webgpuLimits = Object.fromEntries(Object.entries(adapter.limits));
}
}
const gl = canvas.getContext("webgl2");
if (gl) {
report.webgl2 = true;
report.maxTextureSize = gl.getParameter(gl.MAX_TEXTURE_SIZE);
}
report.renderer = report.webgpu ? "webgpu" : report.webgl2 ? "webgl2" : "canvas";
return report;
}
detection 흐름
const hasWebGPU = "gpu" in navigator;
const gl = canvas.getContext("webgl2");
const hasWebGL2 = !!gl;
WebGPU는 navigator.gpu가 있어도 adapter/device 요청이 실패할 수 있습니다.
capability를 UI와 로그에 남긴다
async function bootEditor(canvas) {
const capability = await detectGpuCapabilities(canvas);
const renderer = await createRendererForCapability(canvas, capability);
window.__EDITOR_GPU_CAPABILITY__ = capability;
renderCapabilityBadge(document.querySelector("[data-gpu-badge]"), capability);
return { renderer, capability };
}
function renderCapabilityBadge(root, capability) {
root.textContent = [
`renderer=${capability.renderer}`,
`webgpu=${capability.webgpu}`,
`webgl2=${capability.webgl2}`,
`maxTexture=${capability.maxTextureSize}`
].join(" ");
}
실패한 renderer 선택은 숨기지 않는 편이 좋습니다. 사용자가 보고하는 버그에도 capability report가 같이 남아야 원인 추적이 가능합니다.
오늘의 핵심
renderer 선택은 feature detection과 capability report로 결정합니다. 실패도 정상 경로로 설계해야 합니다.