예제
저장소에는 실행할 수 있는 예제가 98개 있습니다. 지도용 패스와 ShaderToy 시절의 화면 공간 효과부터 컴퓨트 커널까지 다루며, 그 가운데 12개는 에뮬레이션 배정밀도를 씁니다. 예제 디렉터리에서 둘러볼 수 있습니다.
예제로 배우는 순서
각 단계는 Language Guide의 한 개념을 실제 shader 작성으로 연결합니다.
- 1. 첫 shader
"use typeshade" 파일의 기본 형태와 shader entry를 먼저 익힙니다.
Quick start → - 2. 값과 타입
TypeScript의 type/class가 GPU value layout으로 어떻게 내려가는지 봅니다.
Types → - 3. 계산을 함수로
helper function과 stage entry를 조합해 실제 shader 계산을 구성합니다.
Functions → - 4. GPU 데이터
vector, matrix, array와 host-owned resource를 연결합니다.
Resources → - 5. 실제 예제
저장소의 예제를 읽으며 여러 개념을 하나의 shader로 조합합니다.
Source examples →
TypeShade MNIST 학습
실제 MNIST 데이터에서 순전파, 손실, 기울기와 SGD 업데이트를 TypeShade로 계산한 실험입니다.
MNIST 학습 실험 살펴보기 →TypeScript 소스로 쓴 예제
예제는 모두 "use typeshade"로 시작하는 TypeScript 파일이고, compile()이 파일의 바이트를 그대로 읽어 컴파일한다. 파일마다 언어의 한 부분을 보여 주므로 이 페이지에서도 언어 기능별로 분류한다. 이 가운데 73개는 GLSL ES 3.00 형태가 있고, 나머지는 WGSL만 생성합니다. 페이지가 그릴 수 있는 예제에는 그림이 붙습니다.
지도
-
음영 기복도 음영 기복. -
fp64 딥 줌 에뮬레이션 배정밀도(f32 두 개로 만든 df64). -
fp64 체커 평면 월드 평면 위의 1단위 체커보드. -
fp64 쌍곡선 항법 LORAN 방식의 해도 격자. -
fp64 중심 기준 좌표 행성 규모 엔진이 시점 기준으로 렌더링하는 이유.
화면 공간
-
플라스마 사인파를 여러 개 더해 만든 고전 플라스마에 RGB 팔레트로 색을 입혔습니다. -
보로노이 움직이는 셀룰러 노이즈. -
줄리아 집합 탈출 시간으로 그리는 줄리아 프랙탈. -
만델브로 집합 탈출 시간을 매끄럽게 이어 칠한 만델브로 집합. -
도메인 워핑 fbm 출력을 다시 fbm에 넣습니다. -
터널 데모신 시절의 터널. -
바다 수평선 원리부터 계산해 그린 바다 풍경. -
별밭 텍스처 없이 그린 밤하늘. -
만화경 극좌표로 접는 거울 반사. -
fp64 줄리아 집합 같은 배정밀도 기법을 줄리아 집합으로 보인 예제. -
fp64 버닝 십 버닝 십 프랙탈입니다. 제곱하기 전에 |Re z|, |Im z|로 접고, 바늘처럼 뾰족한 부분을 확대합니다. -
fp64 뉴턴 프랙탈 z³ = 1을 푸는 뉴턴 방법입니다. 색은 그 픽셀이 어느 세제곱근으로 수렴하는지 나타냅니다. -
fp64 거리 추정 거리 추정(d = ½·|z|·ln|z|/|dz|)으로 만델브로 경계를 그립니다. 정밀도는 식 중간에서 나눕니다. -
fp64 오래 켜 둔 시계 오래 켜 두면 생기는 애니메이션 버그. -
fp64 파국적 상쇄 수치해석 교과서의 그 그래프를 GPU로 그립니다. -
fp64 사인 스윕 큰 기준값에 화면에서 조금씩 움직이는 값을 더한 x로 sin(x)를 구합니다. -
그레이디언트 패스 섞는 비율을 조절할 수 있는 세로 방향 두 색 그러데이션.
스테이지와 IO 구조체
-
헬로 삼각형 가장 작은 완전한 TypeShade 프로그램입니다. -
헬로 varying 삼각형을 다시 그리되, 이번에는 버텍스 스테이지에서 프래그먼트 스테이지로 uvvarying을 넘깁니다. 두 스테이지가VsOut클래스 하나를 함께 씁니다. - 그림 없음: 이 예제는 페이지가 그릴 수 있는 것이 아닙니다. 헬로 버텍스 속성
vertex_index대신 버퍼에서 버텍스 입력을 받습니다. -
위치만 돌려주는 버텍스 가장 작은 렌더 쌍입니다. -
같은 IO 구조체 둘 필드가 똑같은 IO 구조체 둘, 곧 버텍스 출력과 프래그먼트 입력입니다. 객체 리터럴이 어느 쪽을 만드는지는 리터럴이 놓인 세 자리가 각각 정합니다. -
정수 varying과 고를 수 없는 보간 WGSL 방식의 진입점 입출력입니다. - 그림 없음: 이 예제는 페이지가 그릴 수 있는 것이 아닙니다. 사용자 클립 평면WGSL 전용
@builtin("clip_distances")로 사용자 클립 평면 네 개를 둡니다. 래스터라이저가 래스터화하기 전에 읽는 버텍스 출력입니다.
리소스
- 그림 없음: 이 예제는 페이지가 그릴 수 있는 것이 아닙니다. 헬로 유니폼WGSL 전용
declare const scale: uniform<f32>한 줄뿐입니다. -
헬로 유니폼 블록 GLSL ES 3.00 형태가 있는 쪽의 유니폼입니다. - 그림 없음: 이 예제는 페이지가 그릴 수 있는 것이 아닙니다. 헬로 카메라 유니폼WGSL 전용
mat4와vec3를 담은Camera클래스를uniform<Camera>뒤에 두고, 평범한 헬퍼 함수가 읽습니다. - 그림 없음: 이 예제는 페이지가 그릴 수 있는 것이 아닙니다. 텍스처, 샘플러, 오버라이드 전체 화면 삼각형이
sampler를 거쳐texture_2d<f32>를 샘플링하고,override<f32>특수화 상수 두 개로 색을 입힙니다. - 그림 없음: 이 예제는 페이지가 그릴 수 있는 것이 아닙니다. 런타임 배열 길이WGSL 전용 런타임 크기 스토리지 배열을 도는 커널이라면 반드시 필요한 경계 검사입니다.
- 그림 없음: 이 예제는 페이지가 그릴 수 있는 것이 아닙니다. 스토리지 텍스처WGSL 전용 컴퓨트 진입점이 텍셀 좌표로 직접 쓰는 이미지입니다. 샘플러도 필터링도 없습니다.
- 그림 없음: 이 예제는 페이지가 그릴 수 있는 것이 아닙니다. 비교로 읽는 그림자 맵
sampler_comparison을 거쳐 깊이 텍스처를textureSampleCompare와textureSampleCompareLevel로 읽습니다. 평범한 2D 그림자 맵과 캐스케이드 배열 양쪽에서 씁니다. - 그림 없음: 이 예제는 페이지가 그릴 수 있는 것이 아닙니다. 큐브와 3D 텍스처, 바이어스와 그레이디언트 환경 맵은 방향으로 찾는
texture_cube<f32>, 컬러 그레이딩 표는 셰이딩한 색으로 색인하는texture_3d<f32>이입니다.textureSampleBias와textureSampleGrad를 쓰고, 점광원의 그림자는 광원에서 나가는 방향으로 비교하는texture_depth_cube이입니다. - 그림 없음: 이 예제는 페이지가 그릴 수 있는 것이 아닙니다. WGSL에만 있는 텍스처WGSL 전용 색상 램프는
texture_1d<f32>, 환경 맵 둘은 레이어로 고르는texture_cube_array<f32>이입니다.textureGatherCompare로 퍼센티지 클로저 필터를 손으로 짜고,textureGather로 텍셀 네 개에서 채널 하나를 모으며, 점광원의 그림자는texture_depth_cube_array이입니다. - 그림 없음: 이 예제는 페이지가 그릴 수 있는 것이 아닙니다. 직접 리졸브하는 멀티샘플 텍스처WGSL 전용 MSAA 렌더 타깃을
texture_multisampled_2d<f32>로 두고textureLoad(t, coords, sampleIndex)로 샘플을 하나씩 읽어textureNumSamples만큼 평균을 구합니다. 깊이 어태치먼트는texture_depth_multisampled_2d이입니다. -
목록을 담은 유니폼 array<f32, 4>를 담은uniform이입니다. - 그림 없음: 이 예제는 페이지가 그릴 수 있는 것이 아닙니다. 분기 안의 샘플링과 그것을 허용하는 지시어 WGSL은
textureSample을 균일한 제어 흐름에서만 부르게 합니다.
값과 제어 흐름
-
모듈 상수 컴파일러가 허용하는 모든 스칼라 타입으로 모듈 범위 상수를 하나씩 선언합니다. -
모듈의 벡터 상수와 배열 상수 전체 화면 삼각형을 모듈 범위의 array<vec4, 3>팔레트와array<f32, 3>구간값으로 띠 지어 칠하고, 앞서 선언한 스칼라 상수로 만든vec3상수도 함께 씁니다. -
배열 리터럴 전체 화면 삼각형의 꼭짓점은 array<f32, 3>목록 두 개에서 오고, 색은array<i32, 3>으로 가중한array<vec3, 3>구간값에서 옵니다. -
변환하는 생성자 전체 화면 삼각형의 꼭짓점은 vec2(vec2u(...))에서 오고, 색은f32에서u32로 갔다가 다시f32로 돌아오는 왕복에서 옵니다. -
mat4 너머의 행렬 matCxR는 모두 타입입니다. -
에뮬레이션 배정밀도 소스로 쓴 f64인터페이스입니다. -
비트 필드 띠 전체 화면 삼각형의 색을 switch로 고릅니다. 띠 번호는&=,|=,<<=,>>=,^=로 만들고,let x: f32는 값을 넣기 전에 먼저 선언하며, varying은{ pos, uv }축약형으로 돌려줍니다. -
블록 스코프 i를 도는 반복문 둘이 이어지고, 반복문 본문의p옆에if분기의p가 있으며, 안쪽p가 바깥쪽을 가립니다. -
구조체와 배열을 고르는 조건식 분기 둘은 구조체, 다른 둘은 고정 길이 배열이고, 실행 중에 고릅니다. -
컷아웃 (소스 언어) 프래그먼트 진입점이 부르는 헬퍼 안에서 discard를 씁니다.fwidth가 테두리를 부드럽게 하고,saturate,exp2,**가 감쇠 곡선을 만듭니다. -
매개변수 기본값 매개변수에 기본값을 둔 헬퍼 셋입니다. 호출마다 생략하는 인자가 다릅니다. -
되돌려 쓰는 매개변수: @inout과 @out 호출한 쪽의 변수를 바꾸는 함수들입니다. 아직 값이 없는 지역 변수에 결과를 쓰는 함수도 있습니다. -
내장 함수 한 바퀴 reflect,refract,faceForward가 범프에 빛을 주고,transpose와determinant가 호스트 행렬을 읽으며, 비트 내장 함수(firstLeadingBit,reverseBits,countOneBits,extractBits,insertBits)가 화면에 띠를 만듭니다. 띠가 시작하는 자리는fwidthCoarse가 표시합니다. -
불 벡터 벡터 둘을 비교하면 결과는 불 벡터입니다. -
정수 abs와 dot 레지스트리가 이식 가능하다고 했지만 실제로는 그렇지 않았던 내장 함수 둘입니다. -
패킹, bitcast, 생성자 WGSL에는 있지만 이 언어에 없던 이식 가능한 내장 함수들입니다. - 그림 없음: 이 예제는 페이지가 그릴 수 있는 것이 아닙니다. 패킹된 4x8 정수 내장 함수WGSL 전용
u32하나를 바이트 네 개로 읽거나 네 개를 다시 써 넣는 내장 함수 여덟 개입니다. -
주변 변수를 읽고 쓰는 로컬 함수 ring은 TypeScript 클로저처럼 프래그먼트 진입점의p와width를 읽고 그glow에 더합니다. -
함수를 받는 함수 cover와around4는 거리 필드를 함수f: Field로 받고, 제네릭 함수가 타입 인자 조합마다 한 번 컴파일되듯 호출이 넘기는 함수마다 한 번씩 컴파일된다(규칙 8.18). -
본문이 정하는 반환 타입 반환 타입을 적은 함수가 하나도 없고, TypeScript가 추론하듯 저마다 본문이 돌려주는 것을 돌려준다(규칙 8.19). -
배열의 메서드 array<Light, 3>에 든 조명 세 개를 TypeScript 작성자가 먼저 떠올리는 배열 메서드로 비춥니다. 호출마다 배열 타입과 넘긴 함수에 맞춘 카운트 루프가 만들어진다(규칙 8.18, 언어 문서 §63). -
데이터를 도는 루프 데이터를 다루는 프로그램이 쓰는 세 가지 루프를 Tint와 실제 WebGL2 컨텍스트로 확인합니다. -
경로 추적기 평범한 TypeScript로 쓴 작은 경로 추적기입니다.
클래스와 제네릭
-
나메크의 캡슐 코퍼레이션 우주선 드래곤볼 Z의 캡슐 코퍼레이션 우주선을 나메크에 놓은 장면입니다. 우주선, 착륙 장치, 나무, 지형, 글자, 재질, 셀 셰이딩과 카메라를 공유 SDF 장면을 중심으로 TypeShade 클래스로 구성합니다. -
클래스 메서드 생성자와 메서드 하나, 정적 함수 하나를 둔 class Ray, 그리고hit(ray)메서드가 광선을 따라간 거리를 돌려주는class Sphere이입니다. -
자기 객체를 바꾸는 메서드 class Body의step,turn,advance가this에 값을 넣으므로, 각 메서드는 자기 객체를 참조로 받습니다. - 그림 없음: 이 예제는 페이지가 그릴 수 있는 것이 아닙니다. 객체를 바꾸는 메서드들WGSL 전용
class Particle의step,bounce,tick이this에 값을 넣고, 스토리지 요소 위에서 호출됩니다. -
상속 구체 메서드 하나와 추상 메서드 하나를 둔 abstract class Shape, 이를 상속한 클래스 둘, 그리고 그 하위 클래스를 다시 상속해super를 부르는 클래스 하나입니다. -
믹스인 패턴 본문이 return class extends Base { ... }하나뿐인function Tinted(Base)를 서로 다른 도형 클래스 둘에 적용합니다. -
단형화로 만드는 제네릭 제네릭 헬퍼 셋입니다. 파일이 부를 때 쓴 인자 타입 조합마다 한 번씩 컴파일됩니다. -
단형화로 만드는 제네릭 클래스 f32와 vec3에 쓴 class Slot<T>이다. 모듈에는Slot_f32와Slot_vec3가 서로 다른 구조체로 들어가고, 저마다 생성자와 모든 메서드의 복사본을 따로 갖습니다. -
튜플과 브랜드 별칭 튜플은 타입이 길이를 정해 둔 목록이고 array<T, N>이 바로 그것이므로,[f32, f32]는 곧array<f32, 2>이입니다. -
게터, 세터, 비공개 이름, 매개변수 프로퍼티 TypeScript 클래스를 쓰는 방식 그대로 작성한 class Ring이입니다. -
자기 객체를 바꾸고 값을 돌려주는 메서드 next()가 생성기의 상태를 앞으로 옮기고 뽑은 값을 돌려주는class Rng입니다. -
빌더 체인, 접근자의 super, 서브클래스가 물려받는 정적 멤버 모든 return이return this인 메서드는 자기 객체를 돌려주므로a.at(p).tinted(c)는 호출을 차례로a에서 실행하고,new Disc().at(p).sized(r)는new가 만든 값을 임시 변수에 담는다(규칙 8.10). -
객체 안의 객체, 객체를 담은 const, 함수를 담은 필드, 계약으로서의 인터페이스 ring.advance(dt)는 자신이 담은Mover의step을 불러 고리를 옮깁니다. 그래서step이 어느 클래스의 것이든advance는 자기 객체를 바꾸고 참조로 받는다(규칙 8.10). -
클래스 기반 3D SDF 레이 트레이서 추상 SDF 도형 클래스와 상속으로 만든 3D 레이 트레이서입니다. 구체, 상자, 토러스, 평면을 구면 추적으로 렌더링합니다.
가져오기
여러 패스
모듈 상태와 컴퓨트
-
인보케이션별 상태 최상위의 평범한 let seed: u32는 WGSL의var<private>이입니다. 인보케이션마다 복사본이 하나씩 있고, 그 인보케이션의 모든 함수가 함께 씁니다. - 그림 없음: 이 예제는 페이지가 그릴 수 있는 것이 아닙니다. 워크그룹 스크래치 메모리WGSL 전용
let tile: workgroup<array<f32, 64>>는 WGSL의var<workgroup>이입니다. 워크그룹마다 복사본이 하나씩 있어 그 안의 인보케이션들이 함께 쓰며, 여기서는 인보케이션이 한 칸씩 차지하는 스크래치로 씁니다. 원자적 값의 워크그룹 배열과 인보케이션별 카운터도 함께 둡니다. - 그림 없음: 이 예제는 페이지가 그릴 수 있는 것이 아닙니다. 워크그룹 리덕션WGSL 전용 인보케이션 64개가 값 64개를 워크그룹 메모리로 하나에 모읍니다.
workgroupBarrier()가 라운드 순서를 잡습니다. - 그림 없음: 이 예제는 페이지가 그릴 수 있는 것이 아닙니다. 원자적 히스토그램WGSL 전용 여러 인보케이션이
atomicAdd(bins[bin], 1)로 같은 칸에 동시에 값을 더합니다. 한 번의 호출은 쪼갤 수 없는 한 걸음이고, 스토리지 구조체의 필드와storage<atomic<u32>>선언이 위치를 적는 나머지 두 가지 모양을 보여 주며, 원자 연산이 돌려주는 값은 더하기 전에 들어 있던 값입니다. - 그림 없음: 이 예제는 페이지가 그릴 수 있는 것이 아닙니다. GPU에서 온 콘솔 출력WGSL 전용 컴퓨트 커널 안에서
console.log("i =", gid.x, p)를 부릅니다. 문자열 리터럴은 라벨이 되고, 크기가 정해진 값은 무엇이든 인자로 넘길 수 있습니다. - 그림 없음: 이 예제는 페이지가 그릴 수 있는 것이 아닙니다. 비교 후 교환, 유니폼 로드, 텍스처 배리어WGSL 전용 WGSL에는 있지만 이 언어에 없던 동기화 내장 함수 세 개입니다.
- 그림 없음: 이 예제는 페이지가 그릴 수 있는 것이 아닙니다. 컴퓨트 리덕션WGSL 전용 @workgroup_size가 붙은 컴퓨트 커널이입니다. 입력 스토리지 버퍼의 한 구간을 reduce()로 접어 출력 원소 하나로 만듭니다.
- 그림 없음: 이 예제는 페이지가 그릴 수 있는 것이 아닙니다. 이차원 워크그룹WGSL 전용
@compute([8, 8])는 WGSL의@workgroup_size(8, 8)이입니다. - 그림 없음: 이 예제는 페이지가 그릴 수 있는 것이 아닙니다. 입력 크기에 맞춘 워크그룹WGSL 전용
override<u32>하나가 컴퓨트 진입점의 워크그룹 크기와 공유 스크래치 배열의 바깥쪽 길이를 정합니다.
커널이 되는 루프
- 그림 없음: 이 예제는 페이지가 그릴 수 있는 것이 아닙니다. 커널로 도는 루프WGSL 전용 로드맵에 나오는 지형 예제입니다.
- 그림 없음: 이 예제는 페이지가 그릴 수 있는 것이 아닙니다. 루프 안의 리덕션WGSL 전용 배열을 도는 루프로 합, 평균과 분산, 히스토그램을 구합니다.
- 그림 없음: 이 예제는 페이지가 그릴 수 있는 것이 아닙니다. 구조체 배열을 도는 루프WGSL 전용 파티클 한 걸음을
array<Particle>을 도는 루프로 씁니다. - 그림 없음: 이 예제는 페이지가 그릴 수 있는 것이 아닙니다. CPU에서 도는 루프WGSL 전용 반복이 서로 독립인지 보는 증명이 거부하는 루프를 규칙마다(R1부터 R6까지) 하나씩 둡니다.
- 그림 없음: 이 예제는 페이지가 그릴 수 있는 것이 아닙니다. 커널 함수 안의 배열 메서드WGSL 전용
sumOfSquares,scale,firstAbove는 TypeScript 개발자가 먼저 쓰는Array.prototype의 메서드로 배열을 줄이고, 쓰고, 찾는다(변경 0079). - 그림 없음: 이 예제는 페이지가 그릴 수 있는 것이 아닙니다. push로 덧붙이는 커널WGSL 전용
strong은 문턱값보다 큰 원소의 인덱스를out.push(i)로 덧붙인다(변경 0078). - 그림 없음: 이 예제는 페이지가 그릴 수 있는 것이 아닙니다. Set에 고유한 라벨을 모으는 커널WGSL 전용
labels는 영이 아닌 픽셀의 라벨을seen.add(...)로Set<u32>에 넣고(변경 0080),latest는 키마다 마지막에 넣은 값을Map<u32, f32>에 둡니다. - 그림 없음: 이 예제는 페이지가 그릴 수 있는 것이 아닙니다. 이미지를 쓰는 커널WGSL 전용
invert는texture_2d<f32>를 읽고texture_storage_2d에 저장하므로 커널 함수이다(규칙 8.22, 변경 0077).
호스트 예제
예제마다 파일이 두 개입니다. 하나는 "use typeshade" 모듈이고, 다른 하나는 애플리케이션이 쓰는 방식 그대로 그 모듈을 실행하는 host.ts이입니다. 호스트는 Vite 플러그인으로 모듈을 가져와 모듈이 내보내는 것을 부릅니다. 페이지마다 두 파일과, 호스트가 실행되는 tier를 보여 줍니다.
- 모듈과 그 모듈을 실행하는 호스트, 두 파일입니다. 캔버스에 그리기 전체 화면
@fragment진입점과 이를 그리는 호스트입니다. - 모듈과 그 모듈을 실행하는 호스트, 두 파일입니다. 컴퓨트 진입점 디스패치
@compute진입점과 호스트입니다. - 모듈과 그 모듈을 실행하는 호스트, 두 파일입니다. 커널 함수 호출 커널 함수 두 개와 이를 부르는 호스트입니다.
- 모듈과 그 모듈을 실행하는 호스트, 두 파일입니다. 데이터를 GPU에 두기 커널 함수 세 개와, 이를
resident()배열 위에서 이어 부르는 호스트입니다. - 모듈과 그 모듈을 실행하는 호스트, 두 파일입니다. CPU와 GPU가 함께 쓰는 헬퍼 프래그먼트 진입점이 GPU에서 그리고 호스트가 CPU에서 부르는 지형 함수
height입니다. - 모듈과 그 모듈을 실행하는 호스트, 두 파일입니다. 문자열 키와 Record 채널 이름은 u32 id가 되고 Record는 id 순서의 배열이 된다(변경 0081).
- 모듈과 그 모듈을 실행하는 호스트, 두 파일입니다. 컴파일된 프로그램 실행 버텍스 진입점과 프래그먼트 진입점, 그리고 엔진처럼 이를 실행하는 호스트입니다.
- 모듈과 그 모듈을 실행하는 호스트, 두 파일입니다. 커널 호출 체인 합치기 커널 함수 다섯 개와,
typeshade/fuse의fuse()안에서 이를 부르는 호스트입니다. - 모듈과 그 모듈을 실행하는 호스트, 두 파일입니다. Set과 Map에 모으기 JavaScript의
Set과Map을 받는 커널 함수 네 개와, 이를 부르는 호스트이다(변경 0080).
이 빌드 이후에 추가된 예제
컴파일러에는 있지만 이 사이트 빌드에는 아직 없는 예제입니다. 각 페이지는 컴파일러의 main 브랜치가 게시한 예제 데이터로 채웁니다.
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는 이 선택 함수를 제공합니다.