콘텐츠로 이동

결정론

alpha2의 약속은 모든 대상 환경이 같은 렌더링 코드를 실행하므로 하나의 프로젝트가 어디서나 똑같이 렌더링된다는 것입니다. 이 페이지에서는 무엇이 완전히 같고, 무엇이 가까울 뿐이며, 무엇이 엔진 밖에 있는지 정확히 설명합니다. 다 읽고 나면 브라우저 프리뷰와 서버 export를 비교할 때 무엇을 믿어도 되는지 알 수 있습니다.

다음은 구조상 모든 대상 환경에서 성립합니다.

  • 시간이 정확합니다. 시간은 정수 틱이고 프레임 그리드도 정수로 계산하므로, 모든 호스트가 한 프로젝트에 대해 같은 프레임 시각과 같은 소스 시각을 고릅니다. 시간과 틱을 참고하세요.
  • 문서를 같은 방식으로 읽습니다. 모든 대상 환경이 엔진 자체의 모델 코드로 프로젝트를 불러오므로, 한 환경이 받아들인 문서는 다른 환경도 같은 의미로 받아들입니다. (TypeScript의 validateProject는 이 검사를 그대로 따라 하므로 불러오기 전에 미리 실행할 수 있습니다.)
  • 렌더링 코드가 같습니다. 브라우저, 네이티브 호스트, Rust 크레이트가 같은 엔진을, 같은 내장 이펙트와 트랜지션으로 실행합니다.

테스트가 비트 단위로 확인하는 것

섹션 제목: “테스트가 비트 단위로 확인하는 것”
보장 확인하는 곳
CPU 렌더러는 네이티브, Node.js 위의 WebAssembly, 패키지된 브라우저 바인딩에서 같은 바이트를 그리며, 어떤 머신에서든 스레드 수와 상관없이 같습니다. scripts/test-render-determinism.mjs, 해시는 tests/render_determinism에 고정
오디오 믹스는 네이티브와 WebAssembly에서 비트 단위로 같습니다. scripts/test-audio-determinism.mjs, 해시는 tests/audio_determinism에 고정
같은 폰트라면 텍스트는 WebAssembly와 네이티브에서 같은 픽셀로 래스터화됩니다. scripts/test-wasm-parity.mjs
alpha2-host는 CLI, serve, Python 클라이언트 중 어디서 실행하든, 디코딩 동시성을 높여도 같은 바이트를 씁니다. scripts/test-host-cli-parity.mjs

레이아웃 측정(브라우저의 measureLayout, 네이티브의 measure_layout)도 비트 단위까지 같은 답을 냅니다.

브라우저에서는 WebEffectRegistry.createCpu로 이 CPU 렌더러를 쓸 수 있으며, 네이티브 CPU 렌더러와 정확히 같은 그림을 그립니다. 네이티브 호스트에서는 --renderer cpu(또는 renderer: "cpu")를 씁니다.

GPU 출력은 디바이스마다 조금씩 다릅니다. FMA(fused multiply-add) 축약, fract, 서브텍셀 반올림이 GPU마다 달라서 가장자리에서 최대 7코드까지 차이가 납니다. 디바이스 간 테스트는 4코드까지의 차이를 허용하며, 소수의 고립된 샘플에는 8코드까지 허용합니다. 저장소에는 백엔드별 기준 이미지(Direct3D 12, Metal, GL, lavapipe 등)가 따로 있습니다. 패키지된 브라우저 엔진도 같은 방식으로 네이티브 호스트와 비교합니다. I420 코드 차이는 최대 4, 평균 오차는 최대 0.5입니다.

CPU 렌더러와 GPU는 가깝지만 같지는 않습니다. CPU 렌더러는 GPU와 같은 렌더 그래프를 패스 단위로 그리며, 패리티 테스트가 CPU의 모든 패스를 허용 오차 범주 안에서 GPU의 패스와 비교합니다.

따라서 머신 간에 바이트 단위로 같은 프레임이 필요하다면 CPU 렌더러로 렌더링하세요. GPU로 렌더링한다면, 보기에는 같지만 몇 코드 차이가 나는 프레임을 예상하세요.

폰트. 엔진은 호스트가 등록한 폰트로만, 등록한 순서대로 텍스트를 그립니다. 같은 폰트 파일은 같은 픽셀을 냅니다. 폰트가 다르거나 폴백 순서가 다르면 텍스트가 달라질 수 있습니다. 브라우저와 네이티브 호스트에 같은 파일을 주세요.

디코더. 엔진은 받은 프레임으로 렌더링합니다. 브라우저에서는 앱이(예: WebCodecs로), 네이티브에서는 FFmpeg가, Rust에서는 여러분의 프로그램이 디코딩합니다. 렌더링은 주어진 프레임에 대해 결정론적이지만, 디코더가 무엇을 내놓는지는 디코더에 달려 있습니다.

인코더. 렌더링된 프레임은 결정론적이지만 인코딩된 파일은 인코더에 달려 있습니다. 하드웨어 인코더와 브라우저의 WebCodecs는 엔진의 보장 범위 밖입니다. alpha2-host가 불러올 수 있는 OpenH264 인코더는 슬라이스와 스레드 수를 프레임 높이만으로 정하므로, 어떤 머신에서든 같은 바이트를 export합니다.

런타임 WGSL 이펙트. 런타임에 등록한 이펙트는 GPU에서만 실행되므로 GPU 간 차이의 영향을 받고, 비교할 CPU 렌더러 출력도 없습니다.

같은 시각의 프리뷰와 export는 의도적으로 다를 수 있습니다. export는 프로젝트의 정확한 프레임 그리드에서 export 품질로 오프스크린 렌더링합니다. Rust 크레이트의 QualityProfile::preview()는 절반 해상도에 더 작은 필터 예산으로 렌더링하고, QualityProfile::export()는 전체 해상도로 렌더링합니다. export에 담길 내용을 확인하려면 스틸을 렌더링하세요. @alpha2-sh/node와 Python의 still은 그 시각에 export가 그리는 프레임을 PNG로 그립니다.