검증 방식
푸시마다 도는 검사
저장소의 CI는 푸시와 풀 리퀘스트마다 CI 워크플로에서 다음을 실행합니다.
- 같은 모듈을 f64 산술로 도는 CPU 함수로도 컴파일합니다. 이것이 기준값을 내는 오라클입니다. 기본 모드에서는 동등 비교만 먼저 f32로 반올림해 GPU와 맞추고, 연산마다 반올림하는 f32 모드는 따로 켭니다. 테스트는 이 함수를 알려진 답과 맞춰 보고, 생성된 JavaScript라는 두 번째 CPU 백엔드와도 맞춰 봅니다. 둘은 비트 단위로 같아야 합니다. 드라이버의 반올림에 대해서는 아무것도 말해 주지 않고, 이 저장소에서 GPU 출력을 여기에 맞춰 보지는 않습니다. src/core/oracle.ts
- 컴파일 게이트는 등록된 예제를 전부 출력합니다. WGSL은 헤드리스 Chromium 안의 Tint에 넘기고, 렌더링 가능한 예제의 GLSL ES 3.00 두 단계는 실제 WebGL2 컨텍스트에서 컴파일하고 링크합니다. 컴파일될 수 없는 셰이더도 각 컴파일러에 하나씩 넘깁니다. 어느 쪽이든 그것을 받아들이면 게이트는 실패하고, 예제에 대한 판정은 무효가 됩니다. scripts/compile-gate.ts
- 골든 파일에는 모든 예제의 출력 바이트가 들어 있어서, 백엔드가 조금이라도 바뀌면 리뷰에서 diff로 드러납니다. emit-goldens.test.ts
두 백엔드에서 같은 패스
첫 페이지의 gradient 패스를 백엔드마다 한 번씩 그렸습니다. 두 백엔드의 픽셀 비교는 아직 커밋되어 있지 않습니다.
코드를 쓰는 동안
유니폼 블록은 한 번 선언하고, 필드를 읽는 곳마다 그 선언에 맞춰 타입 검사를 받습니다. 하나만 잘못 써도 문자열이 GPU에 닿기 전에 편집기에서 TypeScript가 알려 줍니다.
const U = uniformStruct('Uniforms', { group: 0, binding: 0, as: 'U' }, { time: f32T, top: vec4fT, bottom: vec4fT,})
const fsGradient = fn('fs_gradient', { vo: VsOut }, (p) => { const t = p.vo.uv.y.add(U.field.time.mul(0.05)) return vec4(mix(U.field.bottom.rgb, U.field.colour.rgb, t), f32(1))}, { stage: 'fragment', retAttr: '@location(0)' })오류 TS2339, 7행 47열: Property 'colour' does not exist on type '{ readonly time: ReadonlyNode<"f32">; readonly top: ReadonlyNode<"vec4<f32>">; readonly bottom: ReadonlyNode<"vec4<f32>">; }'.
| 필드 | 타입 | 오프셋 | 크기 |
|---|---|---|---|
| time | f32 | 0 | 4 |
| top | vec4<f32> | 16 | 16 |
| bottom | vec4<f32> | 32 | 16 |