예제
이 페이지에서

예제

저장소에는 실행할 수 있는 예제가 98개 있습니다. 지도용 패스와 ShaderToy 시절의 화면 공간 효과부터 컴퓨트 커널까지 다루며, 그 가운데 12개는 에뮬레이션 배정밀도를 씁니다. 예제 디렉터리에서 둘러볼 수 있습니다.

예제로 배우는 순서

각 단계는 Language Guide의 한 개념을 실제 shader 작성으로 연결합니다.

  1. 1. 첫 shader

    "use typeshade" 파일의 기본 형태와 shader entry를 먼저 익힙니다.

    Quick start →
  2. 2. 값과 타입

    TypeScript의 type/class가 GPU value layout으로 어떻게 내려가는지 봅니다.

    Types →
  3. 3. 계산을 함수로

    helper function과 stage entry를 조합해 실제 shader 계산을 구성합니다.

    Functions →
  4. 4. GPU 데이터

    vector, matrix, array와 host-owned resource를 연결합니다.

    Resources →
  5. 5. 실제 예제

    저장소의 예제를 읽으며 여러 개념을 하나의 shader로 조합합니다.

    Source examples →

TypeShade MNIST 학습

실제 MNIST 데이터에서 순전파, 손실, 기울기와 SGD 업데이트를 TypeShade로 계산한 실험입니다.

MNIST 학습 실험 살펴보기 →

TypeScript 소스로 쓴 예제

예제는 모두 "use typeshade"로 시작하는 TypeScript 파일이고, compile()이 파일의 바이트를 그대로 읽어 컴파일한다. 파일마다 언어의 한 부분을 보여 주므로 이 페이지에서도 언어 기능별로 분류한다. 이 가운데 73개는 GLSL ES 3.00 형태가 있고, 나머지는 WGSL만 생성합니다. 페이지가 그릴 수 있는 예제에는 그림이 붙습니다.

지도

화면 공간

스테이지와 IO 구조체

리소스

값과 제어 흐름

클래스와 제네릭

가져오기

여러 패스

모듈 상태와 컴퓨트

커널이 되는 루프

호스트 예제

예제마다 파일이 두 개입니다. 하나는 "use typeshade" 모듈이고, 다른 하나는 애플리케이션이 쓰는 방식 그대로 그 모듈을 실행하는 host.ts이입니다. 호스트는 Vite 플러그인으로 모듈을 가져와 모듈이 내보내는 것을 부릅니다. 페이지마다 두 파일과, 호스트가 실행되는 tier를 보여 줍니다.

gradient 패스의 GLSL ES 3.00 출력

gradient 패스 gradient-twin.shade.ts는 프래그먼트 단계로 이 GLSL ES 3.00 main을 낸다.

void main() {
float t = (uv.y + u.mix_bias);
vec3 rgb = mix(u.bottom.rgb, u.top.rgb, t);
_ret = vec4(rgb, 1.0);
}

모듈 전체는 WGSL로 30줄이고, GLSL은 버텍스 단계 17줄, 프래그먼트 단계 17줄이다. 유니폼 타입, 바이트 오프셋, 바인드 그룹 항목, 진입점 시그니처는 reflect()에서 나온다. reflect()는 같은 중간 표현을 읽지만 출력 경로에는 관여하지 않으므로, 호스트는 그 레이아웃대로 유니폼 버퍼를 채우면 된다. 검증 페이지에는 유니폼 블록의 복원된 레이아웃이 잘못 쓴 필드의 진단과 나란히 있다.

에뮬레이션 배정밀도

WGSL에도 GLSL ES 3.00에도 배정밀도 부동소수점은 없다. TypeShade는 f32 값 두 개를 합치지 않고 나란히 든 쌍으로 이를 에뮬레이션하고, 산술, 비교, 일부 내장 함수를 그 쌍에 대한 호출로 바꿔 낸다. 그 범위 밖의 연산은 출력할 때 코드가 붙은 오류로 실패한다. 쓰는 코드는 그대로이고 선언한 타입만 다르다. deep-zoom 예제에서 origin 필드는 소스에서 f64로 선언되고 유니폼 블록에서는 vec2<f32> 자리를 차지하며, 호스트가 그 자리를 분리한 쌍으로 채운다.

f64 산술을 하는 모듈에는 가드 텍스처 바인딩도 주입되는데, 호스트는 이 텍스처를 흰색 텍셀 하나로 채워야 합니다. GPU 드라이버의 셰이더 컴파일러는 텍셀 읽기를 미리 계산해 버릴 수 없는데, 그 읽기가 없으면 오차 보정 항을 마음대로 최적화해 없앨 수 있기 때문입니다. 연산마다 f32의 몇 배가 들므로 이 타입은 값 하나하나에 대해 골라서 씁니다. 예제는 fp64-deep-zoom-twin.shade.ts입니다.

이 가드는 에뮬레이션의 'float' 플레이버에 속합니다. Apple GPU에는 'integer' 플레이버가 필요합니다. 이 플레이버는 같은 오차 항을 정수 연산으로 계산하고, 가드를 바인딩하지 않습니다. 기본값은 실제 디바이스나 컨텍스트에서 자동으로 선택하며, 사용 가능한 경우 사용자 에이전트 정보도 참고합니다. Apple이나 Metal 신호가 있으면 'integer'를, CPU이거나 GPU 신호를 알 수 없으면 'float'를 선택합니다. 신호를 알 수 없을 때의 선택이 확장 정밀도를 보장하지는 않습니다. createDevice({ fp64Flavor })나 configure({ fp64Flavor })로 선택을 재정의할 수 있습니다. recommendFp64Flavor는 이 선택 함수를 제공합니다.

TypeScript로 쓰고 TypeShade가 컴파일한 fp64 deep zoom (source twin) 셰이더. 빌드할 때 렌더링함.
같은 월드 좌표를 두 번 그렸습니다. 왼쪽은 f32, 오른쪽은 f64 (emulated)이입니다. f32 쪽은 줄무늬가 계단처럼 나오는데, 이 거리에서는 f32의 ulp 하나가 줄무늬에 필요한 소수 부분보다 거칠기 때문입니다. 다른 쪽은 매끄럽게 나옵니다.

이 페이지 편집 문제 보고