TL;DR

  • wgsl-rs가 Rust 코드를 WGSL로 변환하는 0.1.0-beta를 출시했으며, Rust와 WGSL 사이의 차이를 체계적으로 처리하고 런타임 wgpu 코드 생성을 지원함.
  • 베타 개발의 주요 작업은 런타임 IR 기반 wgpu 코드 생성, Rust와 WGSL의 불일치 수정, WGSL 어휘 지원·버그 수정·문서화를 통한 출시 준비임.
  • 연산자 우선순위 차이로 인한 오컴파일을 막기 위해 이항식을 모두 괄호로 감싸고, 벡터 비교를 all(...) 기반으로 변환하며, 정수 리터럴의 타입 추론을 위한 패스를 추가함.
  • 런타임 IR 순회로 제네릭 템플릿 모듈에서 wgpu 파이프라인을 만들 수 있으며, 호출 그래프를 분석해 바인딩의 셰이더 단계 가시성을 결정함.
  • wgsl-rs에는 게임 개발자와 gpui-ce 프로젝트가 사용자로 참여하고 있으며, 다음 단계는 crabslab·craballoc 이식과 GPU 기반 ECS 및 Renderling 셰이더·링크 구조 개편임.

`wgsl-rs` 베타 출시 회고

  • wgsl-rs를 출시함. 이번 베타 릴리스에는 상당한 작업이 들어갔으며, 지금까지 진행한 프로젝트 가운데 가장 체계적으로 구성된 프로젝트라고 평가함.
  • 프로젝트 개요는 GitHub 저장소와 이전 글인 *Introducing wgsl-rs*에서 확인할 수 있음.

개인적인 변화

  • 시간제 개발자로 혼자 진행하기에는 wgsl-rs의 작업 규모가 지나치게 컸음.
  • 9월 초 본업을 잃은 뒤 프로젝트에 평소보다 더 많은 시간을 쓸 수 있었음. 다만 실제로 시간이 무한했던 것은 아님.

주요 성과

  • *Introducing wgsl-rs* 이후 4개월 동안의 주요 작업은 세 가지임.
  • wgpu 코드 생성을 런타임 중간 표현(IR) 기반으로 전환함.
  • Rust와 WGSL이 조용히 서로 다르게 동작하는 모든 부분을 체계적으로 찾아 해결함.
  • WGSL 어휘 지원 범위를 확인하고 버그를 수정하며 문서를 갖춰 0.1.0-beta를 출시함.
  • 기술 독자에게 흥미로울 만한 개발 기록의 주요 내용을 정리함.

가장 흥미로운 기술 변경 5가지

  • 연산자 우선순위 역전(#159, 9월 20일)
  • Rust에서는 &, ^, |, <<, >>가 ==보다 우선순위가 높지만 WGSL에서는 그 반대임.
  • 렌더러가 이항식을 평평하게 출력해 Rust의 (0 & 0) == 0이 WGSL에서 0 & 0 == 0이 됐고, 이는 0 & (0 == 0)으로 다시 파싱돼 조용한 타입 오류성 오컴파일을 일으킴. 같은 종류의 문제로 -(a + b)가 -a + b로 바뀌기도 함.
  • 우선순위를 고려하는 렌더러보다 정확성을 우선해 모든 이항식을 완전히 괄호로 감싸도록 수정함.
  • 벡터 동등성 비교는 마스크를 반환함(#164, 9월 15일)
  • Rust의 ==는 bool을 반환하지만 WGSL의 ==는 vecN을 반환함.
  • Rust 코드에서는 요소별 마스크를 직접 만들 수 없으므로, 단형화 이후 패스에서 벡터 ==를 all(lhs == rhs)로, !=를 !(all(...))로 재작성함.
  • 요소별 비교를 위한 우회 방법으로 cmp_eq와 cmp_ne 자유 함수를 추가함. 타입을 추론할 수 없는 경우 패스가 변환하지 않고 넘어가므로 CPU 전용 코드의 컴파일은 유지됨.
  • 리터럴 접미사 패스(#145, 9월 21~26일)
  • Rust는 문맥에 따라 0을 u32로 추론하지만 WGSL은 접미사 없는 정수 리터럴을 i32로 처리함. 따라서 Rust에서 컴파일되는 select(0, 1, data)가 naga 검증에서 실패함.
  • GLM 5.2와 함께 스코프를 추적하는 ‘앵커링 패스’를 구축해 디섀도잉 슬롯에 배치함. 이 위치에서는 소스 코드, 상수 치환, 타입 치환, 확장 기능 하위 변환에서 오는 네 가지 리터럴 출처를 모두 확인함.
  • Copilot과 Kimi K3를 활용한 일곱 차례 검토 뒤, 모든 경우를 명시적으로 처리하고 기본 분기(catch-all)가 없는 하향식이 아닌 상향식 infer(expr) -> Option 추론으로 통합함.
  • 루프 변수 타입 추론은 제약 조건 해결기 대신 ‘탐색(probe)’을 사용하는 방식으로 rustc의 역방향 추론을 모방함.
  • IR에서 런타임 wgpu 연결 생성(6월 6일, #120 및 7월 11·18일)
  • syn 트리를 순회하던 절차적 매크로 생성 wgpu 코드 약 650줄을 런타임 IR 순회로 대체함.
  • 이에 따라 제네릭 ‘템플릿’ 모듈에서 런타임에 path::to::module::instantiate::()를 호출해 실제 wgpu 파이프라인을 생성할 수 있음.
  • 버퍼 크기 계산은 size_of::() 대신 WGSL §14.4.1을 따름. size_of::()는 repr(C)가 아닌 구조체에서 올바르지 않았음.
  • API 역할은 wgsl_rs::Source가 ‘명세’, ir::Module이 ‘AST’이며, 순환 의존성을 방지하기 위해 메서드는 확장 트레이트에 배치함. wgsl-rs-ir가 wgsl-rs에 의존할 수 없기 때문임.
  • 호출 그래프 기반 바인딩 단계 가시성(7월 18일, 이후 #177 및 9월 20일)
  • 분석기가 ShaderStages::all()을 하드코딩해 VERTEX_WRITABLE_STORAGE를 불필요하게 요구했고, 모든 read_write 컴퓨트 디스패치가 깨지는 문제가 있었음.
  • 엔트리 포인트별 식별자 스캔을 먼저 적용한 뒤, 보조 함수에서만 사용되는 바인딩도 올바르게 처리하도록 전체 전이 호출 그래프 도달성 분석으로 발전시킴.
  • 모듈 전체 스캔은 필요하지 않은 기능까지 사용자에게 요구하는 지나치게 넓은 가시성을 만들기 때문에 채택하지 않음.

사용자

  • 베타 출시를 서두른 이유 가운데 하나는 이미 프로젝트 사용자가 있었기 때문임. 연락을 준 두 사용자 중 한 명은 Jak Kos(jakkos-net on GitHub)임.

안녕하세요, 정말 멋진 프로젝트네요. 지난 며칠 동안 제 게임 개발 프로젝트의 WGSL 셰이더를 옮기며 즐겁게 작업했어요. 감사합니다 :D!

— jakkos-net

  • Jak은 스토리지 텍스처 지원 누락 등 초기 구현의 여러 공백을 찾아냈으며, 게임을 wgsl-rs로 포팅하는 동안 발견한 버그의 이슈를 등록해 도움을 줌.
  • Jak에게 감사를 전함.

`gpui-ce`

  • 또 다른 반가운 소식은 gpui-ce 프로젝트가 셰이더 계층에 wgsl-rs를 사용한다는 점임.
  • gpui-ce는 Zed 편집기의 gpui 크레이트를 커뮤니티가 포크한 프로젝트임.
  • 웹 DOM에서 영감을 얻은 즉시 모드 렌더링 API를 제공함. 다만 그 방식은 단순한 즉시 모드 렌더링보다 더 세밀함.
  • 현재 별 1.2k개를 받은 규모 있고 인상적인 프로젝트에 통합된 점을 영광으로 여김.
  • 프로젝트 유지관리자인 Miles Wirht가 연락해 저장소의 셰이더를 보여줬지만, 소개 이메일이 스팸 폴더로 분류돼 이 소식을 거의 놓칠 뻔함.
  • Miles에게 감사를 전함.

그 밖의 사용자

  • wgsl-rs를 사용 중이며 소개를 원한다면 연락을 요청함.

마무리와 다음 계획

  • 다음으로 Rust-GPU에서 crabslab과 craballoc을 wgsl-rs로 포팅할 계획임.
  • 그 뒤 GPU에서 실행되는 ECS를 작성하고, 전체 스택을 사용해 Renderling의 셰이더와 연결 구조를 다시 작성할 계획임.
  • 읽어준 독자에게 감사를 전함.