WebGPU 셰이딩 언어

W3C 후보 권고안 초안,

이 문서에 대한 자세한 정보
이 버전:
https://www.w3.org/TR/2026/CRD-WGSL-20260825/
최신 공개 버전:
https://www.w3.org/TR/WGSL/
편집자 초안:
https://gpuweb.github.io/gpuweb/wgsl/
이전 버전:
변경 이력:
https://www.w3.org/standards/history/WGSL/
피드백:
제목 줄을 “[WGSL] … 메시지 주제 …”로 하여 public-gpu@w3.org로 보내십시오(보관 자료)
GitHub
편집자:
(Google)
(Google)
이전 편집자:
(Apple Inc.)
(Google)
참여:
이슈 제출 (미해결 이슈)
테스트 스위트:
WebGPU CTS 셰이더/

초록

WebGPU용 셰이딩 언어.

이 문서의 상태

이 절에서는 이 문서가 발행된 시점의 상태를 설명한다. 현재 W3C 발행물 목록과 이 기술 보고서의 최신 개정판은 W3C 표준 및 초안 색인에서 확인할 수 있다.

이 명세에 대한 피드백과 의견을 환영한다. 이 명세에 관한 논의에는 GitHub 이슈를 사용하는 것이 권장된다. 또는 GPU for the Web 워킹 그룹의 메일링 리스트인 public-gpu@w3.org로 의견을 보낼 수 있다(보관 자료). 이 초안은 워킹 그룹에서 아직 논의해야 하는 일부 미결 이슈를 강조한다. 이러한 이슈의 유효성 여부를 포함하여 그 결과에 관해서는 어떠한 결정도 내려지지 않았다.

이 문서는 GPU for the Web 워킹 그룹권고안 트랙을 사용하여 후보 권고안 초안으로 발행했다. 이 문서는 적어도 까지 후보 권고안으로 유지된다.

그룹은 최신 GPU 시스템 API를 기반으로 배포된 브라우저 중 적어도 두 개에서 각 기능의 구현을 입증할 예정이다. 테스트 스위트는 구현 보고서를 작성하는 데 사용된다.

후보 권고안으로 발행되었다고 해서 W3C와 그 회원이 이를 승인한다는 의미는 아니다. 후보 권고안 초안에는 워킹 그룹이 후속 후보 권고안 스냅샷에 포함하려는 이전 후보 권고안의 변경 사항이 통합되어 있다.

이 문서는 언제든지 유지·업데이트된다. 이 문서의 일부는 작업 중이다.

이 문서는 W3C 특허 정책에 따라 운영되는 그룹에서 작성했다. W3C는 그룹의 산출물과 관련하여 이루어진 모든 특허 공개의 공개 목록을 유지한다. 해당 페이지에는 특허를 공개하는 방법도 포함되어 있다. 자신이 필수 청구항을 포함한다고 판단하는 특허를 실제로 알고 있는 개인은 W3C 특허 정책 제6절에 따라 해당 정보를 공개해야 한다.

이 문서에는 2025년 8월 18일 W3C 프로세스 문서가 적용된다.

1. 소개

WebGPU 셰이딩 언어(WGSL)는 [WebGPU]용 셰이더 언어이다. 즉, WebGPU API를 사용하는 애플리케이션은 WGSL을 사용하여 GPU에서 실행되는 셰이더라는 프로그램을 표현한다.

// 텍스처가 적용된 기하 도형을 점 광원으로 조명하는 프래그먼트 셰이더.

// 스토리지 버퍼 바인딩의 광원.
struct PointLight {
  position : vec3f,
  color : vec3f,
}

struct LightStorage {
  pointCount : u32,
  point : array<PointLight>,
}
@group(0) @binding(0) var<storage> lights : LightStorage;

// 텍스처 및 샘플러.
@group(1) @binding(0) var baseColorSampler : sampler;
@group(1) @binding(1) var baseColorTexture : texture_2d<f32>;

// 함수 인수는 버텍스 셰이더에서 가져온 값이다.
@fragment
fn fragmentMain(@location(0) worldPos : vec3f,
                @location(1) normal : vec3f,
                @location(2) uv : vec2f) -> @location(0) vec4f {
  // 텍스처에서 표면의 기본 색상을 샘플링한다.
  let baseColor = textureSample(baseColorTexture, baseColorSampler, uv);

  let N = normalize(normal);
  var surfaceColor = vec3f(0);

  // 장면의 점 광원을 순회한다.
  for (var i = 0u; i < lights.pointCount; i++) {
    let worldToLight = lights.point[i].position - worldPos;
    let dist = length(worldToLight);
    let dir = normalize(worldToLight);

    // 이 광원이 표면 색상에 기여하는 정도를 결정한다.
    let radiance = lights.point[i].color * (1 / pow(dist, 2));
    let nDotL = max(dot(N, dir), 0);

    // 광원의 기여도를 표면 색상에 누적한다.
    surfaceColor += baseColor.rgb * radiance * nDotL;
  }

  // 누적된 표면 색상을 반환한다.
  return vec4(surfaceColor, baseColor.a);
}

1.1. 개요

WebGPU는 GPU 명령의 형태로 작업 단위를 GPU에 전달한다. WGSL은 두 종류의 GPU 명령을 다룬다.

두 종류의 파이프라인 모두 WGSL로 작성된 셰이더를 사용한다.

셰이더는 파이프라인에서 셰이더 스테이지를 실행하는 WGSL 프로그램의 일부이다. 셰이더는 다음으로 구성된다.

참고: WGSL 프로그램에는 진입점이 필요하지 않다. 그러나 진입점은 GPUProgrammableStage를 생성하는 데 필요하므로 이러한 프로그램은 API에서 실행할 수 없다.

셰이더 스테이지를 실행할 때 구현은 다음을 수행한다.

WGSL 프로그램은 다음으로 구성된다.

참고: 현재 WGSL 프로그램은 하나의 WGSL 모듈로 구성된다.

WGSL은 명령형 언어이다. 동작은 실행할 문의 시퀀스로 지정된다. 문은 다음을 수행할 수 있다.

WGSL은 정적 유형 언어이다. 특정 표현식에서 계산되는 각 값은 프로그램 소스만 조사하여 결정되는 특정 유형에 속한다.

WGSL에는 불리언과 숫자 (정수부동 소수점)를 설명하는 유형이 있다. 이러한 유형은 복합 유형 (벡터, 행렬, 배열구조체)으로 집계할 수 있다. WGSL에는 고유한 연산을 제공하는 특수 유형(예: 원자적 유형)이 있다. WGSL은 메모리에 저장할 수 있는 유형을 메모리 뷰로 설명한다. WGSL은 일반적으로 사용되는 렌더링 유형을 텍스처 및 샘플러 형태로 제공한다. 이러한 유형에는 그래픽 렌더링용으로 일반적으로 제공되는 GPU 하드웨어의 기능을 노출하는 관련 내장 함수가 있다.

WGSL은 암시적 변환과 승격이 매우 제한적이다. 인수로 함수 호출에 전달되는 추상 유형 및 버퍼 포인터에서만 암시적 변환과 승격을 제공한다. 값을 하나의 구체적 숫자 또는 불리언 유형에서 다른 유형으로 변환하려면 명시적 변환, 값 생성자 또는 비트 재해석이 필요하다. 그러나 WGSL은 스칼라 유형을 벡터 유형으로 승격하는 제한적인 기능을 제공한다. 이는 복합 유형에도 적용된다.

셰이더 스테이지의 작업은 하나 이상의 호출로 분할되며, 각 호출은 약간 다른 조건에서 진입점을 실행한다. 셰이더 스테이지의 호출은 특정 변수에 대한 접근을 공유한다.

그러나 호출은 호출을 동료 호출과 구별하는 식별 값을 제공하는 내장 입력을 포함하여 서로 다른 셰이더 스테이지 입력 집합에 작용한다. 각 호출에는 비공개함수 주소 공간의 변수 형태로 자체적인 독립 메모리 공간이 있다.

셰이더 스테이지 내의 호출은 동시에 실행되며, 흔히 병렬로 실행될 수 있다. 셰이더 작성자는 셰이더 스테이지 호출의 동적 동작이 다음을 충족하도록 해야 한다.

WGSL은 특정 기능에 대해 가능한 여러 동작을 허용하는 경우가 있다. 서로 다른 구현이 서로 다른 동작을 나타낼 수 있으므로 이는 이식성 위험 요소이다. WGSL의 설계는 이러한 사례를 최소화하는 것을 목표로 하지만, 실현 가능성과 광범위한 장치에서 높은 성능을 달성하려는 목표에 의해 제약된다.

동작 요구 사항은 구현이 WGSL 프로그램을 처리하거나 실행할 때 수행하는 작업이다. 이는 프로그래머와의 계약에서 구현이 지는 의무를 설명한다. 명세는 이러한 의무가 명백하지 않을 수 있는 경우 이를 명시적으로 기술한다.

1.2. 구문 표기법

다음 구문 표기법은 WGSL 구문 문법의 규칙을 설명한다.

1.3. 수학 용어 및 표기법

각도:

쌍곡각은 전통적인 의미의 각도가 아니라 단위가 없는 넓이이다. 구체적으로는 다음과 같다.

그러면 넓이 axa의 쌍곡코사인이고 ya의 쌍곡사인인 쌍곡각이다.

양의 무한대는 +∞로 표기하며 모든 실수보다 엄격하게 큰 고유한 값이다.

음의 무한대는 −∞로 표기하며 모든 실수보다 엄격하게 작은 고유한 값이다.

확장 실수 (아핀 확장 실수라고도 함)는 실수에 +∞와 −∞를 합친 집합이다. 컴퓨터는 부동 소수점 유형을 사용하여 두 무한대의 값을 포함한 확장 실수를 근사적으로 표현한다. § 15.7 부동 소수점 평가를 참조한다.

구간은 하한과 상한이 있는 연속적인 숫자 집합이다. 문맥에 따라 정수, 부동 소수점 수, 실수 또는 확장 실수의 집합이다.

내림 표현식확장 실수 x에 대해 다음과 같이 정의된다.

올림 표현식확장 실수 x에 대해 다음과 같이 정의된다.

truncate 함수는 확장 실수 x에 대해 다음과 같이 정의된다.

roundUp 함수는 양의 정수 kn에 대해 다음과 같이 정의된다.

roundDown 함수는 양의 정수 kn에 대해 다음과 같이 정의된다.

cr행 행렬 A전치A의 행을 AT의 열로 복사하여 형성한 rc행 행렬 AT이다.

열 벡터의 전치는 열 벡터를 1행 행렬로 해석하여 정의한다. 마찬가지로 행 벡터의 전치는 행 벡터를 1열 행렬로 해석하여 정의한다.

2. WGSL 모듈

WGSL 프로그램은 하나의 WGSL 모듈로 구성된다.

모듈은 선택적인 지시문의 시퀀스와 그 뒤에 오는 모듈 범위 선언어설션으로 구성된다. 모듈은 다음으로 구성된다.

translation_unit :

global_directive * ( global_decl | global_assert | ';' ) *

global_decl :

global_variable_decl ';'

| global_value_decl ';'

| type_alias_decl ';'

| struct_decl

| function_decl

2.1. 셰이더 수명 주기

WGSL 프로그램 및 그 안에 포함될 수 있는 셰이더의 수명 주기에는 네 가지 주요 이벤트가 있다. 처음 두 이벤트는 WGSL 프로그램의 실행을 준비하는 데 사용되는 WebGPU API 메서드에 대응한다. 마지막 두 이벤트는 셰이더 실행의 시작과 종료이다.

이벤트는 다음과 같다.

  1. 셰이더 모듈 생성

    • 이는 WebGPU createShaderModule() 메서드가 호출될 때 발생한다. 이때 WGSL 프로그램의 소스 텍스트가 제공된다.

  2. 파이프라인 생성

    • 이는 WebGPU createComputePipeline() 메서드 또는 WebGPU createRenderPipeline() 메서드가 호출될 때 발생한다. 이 메서드는 다른 구성 정보와 함께 이전에 생성된 셰이더 모듈을 하나 이상 사용한다.

    • 파이프라인을 생성하는 동안에는 GPUProgrammableStage의 지정된 진입점에 대한 셰이더를 형성하는 코드만 고려한다. 즉, 진입점과 관련이 없는 코드는 컴파일 전에 사실상 제거된다.

    • 참고:셰이더 스테이지는 별도로 컴파일되는 것으로 간주되므로 모듈의 서로 다른 부분을 포함할 수 있다.

  3. 셰이더 실행 시작

  4. 셰이더 실행 종료

    • 이는 셰이더의 모든 작업이 완료될 때 발생한다.

      • 모든 호출이 종료되고,

      • 리소스에 대한 모든 접근이 완료되며,

      • 출력이 있는 경우 다운스트림 파이프라인 스테이지로 전달된다.

이벤트의 순서는 다음 이유로 정해진다.

2.2. 오류

WebGPU 구현은 다음 두 가지 이유로 셰이더를 처리하지 못할 수 있다.

셰이더 수명 주기의 세 단계에서 처리 오류가 발생할 수 있다.

참고: 예를 들어 데이터 경쟁은 감지하지 못할 수 있다.

각 요구 사항은 가능한 가장 이른 시점에 검사된다. 즉, 다음과 같다.

문맥에서 명확하지 않은 경우 이 명세는 특정 요구 사항을 충족하지 못하면 셰이더 생성 오류, 파이프라인 생성 오류 또는 동적 오류 중 어느 것이 발생하는지를 나타낸다.

오류의 결과는 다음과 같다.

2.3. 진단

구현은 셰이더 모듈 생성 또는 파이프라인 생성 중에 진단을 생성할 수 있다. 진단은 애플리케이션 작성자에게 도움을 주기 위해 구현이 생성하는 메시지이다.

트리거 규칙이라는 특정 조건이 충족되면 진단이 생성되거나 트리거된다. 소스 텍스트에서 조건이 충족되는 위치는 소스 텍스트 내의 점 또는 범위로 표현하며, 이를 트리거 위치라고 한다.

진단에는 다음 속성이 있다.

진단의 심각도는 다음 중 하나이며, 가장 높은 것부터 가장 낮은 것까지 나열되어 있다.

오류

진단이 오류이다. 이는 셰이더 생성 오류 또는 파이프라인 생성 오류에 해당한다.

경고

진단은 애플리케이션 개발자가 주의를 기울일 만하지만 오류는 아닌 이상 상태를 설명한다.

정보

진단은 애플리케이션 개발자가 주의를 기울일 만하지만 오류나 경고는 아닌 주목할 만한 조건을 설명한다.

꺼짐

진단이 비활성화된다. 애플리케이션에 전달되지 않는다.

트리거 규칙의 이름은 다음 중 하나이다.

diagnostic_rule_name :

diagnostic_name_token

| diagnostic_name_token '.' diagnostic_name_token

2.3.1. 진단 처리

트리거된 진단은 다음과 같이 처리된다.

  1. 각 진단 D에 대해 D의 트리거 위치를 포함하고 동일한 트리거 규칙을 가지면서 영향을 받는 범위가 가장 작은 진단 필터를 찾는다.

    • 이러한 필터가 존재하면 D에 적용하여 D심각도를 업데이트한다.

    • 그렇지 않으면 D는 변경되지 않는다.

  2. 심각도가 꺼짐인 진단을 폐기한다.

  3. 남아 있는 진단 중 하나 이상인 DI의 심각도가 정보이면 다음을 수행한다.

    • 트리거 규칙이 동일한 다른 정보 진단을 폐기하여 원래 진단 DI만 남겨도 된다.

  4. 남아 있는 진단 중 하나 이상인 DW의 심각도가 경고이면 다음을 수행한다.

    • 트리거 규칙이 동일한 다른 정보 또는 경고 진단을 폐기하여 원래 진단 DW만 남겨도 된다.

  5. 남아 있는 진단 중 하나 이상의 오류 심각도가 있으면 다음을 수행한다.

  6. 셰이더 모듈 생성 시점에 처리하는 경우 남아 있는 진단은 WebGPU GPUCompilationInfo 객체의 messages 멤버를 채운다.

  7. 파이프라인 생성 중에 처리하는 경우 오류 진단은 GPUProgrammableStage를 검증할 때 WebGPU 검증 실패를 발생시킨다.

참고: 이 규칙은 구현이 오류를 감지하는 즉시 WGSL 모듈 처리를 중단할 수 있도록 허용한다. 또한 특정 종류의 경고에 대한 분석은 첫 번째 경고에서 중단할 수 있으며, 특정 종류의 정보 진단에 대한 분석은 첫 번째 발생에서 중단할 수 있다. WGSL은 서로 다른 종류의 분석을 수행하는 순서나 단일 분석 내의 순서를 지정하지 않는다. 따라서 동일한 WGSL 모듈에 대해 서로 다른 구현이 동일한 심각도를 가진 서로 다른 진단 인스턴스를 보고할 수 있다.

2.3.2. 필터링 가능한 트리거 규칙

대부분의 진단은 무조건 WebGPU 애플리케이션에 보고된다. 일부 종류의 진단은 부분적으로 해당 트리거 규칙의 이름을 지정하여 필터링할 수 있다. 다음 표에는 필터링할 수 있는 표준 트리거 규칙 집합이 나열되어 있다.

필터링 가능한 진단 트리거 규칙
필터링 가능한 트리거 규칙 기본 심각도 트리거 위치 설명
derivative_uniformity 오류 도함수를 계산하는 내장 함수에 대한 호출 지점의 위치. 즉, 다음 중 하나에 대한 호출 위치이다. 내장 함수 호출이 도함수를 계산하지만 균일성 분석으로는 호출이 균일한 제어 흐름에서 발생함을 증명할 수 없다.

§ 15.2 균일성을 참조한다.

subgroup_uniformity 오류 서브그룹 또는 쿼드 내장 함수에 대한 호출 지점의 위치. 서브그룹 또는 쿼드 내장 함수 호출이지만 균일성 분석으로는 호출이 균일한 제어 흐름에서 발생함을 증명할 수 없다. 또한 균일성 분석으로 다음 매개변수 값이 균일함을 증명할 수 없는 경우이다.

§ 15.2 균일성을 참조한다.

단일 진단 이름 토큰으로 구성된 인식되지 않는 트리거 규칙을 사용하면 사용자 에이전트가 경고를 트리거해야 한다.

구현은 여기에 지정되지 않은 트리거 규칙을 지원할 수 있다. 단, 해당 규칙은 diagnostic_rule_name의 다중 토큰 형식을 사용하여 표기해야 한다. 다중 토큰 형식으로 표기된 인식되지 않는 트리거 규칙을 사용하면 그 자체로 진단을 트리거할 수도 있다.

이 명세의 향후 버전은 특정 규칙을 제거하거나 기본 심각도를 약화하면서 (즉, 현재 기본값을 심각도가 더 낮은 기본값으로 대체하면서도) 이전 버전과의 호환성을 충족하는 것으로 간주될 수 있다. 예를 들어 WGSL의 향후 버전은 derivative_uniformity의 기본 심각도를 error에서 warning 또는 info로 변경할 수 있다. 명세가 이와 같이 변경된 후에도 이전에 유효했던 프로그램은 계속 유효하다.

2.3.3. 진단 필터링

필터링 가능한 트리거 규칙을 가진 진단트리거되면 WGSL은 해당 진단을 폐기하거나 심각도를 수정하는 메커니즘을 제공한다.

진단 필터 DF에는 세 개의 매개변수가 있다.

진단 필터 DF(AR,NS,TR)를 진단 D에 적용하면 다음과 같은 효과가 있다.

범위 진단 필터영향 범위가 지정된 소스 텍스트 범위인 진단 필터이다. 범위 진단 필터는 다음 표에 지정된 대로 영향을 받는 소스 범위의 시작 부분에서 @diagnostic 특성으로 지정한다. @diagnostic 특성은 그 밖의 위치에 나타나서는 안 된다.

범위 진단 필터의 배치
배치 영향 범위
복합문시작. 복합문.
함수 선언시작. 함수 선언.
if 문의 시작. if 문: 모든 제어 조건 표현식을 포함한 if_clause와 연관된 모든 else_if_clauseelse_clause 절.
switch 문의 시작. switch 문: 선택자 표현식 및 switch_body.
switch_body시작. switch_body.
loop 문의 시작. loop 문.
while 문의 시작. while 문: 조건 표현식과 루프 본문 모두.
for 문의 시작. for 문: for_header 및 루프 본문.
loop, while 또는 for 루프의 루프 본문을 여는 중괄호 ('{') 바로 앞. 루프 본문.
continuing_compound_statement시작. continuing_compound_statement.

참고: 다음 항목도 복합문이다. 함수 본문, case 절, 독립 default 절, whilefor 루프의 본문, 그리고 if_clause, else_if_clauseelse_clause의 본문.

예제: 텍스처 샘플링의 범위 진단 필터
var<private> d: f32;
fn helper() -> vec4<f32> {
  // "if" 본문에서 derivative_uniformity 진단을
  // 비활성화한다.
  if (d < 0.5) @diagnostic(off,derivative_uniformity) {
    return textureSample(t,s,vec2(0,0));
  }
  return vec4(0.0);
}

전역 진단 필터를 사용하면 전체 WGSL 모듈에 진단 필터를 적용할 수 있다.

예제: 도함수 균일성을 위한 전역 진단 필터
diagnostic(off,derivative_uniformity);
var<private> d: f32;
fn helper() -> vec4<f32> {
  if (d < 0.5) {
    // 여기에서는 전역 진단 필터가
    // derivative_uniformity 진단을 비활성화한다.
    return textureSample(t,s,vec2(0,0));
  } else {
    // derivative_uniformity 진단의 심각도를 'warning'으로 설정한다.
    @diagnostic(warning,derivative_uniformity) {
      return textureSample(t,s,vec2(0,0));
    }
  }
  return vec4(0.0);
}

진단 필터 DF(AR1,NS1,TR1)과 DF(AR2,NS2,TR2)은 다음과 같은 경우 충돌한다.

진단 필터충돌해서는 안 된다.

참고: 여러 전역 진단 필터충돌하지 않는 경우 이를 허용한다.

WGSL의 진단 필터는 영향 범위가 완벽하게 중첩되도록 설계되었다. DF1의 영향 범위와 DF2의 영향 범위가 겹치는 경우 DF1의 영향 범위가 DF2의 영향 범위에 완전히 포함되거나 그 반대이다.

소스 위치 L 및 트리거 규칙 TR에 대한 가장 가까운 둘러싸는 진단 필터가 존재하는 경우 다음을 충족하는 진단 필터 DF(AR,NS,TR)이다.

영향 범위는 중첩되므로 가장 가까운 둘러싸는 진단은 다음과 같다.

2.4. 제한

WGSL 구현은 다음 제한을 충족하는 셰이더를 지원한다. WGSL 구현은 지정된 제한을 초과하는 셰이더를 지원할 수 있다.

참고: WGSL 구현이 지정된 제한을 초과하는 셰이더를 지원하지 않는다면 오류를 발생시켜야 한다.

정량화할 수 있는 셰이더 복잡도 제한
제한 지원되는 최솟값
구조체 유형의 최대 멤버 수 1023
복합 유형의 최대 중첩 깊이 15
함수에서 중괄호로 둘러싸인 문의 최대 중첩 깊이 127
함수의 최대 매개변수255
switch 문에서 case 선택자 값의 최대 수. 각 case 문에 있는 case 값 수의 합으로, default 절을 포함한다. 1023
단일 셰이더정적으로 접근하며 private 주소 공간에서 인스턴스화된 모든 변수의 최대 합산 바이트 크기 8192
단일 함수에서 선언되고 function 주소 공간에서 인스턴스화된 모든 변수의 최대 합산 바이트 크기 8192
단일 셰이더정적으로 접근하며 workgroup 주소 공간에서 인스턴스화된 모든 변수의 최대 합산 바이트 크기

이 제한의 목적상 override 값을 대입할 때 고정 풋프린트 배열은 생성 시 고정되는 풋프린트 배열로 취급한다.

이는 WebGPU의 maxComputeWorkgroupStorageSize 제한을 독립적인 WGSL 제한으로 매핑한다.

16384
즉시 데이터 변수의 최대 바이트 크기.

이는 WebGPU의 maxImmediateSize 제한을 독립적인 WGSL 제한으로 매핑한다.

64
배열 유형의 값 생성자 표현식에 있는 최대 요소 수 2047

3. 텍스트 구조

text/wgsl 미디어 유형은 콘텐츠를 WGSL 모듈로 식별하는 데 사용된다. 부록 A: text/wgsl 미디어 유형을 참조한다.

WGSL 모듈은 바이트 순서 표시(BOM) 없이 UTF-8 인코딩을 사용하는 유니코드 텍스트이다.

WGSL 모듈 텍스트는 다음을 형성하는 연속적인 비어 있지 않은 집합으로 그룹화된 유니코드 코드 포인트의 시퀀스로 구성된다.

프로그램 텍스트에는 null 코드 포인트(U+0000)가 포함되어서는 안 된다.

3.1. 구문 분석

WGSL 모듈을 구문 분석하려면 다음을 수행한다.

  1. 주석을 제거한다.

    • 첫 번째 주석을 공백 코드 포인트(U+0020)로 대체한다.

    • 주석이 남지 않을 때까지 반복한다.

  2. § 3.9 템플릿 목록알고리즘을 사용하여 템플릿 목록을 찾는다. 이 단계는 '<'(U+003C)와 '>'(U+003E) 코드 포인트가 템플릿 목록 구분 기호로 사용되는 경우와 비교 연산자 등에 사용되는 경우를 구분한다.

  3. 전체 텍스트를 구문 분석하여 translation_unit 문법 규칙과 일치하는지 확인한다. 구문 분석에서는 다음과 같이 사용자 지정된 LALR(1) 파서(하나의 선행 탐색 토큰)를 [DeRemer1969] 사용한다.

    • 토큰화는 구문 분석과 교차하여 수행되며 문맥을 인식한다. 파서가 다음 토큰을 요청할 때:

      • 공백 코드 포인트의 초기 시퀀스를 소비하고 무시한다.

      • 다음 코드 포인트가 템플릿 목록의 시작이면 이를 소비하고 _template_args_start를 반환한다.

      • 다음 코드 포인트가 템플릿 목록의 끝이면 이를 소비하고 _template_args_end를 반환한다.

      • 그렇지 않으면:

        • 토큰 후보는 아직 소비하지 않은 나머지 코드 포인트의 비어 있지 않은 접두사로 형성된 모든 WGSL 토큰이다.

        • 반환되는 토큰은 현재 파서 상태에서 유효한 선행 탐색 토큰이기도 한 가장 긴 토큰 후보이다. [VanWyk2007]

다음과 같은 경우 셰이더 생성 오류가 발생한다.

참고:위 절차에서는 템플릿 목록 탐색을 문법 기반 구문 분석(3단계) 전에 수행되는 별도의 단계(2단계)로 설명한다. 이러한 분리는 명세를 단순화한다. 그러나 토큰화 전에 별도의 처리 단계를 삽입하므로 위 절차를 일부 도구에 매핑하기에는 불편할 수 있다.

대안은 템플릿 목록 탐색과 토큰화를 교차하여 수행하는 것이다. 이 접근 방식에서는 템플릿 목록이 나타날 수 있는 문법 규칙의 모든 위치에 합성 토큰(_disambiguate_template)을 배치한다. 스캐너가 _disambiguate_template 토큰을 일치시키려고 할 때:

향후 토큰 스캐닝 단계에서는 기록된 템플릿 목록 구분 기호의 위치를 사용하여 지시된 대로 _template_args_start_template_args_end 토큰을 생성한다.

이 대안적 접근 방식은 비규범적이다. 규범적 문법에는 대안적 접근 방식을 사용하는 구현을 돕기 위한 _disambiguate_template 토큰이 포함된다. 표준 접근 방식을 사용하는 파서는 합성 토큰을 무시하거나, 이와 동등하게 항상 빈 문자열과 성공적으로 일치시킬 수 있다.

3.2. 공백 및 줄바꿈

공백은 유니코드 Pattern_White_Space 속성에 속하는 하나 이상의 코드 포인트를 임의로 조합한 것이다. 다음은 Pattern_White_Space에 속하는 코드 포인트 집합이다.

줄바꿈은 줄의 끝을 나타내는 공백 코드 포인트의 연속적인 시퀀스이다. 이는 UAX14 제6.1절 맞춤 설정할 수 없는 줄바꿈 규칙LB4LB5에 정의된 “필수 줄바꿈”을 나타내는 공백으로 정의된다. 즉, 줄바꿈은 다음 중 하나이다.

참고: 줄 번호로 소스 텍스트 위치를 보고하는 진단은 줄 수를 계산할 때 줄바꿈을 사용해야 한다.

3.3. 주석

주석토큰을 구분할 수 있다는 점을 제외하면 WGSL 프로그램의 유효성이나 의미에 영향을 주지 않는 텍스트 범위이다. 셰이더 작성자는 주석을 사용하여 프로그램을 문서화할 수 있다.

줄 끝 주석은 두 코드 포인트 //(U+002F 다음에 U+002F)와 그 뒤에 오는 코드 포인트로 구성된 주석의 한 종류이며, 다음은 포함하지 않고 그 직전까지 이어진다.

블록 주석은 다음으로 구성되는 주석의 한 종류이다.

참고: 블록 주석은 중첩할 수 있다. 블록 주석에는 서로 대응하는 시작 및 종료 텍스트 시퀀스가 필요하고 임의 중첩을 허용하므로 정규 표현식으로 블록 주석을 인식할 수 없다. 이는 정규 언어의 펌핑 보조정리에서 비롯된 결과이다.

예제: 주석
const f = 1.5; // 이것은 줄 끝 주석이다.
const g = 2.5; /* 이것은 여러 줄에
                걸쳐 있는 블록 주석이다.
                /* 블록 주석은 중첩할 수 있다.
                 */
                그러나 모든 블록 주석은 종료되어야 한다.
               */

3.4. 토큰

토큰은 다음 중 하나를 형성하는 연속적인 코드 포인트 시퀀스이다.

3.5. 리터럴

리터럴은 다음 중 하나이다.

literal :

int_literal

| float_literal

| bool_literal

3.5.1. 불리언 리터럴

예제: 불리언 리터럴
const a = true;
const b = false;
bool_literal :

'true'

| 'false'

3.5.2. 숫자 리터럴

숫자 리터럴의 형식은 패턴 일치를 통해 정의된다.

정수 리터럴은 다음과 같다.

참고: 다른 언어에서 선행 0이 8진수를 의미하는 표기법과 혼동하지 않도록 0이 아닌 정수 리터럴 앞에 0을 붙이는 것(예: 012)은 금지된다.

int_literal :

decimal_int_literal

| hex_int_literal

decimal_int_literal :

/0[iu]?/

| /[1-9][0-9]*[iu]?/

예제: 10진수 정수 리터럴
const a = 1u;
const b = 123;
const c = 0;
const d = 0i;
hex_int_literal :

/0[xX][0-9a-fA-F]+[iu]?/

예제: 16진수 정수 리터럴
const a = 0x123;
const b = 0X123u;
const c = 0x3f;

부동 소수점 리터럴10진수 부동 소수점 리터럴 또는 16진수 부동 소수점 리터럴이다.

float_literal :

decimal_float_literal

| hex_float_literal

부동 소수점 리터럴에는 분수를 나타내는 가수와 선택적인 지수라는 두 가지 논리적 부분이 있다. 대략적으로 리터럴의 값은 가수에 밑을 주어진 지수만큼 거듭제곱한 값을 곱한 것이다. 가수 숫자가 0이 아니거나 그 왼쪽과 오른쪽에 모두 0이 아닌 가수 숫자가 있으면 유효하다. 유효 숫자는 왼쪽에서 오른쪽으로 센다. N번째 유효 숫자의 왼쪽에는 N-1개의 유효 숫자가 있다.

10진수 부동 소수점 리터럴은 다음과 같다.

decimal_float_literal :

/0[fh]/

| /[1-9][0-9]*[fh]/

| /[0-9]*\.[0-9]+([eE][+-]?[0-9]+)?[fh]?/

| /[0-9]+\.[0-9]*([eE][+-]?[0-9]+)?[fh]?/

| /[0-9]+[eE][+-]?[0-9]+[fh]?/

예제: 10진수 부동 소수점 리터럴
const a = 0.e+4f;
const b = 01.;
const c = .01;
const d = 12.34;
const f = .0f;
const g = 0h;
const h = 1e-3;
10진수 부동 소수점 리터럴의 수학적 값은 다음과 같이 계산한다.

참고: 10진 가수는 20개의 10진수 숫자 이후에서 잘리며, 분수에서 약 log(10)/log(2)×20 ≈ 66.4개의 유효 비트를 보존한다.

16진수 부동 소수점 리터럴은 다음과 같다.

hex_float_literal :

/0[xX][0-9a-fA-F]*\.[0-9a-fA-F]+([pP][+-]?[0-9]+[fh]?)?/

| /0[xX][0-9a-fA-F]+\.[0-9a-fA-F]*([pP][+-]?[0-9]+[fh]?)?/

| /0[xX][0-9a-fA-F]+[pP][+-]?[0-9]+[fh]?/

예제: 16진수 부동 소수점 리터럴
const a = 0xa.fp+2;
const b = 0x1P+4f;
const c = 0X.3;
const d = 0x3p+2h;
const e = 0X1.fp-4;
const f = 0x3.2p+2h;
16진수 부동 소수점 리터럴의 수학적 값은 다음과 같이 계산한다.

참고: 16진 가수는 16개의 16진수 숫자 이후에서 잘리며, 분수에서 약 4 ×16 = 64개의 유효 비트를 보존한다.

숫자 리터럴에 접미사가 있으면 리터럴은 특정 구체적 스칼라 유형의 값을 나타낸다. 그렇지 않으면 리터럴은 아래에서 정의하는 추상 숫자 유형 중 하나의 값을 나타낸다. 어느 경우든 리터럴이 나타내는 값은 § 15.7.6 부동 소수점 변환의 규칙에 따라 대상 유형으로 변환한 후의 수학적 값이다.

숫자 리터럴을 유형에 매핑
숫자 리터럴 접미사 유형
정수 리터럴 i i32 42i
정수 리터럴 u u32 42u
정수 리터럴 AbstractInt 124
부동 소수점 리터럴 f f32 42f 1e5f 1.2f 0x1.0p10f
부동 소수점 리터럴 h f16 42h 1e5h 1.2h 0x1.0p10h
부동 소수점 리터럴 AbstractFloat 1e5 1.2 0x1.0p10

다음과 같은 경우 셰이더 생성 오류가 발생한다.

참고: 16진 부동 소수점 값 0x1.00000001p0을 정확하게 표현하려면 33개의 가수 비트가 필요하지만, f32에는 명시적 가수 비트가 23개뿐이다.

참고: f 접미사를 사용하여 16진 부동 소수점 리터럴을 해당 유형으로 강제하려면 리터럴에서 이진 지수도 사용해야 한다. 예를 들어 0x1p0f로 작성한다. 이와 달리 0x1f는 16진수 정수 리터럴이다.

3.6. 키워드

키워드는 미리 정의된 언어 개념을 참조하는 토큰이다. WGSL 키워드 목록은 § 16.1 키워드 요약을 참조한다.

3.7. 식별자

식별자는 이름으로 사용되는 토큰의 한 종류이다. § 5 선언 및 범위를 참조한다.

WGSL은 사용 사례를 구분하기 위해 두 개의 문법 비단말 기호를 사용한다.

ident :

ident_pattern_token _disambiguate_template

member_ident :

ident_pattern_token

식별자의 형식은 유니코드 버전 14.0.0유니코드 표준 부록 #31을 기반으로 하며 다음과 같이 보충된다.

식별자는 UAX31 문법을 기준으로 설명한 다음 프로파일을 사용한다.

<Identifier> := <Start> <Continue>* (<Medial> <Continue>+)*

<Start> := XID_Start + U+005F
<Continue> := <Start> + XID_Continue
<Medial> :=

이는 다음과 같이 ASCII가 아닌 코드 포인트를 가진 식별자도 유효하다는 뜻이다. Δέλτα, réflexion, Кызыл, 𐰓𐰏𐰇, 朝焼け, سلام, 검정, שָׁלוֹם, गुलाबी, փիրուզ.

단, 다음은 예외이다.

ident_pattern_token :

/([_\p{XID_Start}][\p{XID_Continue}]+)|([\p{XID_Start}])/u

유니코드 버전 14.0.0용 유니코드 문자 데이터베이스에는 XID_StartXID_Continue의 모든 유효한 코드 포인트를 포함하는 비규범적 목록이 있다.

참고: 일부 내장 함수반환 유형은 WGSL 소스에서 이름을 사용할 수 없는 구조체 유형이다. 이러한 구조체 유형은 밑줄 두 개로 시작하는 이름으로 미리 선언된 것처럼 설명된다. 결과 값은 유형 추론을 사용하여 새로 선언된 let 또는 var에 저장하거나 그 멤버 중 하나를 즉시 이름으로 추출할 수 있다. frexpmodf 설명에 있는 사용 예를 참조한다.

3.7.1. 식별자 비교

두 WGSL 식별자는 동일한 코드 포인트 시퀀스로 구성된 경우에만 동일하다.

참고: 이 명세는 비교를 목적으로 값에 유니코드 정규화를 적용하는 것을 허용하지 않는다. 시각적·의미적으로 동일하더라도 서로 다른 유니코드 문자 시퀀스를 사용하는 값은 일치하지 않는다. 콘텐츠 작성자는 값 선택 시 동일한 인코딩 시퀀스를 일관되게 사용하거나 잠재적으로 문제가 될 수 있는 문자를 피하는 것이 좋다. 자세한 내용은 [CHARMOD-NORM]을 참조한다.

참고: 식별자의 모든 인스턴스를 해당 식별자의 동형 이의어 중 하나로 대체했을 때 WGSL 모듈의 의미가 바뀐다면 사용자 에이전트는 개발자에게 표시되는 경고를 발생시켜야 한다. (동형 문자는 독자에게 다른 코드 포인트 시퀀스와 동일하게 보일 수 있는 코드 포인트 시퀀스이다. 동형 문자를 감지하기 위한 매핑의 예로는 이전 단락에서 언급한 변환, 매핑 및 일치 알고리즘이 있다. 식별자가 하위 시퀀스를 그 동형 문자로 반복해서 대체하여 한 시퀀스를 다른 시퀀스로 변환할 수 있으면 두 코드 포인트 시퀀스는 동형 이의어이다.)

3.8. 문맥 종속 이름

문맥 종속 이름은 특정 문법적 문맥에서만 개념의 이름을 지정하는 데 사용되는 토큰이다. 토큰의 철자는 식별자와 같을 수 있지만 선언된 객체로 해석되지는 않는다. 이 절에는 문맥 종속 이름으로 사용되는 토큰을 나열한다. 토큰은 키워드 또는 예약어여서는 안 된다.

3.8.1. 특성 이름

§ 12 특성을 참조한다.

특성 이름은 다음과 같다.

3.8.2. 내장 값 이름

내장 값 이름 토큰내장 값의 이름에 사용되는 토큰이다.

§ 13.3.1.1 내장 입력 및 출력을 참조한다.

builtin_value_name :

ident_pattern_token

내장 값의 이름은 다음과 같다.

3.8.3. 진단 규칙 이름

진단 이름 토큰은 진단 트리거 규칙의 이름에 사용되는 토큰이다.

§ 2.3 진단을 참조한다.

diagnostic_name_token :

ident_pattern_token

미리 정의된 진단 규칙 이름은 다음과 같다.

3.8.4. 진단 심각도 제어 이름

유효한 진단 필터 심각도 제어 이름은 § 2.3 진단에 나열되어 있지만 식별자와 형식이 같다.

severity_control_name :

ident_pattern_token

진단 필터 심각도 제어 이름은 다음과 같다.

3.8.5. 확장 이름

유효한 활성화 확장 이름은 § 4.1.1 확장 활성화에 나열되어 있지만 일반적으로 식별자와 형식이 같다.

enable_extension_name :

ident_pattern_token

활성화 확장 이름은 다음과 같다.

유효한 언어 확장 이름은 § 4.1.2 언어 확장에 나열되어 있지만 일반적으로 식별자와 형식이 같다.

language_extension_name :

ident_pattern_token

언어 확장 이름은 다음과 같다.

3.8.6. 보간 유형 이름

보간 유형 이름 토큰interpolate_type_name을 위한 보간 유형의 이름에 사용되는 토큰이다.

§ 13.3.1.4 보간을 참조한다.

보간 유형 이름은 다음과 같다.

3.8.7. 보간 샘플링 이름

보간 샘플링 이름 토큰보간 샘플링의 이름에 사용되는 토큰이다.

§ 13.3.1.4 보간을 참조한다.

interpolate_sampling_name :

ident_pattern_token

보간 샘플링 이름은 다음과 같다.

3.8.8. 스위즐 이름

스위즐 이름은 벡터 접근 표현식스위즐 뷰 표현식에 사용된다.

swizzle_name :

/[rgba]/

| /[rgba][rgba]/

| /[rgba][rgba][rgba]/

| /[rgba][rgba][rgba][rgba]/

| /[xyzw]/

| /[xyzw][xyzw]/

| /[xyzw][xyzw][xyzw]/

| /[xyzw][xyzw][xyzw][xyzw]/

3.8.9. 깊이 모드 이름

깊이 모드 이름 토큰fragment_depth 기능이 지원될 때 frag_depth 내장 값에 사용되는 토큰이다.

3.9. 템플릿 목록

템플릿 매개변수화는 일반 개념을 수정하는 매개변수를 지정하는 방법입니다. 템플릿 매개변수화를 작성하려면 일반 개념을 작성한 다음 템플릿 목록을 작성합니다.

주석공백을 무시할 때, 템플릿 목록은 다음과 같습니다.

템플릿 매개변수의 형식은 아래의 템플릿 목록 탐색 알고리즘에 의해 암묵적으로 정의됩니다. 일반적으로 이름, 식 또는 타입입니다.

참고: 예를 들어 vec3<f32>라는 구문은 vec3가 수정되는 일반 개념이고, <f32>가 하나의 매개변수인 f32 타입을 포함하는 템플릿 목록인 템플릿 매개변수화입니다. 이 둘을 합친 vec3<f32>는 특정 벡터 타입을 나타냅니다.

참고: 예를 들어 var<storage,read_write>라는 구문은 일반적인 var 개념을 템플릿 매개변수 storageread_write로 수정합니다.

참고:예를 들어 array<vec4<f32>>라는 구문에는 두 개의 템플릿 매개변수화가 있습니다.

템플릿 목록을 구분하는 '<'(U+003C) 및 '>'(U+003E) 코드 포인트는 다음을 표기할 때도 사용됩니다.

구문적 모호성은 템플릿 목록을 우선하는 방식으로 해결됩니다.

템플릿 목록 탐색 알고리즘은 아래와 같습니다. 이 알고리즘은 다음과 같은 가정과 속성을 사용합니다.

  1. 템플릿 매개변수이므로 '<'(U+003C) 또는 '='(U+003D) 코드 포인트로 시작하지 않습니다.

  2. 식에는 ';'(U+003B), '{'(U+007B) 또는 ':'(U+003A) 코드 포인트가 포함되지 않습니다.

  3. 식에는 대입이 포함되지 않습니다.

  4. '='(U+003D) 코드 포인트는 비교 연산의 일부일 때만 나타납니다. 즉, 다음 중 하나에만 나타납니다. '<=', '>=', '==' 또는 '!='. 그 외의 경우 '='(U+003D) 코드 포인트는 대입의 일부로 나타납니다.

  5. 템플릿 목록 구분자는 괄호 '(...)'와 배열 인덱싱 '[...]'으로 형성된 중첩 식을 따릅니다. 템플릿 목록의 시작과 끝은 동일한 중첩 수준에 나타나야 합니다.

알고리즘: 템플릿 목록 탐색

입력: 프로그램 소스 텍스트.

레코드 타입:

UnclosedCandidate를 다음을 포함하는 레코드 타입이라고 합니다.

TemplateList를 다음을 포함하는 레코드 타입이라고 합니다.

출력: DiscoveredTemplateLists, TemplateList 레코드의 목록.

절차:

참고:다음과 같이 알고리즘을 수정하여 템플릿 매개변수의 소스 범위를 찾을 수 있습니다.

참고: 일부 숫자 리터럴은 문자로 끝나므로 알고리즘은 리터럴을 명시적으로 건너뜁니다. 예를 들면 1.0f입니다. 끝의 fident_pattern_token의 시작으로 오인해서는 안 됩니다.

참고: A ( B < C, D > ( E ) )라는 구문에서 < C, D > 부분은 템플릿 목록입니다.

참고: 알고리즘은 식의 중첩을 따릅니다. 특정 템플릿 목록의 시작과 끝은 서로 다른 식 중첩 수준에 나타날 수 없습니다. 예를 들어 array<i32,select(2,3,a>b)>에서 템플릿 목록에는 세 개의 매개변수가 있으며 마지막 매개변수는 select(2,3,a>b)입니다. a>b'>'select 함수를 호출하는 식에서 괄호로 묶인 부분 안에 있으므로 템플릿 목록을 끝내지 않습니다.

참고: 템플릿 목록의 양 끝은 동일한 인덱싱 식 안에 나타나야 합니다. 예를 들어 a[b<d]>()에는 유효한 템플릿 목록이 없습니다.

참고: A<B<<C>라는 구문에서 B<<C라는 구문은 B, 왼쪽 시프트 연산자 '<<', C가 차례로 이어진 것으로 구문 분석됩니다. 템플릿 탐색 알고리즘은 B와 이어지는 '<'(U+003C)를 검사하기 시작하지만, 다음 '<'(U+003C) 코드 포인트가 템플릿 인수를 시작할 수 없다는 것을 확인하므로 B 바로 다음의 '<'는 템플릿 목록의 시작이 아닙니다. 처음의 '<'와 마지막 '>'만 템플릿 목록 구분자이며, 이 목록의 템플릿 매개변수는 B<<C입니다.

참고: A<B<=C>라는 구문도 이전 참고와 유사하게 분석되므로 B<=C라는 구문은 B, 이어지는 작거나 같음 연산자 '<=', 이어지는 C로 구문 분석됩니다. 템플릿 탐색 알고리즘은 B와 이어지는 '<'(U+003C)를 검사하기 시작하지만, 다음 '='(U+003D) 코드 포인트가 템플릿 인수를 시작할 수 없다는 것을 확인하므로 B 바로 다음의 '<'는 템플릿 목록의 시작이 아닙니다. 처음의 '<'와 마지막 '>'만 템플릿 목록 구분자이며, 이 목록의 템플릿 매개변수는 B<=C입니다.

참고: A<(B>=C)>라는 구문을 검사할 때 템플릿 목록은 하나이며, 첫 번째 '<'(U+003C) 코드 포인트에서 시작하고 마지막 '>'(U+003E) 코드 포인트에서 끝나며 템플릿 인수로 B>=C를 갖습니다. 첫 번째 '>'(U+003C) 코드 포인트(B 다음)를 검사한 후에는 '=' (U+003D) 코드 포인트를 대입의 일부로 가정하지 않도록 특별히 인식해야 합니다.

참고: A<(B!=C)>라는 구문을 검사할 때 템플릿 목록은 하나이며, 첫 번째 '<'(U+003C) 코드 포인트에서 시작하고 마지막 '>'(U+003E) 코드 포인트에서 끝나며 템플릿 인수로 B!=C를 갖습니다. '!'(U+0021) 코드 포인트('B' 다음)를 검사한 후에는 '=' (U+003D) 코드 포인트를 대입의 일부로 가정하지 않도록 특별히 인식해야 합니다.

참고: A<(B==C)>라는 구문을 검사할 때 템플릿 목록은 하나이며, 첫 번째 '<'(U+003C) 코드 포인트에서 시작하고 마지막 '>'(U+003E) 코드 포인트에서 끝나며 템플릿 인수로 B==C를 갖습니다. 첫 번째 '='(U+003D) 코드 포인트('B' 다음)를 검사한 후에는 두 번째 '='(U+003D) 코드 포인트를 특별히 인식하여 둘 중 어느 것도 대입의 일부로 가정하지 않도록 해야 합니다.

템플릿 목록 탐색이 완료되면, 구문 분석반드시 각 템플릿 목록을 template_list 문법 규칙에 일치시키려고 시도합니다.

template_list :

_template_args_start template_arg_comma_list _template_args_end

template_arg_comma_list :

template_arg_expression ( ',' template_arg_expression ) * ',' ?

template_arg_expression :

expression

4. 지시문

지시문은 WebGPU 구현이 WGSL 프로그램을 처리하는 방식을 수정하는 토큰 시퀀스입니다.

지시문은 선택 사항입니다. 지시문이 있는 경우 모든 지시문은 모든 선언 또는 const 단언보다 앞에 나타나야 합니다.

global_directive :

diagnostic_directive

| enable_directive

| requires_directive

4.1. 확장

WGSL은 시간이 지남에 따라 발전할 것으로 예상됩니다.

확장은 WGSL 명세에 대한 일관된 수정 집합을 명명하여 묶은 것으로, 다음 항목을 조합하여 구성됩니다.

가정적으로 확장은 다음을 수행할 수 있습니다.

확장에는 활성화 확장언어 확장이라는 두 종류가 있습니다.

4.1.1. 활성화 확장

활성화 확장은 다음 조건을 모두 충족할 때만 기능을 사용할 수 있는 확장입니다.

활성화 확장은 보편적으로 지원되지 않는 하드웨어 기능을 노출하기 위한 것입니다.

활성화 지시문은 하나 이상의 활성화 확장에 대한 지원을 켜는 지시문입니다. 구현이 나열된 활성화 확장을 모두 지원하지 않으면 셰이더 생성 오류가 발생합니다.

enable_directive :

'enable' enable_extension_list ';'

enable_extension_list :

enable_extension_name ( ',' enable_extension_name ) * ',' ?

다른 지시문과 마찬가지로 활성화 지시문이 있으면 모든 선언const 단언보다 앞에 나타나야 합니다. 확장 이름은 식별자가 아닙니다. 확장 이름은 선언으로 해석되지 않습니다.

유효한 활성화 확장은 다음 표에 나열되어 있습니다.

활성화 확장
WGSL 활성화 확장 WebGPU GPUFeatureName 설명
f16 "shader-f16" WGSL 모듈에서 f16 타입을 유효하게 사용할 수 있습니다. 그렇지 않으면 f16을 직접 또는 간접적으로 사용할 때 셰이더 생성 오류가 발생합니다.
clip_distances "clip-distances" WGSL 모듈에서 내장 변수 clip_distances를 유효하게 사용할 수 있습니다. 그렇지 않으면 clip_distances를 사용할 때 셰이더 생성 오류가 발생합니다.
dual_source_blending "dual-source-blending" WGSL 모듈에서 특성 blend_src를 유효하게 사용할 수 있습니다. 그렇지 않으면 blend_src를 사용할 때 셰이더 생성 오류가 발생합니다.
subgroups "subgroups" WGSL 모듈에서 하위 그룹 내장 값, 하위 그룹 내장 함수쿼드 내장 함수를 유효하게 사용할 수 있습니다. 그렇지 않으면 이를 사용할 때 셰이더 생성 오류가 발생합니다.
primitive_index "primitive-index" WGSL 모듈에서 내장 변수 primitive_index를 유효하게 사용할 수 있습니다. 그렇지 않으면 primitive_index를 사용할 때 셰이더 생성 오류가 발생합니다.
subgroup_size_control "subgroup-size-control" WGSL 모듈에서 특성 subgroup_size를 유효하게 사용할 수 있습니다. 그렇지 않으면 subgroup_size를 사용할 때 셰이더 생성 오류가 발생합니다. subgroup_size_control이 활성화되면 subgroups자동으로 활성화됩니다.
예제: 가상의 활성화 확장 사용
// 임의 정밀도 부동 소수점 타입을 위한 가상의 확장을 활성화합니다.
enable arbitrary_precision_float;
enable arbitrary_precision_float; // 중복 활성화 지시문도 허용됩니다.

// 반올림 모드를 제어하는 가상의 확장을 활성화합니다.
enable rounding_mode;

// arbitrary_precision_float가 다음의 사용을 활성화한다고 가정합니다.
//    - 타입 f<E,M>
//    - 함수 반환, 형식 매개변수 및 let 선언의 타입으로 사용
//    - AbstractFloat로부터 생성하는 값 생성자로 사용
//    - 나눗셈 연산자 /의 피연산자
// @rounding_mode 특성이 rounding_mode 활성화 지시문에 의해 활성화된다고 가정합니다.
@rounding_mode(round_to_even)
fn halve_it(x : f<8, 7>) -> f<8, 7> {
  let two = f<8, 7>(2);
  return x / 2; // 최근접 짝수 방향 반올림 모드를 사용합니다.
}

4.1.2. 언어 확장

언어 확장은 구현에서 지원하면 자동으로 사용할 수 있는 확장입니다. 프로그램에서 이를 명시적으로 요청할 필요는 없습니다.

언어 확장은 어떤 WebGPU 구현에서도 합리적으로 지원할 수 있는 기능을 구체화합니다. 기능이 보편적으로 지원되지 않는다면, 이는 일부 WebGPU 구현에서 아직 해당 기능을 구현하지 않았기 때문입니다.

참고: 예를 들어 do-while 루프는 언어 확장이 될 수 있습니다.

WebGPU GPU 객체의 wgslLanguageFeatures 멤버는 구현에서 지원하는 언어 확장 집합을 나열합니다.

requires 지시문은 프로그램이 하나 이상의 언어 확장을 사용함을 문서화하는 지시문입니다. 이 지시문은 구현에서 노출하는 기능을 변경하지 않습니다. 구현이 필수 확장 중 하나를 지원하지 않으면 셰이더 생성 오류가 발생합니다.

WGSL 모듈은 requires 지시문을 사용하여 이식성이 없을 가능성과, 이식성을 위해 의도한 최소 기준을 알릴 수 있습니다.

참고: WebGPU 구현 외부의 도구는 프로그램에서 사용한 모든 언어 확장이 프로그램의 requires 지시문에 포함되는지 확인할 수 있습니다.

requires_directive :

'requires' language_extension_list ';'

language_extension_list :

language_extension_name ( ',' language_extension_name ) * ',' ?

다른 지시문과 마찬가지로 requires 지시문이 있으면 모든 선언const 단언보다 앞에 나타나야 합니다. 확장 이름은 식별자가 아닙니다. 확장 이름은 선언으로 해석되지 않습니다.

언어 확장
WGSL 언어 확장 설명
readonly_and_readwrite_storage_textures readread_write 접근 모드스토리지 텍스처와 함께 사용할 수 있도록 합니다. 또한 textureBarrier 내장 함수를 추가합니다.
packed_4x8_integer_dot_product dot4U8Packeddot4I8Packed 내장 함수를 사용하는 내적 명령의 입력으로 8비트 정수의 4성분 벡터를 패킹한 32비트 정수 스칼라를 사용할 수 있도록 지원합니다. 또한 pack4xI8, pack4xU8, pack4xI8Clamp, pack4xU8Clamp, unpack4xI8unpack4xU8 내장 함수를 사용하여 8비트 정수의 패킹된 4성분 벡터를 패킹하고 언패킹하는 명령을 추가합니다.
unrestricted_pointer_parameters 사용자 정의 함수에서 다음 제한을 제거합니다.

사용자 정의 함수에서 포인터 타입 매개변수는 다음 주소 공간 중 하나에 있어야 합니다.

사용자 정의 함수에 전달되는 포인터 타입의 각 인수는 해당 루트 식별자와 동일한 메모리 뷰가져야 합니다.

pointer_composite_access 루트 식이 포인터이고 참조를 산출하는 복합 값 분해 식을 지원합니다.

예를 들어 p가 멤버 m을 가진 구조체를 가리키는 포인터이면 p.mp가 가리키는 구조체 내부의 m 메모리 위치에 대한 참조입니다.

마찬가지로 pa가 배열을 가리키는 포인터이면 pa[i]pa가 가리키는 배열의 i번째 요소에 대한 메모리 위치의 참조입니다.

uniform_buffer_standard_layout uniform 주소 공간의 버퍼가 다른 주소 공간과 동일한 메모리 레이아웃 제약 조건을 사용할 수 있도록 합니다.
subgroup_id subgroups 확장이 활성화된 경우 subgroup_idnum_subgroups 내장 값을 사용할 수 있도록 합니다.
subgroup_uniformity 하위 그룹쿼드 내장 함수의 균일 제어 흐름을 위해 동일한 하위 그룹에 있는 모든 호출을 포함하는 추가 범위인 하위 그룹을 추가합니다.

참고: 하위 그룹 및 쿼드 내장 함수를 사용하려면 subgroups 확장을 활성화해야 합니다.

texture_and_sampler_let let 선언유효 값 타입으로 텍스처 또는 샘플러 타입을 사용할 수 있도록 합니다.
texture_formats_tier1 다음과 같은 추가 텍셀 형식을 지원합니다. rgba16unorm, rgba16snorm, rg8unorm, rg8snorm, rg8uint, rg8sint, rg16unorm, rg16snorm, rg16uint, rg16sint, rg16float, r8unorm, r8snorm, r8uint, r8sint, r16unorm, r16snorm, r16uint, r16sint, r16float, rgb10a2unorm, rgb10a2uint, rg11b10ufloat
linear_indexing global_invocation_indexworkgroup_index 내장 값을 지원합니다.
immediate_address_space immediate 주소 공간을 활성화하여 변수를 var<immediate>로 선언하고 WebGPU API를 통해 명령 인코더에서 직접 전달되는 자주 업데이트되는 소량의 데이터에 바인딩할 수 있도록 합니다.
fragment_depth frag-depth 내장 값에 새로운 depth_mode 내장 매개변수를 도입합니다. 모드는 lessgreater이며, 프래그먼트 셰이더가 기존 깊이보다 작거나 큰 것이 보장되는 깊이 값만 기록한다고 선언할 때 사용됩니다.
buffer_view 버퍼 타입 및 buffer_view 내장 함수를 사용할 수 있도록 합니다.

다른 호스트 공유 가능 타입으로 재해석할 수 있는 불투명 저장소 타입의 변수를 선언할 수 있도록 합니다.

swizzle_assignment 스위즐 뷰 타입을 지원합니다.

이를 통해 스위즐 대입이 가능해집니다. 하나의 대입문으로 전체 벡터를 업데이트하지 않고도 벡터의 여러 성분을 업데이트할 수 있습니다.

예를 들어 변수 v가 4요소 벡터이면 v.xz = vec2(1,2);는 한 번 읽고 한 번 쓰면서 v.x = 1; v.z = 2;를 작성하는 축약형입니다.

pointer_composite_access도 지원되면 포인터에서도 작동합니다. p가 3개 이상의 요소를 가진 벡터를 가리키는 포인터이면 p.xz = vec2(1,2);(*p).x = 1; (*p).z = 2;의 축약형입니다.

참고: 장기적으로 WGSL은 해당 시점에 일반적으로 지원되는 언어 확장의 모든 기능을 구체화하는 언어 확장을 정의할 것입니다. requires 지시문에서 이들은 그러한 공통 기능을 모두 나열하는 축약형으로 사용됩니다. 이들은 점진적으로 증가하는 기능 집합을 나타내며 일종의 언어 버전으로 볼 수 있습니다.

4.2. 전역 진단 필터

전역 진단 필터영향 범위가 WGSL 모듈 전체인 진단 필터입니다. 이는 지시문이므로 모든 모듈 범위 선언보다 앞에 나타납니다. 특성 형식과 동일하게 표기하지만 선행 @(U+0040) 코드 포인트가 없고 끝에 세미콜론이 붙습니다.

diagnostic_directive :

'diagnostic' diagnostic_control ';'

5. 선언과 범위

선언식별자를 다음 종류의 객체 중 하나와 연결합니다.

즉, 선언은 객체에 대한 이름을 도입합니다.

선언이 프로그램 소스에는 나타나지만 다른 선언의 텍스트 외부에 있으면 해당 선언은 모듈 범위에 있습니다.

함수 선언은 모듈 범위에 나타납니다. 함수 선언에는 형식 매개변수가 있으면 그 선언이 포함되며, 함수의 본문 안에 변수 및 값 선언을 포함할 수 있습니다. 따라서 이러한 포함된 선언은 모듈 범위에 있지 않습니다.

참고: 다른 선언을 포함하는 유일한 종류의 선언은 함수 선언입니다.

특정 객체는 WebGPU 구현에서 제공되며 WGSL 모듈 소스가 시작되기 전에 선언된 것처럼 취급됩니다. 이러한 객체를 미리 선언된 객체라고 합니다. 예를 들어 WGSL은 다음을 미리 선언합니다.

선언의 범위는 선언된 식별자가 연결된 객체를 잠재적으로 나타내는 프로그램 소스 위치의 집합입니다. 이러한 소스 위치에서 식별자가 해당 선언의 범위 내에 있다고 합니다.

선언이 나타나는 위치에 따라 범위가 결정됩니다.

동일한 WGSL 소스 프로그램의 두 선언은 다음 조건을 동시에 충족해서는 안 됩니다.

참고: 미리 선언된 객체에는 WGSL 소스의 선언이 없습니다. 따라서 모듈 범위나 함수 내부에서 사용자가 지정한 선언은 미리 선언된 객체와 동일한 이름을 가질 수 있습니다.

식별자는 문법적 문맥에 따라 다음과 같이 구분하여 사용됩니다.

ident 토큰이 다른 곳에서 선언된 객체를 나타내는 이름으로 나타날 때, 해당 토큰은 어떤 선언의 범위 내있어야 합니다. 식별자 토큰이 나타내는 객체는 다음과 같이 결정됩니다.

위 알고리즘을 사용하여 식별자를 선언에 매핑할 때 식별자가 해당 선언으로 해석된다고 합니다. 마찬가지로 식별자가 선언된 객체로 해석된다고도 합니다.

모듈 범위 선언이 재귀적이면 셰이더 생성 오류입니다. 즉, 선언 사이에 순환이 존재할 수 없습니다.

다음과 같은 방향 그래프를 고려합니다.

이 그래프에는 순환이 없어야 합니다.

참고: 함수 본문함수 선언의 일부이므로 함수는 직접적으로든 간접적으로든 재귀적이어서는 안 됩니다.

참고:모듈 범위 식별자 선언은 텍스트에서 해당 선언의 사용보다 앞에 있어야 합니다.

예제: 유효한 선언과 유효하지 않은 선언
// 유효함: 사용자 정의 변수는 내장 함수와 같은 이름을 가질 수 있습니다.
var<private> modf: f32 = 0.0;

// 유효함: foo_1은 프로그램 전체에서 범위 내에 있습니다.
var<private> foo: f32 = 0.0; // foo_1

// 유효함: bar_1은 프로그램 전체에서 범위 내에 있습니다.
var<private> bar: u32 = 0u; // bar_1

// 유효함: my_func_1은 프로그램 전체에서 범위 내에 있습니다.
// 유효함: foo_2는 함수가 끝날 때까지 범위 내에 있습니다.
fn my_func(foo: f32) { // my_func_1, foo_2
  // 'foo'에 대한 모든 참조는 함수 매개변수로 해석됩니다.

  // 유효하지 않음: modf는 모듈 범위 변수로 해석됩니다.
  let res = modf(foo);

  // 유효하지 않음: foo_2의 범위는 함수 끝에서 종료됩니다.
  var foo: f32; // foo_3

  // 유효함: bar_2는 함수가 끝날 때까지 범위 내에 있습니다.
  var bar: u32; // bar_2
  // 'bar'에 대한 참조는 bar_2로 해석됩니다.
  {
    // 유효함: foo_4는 복합문이 끝날 때까지 범위 내에 있습니다.
    var foo : f32; // foo_4

    // 유효함: bar_3은 복합문이 끝날 때까지 범위 내에 있습니다.
    var bar: u32; // bar_3
    // 'bar'에 대한 참조는 bar_3으로 해석됩니다.

    // 유효하지 않음: bar_4의 범위 끝은 bar_3과 같습니다.
    var bar: i32; // bar_4

    // 유효함: i_1은 for 루프가 끝날 때까지 범위 내에 있습니다.
    for ( var i: i32 = 0; i < 10; i++ ) { // i_1
      // 유효하지 않음: i_2의 범위 끝은 i_1과 같습니다.
      var i: i32 = 1; // i_2.
    }
  }

  // 유효하지 않음: bar_5의 범위 끝은 bar_2와 같습니다.
  var bar: u32; // bar_5

  // 유효함: 모듈 범위 선언인 later_def는 프로그램 전체에서 범위 내에 있습니다.
  var early_use : i32 = later_def;
}

// 유효하지 않음: bar_6의 범위는 bar_1과 같습니다.
var<private> bar: u32 = 1u; // bar_6

// 유효하지 않음: my_func_2의 범위 끝은 my_func_1과 같습니다.
fn my_func() { } // my_func_2

// 유효함: my_foo_1은 프로그램 전체에서 범위 내에 있습니다.
fn my_foo( //my_foo_1
  // 유효함: my_foo_2는 함수가 끝날 때까지 범위 내에 있습니다.
  my_foo: i32 // my_foo_2
) { }

var<private> later_def : i32 = 1;
예제: 미리 선언된 객체 가리기
// 이 선언은 미리 선언된 'min' 내장 함수를 가립니다.
// 이 선언은 모듈 범위에 있으므로 소스 전체에서 범위 내에 있습니다.
// 내장 함수에는 더 이상 접근할 수 없습니다.
fn min() -> u32 { return 0; }

const rgba8unorm = 12; // 미리 선언된 'rgba8unorm' 열거자를 가립니다.

6. 타입

프로그램은 값을 계산합니다.

WGSL에서 타입은 값의 집합이며 각 값은 정확히 하나의 타입에 속합니다. 값의 타입은 해당 값에 수행할 수 있는 연산의 구문과 의미를 결정합니다.

예를 들어 수학적 숫자 1은 WGSL에서 다음과 같이 서로 다른 값에 대응합니다.

WGSL은 이들의 기계 표현과 연산이 다르므로 서로 다른 값으로 취급합니다.

일부 타입은 불투명합니다. 이는 그 값에 WGSL 프로그램 내에서 직접 검사하거나 분해하거나 조작할 수 없는 구현 정의 표현이 있음을 의미합니다.

타입은 미리 선언되거나 WGSL 소스에서 선언을 통해 생성됩니다.

일부 타입은 템플릿 매개변수화로 표현됩니다. 타입 생성자템플릿 목록으로 매개변수화될 때 타입을 나타내는 미리 선언된 객체입니다. 예를 들어 타입 atomic<u32>은 타입 생성자 atomic과 템플릿 목록 <u32>을 결합합니다.

타입의 개념과 해당 타입을 나타내는 WGSL의 구문을 구분합니다. 많은 경우 이 명세에서 타입을 표기하는 방법은 WGSL 구문과 같습니다. 예:

일부 WGSL 타입은 소스 프로그램을 분석하고 프로그램의 런타임 동작을 결정하는 데만 사용됩니다. 이 명세에서는 이러한 타입을 설명하지만 WGSL 소스 텍스트에는 나타나지 않습니다.

참고: 참조 타입은 WGSL 모듈에 작성되지 않습니다. § 6.5.3 참조 및 포인터 타입을 참조하십시오.

참고: 스위즐 뷰 타입은 WGSL 모듈에 작성되지 않습니다. § 6.5.4 스위즐 뷰 타입을 참조하십시오.

6.1. 타입 검사

WGSL 값은 식을 평가하여 계산됩니다. 은 이름이 "expression"으로 끝나는 WGSL 문법 규칙 중 하나로 구문 분석되는 소스 텍스트 구간입니다. 식 E에는 외부 식 E 안에 완전히 포함된 식인 하위 식이 포함될 수 있습니다. 최상위 식은 그 자체가 하위 식이 아닌 식입니다. § 8.19 식 문법 요약을 참조하십시오.

식 평가로 생성되는 특정 값은 다음 항목에 따라 달라집니다.

특정 식을 평가하여 나올 수 있는 값은 항상 특정 WGSL 타입에 속하며, 이를 식의 정적 타입이라고 합니다. WGSL 규칙은 식의 정적 타입이 해당 식의 정적 문맥에만 의존하도록 설계되었습니다.

타입 단언은 일부 WGSL 소스 식을 WGSL 타입에 매핑한 것입니다. 표기법

e : T

T가 WGSL 식 e의 정적 타입임을 의미하는 타입 단언입니다.

참고: 타입 단언은 프로그램 텍스트에 관한 사실을 진술한 것입니다. 런타임 검사가 아닙니다.

문은 흔히 식을 사용하며 해당 식의 정적 타입에 요구 사항을 부과할 수 있습니다. 예:

성공적으로 구문 분석된 WGSL 모듈의 타입 검사는 각 식을 정적 타입에 매핑하고 각 문의 타입 요구 사항이 충족되는지 검증하는 과정입니다. 타입 검사에 실패하면 셰이더 생성 오류의 특수한 경우인 타입 오류가 발생합니다.

타입 검사는 구문 구절에 타입 규칙을 재귀적으로 적용하여 수행할 수 있습니다. 여기서 구문 구절 또는 입니다. 타입 규칙구문 구절정적 문맥이 해당 구절에 포함된 식의 정적 타입을 결정하는 방법을 설명합니다. 타입 규칙은 두 부분으로 구성됩니다.

타입 규칙의 전제 조건과 결론에는 타입 매개변수가 있을 수 있습니다. 타입 규칙의 결론이나 전제 조건에 타입 매개변수가 포함되어 있으면 해당 규칙이 매개변수화되었다고 합니다. 포함되어 있지 않으면 규칙이 완전히 구체화되었다고 합니다. 매개변수화된 규칙의 각 타입 매개변수를 타입으로 치환하고, 규칙에서 특정 매개변수가 나타나는 모든 곳에 동일한 타입을 사용하여 완전히 구체화된 타입 규칙을 만들 수 있습니다. 규칙의 타입 매개변수에 타입을 할당하는 것을 치환이라고 합니다.

예를 들어 다음은 논리 부정 (!e 형식의 식)에 대한 타입 규칙입니다.

전제 조건 결론
e: T
T는 bool 또는 vecN<bool>
!e: T

이 규칙은 타입 매개변수 T를 포함하므로 매개변수화된 규칙입니다. T는 네 타입 bool, vec2<bool>, vec3<bool> 또는 vec4<bool> 중 하나를 나타낼 수 있습니다. Tvec3<bool>에 매핑하는 치환을 적용하면 다음과 같이 완전히 구체화된 타입 규칙이 생성됩니다.

전제 조건 결론
e: vec3<bool>
!e: vec3<bool>

매개변수화된 규칙의 다른 조건을 충족하는 치환을 적용하여 만들 수 있는 완전히 구체화된 각 규칙을 해당 매개변수화된 규칙의 오버로드라고 합니다. 예를 들어 불리언 부정 규칙에는 타입 매개변수 T에 타입을 할당할 수 있는 방법이 네 가지이므로 네 개의 오버로드가 있습니다.

참고: 즉, 매개변수화된 타입 규칙은 완전히 구체화된 타입 규칙 모음의 패턴을 제공하며, 각 규칙은 매개변수화된 규칙에 서로 다른 치환을 적용하여 생성됩니다.

다음 조건을 충족하면 타입 규칙이 구문 구절에 적용됩니다.

식에 적용되는 완전히 구체화된 타입 규칙을 생성하는 치환이 존재하면 매개변수화된 타입 규칙이 해당 식에 적용됩니다.

1u+2u라는 식을 살펴봅니다. 이 식에는 1u2u라는 두 개의 리터럴 하위 식이 있으며 둘 다 u32 타입입니다. 최상위 식은 덧셈입니다. § 8.8 산술식의 규칙을 참조하면 다음과 같은 이유로 덧셈 타입 규칙이 해당 식에 적용됩니다.

구문 구절을 분석할 때 다음 세 가지 경우가 발생할 수 있습니다.

위의 예를 계속하면 1u+2u라는 식에는 하나의 타입 규칙만 적용되므로 타입 검사는 해당 타입 규칙의 결론, 즉 1u+2u가 u32 타입이라는 결론을 받아들입니다.

다음 조건을 충족하면 WGSL 소스 프로그램은 올바르게 타입이 지정된 프로그램입니다.

그렇지 않으면 타입 오류가 발생하며 소스 프로그램은 유효한 WGSL 모듈이 아닙니다.

WGSL 모듈의 타입 검사는 프로그램 소스 텍스트만 검사하여 성공하거나 타입 오류를 발견하기 때문에 WGSL은 정적 타입 언어입니다.

6.1.1. 타입 규칙 표

식에 대한 WGSL 타입 규칙은 타입 규칙마다 하나의 행을 갖는 타입 규칙 표로 구성됩니다.

식의 의미는 해당 식을 평가할 때 발생하는 효과이며, 주로 결괏값을 생성하는 것입니다. 식에 적용되는 타입 규칙의 설명 열은 식의 의미를 지정합니다. 의미는 일반적으로 모든 하위 식의 가정된 값을 포함하여 타입 규칙 매개변수의 값에 따라 달라집니다. 때로는 식의 의미에 하위 식이 일으키는 결괏값 이외의 효과처럼 결괏값 생성 이외의 효과가 포함됩니다.

예제: 식의 부수 효과
fn foo(p : ptr<function, i32>) -> i32 {
  let x = *p;
  *p += 1;
  return x;
}

fn bar() {
  var a: i32;
  let x = foo(&a); // foo 호출은 값을 반환하고
                   // a의 값을 업데이트합니다
}

6.1.2. 변환 순위

타입 단언 e:T타입 규칙 전제 조건으로 사용되는 경우 다음 조건 중 하나를 충족하면 해당 전제 조건이 충족됩니다.

이 규칙은 아래 표에 정의된 타입 쌍에 대한 ConversionRank 함수로 성문화됩니다. ConversionRank 함수는 한 타입(Src)의 값을 다른 타입(Dest)으로 자동 변환하는 것에 대한 선호도와 실행 가능성을 나타냅니다. 순위가 낮을수록 더 선호됩니다.

실행 가능한 자동 변환은 값을 Src 타입에서 Dest 타입으로 변환하며, ConversionRank(Src,Dest)가 유한할 때 허용됩니다. 이러한 변환은 § 15.7 부동 소수점 평가에 설명된 제한을 전제로 값을 보존합니다.

참고: 자동 변환은 두 종류의 상황에서만 발생합니다. 첫째, 상수 식을 GPU에서 사용할 수 있는 해당 타입의 숫자 값으로 변환할 때입니다. 둘째, 메모리 참조에서 로드가 발생하여 해당 메모리에 저장된 값을 산출할 때입니다.

참고: 순위가 무한대인 변환은 실행할 수 없습니다. 즉, 허용되지 않습니다.

참고: 변환을 수행하지 않으면 변환 순위는 0입니다.

한 타입에서 다른 타입으로의 ConversionRank
Src Dest ConversionRank(Src,Dest) 설명
T T 0 항등 변환. 변환을 수행하지 않습니다.
ref<AS,T,AM>
AS주소 공간이고, 접근 모드 AMread 또는 read_write입니다.
T 0 로드 규칙을 적용하여 메모리 참조에서 값을 로드합니다.
swizzle<AS,S,N,K>
vecK<S> 0 스위즐 뷰 로드 규칙을 적용하여 스위즐 뷰에서 벡터 값을 로드합니다.
AbstractFloat f32 1 § 15.7.6 부동 소수점 변환 참조
AbstractFloat f16 2 § 15.7.6 부동 소수점 변환 참조
AbstractInt i32 3 값이 i32에 속하면 항등 변환입니다. 그렇지 않으면 셰이더 생성 오류가 발생합니다.
AbstractInt u32 4 값이 u32에 속하면 항등 변환입니다. 그렇지 않으면 셰이더 생성 오류가 발생합니다.
AbstractInt AbstractFloat 5 § 15.7.6 부동 소수점 변환 참조
AbstractInt f32 6 AbstractInt에서 AbstractFloat로 변환한 다음, AbstractFloat에서 f32로 변환한 것처럼 동작합니다.
AbstractInt f16 7 AbstractInt에서 AbstractFloat로 변환한 다음, AbstractFloat에서 f16으로 변환한 것처럼 동작합니다.
vecN<S> vecN<T> ConversionRank(S,T) 성분 타입에서 변환 순위를 상속합니다.
matCxR<S> matCxR<T> ConversionRank(S,T) 성분 타입에서 변환 순위를 상속합니다.
array<S,N> array<T,N> ConversionRank(S,T) 성분 타입에서 변환 순위를 상속합니다. 참고: 고정 크기 배열추상 성분 타입을 가질 수 있습니다.
__frexp_result_abstract __frexp_result_f32 1
__frexp_result_abstract __frexp_result_f16 2
__frexp_result_vecN_abstract __frexp_result_vecN_f32 1
__frexp_result_vecN_abstract __frexp_result_vecN_f16 2
__modf_result_abstract __modf_result_f32 1
__modf_result_abstract __modf_result_f16 2
__modf_result_vecN_abstract __modf_result_vecN_f32 1
__modf_result_vecN_abstract __modf_result_vecN_f16 2
ptr<AS, buffer<N1>, AM>
여기서 Src는 함수 호출 인수의 타입입니다.
ptr<AS, buffer<N2>, AM>
여기서 N1N2는 모두 상수 식이고 Dest는 Src에 있는 인수에 대응하는 형식 매개변수의 타입입니다.
N2 < N1이면 1,
그렇지 않으면 무한대
고정 크기 버퍼 포인터 인수를 더 작은 크기의 포인터 매개변수로 변환합니다.1
ptr<AS, buffer<N>, AM>
여기서 Src는 함수 호출 인수의 타입입니다.
ptr<AS, buffer, AM>
여기서 Dest는 Src에 있는 인수에 대응하는 형식 매개변수의 타입입니다.
1 고정 크기 버퍼 포인터 인수를 런타임 크기 버퍼 포인터 매개변수로 변환합니다.1
S T
위의 경우가 적용되지 않음
무한대 다른 타입 사이에는 자동 변환이 없습니다.
  1. 이러한 변환에는 unrestricted_pointer_parametersbuffer_view 언어 기능이 필요합니다.

다음 조건을 충족하면 타입 T는 타입 S구체화입니다.

T 타입 값 e값 구체화TT의 구체화로 매핑하는 실행 가능한 변환을 e에 적용하여 얻은 값입니다.

참고: f32로의 변환은 항상 f16으로의 변환보다 선호되므로, 모듈에서 f16 확장이 활성화된 경우에만 자동 변환으로 f16 값이 생성될 수 있습니다.

6.1.3. 오버로드 결정

둘 이상의 타입 규칙이 구문 구절에 적용될 때 어느 규칙을 적용할지 결정하는 동률 해결 절차가 사용됩니다. 이 절차를 오버로드 결정이라고 하며, 타입 검사가 이미 하위 식의 정적 타입을 성공적으로 찾았다고 가정합니다.

구문 구절 PP적용되는 모든 타입 규칙을 살펴봅니다. 오버로드 결정 알고리즘에서는 이러한 타입 규칙을 오버로드 후보라고 합니다. 각 후보에는 다음이 적용됩니다.

P의 오버로드 결정은 가장 선호되는 단일 오버로드 후보를 찾는 것을 목표로 다음과 같이 진행됩니다.

  1. 각 후보 C에 대해 구문 구절에 있는 하위 식의 변환 순위를 열거합니다. 후보의 전제 조건이 충족되었으므로 Pi번째 하위 식에는 다음이 적용됩니다.

    • 하위 식의 정적 타입이 계산되었습니다.

    • 식의 정적 타입에서 전제 조건의 해당 타입 단언이 요구하는 타입으로의 실행 가능한 자동 변환이 있습니다. C.R(i)를 해당 변환의 ConversionRank라고 합니다.

  2. 실행 가능한 자동 변환 후 후보의 하위 식 중 하나가 추상 타입으로 해석되지만 다른 하위 식은 상수 식이 아닌 모든 후보를 제거합니다.

    참고: 따라서 구절의 하위 식 중 하나라도 상수 식이 아니면 구절의 모든 하위 식은 구체 타입이어야 합니다.

  3. 후보 순위 지정: 두 오버로드 후보 C1C2가 주어졌을 때, 다음 조건을 충족하면 C1C2보다 선호됩니다.

    • P의 각 식 위치 i에서 C1.R(i) ≤ C2.R(i)입니다.

      • 즉, C1P에 적용하는 데 필요한 각 식 변환은 C2P에 적용하는 데 필요한 해당 식 변환만큼 선호됩니다.

    • C1.R(i) < C2.R(i)인 식 위치 i가 하나 이상 있습니다.

      • 즉, C1을 적용하는 데 필요한 식 변환 중 C2를 적용하는 데 필요한 해당 변환보다 엄격히 더 선호되는 변환이 하나 이상 있습니다.

  4. 다른 모든 후보보다 선호되는 단일 후보 C가 있으면 오버로드 결정이 성공하여 후보 타입 규칙 C를 산출합니다. 그렇지 않으면 오버로드 결정이 실패합니다.

6.2. 일반 타입

일반 타입은 불리언 값, 숫자, 벡터, 행렬 또는 이러한 값의 집합체를 기계에서 표현하기 위한 타입입니다.

일반 타입스칼라 타입, 원자 타입 또는 복합 타입입니다.

참고: WGSL의 일반 타입은 C++의 Plain-Old-Data 타입과 유사하지만 원자 타입과 추상 숫자 타입도 포함합니다.

6.2.1. 추상 숫자 타입

이러한 타입은 WGSL 소스에 표기할 수 없습니다. 타입 검사에서만 사용됩니다.

특정 식은 셰이더 생성 시점에 평가되며, GPU에서 직접 구현하는 것보다 더 큰 숫자 범위와 정밀도를 사용할 수 있습니다.

WGSL은 이러한 평가를 위해 두 가지 추상 숫자 타입을 정의합니다.

이러한 타입 중 하나에 속하는 식을 평가할 때 오버플로가 발생하거나 무한대 또는 NaN 값이 생성되어서는 안 됩니다.

타입이 추상 숫자 타입이거나 추상 숫자 타입을 포함하면 해당 타입은 추상 타입입니다. 추상 타입이 아니면 구체 타입입니다.

접미사가 없는 숫자 리터럴추상 숫자 타입의 값을 나타냅니다.

예: 식 log2(32)는 다음과 같이 분석됩니다.

예: 식 1 + 2.5는 다음과 같이 분석됩니다.

예: let x = 1 + 2.5;

예: 1u + 2.5셰이더 생성 오류를 발생시킵니다.

예: -1 * i32(-2147483648)셰이더 생성 오류를 발생시키지 않습니다.

예제: 리터럴의 타입 추론
// 명시적으로 타입이 지정된 부호 없는 정수 리터럴입니다.
var u32_1 = 1u; // 변수는 u32를 저장합니다

// 명시적으로 타입이 지정된 부호 있는 정수 리터럴입니다.
var i32_1 = 1i; // 변수는 i32를 저장합니다

// 명시적으로 타입이 지정된 부동 소수점 리터럴입니다.
var f32_1 = 1f; // 변수는 f32를 저장합니다

// 명시적으로 타입이 지정된 부호 없는 정수 리터럴은 부정할 수 없습니다.
var u32_neg = -1u; // 유효하지 않음: 단항 빼기는 u32를 지원하지 않습니다

// 구체 타입이 필요하지만 문이나 식의 어떤 부분도 특정 구체 타입을
// 강제하지 않으면 정수 리터럴은 i32 값으로 해석됩니다.
//   let 선언의 초기화 값은 생성 가능 타입 또는 포인터여야 합니다.
//   AbstractInt에서 생성 가능 타입으로의 가장 선호되는 자동 변환은
//   변환 순위 2인 AbstractInt에서 i32로의 변환입니다. 따라서 '1'은 i32로 추론됩니다.
let some_i32 = 1; // let some_i32: i32 = 1i;와 같음

// 선언 타입에서 추론됩니다.
var i32_from_type : i32 = 1; // 변수는 i32를 저장합니다. AbstractInt에서 i32, 변환 순위 2
var u32_from_type : u32 = 1; // 변수는 u32를 저장합니다. AbstractInt에서 u32, 변환 순위 3

// 접미사가 없는 정수 리터럴은 필요한 경우 부동 소수점으로 변환될 수 있습니다.
//   변환 순위 5로 AbstractInt를 f32로 자동 변환합니다.
var f32_promotion : f32 = 1; // 변수는 f32를 저장합니다

// 유효하지 않음: 부동 소수점에서 정수로 실행 가능한 변환이 없습니다
var i32_demotion : i32 = 1.0; // 유효하지 않음

// 식에서 추론됩니다.
var u32_from_expr = 1 + u32_1; // 변수는 u32를 저장합니다
var i32_from_expr = 1 + i32_1; // 변수는 i32를 저장합니다

// 값을 표현할 수 있어야 합니다.
let u32_too_large   : u32 = 1234567890123456890; // 유효하지 않음, 오버플로
let i32_too_large   : i32 = 1234567890123456890; // 유효하지 않음, 오버플로
let u32_large : u32 = 2147483649; // 유효함
let i32_large : i32 = 2147483649; // 유효하지 않음, 오버플로
let f32_out_of_range1 = 0x1p500; // 유효하지 않음, 범위를 벗어남
let f32_hex_lost_bits = 0x1.0000000001p0; // 유효하지 않음, f32로 정확히 표현할 수 없음

// 최솟값 정수: AbstractInt에 단항 부정을 적용한 다음 i32로 추론합니다.
// AbstractInt에서 생성 가능 타입으로의 가장 선호되는 변환(가장 낮은
// 변환 순위)은 AbstractInt에서 i32로의 변환입니다.
let i32_min = -2147483648;  // i32 타입을 가집니다

// 유효하지 않음. 위와 같이 AbstractInt에서 i32로의 변환을 선택하지만 값이
// 범위를 벗어나 셰이더 생성 오류가 발생합니다.
let i32_too_large_2 = 2147483648; // 유효하지 않음.

// 하위 식은 AbstractInt 및 AbstractFloat로 해석될 수 있습니다.
// 다음 예제는 모두 유효하며 변수의 값은 6u입니다.
var u32_expr1 = (1 + (1 + (1 + (1 + 1)))) + 1u;
var u32_expr2 = 1u + (1 + (1 + (1 + (1 + 1))));
var u32_expr3 = (1 + (1 + (1 + (1u + 1)))) + 1;
var u32_expr4 = 1 + (1 + (1 + (1 + (1u + 1))));

// 내장 함수 매개변수를 기반으로 추론합니다.

// 가장 선호되는 후보는 clamp(i32,i32,i32)->i32입니다
let i32_clamp = clamp(1, -5, 5);
// 가장 선호되는 후보는 clamp(u32,u32,u32)입니다.
// 리터럴은 AbstractInt에서 u32로의 자동 변환을 사용합니다.
let u32_clamp = clamp(5, 0, u32_from_expr);
// 가장 선호되는 후보는 clamp(f32,f32,f32)->f32입니다
// 리터럴은 AbstractInt에서 f32로의 자동 변환을 사용합니다.
let f32_clamp = clamp(0, f32_1, 1);

// 다음 예제는 모두 초깃값이 10f인 f32로 승격됩니다.
let f32_promotion1 = 1.0 + 2 + 3 + 4;
let f32_promotion2 = 2 + 1.0 + 3 + 4;
let f32_promotion3 = 1f + ((2 + 3) + 4);
let f32_promotion4 = ((2 + (3 + 1f)) + 4);

// 타입 규칙 위반.

// 유효하지 않음: 초기화 값은 f32로만 해석될 수 있습니다.
// AbstractFloat에서 u32로 실행 가능한 자동 변환이 없습니다.
let mismatch : u32 = 1.0;

// 유효하지 않음. 부호가 혼합된 매개변수를 허용하는 clamp 오버로드는 없습니다.
let ambiguous_clamp = clamp(1u, 0, 1i);

// 추론은 문 수준에서 완료됩니다.

// let 선언의 초기화 값은 생성 가능 타입 또는 포인터여야 합니다.
// AbstractInt에서 생성 가능 타입으로의 가장 선호되는 자동 변환은
// 변환 순위 2인 AbstractInt에서 i32로의 변환입니다. 따라서 '1'은 i32로 추론됩니다.
let some_i32 = 1; // let some_i32: i32 = 1i;와 같음

let some_f32 : f32 = some_i32; // 타입 오류: i32를 f32에 대입할 수 없습니다

// 또 다른 오버플로 사례
let overflow_u32 = (1 -2) + 1u; // 유효하지 않음, -1은 u32 범위를 벗어납니다

// 이상적인 값은 32비트 범위를 벗어나지만 다시 범위 안으로 돌아옵니다
let out_and_in_again = (0x1ffffffff / 8);

// 유사하지만 유효하지 않습니다
let out_of_range = (0x1ffffffff / 8u); // 계산을 32비트에서 수행해야 하므로
                                       // 0x1ffffffff가 범위를 벗어납니다.

6.2.2. 불리언 타입

bool 타입은 truefalse 값을 포함합니다.

불리언 리터럴 타입 규칙
전제 조건 결론 설명
true: bool 참 값.
false: bool 거짓 값.

6.2.3. 정수 타입

u32 타입은 32비트 부호 없는 정수의 집합입니다.

i32 타입은 32비트 부호 있는 정수의 집합입니다. 부호 비트가 최상위 비트 위치에 있는 2의 보수 표현을 사용합니다.

오버플로가 발생하는 구체 정수 타입에 대한 은 2비트 폭을 법으로 한 결과를 생성합니다.

정수 타입의 극값
타입 최솟값 최댓값
i32 i32(-2147483648) 2147483647i
i32(-0x80000000) 0x7fffffffi
u32 0u 4294967295u
0x0u 0xffffffffu

참고: AbstractInt도 정수 타입입니다.

6.2.4. 부동 소수점 타입

f32 타입은 IEEE-754 binary32(단정밀도) 형식의 32비트 부동 소수점 값 집합입니다. 자세한 내용은 § 15.7 부동 소수점 평가를 참조하십시오.

f16 타입은 IEEE-754 binary16(반정밀도) 형식의 16비트 부동 소수점 값 집합입니다. 프로그램에 f16 확장을 활성화하는 enable f16; 지시문이 포함되지 않은 상태에서 f16 타입을 사용하면 셰이더 생성 오류입니다. 자세한 내용은 § 15.7 부동 소수점 평가를 참조하십시오.

다음 표는 부동 소수점 타입의 특정 극값을 나열합니다. 각 값에는 그에 대응하는 음숫값이 있습니다.

부동 소수점 타입의 극값
타입 가장 작은 양의 비정규 값 가장 작은 양의 정규 값 가장 큰 양의 유한 값 가장 큰 유한한 2의 거듭제곱
f32 1.40129846432481707092e-45f 1.17549435082228750797e-38f 3.40282346638528859812e+38f 0x1p+127f
0x1p-149f 0x1p-126f 0x1.fffffep+127f
f16 5.9604644775390625e-8h 0.00006103515625h 65504.0h 0x1p+15h
0x1p-24h 0x1p-14h 0x1.ffcp+15h

참고: AbstractFloat도 부동 소수점 타입입니다.

6.2.5. 스칼라 타입

스칼라 타입은 bool, AbstractInt, AbstractFloat, i32, u32, f32, 그리고 f16이다.

숫자 스칼라 타입은 AbstractInt, AbstractFloat, i32, u32, f32, 그리고 f16이다.

정수 스칼라 타입은 AbstractInt, i32, 그리고 u32이다.

스칼라 변환은 한 스칼라 타입의 값을 다른 스칼라 타입의 값으로 매핑한다. 일반적으로 결과 값은 대상 타입의 한계 내에서 원래 값에 가깝다. 스칼라 변환은 다음 중 하나로 발생한다.

6.2.6. 벡터 타입

벡터는 2개, 3개 또는 4개의 스칼라 성분을 묶은 시퀀스이다.

타입 설명
vecN<T> 타입 T의 성분 N개로 구성된 벡터. N은 {2, 3, 4} 중 하나여야 하고, T스칼라 타입 중 하나여야 한다. T를 벡터의 성분 타입이라고 한다.

벡터의 성분 타입이 숫자 스칼라이면 해당 벡터를 숫자 벡터라고 한다.

벡터의 주요 사용 사례는 다음과 같다.

벡터와 행렬에 대한 많은 연산은 성분별로 동작한다. 즉, 각 스칼라 성분을 독립적으로 연산하여 결과를 구성한다.

예: 벡터
vec2<f32>  // 두 개의 f32로 구성된 벡터이다.
예: 성분별 덧셈
let x : vec3<f32> = a + b; // a와 b는 vec3<f32>이다
// x[0] = a[0] + b[0]
// x[1] = a[1] + b[1]
// x[2] = a[2] + b[2]

WGSL은 다음 타입 별칭미리 선언한다.

미리 선언된 별칭 원래 타입 제한 사항
vec2i vec2<i32>
vec3i vec3<i32>
vec4i vec4<i32>
vec2u vec2<u32>
vec3u vec3<u32>
vec4u vec4<u32>
vec2f vec2<f32>
vec3f vec3<f32>
vec4f vec4<f32>
vec2h vec2<f16> f16 확장이 필요하다.
vec3h vec3<f16>
vec4h vec4<f16>

6.2.7. 행렬 타입

행렬은 2개, 3개 또는 4개의 부동 소수점 벡터를 묶은 시퀀스이다.

타입 설명
matCxR<T> 타입 TC개의 열과 R개의 행으로 구성된 행렬이다. 여기서 CR은 모두 {2, 3, 4} 중 하나이고, Tf32, f16 또는 AbstractFloat여야 한다. 동일하게 타입 vecR<T>인 C개의 열 벡터로 볼 수도 있다.

행렬의 주요 사용 사례는 선형 변환을 나타내는 것이다. 이 해석에서 행렬의 벡터는 열 벡터로 취급된다.

곱 연산자(*)는 다음 중 하나에 사용된다.

§ 8.8 산술 식을 참조한다.

예: 행렬
mat2x3<f32>  // 32비트 부동 소수점 값으로 구성된 2열 3행 행렬이다.
             // 동일하게 타입 vec3<f32>인 두 개의 열 벡터이다.

WGSL은 다음 타입 별칭미리 선언한다.

미리 선언된 별칭 원래 타입 제한 사항
mat2x2f mat2x2<f32>
mat2x3f mat2x3<f32>
mat2x4f mat2x4<f32>
mat3x2f mat3x2<f32>
mat3x3f mat3x3<f32>
mat3x4f mat3x4<f32>
mat4x2f mat4x2<f32>
mat4x3f mat4x3<f32>
mat4x4f mat4x4<f32>
mat2x2h mat2x2<f16> f16 확장이 필요하다.
mat2x3h mat2x3<f16>
mat2x4h mat2x4<f16>
mat3x2h mat3x2<f16>
mat3x3h mat3x3<f16>
mat3x4h mat3x4<f16>
mat4x2h mat4x2<f16>
mat4x3h mat4x3<f16>
mat4x4h mat4x4<f16>

6.2.8. 원자 타입

원자 타입은 다음 조건을 만족하도록 구체 정수 스칼라 타입을 캡슐화한다.

타입 설명
atomic<T> 타입 T의 원자 타입. Tu32 또는 i32 중 하나여야 한다.

식은 원자 타입으로 평가되어서는 안 된다.

원자 타입은 workgroup 주소 공간의 변수 또는 read_write 접근 모드를 사용하는 스토리지 버퍼 변수에 의해서만 인스턴스화될 수 있다. 이 타입에 대한 연산의 메모리 범위는 타입이 인스턴스화된 주소 공간에 따라 결정된다. workgroup 주소 공간의 원자 타입은 Workgroup 메모리 범위를 가지며, storage 주소 공간의 원자 타입은 QueueFamily 메모리 범위를 가진다.

원자 수정은 원자 객체의 내용을 설정하는 해당 객체에 대한 모든 연산이다. 새 값이 객체의 기존 값과 같더라도 해당 연산은 수정으로 간주된다.

WGSL에서는 각 객체에 대한 원자 수정이 서로 순서화된다. 즉, 셰이더 단계가 실행되는 동안 각 원자 객체 A에 대해 모든 에이전트는 A에 적용된 수정 연산의 순서를 동일하게 관찰한다. 서로 다른 원자 객체의 순서는 어떤 방식으로도 관련되지 않을 수 있으며, 인과 관계가 암시되지 않는다. workgroup 공간의 변수는 하나의 작업 그룹 안에서는 공유되지만, 서로 다른 작업 그룹 사이에서는 공유되지 않는다는 점에 유의한다.

6.2.9. 배열 타입

배열은 인덱스로 접근할 수 있는 요소 값의 시퀀스이다.

타입 설명
array<E,N> 타입 EN개의 요소를 가진 고정 크기 배열.
N을 배열의 요소 수라고 한다.
array<E> 타입 E의 요소로 구성된 런타임 크기 배열. 이러한 배열은 특정 컨텍스트에서만 나타날 수 있다.

배열의 첫 번째 요소는 인덱스 0에 있으며, 이후의 각 요소는 다음 정수 인덱스에 있다. § 8.5.3 배열 접근 식을 참조한다.

식은 런타임 크기 배열 타입으로 평가되어서는 안 된다.

고정 크기 배열의 요소 수 식 N에는 다음 제약 조건이 적용된다.

참고: N오버라이드 선언에 의존하는 경우, 요소 수 값은 파이프라인 생성 시점에 완전히 결정되며, 그렇지 않으면 셰이더 모듈 생성 시점에 완전히 결정된다.

참고: 타입 동등성을 충족하려면 상수 식이 아닌 모든 오버라이드 식은 식별자여야 한다. 오버라이드 가능한 상수로 크기가 결정되는 작업 그룹 변수를 참조한다.

런타임 크기 배열의 요소 수는 해당 스토리지 버퍼 변수와 연결된 버퍼 바인딩의 크기에 따라 결정된다. § 13.3.4 버퍼 바인딩이 런타임 크기 배열의 요소 수를 결정함을 참조한다.

배열 요소 타입은 다음 중 하나여야 한다.

참고: 배열 요소 타입은 버퍼 타입일 수 없다.

참고: 요소 타입은 일반 타입이어야 한다.

두 배열 타입은 다음 조건이 모두 참인 경우에만 동일하다.

예: 오버라이드할 수 없는 요소 수를 가진 고정 크기 배열 타입의 예
// array<f32,8>과 array<i32,8>은 서로 다른 타입이다:
// 요소 타입이 서로 다르다
var<private> a: array<f32,8>;
var<private> b: array<i32,8>;
var<private> c: array<i32,8u>;  // array<i32,8>과 array<i32,8u>는 동일한 타입이다

const width = 8;
const height = 8;

// array<i32,8>, array<i32,8u> 및 array<i32,width>는 동일한 타입이다.
// 요소 수는 8로 평가된다.
var<private> d: array<i32,width>;

// array<i32,height>와 array<i32,width>는 동일한 타입이다.
var<private> e: array<i32,width>;
var<private> f: array<i32,height>;

참고: 오버라이드 가능한 상수로 크기가 결정되는 배열 타입의 유일하게 유효한 용도는 workgroup 주소 공간의 메모리 뷰이다. 여기에는 작업 그룹 변수의 저장소 타입도 포함된다. § 7 변수 및 값 선언을 참조한다.

예: 오버라이드 가능한 상수로 크기가 결정되는 작업 그룹 변수
override blockSize = 16;

var<workgroup> odds: array<i32,blockSize>;
var<workgroup> evens: array<i32,blockSize>; // 동일한 타입

// 다음 항목 중 'odds' 및 'evens'와 동일한 타입인 것은 없다.

// 다른 타입: 식별자 'blockSize'가 아님
var<workgroup> evens_0: array<i32,16>;
// 다른 타입: 요소 수를 표현하는 데 산술 연산을 사용함.
var<workgroup> evens_1: array<i32,(blockSize * 2 / 2)>;
// 다른 타입: 식별자만 사용하지 않고 괄호를 사용함.
var<workgroup> evens_2: array<i32,(blockSize)>;

// 오버라이드 가능한 요소 수는 바깥쪽 수준에만 나타날 수 있으므로
// 유효하지 않은 예이다.
// var<workgroup> both: array<array<i32,blockSize>,2>;

// 오버라이드 가능한 요소 수는 작업 그룹 변수에만 유효하므로
// 유효하지 않은 예이다.
// var<private> bad_address_space: array<i32,blockSize>;

6.2.10. 구조체 타입

구조체는 이름을 가진 멤버 값들을 이름 있는 하나의 그룹으로 묶은 것이다.

타입 설명
struct AStructName {
M1 : T1,
...
MN : TN,
}
식별자 AStructName으로 이름이 지정되고 N개의 멤버를 가진 구조체 타입 선언이다. 여기서 멤버 i의 이름은 식별자 Mi이고 타입은 Ti이다.

N은 1 이상이어야 한다.

동일한 구조체 타입의 두 멤버가 같은 이름을 가져서는 안 된다.

구조체 타입은 모듈 범위에서 선언된다. 프로그램 소스의 다른 위치에서는 구조체 타입을 해당 식별자 이름으로 나타낸다. § 5 선언 및 범위를 참조한다.

두 구조체 타입은 이름이 같은 경우에만 동일하다.

구조체 멤버 타입은 다음 중 하나여야 한다.

참고: 구조체 멤버 타입은 버퍼 타입일 수 없다.

참고: 사용자가 선언한 모든 구조체 타입은 구체 타입이다.

참고: 각 멤버 타입은 일반 타입이어야 한다.

구조체 멤버와 배열 요소 타입에 대한 제한의 결과에는 다음이 포함된다.

예: 구조체
// 세 개의 멤버를 가진 구조체.
struct Data {
  a: i32,
  b: vec2<f32>,
  c: array<i32,10>, // 마지막 쉼표는 선택 사항이다
}

// 타입 Data의 값을 저장하는 변수를 선언한다.
var<private> some_data: Data;
struct_decl :

'struct' ident struct_body_decl

struct_body_decl :

'{' struct_member ( ',' struct_member ) * ',' ? '}'

struct_member :

attribute * member_ident ':' type_specifier

구조체 멤버에는 다음 특성을 적용할 수 있다.

builtin, location, blend_src, interpolate, 그리고 invariant 특성은 IO 특성이다. 구조체 S의 멤버에 있는 IO 특성S진입점형식 매개변수 또는 반환 타입으로 사용될 때만 효과가 있다. § 13.3.1 단계 간 입력 및 출력 인터페이스를 참조한다.

alignsize 특성은 레이아웃 특성이며, 구조체 타입이 유니폼 버퍼 또는 스토리지 버퍼를 정의하는 데 사용되는 경우 필요할 수 있다. § 14.4 메모리 레이아웃을 참조한다.

예: 구조체 선언
struct my_struct {
  a: f32,
  b: vec4<f32>
}
예: 버퍼를 선언하는 데 사용되는 구조체
// 런타임 배열
alias RTArr = array<vec4<f32>>;
struct S {
  a: f32,
  b: f32,
  data: RTArr
}
@group(0) @binding(0) var<storage> buffer: S;

6.2.11. 복합 타입

다른 타입의 조합으로 표현되는 내부 구조를 가진 타입을 복합 타입이라고 한다. 내부 부분은 서로 겹치지 않으며 성분이라고 한다. 복합 값은 해당 성분으로 분해할 수 있다. § 8.5 복합 값 분해 식을 참조한다.

복합 타입은 다음과 같다.

복합 타입 T에 대해 T중첩 깊이NestDepth(T)로 표기하며, 그 값은 다음과 같다.

6.2.12. 생성 가능한 타입

많은 종류의 값은 생성하고, 불러오고, 저장하고, 함수에 전달하고, 함수에서 반환할 수 있다. 이러한 값을 생성 가능하다고 한다.

타입이 다음 중 하나이면 생성 가능하다.

참고: 모든 생성 가능한 타입은 생성 시 고정된 풋프린트를 가진다.

참고: 원자 타입과 런타임 크기 배열 타입은 생성 가능하지 않다. 원자 타입과 런타임 크기 배열을 포함하는 복합 타입도 생성 가능하지 않다.

6.2.13. 고정 풋프린트 타입

변수의 메모리 풋프린트는 변수의 내용을 저장하는 데 사용되는 메모리 위치의 수이다. 변수의 메모리 풋프린트는 저장소 타입에 따라 달라지며 셰이더 수명 주기의 어느 시점에 확정된다. 대부분의 변수는 매우 이른 셰이더 생성 시점에 크기가 결정된다. 일부 변수는 더 늦은 파이프라인 생성 시점에, 다른 변수는 셰이더 실행 시작 시점에야 크기가 결정될 수 있다.

타입을 구체화한 결과의 크기가 셰이더 생성 시점에 완전히 결정되면, 그 타입은 생성 시 고정된 풋프린트를 가진다.

타입의 크기가 파이프라인 생성 시점에 완전히 결정되면, 그 타입은 고정 풋프린트를 가진다.

참고: 모든 구체 생성 시 고정된 풋프린트 타입과 고정 풋프린트 타입은 저장 가능하다.

참고: 파이프라인 생성은 셰이더 생성에 의존하므로 생성 시 고정된 풋프린트를 가진 타입은 고정 풋프린트도 가진다.

생성 시 고정된 풋프린트를 가진 타입은 다음과 같다.

참고: 생성 가능한 타입은 생성 시 고정된 풋프린트를 가진다.

고정 풋프린트를 가진 타입은 다음 중 하나이다.

참고: 상수 식이 아닌 오버라이드 식을 요소 수로 사용하는 고정 크기 배열의 유일하게 유효한 용도는 workgroup 주소 공간의 메모리 뷰이다. 여기에는 작업 그룹 변수의 저장소 타입도 포함된다.

참고: 고정 풋프린트 타입은 직접 또는 간접적으로 원자 타입을 포함할 수 있지만, 생성 가능한 타입은 포함할 수 없다.

참고: 고정 풋프린트 타입에는 런타임 크기 배열, 런타임 크기 버퍼, 런타임 크기 배열을 포함하는 모든 구조체가 제외된다.

6.3. 버퍼 타입

이 타입에는 buffer_view 언어 기능이 필요하다.

버퍼 값은 그 내용을 다른 호스트 공유 가능 타입으로 해석할 수 있는 메모리를 나타낸다. 그 밖의 측면에서 버퍼 값은 불투명하다. 버퍼 값은 변수의 데이터에 여러 타입으로 접근해야 하거나 셰이더 작성자가 하나의 변수를 여러 논리적 변수로 세분화하려는 경우 유용하다.

버퍼 타입은 생성 가능하지 않으며, buffer_view 내장 함수를 통해 데이터를 불투명하지 않은 호스트 공유 가능 타입으로 해석한 후에만 접근할 수 있다.

타입 설명
buffer<N> N바이트의 저장 공간을 가진 고정 크기 버퍼.
N오버라이드 식이어야 한다.
buffer 런타임 크기 버퍼.

은 버퍼 타입으로 평가되어서는 안 된다.

고정 크기 버퍼는 storage, uniformworkgroup 주소 공간의 변수에 의해서만 인스턴스화될 수 있다. storage 및 uniform 주소 공간에서는 크기가 상수 식이어야 한다. 런타임 크기 버퍼는 storage 주소 공간의 변수에 의해서만 인스턴스화될 수 있다.

N이 0보다 크지 않은 경우:

f16 확장이 활성화되어 있고 N이 2로 나누어떨어지지 않는 경우:

f16 확장이 활성화되어 있지 않고 N이 4로 나누어떨어지지 않는 경우:

두 버퍼 타입은 다음 조건 중 하나가 성립하는 경우에만 동일하다.

6.4. 열거형 타입

열거형 타입은 이름 있는 값의 제한된 집합이다. 열거형은 유효한 텍셀 형식 집합과 같이 특정 개념의 가능성 집합을 구별하는 데 사용된다.

열거자열거형에 있는 이름 있는 값 중 하나이다. 각 열거자는 다른 모든 열거자 및 다른 모든 종류의 값과 구별된다.

WGSL 소스에는 새로운 열거자나 새로운 열거형 타입을 선언하는 메커니즘이 없다.

참고: 열거자는 템플릿 매개변수로 사용된다.

참고: 열거자를 복사하거나 다른 이름을 만들 방법은 없다.

6.4.1. 미리 선언된 열거자

다음 표에는 WGSL의 열거형 타입, 미리 선언된 열거자, 그리고 해당 열거형 타입에 필요한 언어 확장이 나열되어 있다. 열거형 타입은 존재하지만 WGSL 소스에서 표기할 수 없다.

미리 선언된 열거자
열거형
(WGSL에서 표기할 수 없음)
미리 선언된 열거자 필요한 언어 확장
접근 모드 read
write
read_write
주소 공간

참고: handle 주소 공간은 WGSL 소스에 절대로 작성되지 않는다.

function
private
workgroup
uniform
storage
텍셀 형식 rgba8unorm
rgba8snorm
rgba8uint
rgba8sint
rgba16unorm texture_formats_tier1
rgba16snorm texture_formats_tier1
rgba16uint
rgba16sint
rgba16float
rg8unorm texture_formats_tier1
rg8snorm texture_formats_tier1
rg8uint texture_formats_tier1
rg8sint texture_formats_tier1
rg16unorm texture_formats_tier1
rg16snorm texture_formats_tier1
rg16uint texture_formats_tier1
rg16sint texture_formats_tier1
rg16float texture_formats_tier1
r32uint
r32sint
r32float
rg32uint
rg32sint
rg32float
rgba32uint
rgba32sint
rgba32float
bgra8unorm
r8unorm texture_formats_tier1
r8snorm texture_formats_tier1
r8uint texture_formats_tier1
r8sint texture_formats_tier1
r16unorm texture_formats_tier1
r16snorm texture_formats_tier1
r16uint texture_formats_tier1
r16sint texture_formats_tier1
r16float texture_formats_tier1
rgb10a2unorm texture_formats_tier1
rgb10a2uint texture_formats_tier1
rg11b10ufloat texture_formats_tier1

6.5. 메모리 뷰

WGSL 프로그램은 일반 값으로 계산하는 것 외에도 메모리 접근 연산을 통해 메모리에서 값을 읽거나 메모리에 값을 쓰는 경우가 많다. 각 메모리 접근은 메모리 뷰를 통해 수행된다.

메모리 뷰는 다음으로 구성된다.

메모리 뷰의 접근 모드는 주소 공간에서 지원되어야 한다. § 7 변수 및 값 선언을 참조한다.

6.5.1. 저장 가능한 타입

변수에 포함된 값은 저장 가능한 타입이어야 한다. 저장 가능한 타입은 § 14.4.4 값의 내부 레이아웃에 설명된 것처럼 WGSL에서 정의한 명시적 표현을 가질 수 있으며, 텍스처샘플러처럼 불투명할 수도 있다.

타입이 구체 타입인 동시에 다음 중 하나이면 저장 가능하다.

참고: 즉, 저장 가능한 타입은 구체 일반 타입, 텍스처 타입, 샘플러 타입 및 버퍼 타입이다.

6.5.2. 호스트 공유 가능 타입

호스트 공유 가능 타입은 호스트와 GPU 사이에서 공유되거나 형식 변환 없이 호스트와 GPU 사이에서 복사되는 버퍼의 내용을 설명하는 데 사용된다. 이 목적으로 사용할 때는 § 14.4 메모리 레이아웃에 설명된 것처럼 타입에 레이아웃 특성을 추가로 적용할 수 있다. § 7.3 var 선언에 설명된 것처럼 유니폼 버퍼스토리지 버퍼 변수의 저장소 타입은 호스트 공유 가능 타입이어야 한다.

타입이 구체 타입인 동시에 다음 중 하나이면 호스트 공유 가능하다.

참고: 단계 간 입력 및 출력 타입에 대한 제한 사항은 § 13.3.1 단계 간 입력 및 출력 인터페이스와 이후 절에 설명되어 있다. 해당 타입도 크기가 정해지지만 계산 방식은 다르다.

참고: 텍스처와 샘플러도 호스트와 GPU 사이에서 공유할 수 있지만 그 내용은 불투명하다. 이 절의 호스트 공유 가능 타입은 특히 스토리지유니폼 버퍼에서 사용하기 위한 것이다.

6.5.3. 참조 및 포인터 타입

WGSL에는 메모리 뷰를 나타내는 두 종류의 타입이 있다. 참조 타입포인터 타입이다.

제약 조건 타입 설명
AS주소 공간이고,
T저장 가능한 타입이며,
AM접근 모드이다.
ref<AS,T,AM> AS에 있으며 타입 T의 값을 보관하고 모드 AM으로 설명되는 메모리 접근을 지원하는 메모리 위치의 메모리 뷰 집합으로 식별되는 참조 타입이다.

여기서 T저장소 타입이다.

참조 타입은 WGSL 소스에 작성되지 않으며, 대신 WGSL 모듈을 분석하는 데 사용된다.

AS주소 공간이고,
T저장 가능한 타입이며,
AM접근 모드이다.
ptr<AS,T,AM> AS에 있으며 타입 T의 값을 보관하고 모드 AM으로 설명되는 메모리 접근을 지원하는 메모리 위치의 메모리 뷰 집합으로 식별되는 포인터 타입이다.

여기서 T저장소 타입이다.

포인터 타입은 WGSL 소스에 나타날 수 있다.

두 포인터 타입은 주소 공간, 저장소 타입 및 접근 모드가 모두 같은 경우에만 동일하다.

WGSL 모듈을 분석할 때 참조 타입과 포인터 타입은 주소 공간, 저장 가능한 타입 및 접근 모드로 완전히 매개변수화된다. 이 명세의 코드 예제에서는 주석을 통해 이 완전히 매개변수화된 형식을 보여 준다.

그러나 WGSL 소스 텍스트에서는 다음과 같다.

예: 포인터 타입
fn my_function(
  /* 'ptr<function,i32,read_write>'는 'function' 주소 공간의 메모리 위치를
     사용하여 'i32' 값을 보관할 메모리를 참조하는 포인터 값의 타입이다.
     여기서 'i32'는 저장소 타입이다.
     암시된 접근 모드는 'read_write'이다.
     기본값은 "주소 공간" 절을 참조한다. */
  ptr_int: ptr<function,i32>,

  // 'ptr<private,array<f32,50>,read_write>'는 'private' 주소 공간의
  // 메모리 위치를 사용하여 타입 'f32'인 요소 50개의 배열을 보관할 메모리를
  // 참조하는 포인터 값의 타입이다.
  // 여기서 저장소 타입은 'array<f32,50>'이다.
  // 암시된 접근 모드는 'read_write'이다.
  // 기본값은 "주소 공간" 절을 참조한다.
  ptr_array: ptr<private, array<f32, 50>>
) { }

참조 타입과 포인터 타입은 모두 메모리 뷰의 집합이다. 특정 메모리 뷰에는 고유한 참조 값과 고유한 포인터 값이 각각 연결된다.

타입 ptr<AS,T,AM>의 각 포인터 값 p는 타입 ref<AS,T,AM>의 고유한 참조 값 r에 대응하며 그 반대도 성립한다. 여기서 pr는 동일한 메모리 뷰를 설명한다.

6.5.4. 스위즐 뷰 타입

스위즐 뷰는 메모리에 있는 벡터 성분의 일부에 접근하고, 읽을 때 성분을 치환하며 쓸 때 여러 위치로 분산하는 데 사용할 수 있다.

스위즐 뷰는 swizzle_assignment 언어 확장으로 활성화된다.

스위즐 뷰는 다음 조건을 만족하는 쌍(p,IndexList)이다.

알고리즘: SwizzleViewRead

포인터 p를 통해 읽은 벡터의 성분을 선택하고 선택적으로 치환하여 구성한 벡터를 산출한다.

참고: 스위즐 뷰를 통한 읽기는 일부 벡터 성분이 결과에 나타나지 않더라도 메모리에서 전체 벡터를 읽는다.

입력: 타입 swizzle<AS,S,N,K>의 스위즐 뷰 (p, IndexList)

출력: (p, IndexList)를 읽은 결과인 타입 vecK<S>의 벡터 값 v.

절차:

  1. 관례에 따라 IndexList = « Idx0, ..., IdxK−1 »이다.

  2. p가 참조하는 메모리에서 벡터 u를 읽는다. u의 타입은 vecN<S>이다.

  3. 다음 조건을 만족하는 타입 vecK<S>의 값 v를 구성한다.

    • v의 성분 iu의 성분 Idxi 값과 같다. 인덱싱 구문을 사용하면 다음과 같다. v[i] = u[Idxi]

알고리즘: SwizzleViewWrite

update 벡터의 성분을 포인터 p가 참조하는 메모리 내 벡터의 지정된 성분에 쓴다.

참고: 스위즐 뷰를 통한 쓰기는 이 과정에서 성분 값이 변경되지 않더라도 메모리의 전체 벡터를 쓴다.

스위즐 뷰 쓰기와 균일성 분석 및 메모리 모델의 상호 작용에 관한 설명은 아래를 참조한다.

입력:

IndexList의 모든 인덱스는 서로 달라야 한다. 이 요구 사항에 따라 KN이다.

변수:

절차:

  1. 관례에 따라 IndexList = « Idx0, ..., IdxK−1 »이다.

  2. 변수 newold_contents로 초기화한다.

  3. 0..K-1의 각 i에 대해:

    • new의 성분 Idxiupdate의 성분 i 값으로 설정한다. 인덱싱 구문을 사용하면 다음과 같다. new[Idxi] = update[i].

  4. newp가 참조하는 메모리에 쓴다.

참고: 모든 Idxi가 서로 달라야 한다고 요구하면 3단계가 new의 각 성분을 최대 한 번만 갱신함이 보장된다.

참고: 2단계와 3단계는 다음 선언적 규칙으로 대체할 수 있다.

타입 vecN<S>의 벡터 new를 구성한다. 여기서 new의 성분 i는 다음과 같다.

  • 0...K−1에 속하는 어떤 j에 대해 i = Idxj이면 update의 성분 j.

  • 그렇지 않으면 old_contents의 성분 i.

스위즐 뷰에는 다음 스위즐 뷰 타입이 있다.

제약 조건 타입 설명
S구체 스칼라 타입이고,
NK는 vecN<S> 및 vecK<S>가 모두 유효한 벡터 타입이 되게 하는 정수이다.
ptr<AS,vecN<S>,read_write>는 유효한 포인터 타입이다.
swizzle<AS,S,N,K> 다음 조건을 만족하는 스위즐 뷰 (p, IndexList)의 집합으로 식별되는 스위즐 뷰 타입이다.
  • p의 타입은 ptr<AS,vecN<S>,read_write>이다.

  • IndexList = « Idx0, ..., IdxK−1 »이다.

  • (p,IndexList)는 타입 vecK<S>의 벡터를 산출하는 스위즐 뷰 읽기 연산을 지원한다.

  • (p,IndexList)는 타입 vecK<S>의 벡터를 쓰는 스위즐 뷰 쓰기 연산을 지원한다.

스위즐 뷰 타입은 WGSL 소스에 작성되지 않으며, 대신 WGSL 모듈을 분석하는 데 사용된다.

스위즐 뷰는 다음 방법으로 구성한다.

이 규칙에 따라 스위즐 뷰의 IndexList 부분은 셰이더 생성 시점에 완전히 결정된다.

자세한 내용은 § 8.6 스위즐 뷰 식을 참조한다.

예: 참조의 스위즐 뷰를 통한 읽기 및 쓰기
fn swizzle_read_and_write() {
  var v: vec4u;

  // 다음과 동일하다: v.y = 1; v.z = 2;
  // 그러나 벡터를 메모리에서 정확히 한 번 읽고 메모리에 정확히 한 번 쓴다.
  v.yz = vec2u(1,2);

  // 다음과 동일하다: let u = vec3(v.a, v.g, v.b);
  // 식 v.agb는 타입 swizzle<function,u32,4,3>의 스위즐 뷰이다.
  // let 선언의 유효 값 타입은 구체적이고 생성 가능한 타입 또는 포인터 타입이어야 한다.
  // 따라서 스위즐 뷰 로드 규칙을 호출하여 스위즐 뷰를 vec3u로 자동 변환한다.
  let u = v.agb;

  // 스위즐은 연쇄할 수 있다.
  // 다음과 동일하다: v.zy = vec2(99,100);
  v.yz.yx = vec2(99,100);

  // 스위즐 뷰에 한 글자를 적용하면 기반 벡터의 스칼라 성분에 대한
  // 참조가 산출된다.
  // 다음과 동일하다: v.z = 99;
  v.yz.y = 99;

  // 스위즐 뷰를 인덱싱하면 벡터 성분 중 하나에 대한 참조가 산출된다.
  // 한 글자 벡터 접근을 구성하는 것처럼 동작하지만, 인덱스는 스위즐 이름에서
  // 사용할 글자를 선택한다.
  v.zy[1] = 50; // v.y = 50;과 동일하다.
}
예: 포인터의 스위즐 뷰를 통한 읽기 및 쓰기
// 이 예제에서는 swizzle_assignment 외에 pointer_composite_access도
// 지원한다고 가정한다.
requires pointer_composite_access;

fn swizzle_read_and_write_via_pointer(p: ptr<function,vec4u>) {
  // 다음과 동일하다: (*p).y = 1; (*p).z = 2;
  p.yz = vec2u(1,2);

  // 다음과 동일하다: let u = vec3((*p).a, (*p).g, (*p).b);
  let u = p.agb;

  // 스위즐은 연쇄할 수 있다.
  // 다음과 동일하다: p.zy = vec2(99,100);
  p.yz.yx = vec2(99,100);

  // 포인터에서 스위즐 뷰를 구성할 수 있다.
  // 스위즐 뷰에 한 글자를 적용하면 기반 벡터의 스칼라 성분에 대한
  // 참조가 산출된다.
  // 다음과 동일하다: (*p).z = 99;
  p.yz.y = 99;

  // 스위즐 뷰를 인덱싱하면 벡터 성분 중 하나에 대한 참조가 산출된다.
  // 한 글자 벡터 접근을 구성하는 것처럼 동작하지만, 인덱스는 스위즐 이름에서
  // 사용할 글자를 선택한다.
  p.zy[1] = 50; // (*p).y = 50;과 동일하다.
}
예: 유효하지 않은 스위즐 뷰
fn invalid_swizzle_cases() {
  var v: vec2u;

  // 유효하지 않음: 성분이 반복되는 스위즐에는 할당할 수 없다
  v.xx = vec2u(1,2);

  // 유효하지 않음: 'z'는 대상 벡터의 범위를 벗어난다.
  v.xz = vec2u(1,2);
  let u = v.xz;

  // 유효하지 않음: xyzw와 rgba 글자 체계를 혼합해서는 안 된다
  v.xr = vec2u(1,2);

  // 스위즐 뷰의 주소를 가져올 수 없다.
  // 여기서 v.xy는 스위즐 뷰 (&v,`01`)이다
  // & 연산자는 스위즐 뷰에 적용되지 않으므로 타입 검사가 실패한다.
  let p = &v.xy;
}

균일성 분석의 목적상 스위즐 뷰 쓰기는 갱신되는 성분의 값 균일성에만 영향을 줄 수 있다. 이것이 전체 스위즐 뷰부분 스위즐 뷰를 구분하는 이유이다.

그러나 기반 벡터의 모든 성분을 쓴다는 사실은 메모리 모델에서 중요하다. 동일한 메모리 내 벡터의 서로 다른 성분을 동시에 갱신하는 서로 다른 두 호출은 데이터 경합을 일으킨다.

예: 서로 다른 벡터 성분에 대한 스위즐 쓰기가 경합할 수 있음
var<workgroup> w: vec4u;

@compute @workgroup_size(2)
fn this_races(@builtin(local_invocation_index) gid: u32) {
  if (gid == 0) {
    w.xy = vec2u(0,1);  // 전체 벡터를 쓰므로 다른 호출과 경합한다.
  } else {
    w.zw = vec2u(2,3);  // 전체 벡터를 쓰므로 다른 호출과 경합한다.
  }
}

6.5.5. 유효하거나 유효하지 않은 메모리 참조

참조 값은 유효하거나 유효하지 않다.

참조를 구성하는 자세한 방법은 § 6.5.9 참조 및 포인터 값 구성에 설명되어 있다. 일반적으로 유효한 참조는 다음 방법으로 구성한다.

일반적으로 유효하지 않은 메모리 참조는 다음 방법으로 구성된다.

유효하지 않은 포인터는 다음 방법으로 구성된다.

유효한 포인터유효한 참조에 대응하는 포인터이다.

유효한 스위즐 뷰는 포인터 값이 유효한 스위즐 뷰이다. 유효하지 않은 스위즐 뷰는 포인터 값이 유효하지 않은 스위즐 뷰이다.

6.5.6. 기원 변수

참조 값 R기원 변수는 다음과 같이 정의된다.

포인터 값의 기원 변수는 대응하는 참조 값의 기원 변수로 정의된다.

스위즐 뷰기원 변수는 해당 스위즐 뷰 포인터의 기원 변수로 정의된다.

참고: 기원 변수는 동적 개념이다. 함수 형식 매개변수의 기원 변수는 해당 함수의 호출 지점에 따라 달라진다. 서로 다른 호출 지점은 서로 다른 기원 변수 내부를 가리키는 포인터를 제공할 수 있다.

유효한 참조는 항상 어떤 변수의 메모리 위치 일부 또는 전부에 대한 비어 있지 않은 메모리 뷰에 대응한다.

유효한 스위즐 뷰는 항상 어떤 변수 내부에 있는 벡터의 메모리 위치에 대응한다.

참고: 참조가 변수 내부의 메모리 위치에 대응하면서도 유효하지 않을 수 있다. 인덱스가 인덱싱되는 타입에 허용되는 값보다 크지만 참조되는 위치는 뒤따르는 형제 데이터 멤버 내부에 있을 때 이러한 상황이 발생할 수 있다.

다음 예제에서 참조 the_particle.position[i]i가 0 또는 1인 경우에만 유효하다. i가 2이면 해당 참조는 유효하지 않은 메모리 참조가 되지만, 그 밖의 측면에서는 the_particle.color_index의 메모리 위치에 대응한다.

예: 변수 내부에 여전히 존재하는 유효하지 않은 메모리 참조
struct Particle {
   position: vec2f,
   velocity: vec2f,
   color_index: i32,
}

@group(0) @binding(0)
var<storage,read_write> the_particle: Particle;

fn particle_velocity_component(p: Particle, i: i32) -> f32 {
  return the_particle.velocity[i]; // i가 0 또는 1이면 유효한 참조이다.
}

6.5.7. 범위를 벗어난 접근

유효하지 않은 메모리 참조 또는 유효하지 않은 스위즐 뷰접근하는 연산은 범위를 벗어난 접근이다.

범위를 벗어난 접근은 프로그램 결함이다. 작성된 그대로 수행되면 일반적으로 다음 중 하나가 발생하기 때문이다.

따라서 구현은 작성된 그대로 접근을 수행하지 않는다. 범위를 벗어난 접근을 실행하면 동적 오류가 발생한다.

참고: 저장소 타입을 잘못 해석하는 예는 이전 절의 예제에서 볼 수 있다. i가 2이면 식 the_particle.velocity[i]의 타입은 ref<storage,f32,read_write>이다. 이는 f32저장소 타입으로 사용하는 메모리 뷰라는 의미이다. 그러나 해당 메모리 위치는 color_index 멤버에 할당되므로 실제로 저장된 값의 타입은 i32이다.

참고:범위를 벗어난 접근은 동적 오류를 일으키며, 그 결과는 여러 가지가 될 수 있다.

가능한 결과에는 다음이 포함되지만 이에 한정되지는 않는다.

트랩

셰이더 호출이 즉시 종료되고 셰이더 단계 출력이 0 값으로 설정된다.

유효하지 않은 로드

유효하지 않은 참조로부터 수행되는 로드는 다음 중 하나를 반환할 수 있다.

유효하지 않은 저장

유효하지 않은 참조에 대한 저장은 다음 중 하나를 수행할 수 있다.

유효하지 않은 로드 또는 저장이 공유 주소 공간의 변수 내부에 있는 다른 위치에 접근하도록 리디렉션되면 데이터 경합이 발생할 수 있다. 예를 들어 동시에 실행되는 여러 호출의 접근이 배열의 첫 번째 요소로 리디렉션될 수 있다. 하나 이상의 접근이 쓰기이고 다른 방식으로 동기화되지 않았다면 그 결과는 데이터 경합이며, 따라서 동적 오류이다.

범위를 벗어난 접근은 균일성 분석의 가정을 무효화한다. 예를 들어 호출이 범위를 벗어난 접근으로 인해 일찍 종료되면 더 이상 집합 연산에 참여할 수 없다. 특히 workgroupBarrier 호출은 셰이더를 멈추게 할 수 있고 도함수는 유효하지 않은 결과를 산출할 수 있다.

6.5.8. 참조 및 포인터의 사용 사례

참조와 포인터는 사용 방식에 따라 구별된다.

참조를 이러한 방식으로 정의하면 변수를 단순하고 관용적으로 사용할 수 있다.

예: 참조 타입을 사용한 간단한 변수 사용
@compute @workgroup_size(1)
fn main() {
  // 'i'의 참조 타입은 ref<function,i32,read_write>이다
  // 'i'의 메모리 위치에는 i32 값 0이 저장된다.
  var i: i32 = 0;

  // 'i + 1'은 'i' 하위 식의 타입이 i32인 타입 규칙에만 일치할 수 있다.
  // 따라서 식 'i + 1'의 타입은 i32이고, 평가할 때 'i' 하위 식은 평가 시점에
  // 'i'의 메모리 위치에 저장된 i32 값으로 평가된다.
  let one: i32 = i + 1;

  // 'i'가 참조하는 위치의 값을 갱신하여 값 2를 보관하게 한다.
  i = one + 1;

  // 'i'가 참조하는 위치의 값을 갱신하여 값 5를 보관하게 한다.
  // 우변 평가는 할당이 적용되기 전에 발생한다.
  i = i + 3;
}
예: 참조를 반환하면 해당 참조를 통해 로드된 값이 반환됨
var<private> age: i32;
fn get_age() -> i32 {
  // 반환 문의 식은 함수에 선언된 반환 타입과 일치해야 하므로
  // 해당 식의 타입은 'i32'여야 한다.
  // 'age' 식의 타입은 ref<private,i32,read_write>이다.
  // 참조의 저장소 타입이 식에 필요한 타입과 일치하고 다른 타입 규칙이
  // 적용되지 않으므로 로드 규칙을 적용한다.
  // 이 컨텍스트에서 'age'를 평가한 결과는 반환 문이 실행되는 시점에
  // 'age'가 참조하는 메모리 위치에서 로드된 i32 값이다.
  return age;
}

fn caller() {
  age = 21;
  // copy_age 상수는 i32 값 21을 얻는다.
  let copy_age: i32 = get_age();
}

포인터를 이러한 방식으로 정의하면 다음 두 가지 주요 사용 사례가 가능해진다.

예: 변수 일부의 짧은 이름으로 포인터 사용
struct Particle {
  position: vec3<f32>,
  velocity: vec3<f32>
}
struct System {
  active_index: i32,
  timestep: f32,
  particles: array<Particle,100>
}
@group(0) @binding(0) var<storage,read_write> system: System;

@compute @workgroup_size(1)
fn main() {
  // storage 메모리의 특정 Particle에 대한 포인터를 구성한다.
  let active_particle = &system.particles[system.active_index];

  let delta_position: vec3<f32> = (*active_particle).velocity * system.timestep;
  let current_position: vec3<f32>  = (*active_particle).position;
  (*active_particle).position = delta_position + current_position;
}
예: 포인터를 형식 매개변수로 사용
fn add_one(x: ptr<function,i32>) {
  /* 'x'의 위치를 갱신하여 그다음으로 큰 정숫값을 포함하게 한다
     (또는 가장 작은 음의 i32 값으로 순환하게 한다).
     좌변에서 단항 '*'는 포인터를 할당할 수 있는 참조로 변환한다.
     기본적으로 read_write 접근 모드를 가진다.
     /* 우변에서는:
        - 단항 '*'가 포인터를 read_write 접근 모드의 참조로 변환한다.
        - 일치하는 유일한 타입 규칙은 덧셈(+)에 대한 규칙이며 '*x'의 타입이
          '*x'의 저장소 타입인 i32일 것을 요구한다. 따라서 로드 규칙이 적용되고
          '*x'는 평가 시점에 '*x'의 메모리에 저장된 값, 즉 i32 값 0으로 평가된다.
        - 0에 1을 더하여 우변의 최종 값 1을 생성한다. */
     '*x'의 메모리에 1을 저장한다. */
  *x = *x + 1;
}

@compute @workgroup_size(1)
fn main() {
  var i: i32 = 0;

  // 'i'의 내용을 수정하여 1을 포함하게 한다.
  // 단항 '&'를 사용하여 'i'의 포인터 값을 얻는다.
  // 이는 호출된 함수가 'i'의 메모리에 접근할 수 있으며 해당 메모리를 수정할 수 있다는
  // 명확한 신호이다.
  add_one(&i);
  let one: i32 = i;  // 'one'의 값은 1이다.
}

6.5.9. 참조 및 포인터 값 구성

참조 값은 다음 방법 중 하나로 구성된다.

모든 경우에 결과의 접근 모드는 원래 참조의 접근 모드와 같다.

예: 복합 참조의 성분 참조
struct S {
    age: i32,
    weight: f32
}
var<private> person: S;
// 다른 위치에서 'person'은 변수의 기반 메모리에 대한 참조를 나타내며
// 타입은 ref<private,S,read_write>이다.

fn f() {
    var uv: vec2<f32>;
    // 이 함수 본문의 나머지 부분에서 'uv'는 변수의 기반 메모리에 대한
    // 참조를 나타내며 타입은 ref<function,vec2<f32>,read_write>이다.

    // 할당의 좌변을 평가한다:
    //   'uv.x'를 평가하여 참조를 산출한다:
    //   1. 먼저 'uv'를 평가하여 'uv' 변수의 메모리에 대한 참조를 산출한다.
    //      결과의 타입은 ref<function,vec2<f32>,read_write>이다.
    //   2. 그런 다음 '.x' 벡터 접근 구문을 적용하여 이전 단계의 참조 값이
    //      가리키는 벡터의 첫 번째 성분 메모리에 대한 참조를 산출한다.
    //      결과의 타입은 ref<function,f32,read_write>이다.
    // 할당의 우변을 평가하면 f32 값 1.0이 산출된다.
    // uv.x가 참조하는 storage 메모리 위치에 f32 값 1.0을 저장한다.
    uv.x = 1.0;

    // 할당의 좌변을 평가한다:
    //   'uv[1]'을 평가하여 참조를 산출한다:
    //   1. 먼저 'uv'를 평가하여 'uv' 변수의 메모리에 대한 참조를 산출한다.
    //      결과의 타입은 ref<function,vec2<f32>,read_write>이다.
    //   2. 그런 다음 '[1]' 배열 인덱스 구문을 적용하여 이전 단계에서 참조한
    //      벡터의 두 번째 성분 메모리에 대한 참조를 산출한다.
    //      결과의 타입은 ref<function,f32,read_write>이다.
    // 할당의 우변을 평가하면 f32 값 2.0이 산출된다.
    // uv[1]이 참조하는 storage 메모리 위치에 f32 값 2.0을 저장한다.
    uv[1] = 2.0;

    var m: mat3x2<f32>;
    // 'm[2]'를 평가할 때:
    // 1. 먼저 'm'을 평가하여 'm' 변수의 메모리에 대한 참조를 산출한다.
    //    결과의 타입은 ref<function,mat3x2<f32>,read_write>이다.
    // 2. 그런 다음 '[2]' 배열 인덱스 구문을 적용하여 이전 단계의 참조 값이
    //    가리키는 세 번째 열 벡터의 메모리에 대한 참조를 산출한다.
    //    따라서 'm[2]' 식의 타입은 ref<function,vec2<f32>,read_write>이다.
    // 'let' 선언은 타입 vec2<f32>에 대한 것이므로 선언 문은 초기화 값의 타입이
    // vec2<f32>일 것을 요구한다.
    // 다른 타입 규칙을 적용할 수 없으므로 로드 규칙이 적용되며, 초기화 값의 평가는
    // 선언이 실행되는 시점에 'm[2]'가 참조하는 메모리 위치에서 로드된
    // vec2<f32> 값을 산출한다.
    let p_m_col2: vec2<f32> = m[2];

    var A: array<i32,5>;
    // 'A[4]'를 평가할 때
    // 1. 먼저 'A'를 평가하여 'A' 변수의 메모리에 대한 참조를 산출한다.
    //    결과의 타입은 ref<function,array<i32,5>,read_write>이다.
    // 2. 그런 다음 '[4]' 배열 인덱스 구문을 적용하여 이전 단계의 참조 값이
    //    참조하는 배열의 다섯 번째 요소 메모리에 대한 참조를 산출한다.
    //    결과 값의 타입은 ref<function,i32,read_write>이다.
    // let 선언은 우변의 타입이 i32일 것을 요구한다.
    // 다른 타입 규칙을 적용할 수 없으므로 로드 규칙이 적용되며, 초기화 값의 평가는
    // 선언이 실행되는 시점에 'A[4]'가 참조하는 메모리 위치에서 로드된
    // i32 값을 산출한다.
    let A_4_value: i32 = A[4];

    // 'person.weight'를 평가할 때
    // 1. 먼저 'person'을 평가하여 모듈 범위에 선언된 'person' 변수의
    //    메모리에 대한 참조를 산출한다.
    //    결과의 타입은 ref<private,S,read_write>이다.
    // 2. 그런 다음 '.weight' 멤버 접근 구문을 적용하여 이전 단계의 참조 값이
    //    참조하는 메모리의 두 번째 멤버에 대한 참조를 산출한다.
    //    결과의 타입은 ref<private,f32,read_write>이다.
    // let 선언은 우변의 타입이 f32일 것을 요구한다.
    // 다른 타입 규칙을 적용할 수 없으므로 로드 규칙이 적용되며, 초기화 값의 평가는
    // 선언이 실행되는 시점에 'person.weight'가 참조하는 메모리 위치에서 로드된
    // f32 값을 산출한다.
    let person_weight: f32 = person.weight;

    // 또는 동일한 구문을 사용하여 포인터에서도 참조를 구성할 수 있다.

    let uv_ptr = &uv;
    // 이 함수 본문의 나머지 부분에서 'uv_ptr'은 'uv'의 기반 메모리에 대한
    // 포인터를 나타내며 타입은 ptr<function,vec2<f32>,read_write>이다.

    // 할당의 좌변을 평가한다:
    //   '*uv_ptr'을 평가하여 참조를 산출한다:
    //   1. 먼저 'uv_ptr'을 평가하여 'uv' 변수의 메모리에 대한 포인터를 산출한다.
    //      결과의 타입은 ptr<function,vec2<f32>,read_write>이다.
    //   2. 그런 다음 간접 참조 식 연산자를 적용하여 'uv'의 메모리에 대한
    //      참조를 산출한다.
    // 할당의 우변을 평가하면 vec2<f32> 값 (1.0, 2.0)이 산출된다.
    // uv가 참조하는 storage 메모리 위치에 값 (1.0, 2.0)을 저장한다.
    *uv_ptr = vec2f(1.0, 2.0);

    // 할당의 좌변을 평가한다:
    //   'uv_ptr.x'를 평가하여 참조를 산출한다:
    //   1. 먼저 'uv_ptr'을 평가하여 'uv' 변수의 메모리에 대한 포인터를 산출한다.
    //      결과의 타입은 ptr<function,vec2<f32>,read_write>이다.
    //   2. 그런 다음 '.x' 벡터 접근 구문을 적용하여 이전 단계의 참조 값이
    //      가리키는 벡터의 첫 번째 성분 메모리에 대한 참조를 산출한다.
    //      결과의 타입은 ref<function,f32,read_write>이다.
    // 할당의 우변을 평가하면 f32 값 1.0이 산출된다.
    // uv.x가 참조하는 storage 메모리 위치에 f32 값 1.0을 저장한다.
    uv_ptr.x = 1.0;

    // 할당의 좌변을 평가한다:
    //   'uv_ptr[1]'을 평가하여 참조를 산출한다:
    //   1. 먼저 'uv_ptr'을 평가하여 'uv' 변수의 메모리에 대한 포인터를 산출한다.
    //      결과의 타입은 ptr<function,vec2<f32>,read_write>이다.
    //   2. 그런 다음 '[1]' 배열 인덱스 구문을 적용하여 이전 단계에서 참조한
    //      벡터의 두 번째 성분 메모리에 대한 참조를 산출한다.
    //      결과의 타입은 ref<function,f32,read_write>이다.
    // 할당의 우변을 평가하면 f32 값 2.0이 산출된다.
    // uv[1]이 참조하는 storage 메모리 위치에 f32 값 2.0을 저장한다.
    uv_ptr[1] = 2.0;

    let m_ptr = &m;
    // 'm_ptr[2]'를 평가할 때:
    // 1. 먼저 'm_ptr'을 평가하여 'm' 변수의 메모리에 대한 포인터를 산출한다.
    //    결과의 타입은 ptr<function,mat3x2<f32>,read_write>이다.
    // 2. 그런 다음 '[2]' 배열 인덱스 구문을 적용하여 이전 단계의 참조 값이
    //    가리키는 세 번째 열 벡터의 메모리에 대한 참조를 산출한다.
    //    따라서 'm[2]' 식의 타입은 ref<function,vec2<f32>,read_write>이다.
    // 'let' 선언은 타입 vec2<f32>에 대한 것이므로 선언 문은 초기화 값의 타입이
    // vec2<f32>일 것을 요구한다.
    // 다른 타입 규칙을 적용할 수 없으므로 로드 규칙이 적용되며, 초기화 값의 평가는
    // 선언이 실행되는 시점에 'm[2]'가 참조하는 메모리 위치에서 로드된
    // vec2<f32> 값을 산출한다.
    let p_m_col2: vec2<f32> = m_ptr[2];

    let A_ptr = &A;
    // 'A[4]'를 평가할 때
    // 1. 먼저 'A'를 평가하여 'A' 변수의 메모리에 대한 포인터를 산출한다.
    //    결과의 타입은 ptr<function,array<i32,5>,read_write>이다.
    // 2. 그런 다음 '[4]' 배열 인덱스 구문을 적용하여 이전 단계의 참조 값이
    //    참조하는 배열의 다섯 번째 요소 메모리에 대한 참조를 산출한다.
    //    결과 값의 타입은 ref<function,i32,read_write>이다.
    // let 선언은 우변의 타입이 i32일 것을 요구한다.
    // 다른 타입 규칙을 적용할 수 없으므로 로드 규칙이 적용되며, 초기화 값의 평가는
    // 선언이 실행되는 시점에 'A[4]'가 참조하는 메모리 위치에서 로드된
    // i32 값을 산출한다.
    let A_4_value: i32 = A_ptr[4];

    let person_ptr = &person;
    // 'person.weight'를 평가할 때
    // 1. 먼저 'person_ptr'을 평가하여 모듈 범위에 선언된 'person' 변수의
    //    메모리에 대한 포인터를 산출한다.
    //    결과의 타입은 ptr<private,S,read_write>이다.
    // 2. 그런 다음 '.weight' 멤버 접근 구문을 적용하여 이전 단계의 참조 값이
    //    참조하는 메모리의 두 번째 멤버에 대한 참조를 산출한다.
    //    결과의 타입은 ref<private,f32,read_write>이다.
    // let 선언은 우변의 타입이 f32일 것을 요구한다.
    // 다른 타입 규칙을 적용할 수 없으므로 로드 규칙이 적용되며, 초기화 값의 평가는
    // 선언이 실행되는 시점에 'person.weight'가 참조하는 메모리 위치에서 로드된
    // f32 값을 산출한다.
    let person_weight: f32 = person_ptr.weight;
}

포인터 값은 다음 방법 중 하나로 구성된다.

모든 경우에 결과의 접근 모드는 원래 포인터의 접근 모드와 같다.

예: 변수에서 가져온 포인터
// f32 값을 저장하기 위해 private 주소 공간에 변수를 선언한다.
var<private> x: f32;

fn f() {
    // i32 값을 저장하기 위해 function 주소 공간에 변수를 선언한다.
    var y: i32;

    // 이름 'x'는 모듈 범위 변수 'x'로 해석되며
    // 참조 타입은 ref<private,f32,read_write>이다.
    // 단항 '&' 연산자를 적용하면 참조가 포인터로 변환된다.
    // 접근 모드는 원래 변수의 접근 모드와 같으므로 완전히 지정된 타입은
    // ptr<private,f32,read_write>이다. 그러나 read_write는 function 주소 공간의
    // 기본 접근 모드이므로 이 경우 read_write를 표기하지 않아도 된다
    let x_ptr: ptr<private,f32> = &x;

    // 이름 'y'는 함수 범위 변수 'y'로 해석되며
    // 참조 타입은 ref<private,i32,read_write>이다.
    // 단항 '&' 연산자를 적용하면 참조가 포인터로 변환된다.
    // 접근 모드의 기본값은 'read_write'이다.
    let y_ptr: ptr<function,i32> = &y;

    // 모듈 범위에 선언된 변수와 구별되는 새 변수이다.
    var x: u32;

    // 여기서 이름 'x'는 이전 문에서 선언된 함수 범위 변수 'x'로 해석되며
    // 타입은 ref<function,u32,read_write>이다.
    // 단항 '&' 연산자를 적용하면 참조가 포인터로 변환된다.
    // 접근 모드의 기본값은 'read_write'이다.
    let inner_x_ptr: ptr<function,u32> = &x;
}

6.5.10. 다른 언어의 참조 및 포인터와 비교

이 절은 참고 사항이며 규범적이지 않다.

WGSL의 참조와 포인터는 다른 언어보다 더 많은 제한을 받는다. 특히 다음과 같다.

참고: 위 규칙에 따라 "댕글링" 포인터, 즉 "활성" 기원 변수의 메모리를 참조하지 않는 포인터를 구성할 수 없다. 메모리 뷰유효하지 않은 메모리 참조일 수 있지만, 기원 변수나 버퍼와 연결되지 않은 메모리 위치절대로 접근하지 않는다.

6.6. 텍스처 및 샘플러 타입

텍셀텍스처에서 독립적으로 접근할 수 있는 가장 작은 요소로 사용되는 스칼라 또는 벡터이다. 텍셀이라는 단어는 텍스처 요소의 줄임말이다.

텍스처는 렌더링에 유용한 특수 연산을 지원하는 텍셀의 모음이다. WGSL에서는 텍스처 내장 함수를 통해 이러한 연산을 호출한다. 전체 목록은 § 17.7 텍스처 내장 함수를 참조한다.

WGSL 텍스처는 WebGPU GPUTexture에 대응한다.

텍스처에는 다음 특성이 있다.

텍셀 형식

각 텍셀의 데이터 표현이다. § 6.6.1 텍셀 형식을 참조한다.

차원 수

격자 좌표의 차원 수와 좌표가 해석되는 방식이다. 차원 수는 1, 2 또는 3이다. 대부분의 텍스처는 데카르트 좌표를 사용한다. 큐브 텍스처는 여섯 개의 정사각형 면을 가지며, 원점에서 원점을 중심으로 하는 큐브를 향하는 방향 벡터로 해석되는 3차원 좌표를 사용하여 샘플링된다.

GPUTextureViewDimension을 참조한다.

크기

각 차원을 따라 이어지는 격자 좌표의 범위이다. 이는 밉 레벨의 함수이다.

밉 레벨 수

밉 레벨 수는 샘플링 텍스처깊이 텍스처에서는 1 이상이며, 스토리지 텍스처에서는 1이다.
밉 레벨 0에는 전체 크기 버전의 텍스처가 포함된다. 이후의 각 밉 레벨에는 이전 밉 레벨 크기의 절반인 이전 밉 레벨의 필터링된 버전이 포함된다. 이때 반올림이 적용될 수 있다.
텍스처를 샘플링할 때는 명시적으로 지정하거나 암시적으로 계산한 세부 수준을 사용하여 텍셀 데이터를 읽을 밉 레벨을 선택한다. 그런 다음 필터링을 통해 이들을 결합하여 샘플링된 값을 생성한다.

배열형

텍스처가 배열형인지 여부이다.

  • 배열형이 아닌 텍스처는 텍셀 격자이다.

  • 배열형 텍스처는 동종 텍셀 격자의 배열이다.

배열 크기

텍스처가 배열형인 경우 동종 격자의 수이다.

샘플 수

텍스처가 다중 샘플링되는 경우 샘플의 수이다.

텍스처의 각 텍셀에는 다음을 포함하는 정수 튜플인 고유한 논리적 텍셀 주소가 연결된다.

텍스처의 물리적 구성은 일반적으로 렌더링 연산에 맞게 최적화된다. 이를 위해 데이터 레이아웃, 데이터 타입 및 셰이더 언어로 직접 표현할 수 없는 내부 연산을 비롯한 많은 세부 사항이 프로그래머에게 숨겨진다.

따라서 셰이더는 텍스처 변수 내의 텍셀 메모리에 직접 접근할 수 없다. 대신 불투명 핸들을 통해 접근한다.

이와 같이 텍스처 타입에서 지원되는 연산 집합은 해당 텍스처 타입의 형식 매개변수를 가진 텍스처 내장 함수의 가용성에 따라 결정된다.

참고: 텍스처 변수가 저장하는 핸들은 셰이더에서 변경할 수 없다. 즉, 접근을 제공하는 기반 텍스처가 변경 가능하더라도 이 변수는 읽기 전용이다. 예를 들면 쓰기 전용 스토리지 텍스처가 있다.

텍스처 타입은 다음 절에서 정의되는 타입 집합이다.

샘플러샘플링 텍스처 또는 깊이 텍스처에서 텍셀에 접근하는 방식을 제어하는 불투명 핸들이다.

WGSL 샘플러는 WebGPU GPUSampler에 매핑된다.

텍셀 접근은 샘플러의 여러 속성을 통해 제어된다.

주소 지정 모드

텍스처 경계와 범위를 벗어난 좌표가 처리되는 방식을 제어한다. 각 텍스처 차원의 주소 지정 모드는 독립적으로 설정할 수 있다. WebGPU GPUAddressMode를 참조한다.

필터 모드

최종 결과를 생성하기 위해 접근할 텍셀을 제어한다. 필터링은 가장 가까운 텍셀을 사용하거나 여러 텍셀 사이를 보간할 수 있다. 여러 필터 모드를 독립적으로 설정할 수 있다. WebGPU GPUFilterMode를 참조한다.

LOD 클램프

접근할 최소 및 최대 세부 수준을 제어한다.

비교

비교 샘플러에서 수행되는 비교의 종류를 제어한다. WebGPU GPUCompareFunction을 참조한다.

최대 이방성

샘플러에서 사용하는 최대 이방성 값을 제어한다.

WGSL 모듈에서는 샘플러를 생성할 수 없으며 샘플러의 상태는 셰이더 내에서 변경할 수 없고 WebGPU API에서만 설정할 수 있다. 샘플러의 상태에는 위에 나열된 속성 등이 포함된다.

필터링 샘플러, 즉 보간 필터링을 사용하는 샘플러를 필터링할 수 없는 형식의 텍스처와 함께 사용하면 파이프라인 생성 오류이다.

참고: 샘플러 변수가 저장하는 핸들은 셰이더에서 변경할 수 없다.

6.6.1. 텍셀 형식

WGSL에서 특정 텍스처 타입은 텍셀 형식으로 매개변수화된다.

텍셀 형식은 다음과 같은 특성을 가진다.

채널

각 채널에는 스칼라가 포함된다. 텍셀 형식에는 최대 네 개의 채널 r, g, ba가 있으며, 일반적으로 빨강, 초록, 파랑 및 알파 채널 개념에 대응한다.

채널 형식

채널의 비트 수와 해당 비트가 해석되는 방식이다.

WGSL의 각 텍셀 형식은 이름이 같은 WebGPU GPUTextureFormat에 대응한다.

WGSL 소스 코드에서는 특정 텍셀 형식만 사용된다. 이러한 텍셀 형식을 정의하는 데 사용되는 채널 형식은 채널 형식 표에 나열되어 있다. 끝에서 두 번째 열은 저장된 채널 비트에서 셰이더에 사용되는 값으로의 변환을 지정한다. 이를 채널 전달 함수 또는 CTF라고도 한다. 세 번째 열은 셰이더 값에서 저장된 채널 비트로의 변환을 지정한다. 이를 역채널 전달 함수 또는 ICTF라고도 한다. 마지막 열은 텍셀 형식에 필요한 언어 확장을 지정한다.

참고: 8unorm의 채널 전달 함수는 {0,...,255}를 부동 소수점 구간 [0.0, 1.0]에 매핑한다.

참고: 8snorm의 채널 전달 함수는 {-128,...,127}을 부동 소수점 구간 [-1.0, 1.0]에 매핑한다.

채널 형식
채널 형식 저장되는 비트 수 저장된 비트의 해석 셰이더 타입 셰이더 값(채널 전달 함수) 쓰기 값 T(역채널 전달 함수)
8unorm 8 부호 없는 정수 v ∈ {0,...,255} f32 v ÷ 255 max(0, min(1, T))
8snorm 8 부호 있는 정수 v ∈ {-128,...,127} f32 v ÷ 127 max(-1, min(1, T))
8uint 8 부호 없는 정수 v ∈ {0,...,255} u32 v min(255, T)
8sint 8 부호 있는 정수 v ∈ {-128,...,127} i32 v max(-128, min(127, T))
16unorm 16 부호 없는 정수 v ∈ {0,...,65535} f32 v ÷ 65535 max(0, min(1, T))
16snorm 16 부호 있는 정수 v ∈ {-32768,...,32767} f32 v ÷ 32767 max(-1, min(1, T))
16uint 16 부호 없는 정수 v ∈ {0,...,65535} u32 v min(65535, T)
16sint 16 부호 있는 정수 v ∈ {-32768,...,32767} i32 v max(-32768, min(32767, T))
16float 16 IEEE-754 binary16 16비트 부동 소수점 값 v f32 v quantizeToF16(T)
32uint 32 32비트 부호 없는 정숫값 v u32 v T
32sint 32 32비트 부호 있는 정숫값 v i32 v T
32float 32 IEEE-754 binary32 32비트 부동 소수점 값 v f32 v T
2unorm 2 부호 없는 정수 v ∈ {0,...,3} f32 v ÷ 3 max(0, min(1, T))
2uint 2 부호 없는 정수 v ∈ {0,...,3} u32 v min(3, T)
10unorm 10 부호 없는 정수 v ∈ {0,...,1023} f32 v ÷ 1023 max(0, min(1, T))
10uint 10 부호 없는 정수 v ∈ {0,...,1023} u32 v min(1023, T)
10float 10 10비트 부동 소수점 값: 바이어스된 지수 5비트, 가수 5비트 v f32 v max(0, T)
11float 11 11비트 부동 소수점 값: 바이어스된 지수 5비트, 가수 6비트 v f32 v max(0, T)

스토리지 텍스처의 텍셀 형식 표에 나열된 텍셀 형식은 하나 이상의 접근 모드에서 WebGPU STORAGE_BINDING 용도를 지원하는 WebGPU 일반 색상 형식에 대응한다. 이러한 텍셀 형식은 § 6.6.5 스토리지 텍스처 타입에서 정의하는 스토리지 텍스처 타입을 매개변수화하는 데 사용된다.

텍셀 형식에 네 개의 채널이 모두 포함되지 않은 경우 다음이 적용된다.

아래 표의 마지막 열은 채널 형식 표에 있는 형식별 채널 전달 함수를 사용한다.

스토리지 텍스처의 텍셀 형식
텍셀 형식 채널 형식 메모리 순서의 채널 대응하는 셰이더 값 필요한 언어 확장
rgba8unorm 8unorm r, g, b, a vec4<f32>(CTF(r), CTF(g), CTF(b), CTF(a))
rgba8snorm 8snorm r, g, b, a vec4<f32>(CTF(r), CTF(g), CTF(b), CTF(a))
rgba8uint 8uint r, g, b, a vec4<u32>(CTF(r), CTF(g), CTF(b), CTF(a))
rgba8sint 8sint r, g, b, a vec4<i32>(CTF(r), CTF(g), CTF(b), CTF(a))
rgba16unorm 16unorm r, g, b, a vec4<f32>(CTF(r), CTF(g), CTF(b), CTF(a)) texture_formats_tier1
rgba16snorm 16snorm r, g, b, a vec4<f32>(CTF(r), CTF(g), CTF(b), CTF(a)) texture_formats_tier1
rgba16uint 16uint r, g, b, a vec4<u32>(CTF(r), CTF(g), CTF(b), CTF(a))
rgba16sint 16sint r, g, b, a vec4<i32>(CTF(r), CTF(g), CTF(b), CTF(a))
rgba16float 16float r, g, b, a vec4<f32>(CTF(r), CTF(g), CTF(b), CTF(a))
rg8unorm 8unorm r, g vec4<f32>(CTF(r), CTF(g), 0.0, 1.0) texture_formats_tier1
rg8snorm 8snorm r, g vec4<f32>(CTF(r), CTF(g), 0.0, 1.0) texture_formats_tier1
rg8uint 8uint r, g vec4<u32>(CTF(r), CTF(g), 0u, 1u) texture_formats_tier1
rg8sint 8sint r, g vec4<i32>(CTF(r), CTF(g), 0, 1) texture_formats_tier1
rg16unorm 16unorm r, g vec4<f32>(CTF(r), CTF(g), 0.0, 1.0) texture_formats_tier1
rg16snorm 16snorm r, g vec4<f32>(CTF(r), CTF(g), 0.0, 1.0) texture_formats_tier1
rg16uint 16uint r, g vec4<u32>(CTF(r), CTF(g), 0u, 1u) texture_formats_tier1
rg16sint 16sint r, g vec4<i32>(CTF(r), CTF(g), 0, 1) texture_formats_tier1
rg16float 16float r, g vec4<f32>(CTF(r), CTF(g), 0.0, 1.0) texture_formats_tier1
r32uint 32uint r vec4<u32>(CTF(r), 0u, 0u, 1u)
r32sint 32sint r vec4<i32>(CTF(r), 0, 0, 1)
r32float 32float r vec4<f32>(CTF(r), 0.0, 0.0, 1.0)
rg32uint 32uint r, g vec4<u32>(CTF(r), CTF(g), 0u, 1u)
rg32sint 32sint r, g vec4<i32>(CTF(r), CTF(g), 0, 1)
rg32float 32float r, g vec4<f32>(CTF(r), CTF(g), 0.0, 1.0)
rgba32uint 32uint r, g, b, a vec4<u32>(CTF(r), CTF(g), CTF(b), CTF(a))
rgba32sint 32sint r, g, b, a vec4<i32>(CTF(r), CTF(g), CTF(b), CTF(a))
rgba32float 32float r, g, b, a vec4<f32>(CTF(r), CTF(g), CTF(b), CTF(a))
bgra8unorm 8unorm b, g, r, a vec4<f32>(CTF(r), CTF(g), CTF(b), CTF(a))
r8unorm 8unorm r vec4<f32>(CTF(r), 0.0, 0.0, 1.0) texture_formats_tier1
r8snorm 8snorm r vec4<f32>(CTF(r), 0.0, 0.0, 1.0) texture_formats_tier1
r8uint 8uint r vec4<u32>(CTF(r), 0u, 0u, 1u) texture_formats_tier1
r8sint 8sint r vec4<i32>(CTF(r), 0, 0, 1) texture_formats_tier1
r16unorm 16unorm r vec4<f32>(CTF(r), 0.0, 0.0, 1.0) texture_formats_tier1
r16snorm 16snorm r vec4<f32>(CTF(r), 0.0, 0.0, 1.0) texture_formats_tier1
r16uint 16uint r vec4<u32>(CTF(r), 0u, 0u, 1u) texture_formats_tier1
r16sint 16sint r vec4<i32>(CTF(r), 0, 0, 1) texture_formats_tier1
r16float 16float r vec4<f32>(CTF(r), 0.0, 0.0, 1.0) texture_formats_tier1
rgb10a2unorm r, g, b: 10unorm a: 2unorm r, g, b, a vec4<f32>(CTF(r), CTF(g), CTF(b), CTF(a)) texture_formats_tier1
rgb10a2uint r, g, b: 10uint a: 2uint r, g, b, a vec4<u32>(CTF(r), CTF(g), CTF(b), CTF(a)) texture_formats_tier1
rg11b10ufloat r, g: 11float b: 10float r, g, b vec4<f32>(CTF(r), CTF(g), CTF(b), 1.0) texture_formats_tier1

WGSL은 표에 있는 각 텍셀 형식에 대한 열거자미리 선언한다.

6.6.2. 샘플링 텍스처 타입

샘플링 텍스처샘플러와 함께 접근할 수 있는 텍스처이다. 샘플러를 사용하지 않고 접근할 수도 있다. 샘플링 텍스처에는 읽기 접근만 허용된다.

텍셀 형식은 텍스처 변수에 바인딩된 GPUTextureformat 특성이다. WebGPU는 텍스처, 바인드 그룹 레이아웃의 sampleType 및 텍스처 변수의 샘플링 타입 사이의 호환성을 검증한다.

텍스처는 샘플링 타입으로 매개변수화되며, 이 타입은 f32, i32 또는 u32여야 한다.

타입 차원 수 배열형
texture_1d<T> 1D 아니요
texture_2d<T> 2D 아니요
texture_2d_array<T> 2D
texture_3d<T> 3D 아니요
texture_cube<T> Cube 아니요
texture_cube_array<T> Cube

6.6.3. 다중 샘플링 텍스처 타입

다중 샘플링 텍스처는 1 이상의 샘플 수를 가진다. 이름과 달리 샘플러와 함께 사용할 수 없다. 샘플 인덱스를 무시하면 각 논리적 텍셀 주소에 여러 텍셀에 해당하는 데이터를 실질적으로 저장한다.

텍셀 형식은 텍스처 변수에 바인딩된 GPUTextureformat 특성이다. WebGPU는 텍스처, 바인드 그룹 레이아웃의 sampleType 및 텍스처 변수의 샘플링 타입 사이의 호환성을 검증한다.

texture_multisampled_2d샘플링 타입으로 매개변수화되며, 이 타입은 f32, i32 또는 u32여야 한다.

타입 차원 수 배열형
texture_multisampled_2d<T> 2D 아니요
texture_depth_multisampled_2d 2D 아니요

6.6.4. 외부 샘플링 텍스처 타입

외부 텍스처texture_2d<f32>와 유사하지만 잠재적으로 다른 표현을 사용하는 불투명한 2차원 부동 소수점 샘플링 텍스처 타입이다. 이러한 서로 다른 표현을 처리하는 textureLoad 또는 textureSampleBaseClampToEdge 내장 함수를 사용하여 읽을 수 있다.

WebGPU § 6.4 GPUExternalTexture를 참조한다.

타입 차원 수 배열형
texture_external 2D 아니요

6.6.5. 스토리지 텍스처 타입

스토리지 텍스처는 샘플러를 사용하지 않고 개별 텍셀 값에 접근할 수 있도록 지원한다.

스토리지 텍스처 타입은 스토리지 텍스처의 텍셀 형식 중 하나로 매개변수화되어야 한다. 텍셀 형식은 § 6.6.1 텍셀 형식에 지정된 변환 함수를 결정한다.

스토리지 텍스처에 텍셀을 쓸 때는 변환 함수의 역함수를 사용하여 셰이더 값을 저장되는 텍셀로 변환한다.

타입 차원 수 배열형
texture_storage_1d<Format, Access> 1D 아니요
texture_storage_2d<Format, Access> 2D 아니요
texture_storage_2d_array<Format, Access> 2D
texture_storage_3d<Format, Access> 3D 아니요

6.6.6. 깊이 텍스처 타입

깊이 텍스처sampler_comparison과 함께 접근할 수 있는 텍스처이다. 샘플러를 사용하지 않고 접근할 수도 있다. 깊이 텍스처에는 읽기 접근만 허용된다.

텍스처의 텍셀 형식GPUTextureBindingLayout에 정의된다.

타입 차원 수 배열형
texture_depth_2d 2D 아니요
texture_depth_2d_array 2D
texture_depth_cube Cube 아니요
texture_depth_cube_array Cube

6.6.7. 샘플러 타입

샘플러는 다음 연산을 조합하여 샘플링 텍스처 또는 깊이 텍스처에 대한 접근을 중개한다.

샘플러 타입은 다음과 같다.

타입 설명
sampler 샘플러. 샘플링 텍스처에 대한 접근을 중개한다.
sampler_comparison 비교 샘플러. 깊이 텍스처에 대한 접근을 중개한다.

샘플러는 WebGPU API에서 생성될 때 매개변수화된다. WGSL 모듈에서는 샘플러를 수정할 수 없다.

샘플러는 텍스처 내장 함수에서만 사용할 수 있다.

sampler
sampler_comparison

6.7. AllTypes 타입

AllTypes 타입은 모든 WGSL 타입의 집합이다.

WGSL 소스에서는 AllTypes 타입을 표기할 수 없다.

미리 선언된 모든 타입과 타입 생성기의 목록은 § 6.10 미리 선언된 타입 및 타입 생성기 요약을 참조한다.

참고:타입은 일반적인 의미의 값이 아니다. 타입은 런타임에 셰이더가 조작하는 데이터가 아니다.

AllTypes 타입은 일반 값을 포함할 수 있는 모든 구문에 타입 검사 규칙을 적용할 수 있도록 존재한다. WGSL은 타입을 값의 한 종류로 정의하고 식이 타입을 나타내도록 허용함으로써 규칙을 일관되게 만든다.

이러한 정의의 동기가 되는 사례는 템플릿 매개변수이다. 템플릿 매개변수는 여러 컨텍스트에서 타입, 열거자 또는 일반 값을 비롯한 여러 종류의 대상을 나타낼 수 있다. 특히 template_arg_expression 문법 규칙은 expression 문법 비단말 기호로 확장된다.

6.8. 타입 별칭

타입 별칭은 기존 타입의 새 이름을 선언한다. 이 선언은 모듈 범위에 나타나야 하며, 해당 선언의 범위는 프로그램 전체이다.

타입 T가 구조체 타입 S타입 별칭으로 정의되면 특성을 포함한 S 멤버의 모든 속성이 T의 멤버에 이어진다.

참고: 별칭이 지정되는 타입이 값 생성자 내장 함수를 지원하면, 타입 별칭이 범위 내에 있고 해당 함수를 호출하는 것이 다른 측면에서도 유효한 경우 원래 타입 지정자 이름 대신 별칭 이름을 통해 해당 함수를 호출할 수 있다.

type_alias_decl :

'alias' ident '=' type_specifier

예: 타입 별칭
alias Arr = array<i32, 5>;

alias RTArr = array<vec4<f32>>;

alias single = f32;     // f32의 별칭을 선언한다
const pi_approx: single = 3.1415;
fn two_pi() -> single {
  return single(2) * pi_approx;
}

6.9. 타입 지정자 문법

§ 8.18 타입 식을 참조한다.

type_specifier :

template_elaborated_ident

template_elaborated_ident :

ident template_list ?

참고: primary_expression 문법 규칙을 통해 template_elaborated_ident로 확장하고 괄호로 묶어 타입을 나타낼 수 있다.

6.10. 미리 선언된 타입 및 타입 생성기 요약

WGSL 소스에서 표기할 수 있는 미리 선언된 타입은 다음과 같다.

WGSL은 frexp, modfatomicCompareExchangeWeak 내장 함수의 반환 타입도 미리 선언한다. 그러나 WGSL 소스에서는 이 타입을 표기할 수 없다.

미리 선언된 타입 생성기는 다음 표에 나열되어 있다.

미리 선언된 타입 생성기
미리 선언된 타입 생성기 상호 참조
array § 6.2.9 배열 타입 참조
atomic § 6.2.8 원자 타입 참조
mat2x2 행렬 타입에 대해 미리 선언된 별칭도 나열하는 § 6.2.7 행렬 타입 참조

참고: 이 타입 생성기는 행렬을 생성하는 값 생성자 식에도 사용된다.

mat2x3
mat2x4
mat3x2
mat3x3
mat3x4
mat4x2
mat4x3
mat4x4
ptr § 6.5.3 참조 및 포인터 타입 참조
texture_1d § 6.6.2 샘플링 텍스처 타입 참조
texture_2d
texture_2d_array
texture_3d
texture_cube
texture_cube_array
texture_multisampled_2d § 6.6.3 다중 샘플링 텍스처 타입 참조
texture_storage_1d § 6.6.5 스토리지 텍스처 타입 참조
texture_storage_2d
texture_storage_2d_array
texture_storage_3d
vec2 벡터 타입에 대해 미리 선언된 별칭도 나열하는 § 6.2.6 벡터 타입 참조

참고: 이 타입 생성기는 벡터를 생성하는 값 생성자 식에도 사용된다.

vec3
vec4

7. 변수 및 값 선언

변수 선언은 데이터 값에 이름을 제공한다.

값 선언은 값의 이름을 생성하며, 해당 값은 일단 선언된 후에는 변경할 수 없다. 값 선언에는 const, override, let 및 형식 매개변수 선언이라는 네 가지 종류가 있으며 아래에서 자세히 설명한다. § 7.2 값 선언을 참조한다.

변수 선언은 값을 저장하는 메모리 위치의 이름을 생성한다. 변수의 접근 모드가 read_write이면 해당 위치에 저장된 값을 갱신할 수 있다. 변수 선언에는 var라는 한 가지 종류만 있지만 아래에서 설명하는 것처럼 주소 공간접근 모드를 여러 조합으로 지정하는 옵션이 있다. § 7.3 var 선언을 참조한다.

참고: 값 선언에는 연결된 메모리 위치가 없다. 예를 들어 어떤 WGSL 식도 값에 대한 포인터를 구성할 수 없다.

함수 정의 외부에 나타나는 선언은 모듈 범위에 있다. 해당 이름은 프로그램 전체에서 범위 내에 있다.

함수 정의 내부에 나타나는 선언은 함수 범위에 있다. 이 이름은 선언 바로 다음 문부터 해당 선언을 직접 둘러싼 중괄호 구분 문 목록의 끝까지 사용할 수 있다. 함수 범위 선언은 동적 컨텍스트이다.

참고:
변수 선언과 값 선언의 전체 구문은 유사하다. 다음 비규범적 그림은 변수 및 값 선언의 일반적인 형식을 보여 준다. 여기서 [...]은 선택적 부분을 나타내고, ...*는 앞 항목의 0회 이상 반복을 나타내며, ...+는 앞 항목의 1회 이상 반복을 나타낸다. 구체적인 구문 규칙은 각 요소에 관한 절을 참조한다.
// 구체적인 값 선언.
             const    name [: type]  = initializer ;
[attribute]* override name [: type] [= initializer];
             let      name [: type]  = initializer ;

// 일반적인 변수 형식.
[attribute]* var[<address_space[, access_mode]>] name [: type] [= initializer];

// 구체적인 변수 선언.
// 함수 범위.
             var[<function>] name [: type] [= initializer];

// 모듈 범위.
             var<private>    name [: type] [= initializer];
             var<workgroup>  name : type;
[attribute]+ var<uniform>    name : type;
[attribute]+ var             name : texture_type;
[attribute]+ var             name : sampler_type;
[attribute]+ var<storage[, access_mode]> name : type;

각 선언에는 명시적으로 지정한 타입 또는 초기화 값이 있어야 한다. 타입과 초기화 값을 모두 지정할 수도 있다. 각 선언은 연결된 데이터 값의 타입을 결정하며, 이를 선언의 유효 값 타입이라고 한다. 선언의 유효 값 타입은 다음과 같다.

각 종류의 값 또는 변수 선언은 초기화 식이 있는 경우 그 형식과 유효 값 타입에 추가 제약을 적용할 수 있다.

변수 및 값 선언 기능 요약.
선언 가변성 범위 유효 값 타입1 초기화 값 지원 초기화 식2 리소스 인터페이스의 일부
const 불변 모듈 또는 함수 생성 가능(구체 또는 추상) 필수 상수 식 아니요
override 불변 모듈 구체 스칼라 선택 사항3 상수 식 또는 오버라이드 식 아니요4
let 불변 함수 구체 생성 가능 타입 또는 포인터 타입. 또한 texture_and_sampler_let 기능이 지원되면 텍스처 또는 샘플러 타입. 필수 상수 식, 오버라이드 식 또는 런타임 식 아니요
var<storage, read>
var<storage>
불변 모듈 구체 호스트 공유 가능 허용되지 않음 예.
스토리지 버퍼
var<storage, read_write>5,6 가변 모듈 구체 호스트 공유 가능 허용되지 않음 예.
스토리지 버퍼
var<uniform> 불변 모듈 구체 생성 가능 호스트 공유 가능 타입 또는 고정 크기 버퍼 허용되지 않음 예.
유니폼 버퍼
var<immediate> 불변 모듈 배열 및 배열 멤버를 포함하는 구조체를 제외한 구체 생성 가능 호스트 공유 가능 타입 허용되지 않음 예.
즉시 데이터
var5 불변7 모듈 텍스처 허용되지 않음 예.
텍스처 리소스
var 불변 모듈 샘플러 허용되지 않음 예.
샘플러 리소스
var<workgroup>6,8 가변 모듈 고정 풋프린트를 가진 구체 일반 타입 또는 고정 크기 버퍼9 허용되지 않음10 아니요
var<private> 가변 모듈 구체 생성 가능 선택 사항10 상수 식 또는 오버라이드 식 아니요
var<function>
var
가변 함수 구체 생성 가능 선택 사항10 상수 식, 오버라이드 식 또는 런타임 식 아니요
  1. const 선언추상 타입일 수 있으며, 타입을 명시적으로 지정하지 않은 경우에만 가능하다.

  2. 식의 타입을 유효 값 타입으로 실현 가능하게 변환할 수 있어야 한다.

  3. 초기화 값을 지정하지 않으면 파이프라인 생성 시점에 값을 제공해야 한다.

  4. 오버라이드 선언은 셰이더 인터페이스의 일부지만 바인딩된 리소스는 아니다.

  5. read 이외의 접근 모드를 가진 스토리지 버퍼스토리지 텍스처에는 버텍스 셰이더 단계에서 정적으로 접근할 수 없다. WebGPU createBindGroupLayout()을 참조한다.

  6. 원자 타입은 가변 스토리지 버퍼 또는 작업 그룹 변수에만 나타날 수 있다.

  7. write 또는 read_write 접근 모드를 가진 스토리지 텍스처의 데이터는 변경할 수 있지만, textureStore 내장 함수를 통해서만 수정할 수 있다. 변수 자체는 수정할 수 없다.

  8. workgroup 주소 공간의 변수에는 컴퓨트 셰이더 단계에서만 정적으로 접근할 수 있다.

  9. 가장 바깥쪽 배열요소 수 또는 버퍼의 크기는 오버라이드 식일 수 있다.

  10. 초기화 값이 없으면 변수를 기본 초기화한다.

7.1. 변수와 값 비교

변수 선언은 WGSL 모듈에서 유일한 가변 데이터이다. 값 선언은 항상 불변이다. 변수에는 연결된 메모리 위치가 있으므로 참조포인터 값의 기초가 될 수 있지만, 값 선언은 포인터나 참조 값의 기초가 될 수 없다.

변수를 사용하려면 변수에 연결된 메모리 위치읽거나 쓰기 위한 추가 연산이 필요하므로, 일반적으로 값 선언을 사용하는 것보다 비용이 더 많이 든다.

일반적으로 작성자는 가장 선호되는 선택지가 먼저 나열된 다음 순서로 선언을 사용하는 것이 좋다.

일반적으로 이렇게 하면 셰이더의 전체 성능이 가장 좋아진다.

7.2. 값 선언

식별자값 선언으로 해석되면 해당 식별자는 그 값을 나타낸다.

WGSL은 여러 종류의 값 선언을 제공한다. 각 선언 종류의 값은 셰이더 수명 주기의 서로 다른 시점에 확정된다. 값 선언의 종류와 해당 값이 확정되는 시점은 다음과 같다.

참고: 형식 매개변수§ 11 함수에 설명되어 있다.

7.2.1. const 선언

const 선언셰이더 생성 시점에 확정되는 데이터 값의 이름을 지정한다. 각 const 선언에는 초기화 값이 필요하다. const 선언은 모듈 또는 함수 범위에서 선언할 수 있다. 초기화 식은 상수 식이어야 한다. const 선언의 타입은 구체 또는 추상 생성 가능 타입이어야 한다. const 선언은 유효 값 타입추상일 수 있는 유일한 선언이다.

참고: 추상 숫자 타입은 WGSL에서 표기할 수 없으므로 타입 추론을 통해서만 사용할 수 있다.

예: 모듈 범위의 const 선언
const a = 4;                  // 값이 4인 AbstractInt.
const b : i32 = 4;            // 값이 4인 i32.
const c : u32 = 4;            // 값이 4인 u32.
const d : f32 = 4;            // 값이 4인 f32.
const e = vec3(a, a, a);      // 값이 (4, 4, 4)인 AbstractInt의 vec3.
const f = 2.0;                // 값이 2인 AbstractFloat.
const g = mat2x2(a, f, a, f); // 다음 값을 가진 AbstractFloat의 mat2x2:
                              // ((4.0, 2.0), (4.0, 2.0)).
                              // AbstractInt a는 AbstractFloat로 변환된다.
                              // AbstractFloat는 AbstractInt로 변환될 수 없다.
const h = array(a, f, a, f);  // 네 개의 성분으로 구성된 AbstractFloat 배열:
                              // (4.0, 2.0, 4.0, 2.0).

7.2.2. override 선언

오버라이드 선언파이프라인 오버라이드 가능 상숫값의 이름을 지정한다. 오버라이드 선언은 모듈 범위에서만 선언되어야 한다. 파이프라인 오버라이드 가능 상수의 값은 파이프라인 생성 시점에 확정된다. 값이 지정되면 WebGPU 파이프라인 생성 메서드에서 제공한 값을 사용하고, 그렇지 않으면 구체화된 초기화 식의 값을 사용한다. 오버라이드 선언의 유효 값 타입구체 스칼라 타입이어야 한다.

초기화 식은 선택 사항이다. 초기화 식이 있으면 오버라이드 식이어야 하며, 파이프라인 오버라이드 가능 상수의 기본값을 나타낸다. 초기화 값을 지정하지 않았고 파이프라인 생성 시점에도 값을 제공하지 않으면 파이프라인 생성 오류이다.

선언에 id 특성이 적용되면 리터럴 피연산자를 파이프라인 상수 ID라고 하며, 이 값은 0 이상 65535 이하의 고유한 정수여야 한다. 즉, 두 오버라이드 선언이 동일한 파이프라인 상수 ID를 사용해서는 안 된다.

애플리케이션은 파이프라인 생성 시점에 오버라이드 선언의 값을 직접 지정할 수 있다. 파이프라인 생성 API는 오버라이드 가능한 상수에서 해당 상수 타입의 값으로 이어지는 매핑을 받는다. 상수는 파이프라인 오버라이드 가능 상수 식별자 문자열로 식별된다. 이 문자열은 파이프라인 상수 ID가 지정된 경우 파이프라인 상수 ID의 10진수 표현이고, 그렇지 않으면 선언된 상수의 이름이다.

예: 파이프라인에서 오버라이드할 수 있는 모듈 상수
@id(0)    override has_point_light: bool = true;  // 알고리즘 제어
@id(1200) override specular_param: f32 = 2.3;     // 숫자 제어
@id(1300) override gain: f32;                     // 반드시 오버라이드해야 함
          override width: f32 = 0.0;              // API 수준에서 "width"라는
                                                  // 이름을 사용하여 지정한다.
          override depth: f32;                    // API 수준에서 "depth"라는
                                                  // 이름을 사용하여 지정한다.
                                                  // 반드시 오버라이드해야 한다.
          override height = 2 * depth;            // 기본값은 API 수준에서
                                                  // 설정되지 않은 경우 다른
                                                  // 오버라이드 가능한 상수에
                                                  // 따라 달라진다.

7.2.3. let 선언

let 선언은 런타임에 해당 문이 실행될 때마다 확정되는 값의 이름을 지정한다. let 선언은 함수 범위에서만 선언되어야 하며, 따라서 동적 컨텍스트이다. let 선언에는 초기화 식이 있어야 한다. 값은 초기화 값의 구체화된 값이다. let 선언의 유효 값 타입구체 생성 가능 타입 또는 포인터 타입 중 하나여야 한다. texture_and_sampler_let 기능이 지원되면 유효 값 타입이 텍스처 또는 샘플러 타입일 수도 있다.

참고: 버퍼 타입은 생성 가능하지 않으므로 버퍼의 포인터만 let 선언이 될 수 있다.

예: 함수 범위에서 let으로 선언된 상수
// 'blockSize'는 i32 값 1024를 나타낸다.
let blockSize: i32 = 1024;

// 'row_size'는 u32 값 16u를 나타낸다. 타입은 추론된다.
let row_size = 16u;

7.3. var 선언

변수는 특정 저장 가능한 타입의 값을 포함할 수 있는 메모리에 대한 이름 있는 참조이다.

변수에는 저장소 타입과 참조 타입이라는 두 가지 타입이 연결된다. 저장소 타입은 참조되는 메모리에 배치할 수 있는 값의 타입이고, 참조 타입은 변수 자체의 타입이다. 변수의 저장소 타입이 T, 주소 공간AS, 접근 모드AM이면 참조 타입은 ref<AS,T,AM>이다. 변수의 저장소 타입은 항상 구체 타입이다.

변수 선언은 다음을 수행한다.

식별자가 변수 선언으로 해석되면, 해당 식별자는 변수 메모리의 참조 메모리 뷰를 나타내는 식이며 타입은 변수의 참조 타입이다. § 8.12 변수 식별자 식을 참조한다.

변수 선언의 주소 공간 또는 접근 모드가 프로그램 소스에 지정되면 var 키워드 뒤의 템플릿 목록으로 작성한다.

private, storage, uniform, workgrouphandle 주소 공간의 변수는 모듈 범위에서만 선언되어야 한다. 반면 function 주소 공간의 변수는 함수 범위에서만 선언되어야 한다. handle과 function을 제외한 모든 주소 공간에는 주소 공간을 지정해야 한다. handle 주소 공간을 지정해서는 안 된다. function 주소 공간 지정은 선택 사항이다.

접근 모드에는 항상 기본값이 있다. storage 주소 공간의 변수를 제외하면 접근 모드를 WGSL 소스에서 지정해서는 안 된다. § 14.3 주소 공간을 참조한다.

uniform 주소 공간의 변수는 유니폼 버퍼 변수이다. 저장소 타입은 호스트 공유 가능 생성 가능 타입 또는 고정 크기 버퍼 타입이어야 하며, 주소 공간 레이아웃 제약 조건을 충족해야 한다.

storage 주소 공간의 변수는 스토리지 버퍼 변수이다. 저장소 타입은 호스트 공유 가능 타입이어야 하며 주소 공간 레이아웃 제약 조건을 충족해야 한다. 변수는 read 또는 read_write 접근 모드로 선언할 수 있으며 기본값은 read이다.

immediate 주소 공간의 변수는 즉시 데이터 변수이다. 저장소 타입은 배열과 배열 멤버를 포함하는 구조체를 제외한 호스트 공유 가능 생성 가능 타입이어야 한다. 각 진입점은 최대 하나의 즉시 데이터 변수에 정적으로 접근해야 한다. 즉시 변수의 값은 WebGPU API 명령 인코더가 기록한 setImmediates 명령을 통해 설정되며, 셰이더가 실행되는 동안 일정하게 유지된다. 변수 크기는 파이프라인 레이아웃의 immediateSize 구성으로 제한된다.

AccessibleSlots는 구조체 멤버 사이와 구조체 끝의 패딩 바이트를 제외한다. 셰이더에서 즉시 데이터 변수에 접근하기 전에 WebGPU API를 통해 접근 가능한 슬롯만 초기화하면 된다.

텍스처 리소스유효 값 타입텍스처 타입인 변수이다. 모듈 범위에서 선언된다. 텍스처의 기반 텍셀 격자에 접근하는 데 사용되는 불투명 핸들을 보유한다. 핸들 자체는 handle 주소 공간에 있으며 항상 읽기 전용이다. 많은 경우 기반 텍셀은 읽기 전용이며 이때 텍스처 변수가 불변이라고 한다. 쓰기 전용 스토리지 텍스처읽기-쓰기 스토리지 텍스처에서는 기반 텍셀을 변경할 수 있으며, 관례적으로 텍스처 변수가 가변이라고 한다.

샘플러 리소스유효 값 타입샘플러 타입인 변수이다. 모듈 범위에서 선언되며 handle 주소 공간에 존재하고 불변이다.

§ 13.3.2 리소스 인터페이스에 설명된 것처럼 유니폼 버퍼, 스토리지 버퍼, 텍스처 및 샘플러는 셰이더의 리소스 인터페이스를 구성한다.

변수의 수명은 셰이더 실행 중 메모리 위치가 변수와 연결되는 기간이다. 모듈 범위 변수의 수명은 셰이더 단계 실행 전체이다. 각 호출에는 privatefunction 주소 공간의 독립적인 변수 버전이 있다. 함수 범위 변수는 동적 컨텍스트이다. 함수 범위 변수의 수명은 해당 범위에 따라 결정된다.

리소스 변수의 메모리 위치가 겹칠 수 있지만, 두 변수 중 하나라도 가변이면 동적 오류이다. 수명이 겹치는 다른 변수의 메모리 위치는 서로 겹치지 않는다. 변수의 수명이 끝나면 해당 메모리를 다른 변수에 사용할 수 있다.

참고: WGSL은 변수의 내용을 해당 변수의 수명 동안에만 관찰할 수 있도록 보장한다.

private, function 또는 workgroup 주소 공간의 변수가 생성되면 초깃값을 가진다. 초기화 값을 지정하지 않으면 초깃값은 기본 초깃값이다. 초깃값은 다음과 같이 계산된다.

다른 주소 공간의 변수는 그리기 명령 또는 디스패치 명령의 바인딩으로 설정되는 리소스이다.

다음 WGSL 코드 조각을 살펴보자.

예: 변수 초깃값
var i: i32;         // 초깃값은 0이다. 권장되는 스타일은 아니다.
loop {
  var twice: i32 = 2 * i;   // 반복할 때마다 다시 평가된다.
  i++;
  if i == 5 { break; }
}
루프 본문은 여섯 번 실행된다. 변수 i는 0, 1, 2, 3, 4, 5의 값을 가지며 변수 twice는 0, 2, 4, 6, 8의 값을 가진다.

다음 WGSL 코드 조각을 살펴보자.

예: 변수를 여러 번 읽기
var x: f32 = 1.0;
let y = x * x + x + 1;
x는 변수이므로 이에 대한 모든 접근은 로드 및 저장 연산으로 변환된다. 그러나 브라우저 또는 드라이버가 중복 로드를 제거하도록 이 중간 표현을 최적화할 것으로 예상된다.
예: 모듈 범위 변수 선언
var<private> decibels: f32;
var<workgroup> worklist: array<i32,10>;

struct Params {
  specular: f32,
  count: i32
}

// 유니폼 버퍼. 항상 읽기 전용이며 더 엄격한 레이아웃 규칙을 가진다.
@group(0) @binding(2)
var<uniform> param: Params;    // 유니폼 버퍼

// 읽기 및 쓰기를 위한 스토리지 버퍼
@group(0) @binding(0)
var<storage,read_write> pbuf: array<vec2<f32>>;

// 텍스처와 샘플러는 항상 "handle" 공간에 있다.
@group(0) @binding(1)
var filter_params: sampler;
예: 버퍼의 접근 모드
// 스토리지 버퍼
@group(0) @binding(0)
var<storage,read> buf1: Buffer;       // 읽을 수 있지만 쓸 수 없다.
@group(0) @binding(0)
var<storage> buf2: Buffer;            // 읽을 수 있지만 쓸 수 없다.
@group(0) @binding(1)
var<storage,read_write> buf3: Buffer; // 읽기와 쓰기가 모두 가능하다.

struct ParamsTable {weight: f32}

// 유니폼 버퍼. 항상 읽기 전용이며 더 엄격한 레이아웃 규칙을 가진다.
@group(0) @binding(2)
var<uniform> params: ParamsTable;     // 읽을 수 있지만 쓸 수 없다.
예: 함수 범위 변수 및 상수
fn f() {
   var<function> count: u32;  // function 주소 공간의 변수.
   var delta: i32;            // function 주소 공간의 또 다른 변수.
   var sum: f32 = 0.0;        // 초기화 값이 있는 function 주소 공간 변수.
   var pi = 3.14159;          // 초기화 값에서 f32 저장소 타입을 추론한다.
}

7.4. 변수 및 값 선언 문법 요약

variable_or_value_statement :

variable_decl

| variable_decl '=' expression

| 'let' optionally_typed_ident '=' expression

| 'const' optionally_typed_ident '=' expression

variable_decl :

'var' _disambiguate_template template_list ? optionally_typed_ident

optionally_typed_ident :

ident ( ':' type_specifier ) ?

global_variable_decl :

attribute * variable_decl ( '=' expression ) ?

global_value_decl :

'const' optionally_typed_ident '=' expression

| attribute * 'override' optionally_typed_ident ( '=' expression ) ?

8.

은 값이 계산되는 방식을 지정한다.

다양한 종류의 값 식은 평가되는 시점과 표현할 수 있는 범위 사이의 절충을 제공한다. 평가가 빠를수록 연산에 더 많은 제약이 있지만, 그 값을 사용할 수 있는 위치는 더 많아진다. 이러한 절충으로 인해 각 값 선언 종류마다 서로 다른 유연성이 생긴다. 상수 식오버라이드 식은 GPU에서 실행되기 전에 평가되므로 최종 GPU 코드에는 식을 계산한 결과만 필요하다. 또한 상수 식셰이더 생성 시점에 평가되므로 오버라이드 식보다 더 많은 상황에서 사용할 수 있다. 예를 들어 함수 범위 변수배열 크기를 정하는 데 사용할 수 있다. 런타임 식상수 식오버라이드 식도 아닌 식이다. 런타임 식은 셰이더 실행 중 GPU에서 계산된다. 런타임 식을 사용할 수 있는 문법 요소는 더 적지만, 다른 런타임 값과 같이 더 폭넓은 종류의 식으로부터 계산할 수 있다.

8.1. 조기 평가 식

WGSL은 런타임 전에 평가할 수 있는 두 종류의 식을 정의한다.

8.1.1. const

셰이더 생성 시점에 평가할 수 있는 식을 상수 식이라고 한다. 식의 모든 식별자가 다음 중 하나로 해석되면 그 식은 상수 식이다.

const 식의 타입은 생성 시 고정된 풋프린트를 갖는 타입으로 해석되어야 한다.

참고: 추상 타입은 상수 식의 추론된 타입이 될 수 있다.

상수 식 E는 다음 중 하나에 해당하는 경우에만 평가된다.

참고: 이 평가 규칙은 단락 평가 연산자 &&||정적 타입을 결정하기 위해 평가해야 하는 부분식이 없는 한 오른쪽 부분식의 평가를 차단한다는 것을 뜻한다.

상수 식은 WebGPU API 메서드를 구현하는 CPU에서 평가될 수 있다. 따라서 AbstractFloat 값에 대한 연산의 정확도 요구 사항은 WebAssembly [WASM-CORE-2] 및 ECMAScript [ECMASCRIPT]와 같은 일반적인 WebGPU 런타임 환경에서 요구되는 것보다 더 엄격하지 않다. 구체 부동 소수점 타입(예: f32)에 대한 정확도 요구 사항은 § 15.7.4.1 구체 부동 소수점 식의 정확도에 명시되어 있다.

예: (42)는 다음과 같이 분석된다.

예: -5는 다음과 같이 분석된다.

예: -2147483648은 다음과 같이 분석된다.

예: const minint = -2147483648;은 다음과 같이 분석된다.

예: let minint = -2147483648;은 다음과 같이 분석된다.

예: false && (10i < i32(5 * 1000 * 1000 * 1000))은 다음과 같이 분석된다.

예: false && array<u32, 1 + 2>(0, 1, 2)[0] == 0

8.1.2. override

파이프라인 생성 시점에 평가할 수 있는 식을 오버라이드 식이라고 한다. 식의 모든 식별자가 다음 중 하나로 해석되면 그 식은 오버라이드 식이다.

참고: 모든 상수 식은 오버라이드 식이기도 하다.

상수 식이 아닌 오버라이드 식은 파이프라인 생성 중에만, 그리고 API가 제공한 값을 오버라이드 선언에 대입한 후에만 검증되거나 평가된다. 오버라이드 선언의 값이 API를 통해 대입되면, 이니셜라이저 식이 있더라도 평가되지 않는다. 그렇지 않으면 오버라이드 식 E는 다음 조건을 모두 만족하는 경우에만 평가된다.

참고: 모든 오버라이드 식을 오버라이드 선언의 이니셜라이저로 사용할 수 있는 것은 아니다. 이러한 이니셜라이저는 구체 스칼라 타입으로 해석되어야 하기 때문이다.

예: override x = 42;는 다음과 같이 분석된다.

예: let y = x + 1;은 다음과 같이 분석된다.

예: vec3(x,x,x)는 다음과 같이 분석된다.

예: 오버라이드 식에서 발생하는 셰이더 생성 오류
override a : i32 = 0;
override b = a / 0; // c 오버라이드를 시도하는지와 관계없이
                    // 셰이더 생성 오류
예: 오버라이드 식에서 발생하는 파이프라인 생성 오류
override a : i32 = 0;
override b = 1 / a;

// b는 frag1 셰이더의 일부이다. frag1을 파이프라인으로 컴파일할 때
// 다음과 같은 경우가 발생할 수 있다.
// * b가 오버라이드되면 오류가 발생하지 않는다.
// * a가 0이 아닌 값으로 오버라이드되면 오류가 발생하지 않는다.
// * a가 0이고 b가 오버라이드되지 않으면 파이프라인 생성 오류가 발생한다.
@fragment
fn frag1() {
  _ = b;
}

// b는 frag2 셰이더의 일부가 아니다. frag2를 파이프라인으로 컴파일할 때는
// b가 오버라이드되지 않고 a의 값이 0이어도 오류가 발생하지 않는다.
@fragment
fn frag2() {
}

8.2. 미정 값

제한적인 경우에 런타임 식은 그 부분식에 지원되지 않는 값을 사용하여 평가될 수 있다.

그러한 경우 평가 결과는 식의 정적 타입에 속하는 미정 값이다. 즉, 구현이 임의로 선택한 정적 타입의 값이다.

식이 평가되는 각각의 고유한 동적 컨텍스트마다 별개의 값이 생성될 수 있다. 예를 들어 루프의 각 반복에서 평가가 한 번씩 일어나면 반복마다 서로 다른 값이 계산될 수 있다.

참고: 타입이 부동 소수점 타입이고 구현이 NaN 값을 지원한다면 런타임에 생성되는 미정 값은 NaN 값일 수 있다.

예: 미정 값 예제
fn fun() {
   var extracted_values: array<i32,2>;
   const v = vec2<i32>(0,1);

   for (var i: i32 = 0; i < 2 ; i++) {
      // 벡터를 인덱싱하는 데 사용된 런타임 식이 벡터의
      // 인덱싱 범위를 벗어나면 벡터 컴포넌트 타입의
      // 미정 값이 생성된다.
      let extract = v[i+5];

      // 이제 'extract'는 i32 타입의 임의의 값이다.

      // 나중을 위해 저장한다.
      extracted_values[i] = extract;

      if extract == extract {
         // 항상 실행된다
      }
      if extract < 2 {
         // 실행될 수도 있고 실행되지 않을 수도 있다.
         // 원래 벡터 컴포넌트가 0과 1이더라도
         // 추출된 값은 이 두 값 중 어느 것도 아닐 수 있다.
      }
   }
   if extracted_values[0] == extracted_values[1] {
      // 실행될 수도 있고 실행되지 않을 수도 있다.
   }
}

fn float_fun(runtime_index: u32) {
   const v = vec2<f32>(0,1); // 부동 소수점 값의 벡터

   // 앞의 예와 마찬가지로 'float_extract'는 미정 값이다.
   // 부동 소수점 타입이므로 NaN일 수 있다.
   let float_extract: f32 = v[runtime_index+5];

   if float_extract == float_extract {
      // 다음 이유로 실행되지 *않을 수도* 있다.
      //  -  'float_extract'가 NaN일 수 있고,
      //  -  NaN은 다른 어떤 부동 소수점 숫자와도 같지 않으며,
      //     다른 NaN과도 같지 않다.
   }
}

8.3. 리터럴 값 식

스칼라 리터럴 타입 규칙
전제 조건 결론 설명
true: bool true 불리언 값.
false: bool false 불리언 값.
e는 접미사가 없는 정수 리터럴 e: AbstractInt 추상 정수 리터럴 값.
e는 접미사가 없는 부동 소수점 리터럴 e: AbstractFloat 추상 부동 소수점 리터럴 값.
ei 접미사가 있는 정수 리터럴 e: i32 32비트 부호 있는 정수 리터럴 값.
eu 접미사가 있는 정수 리터럴 e: u32 32비트 부호 없는 정수 리터럴 값.
ef 접미사가 있는 부동 소수점 리터럴 e: f32 32비트 부동 소수점 리터럴 값.
eh 접미사가 있는 부동 소수점 리터럴 e: f16 16비트 부동 소수점 리터럴 값.

8.4. 괄호로 묶인 식

괄호로 묶인 식의 타입 규칙
전제 조건 결론 설명
e : T ( e ) : T e로 평가된다.
주변 텍스트에서 식을 분리하려면 괄호를 사용한다.

8.5. 복합 값 분해 식

이 절에서는 다음을 위한 식을 설명한다.

이 논의에서 복합 값, 복합 값에 대한 메모리 뷰 또는 스위즐 뷰를 베이스라고 한다.

이러한 식을 구성하는 방법은 두 가지이다.

명명된 컴포넌트 식

베이스 B에 대한 식 뒤에 마침표 '.'(U+002D)를 쓰고 그 뒤에 컴포넌트의 이름을 쓴다.

  • B벡터 또는 구조체 타입이거나, 벡터 또는 구조체 타입에 대한 메모리 뷰이거나, 스위즐 뷰인 경우 지원된다.

  • 유효한 이름은 B의 타입에 따라 달라진다.

인덱싱 식

베이스에 대한 식 뒤에 '['(U+005B), 인덱스에 대한 식, ']'(U+005D)을 차례로 쓴다.

참고: 스위즐 뷰는 인덱싱 식을 직접 지원하지 않는다. 스위즐 뷰 뒤에 인덱싱 식 절이 나타나면 먼저 스위즐 뷰 로드 규칙을 적용하여 벡터 값을 생성한 다음, 그 벡터 값에 인덱싱 식을 적용한다.

구문상 이 두 형식은 component_or_swizzle_specifier 문법 규칙을 사용하여 구현된다.

인덱싱 식의 인덱스 값 i는 0 ≤ i < N이면 범위 내 인덱스이다. 여기서 N은 복합 타입의 컴포넌트(요소) 개수이다.

인덱스 값이 범위 내 인덱스가 아니면 범위를 벗어난 인덱스이다. 범위를 벗어난 인덱스는 대개 프로그래밍 결함이며 흔히 오류를 일으킨다. 자세한 내용은 아래를 참조한다.

또한 벡터 타입은 다른 벡터의 컴포넌트로부터 새 벡터 값을 생성하는 스위즐 구문을 지원한다.

8.5.1. 벡터 접근 식

벡터의 컴포넌트에는 다음 방법 중 하나로 접근할 수 있다.

편의 이름에는 . 표기법을 사용하여 접근한다(예: color.bgra).

편의 문자 표기 집합을 혼합해서는 안 된다. 예를 들어 .rybw는 사용할 수 없다.

편의 문자는 벡터 끝을 넘어선 컴포넌트에 접근해서는 안 된다.

편의 문자는 필요에 따라 문자를 중복하는 것을 포함하여 어떤 순서로든 적용할 수 있다. 제공되는 문자 수는 1개에서 4개 사이여야 한다. 즉, 편의 문자를 사용하면 스칼라 타입이나 유효한 벡터 타입만 생성할 수 있다.

결과 타입은 제공된 문자 수에 따라 달라진다. vec4<f32>를 가정하면 다음과 같다.

접근자 결과 타입
r f32
rg vec2<f32>
rgb vec3<f32>
rgba vec4<f32>
var a: vec3<f32> = vec3<f32>(1., 2., 3.);
var b: f32 = a.y;          // b = 2.0
var c: vec2<f32> = a.bb;   // c = (3.0, 3.0)
var d: vec3<f32> = a.zyx;  // d = (3.0, 2.0, 1.0)
var e: f32 = a[1];         // e = 2.0
8.5.1.1. 벡터 단일 컴포넌트 선택
벡터 분해: 단일 컴포넌트 선택
전제 조건 결론 설명
e: vecN<T>
e.x: T
e.r: T
e의 첫 번째 컴포넌트를 선택한다.

이는 단일 문자 스위즐이다.

e: vecN<T>
e.y: T
e.g: T
e의 두 번째 컴포넌트를 선택한다.

이는 단일 문자 스위즐이다.

e: vecN<T>
N은 3 또는 4
e.z: T
e.b: T
e의 세 번째 컴포넌트를 선택한다.

이는 단일 문자 스위즐이다.

e: vec4<T> e.w: T
e.a: T
e의 네 번째 컴포넌트를 선택한다.

이는 단일 문자 스위즐이다.

e: vecN<T>
i: i32 또는 u32
T구체
e[i]: T 벡터의 i번째 컴포넌트를 선택한다.
첫 번째 컴포넌트의 인덱스는 i=0이다.

i가 범위 [0,N-1] 밖에 있는 경우:

e: vecN<T>
i: i32 또는 u32
T추상
i상수 식
e[i]: T 벡터의 i번째 컴포넌트를 선택한다.
첫 번째 컴포넌트의 인덱스는 i=0이다.

i가 범위 [0,N-1] 밖에 있으면 셰이더 생성 오류이다.

참고: 추상 벡터 값 e상수 식이 아닌 식으로 인덱싱하면, 인덱스를 적용하기 전에 벡터가 구체화된다.

8.5.1.2. 벡터 다중 컴포넌트 선택

이 절의 식은 내부 식에 다중 문자 스위즐을 적용한다.

참고: swizzle_assignment 언어 확장이 지원되지 않으면 다중 문자 스위즐할당의 왼쪽에 나타날 수 없다. 할당의 왼쪽은 참조 타입이어야 하지만, 확장이 없으면 다중 문자 스위즐 식은 항상 벡터 타입의 값을 생성하기 때문이다.

벡터 분해: 다중 컴포넌트 선택
전제 조건 결론 설명
e: vecN<T>
I는 문자 x, y, z 또는 w
J는 문자 x, y, z 또는 w
e.IJ: vec2<T>
첫 번째 컴포넌트가 e.I이고 두 번째 컴포넌트가 e.J인 2컴포넌트 벡터를 계산한다.
문자 zN이 3 또는 4일 때만 유효하다.
문자 wN이 4일 때만 유효하다.
e: vecN<T>
I는 문자 r, g, b 또는 a
J는 문자 r, g, b 또는 a
e.IJ: vec2<T>
첫 번째 컴포넌트가 e.I이고 두 번째 컴포넌트가 e.J인 2컴포넌트 벡터를 계산한다.
문자 bN이 3 또는 4일 때만 유효하다.
문자 aN이 4일 때만 유효하다.
e: vecN<T>
I는 문자 x, y, z 또는 w
J는 문자 x, y, z 또는 w
K는 문자 x, y, z 또는 w
e.IJK: vec3<T>
첫 번째 컴포넌트가 e.I, 두 번째 컴포넌트가 e.J, 세 번째 컴포넌트가 e.K인 3컴포넌트 벡터를 계산한다.
문자 zN이 3 또는 4일 때만 유효하다.
문자 wN이 4일 때만 유효하다.
e: vecN<T>
I는 문자 r, g, b 또는 a
J는 문자 r, g, b 또는 a
K는 문자 r, g, b 또는 a
e.IJK: vec3<T>
첫 번째 컴포넌트가 e.I, 두 번째 컴포넌트가 e.J, 세 번째 컴포넌트가 e.K인 3컴포넌트 벡터를 계산한다.
문자 bN이 3 또는 4일 때만 유효하다.
문자 aN이 4일 때만 유효하다.
e: vecN<T>
I는 문자 x, y, z 또는 w
J는 문자 x, y, z 또는 w
K는 문자 x, y, z 또는 w
L는 문자 x, y, z 또는 w
e.IJKL: vec4<T>
첫 번째 컴포넌트가 e.I, 두 번째 컴포넌트가 e.J, 세 번째 컴포넌트가 e.K, 네 번째 컴포넌트가 e.L인 4컴포넌트 벡터를 계산한다.
문자 zN이 3 또는 4일 때만 유효하다.
문자 wN이 4일 때만 유효하다.
e: vecN<T>
I는 문자 r, g, b 또는 a
J는 문자 r, g, b 또는 a
K는 문자 r, g, b 또는 a
L는 문자 r, g, b 또는 a
e.IJKL: vec4<T>
첫 번째 컴포넌트가 e.I, 두 번째 컴포넌트가 e.J, 세 번째 컴포넌트가 e.K, 네 번째 컴포넌트가 e.L인 4컴포넌트 벡터를 계산한다.
문자 bN이 3 또는 4일 때만 유효하다.
문자 aN이 4일 때만 유효하다.
벡터 메모리 뷰 분해: 스위즐 할당이 지원되지 않을 때의 다중 컴포넌트 선택
전제 조건 결론 설명
swizzle_assignment가 지원되지 않음

pr: ref<AS,vecN<T,AM>> 또는 ptr<AS,vecN<T,AM>>
I는 문자 x, y, z 또는 w
J는 문자 x, y, z 또는 w
AMread 또는 read_write

pr.IJ: vec2<T>
평가 시점에 pr가 참조하는 메모리 위치에 저장된 벡터를 e라고 할 때, e.IJ를 계산한다.

문자 zN이 3 또는 4일 때만 유효하다.
문자 wN이 4일 때만 유효하다.

swizzle_assignment가 지원되지 않음

pr: ref<AS,vecN<T,AM>> 또는 ptr<AS,vecN<T,AM>>
I는 문자 r, g, b 또는 a
J는 문자 r, g, b 또는 a
AMread 또는 read_write

pr.IJ: vec2<T>
평가 시점에 pr가 참조하는 메모리 위치에 저장된 벡터를 e라고 할 때, e.IJ를 계산한다.

문자 bN이 3 또는 4일 때만 유효하다.
문자 aN이 4일 때만 유효하다.

swizzle_assignment가 지원되지 않음

pr: ref<AS,vecN<T,AM>> 또는 ptr<AS,vecN<T,AM>>
I는 문자 x, y, z 또는 w
J는 문자 x, y, z 또는 w
K는 문자 x, y, z 또는 w
AMread 또는 read_write

pr.IJK: vec3<T>
평가 시점에 pr가 참조하는 메모리 위치에 저장된 벡터를 e라고 할 때, e.IJK를 계산한다.

문자 zN이 3 또는 4일 때만 유효하다.
문자 wN이 4일 때만 유효하다.

swizzle_assignment가 지원되지 않음

pr: ref<AS,vecN<T,AM>> 또는 ptr<AS,vecN<T,AM>>
I는 문자 r, g, b 또는 a
J는 문자 r, g, b 또는 a
K는 문자 r, g, b 또는 a
AMread 또는 read_write

pr.IJK: vec3<T>
평가 시점에 pr가 참조하는 메모리 위치에 저장된 벡터를 e라고 할 때, e.IJK를 계산한다.

문자 bN이 3 또는 4일 때만 유효하다.
문자 aN이 4일 때만 유효하다.

swizzle_assignment가 지원되지 않음

pr: ref<AS,vecN<T,AM>> 또는 ptr<AS,vecN<T,AM>>
I는 문자 x, y, z 또는 w
J는 문자 x, y, z 또는 w
K는 문자 x, y, z 또는 w
L는 문자 x, y, z 또는 w
AMread 또는 read_write

pr.IJKL: vec4<T>
평가 시점에 pr가 참조하는 메모리 위치에 저장된 벡터를 e라고 할 때, e.IJKL을 계산한다.

문자 zN이 3 또는 4일 때만 유효하다.
문자 wN이 4일 때만 유효하다.

swizzle_assignment가 지원되지 않음

pr: ref<AS,vecN<T,AM>> 또는 ptr<AS,vecN<T,AM>>
I는 문자 r, g, b 또는 a
J는 문자 r, g, b 또는 a
K는 문자 r, g, b 또는 a
L는 문자 r, g, b 또는 a
AMread 또는 read_write

pr.IJKL: vec4<T>
평가 시점에 pr가 참조하는 메모리 위치에 저장된 벡터를 e라고 할 때, e.IJKL을 계산한다.

문자 bN이 3 또는 4일 때만 유효하다.
문자 aN이 4일 때만 유효하다.

8.5.1.3. 벡터 메모리 뷰 또는 스위즐 뷰에서의 컴포넌트 참조

이 절의 식은 전체 벡터의 메모리 뷰 또는 스위즐 뷰로부터 메모리에 있는 벡터의 단일 컴포넌트에 대한 참조를 구성한다.

WGSL 타입 규칙에 따르면 이러한 식은 다음 위치에 나타날 수 있다.

벡터의 컴포넌트에 대한 쓰기 접근은 해당 벡터와 관련된 모든 메모리 위치에 접근할 수 있다.

참고: 이는 서로 다른 호출이 메모리에 있는 벡터의 서로 다른 컴포넌트에 접근할 때 접근 중 하나 이상이 쓰기 접근이면 해당 접근들을 동기화해야 한다는 뜻이다. § 17.11 동기화 내장 함수를 참조한다.

벡터에 대한 메모리 뷰에서 컴포넌트에 대한 참조 얻기
전제 조건 결론 설명
r: ref<AS,vecN<T>,AM> 또는
ptr<AS,vecN<T>,AM>
r.x: ref<AS,T,AM>
r.r: ref<AS,T,AM>
메모리 뷰 r이 참조하는 벡터의 첫 번째 컴포넌트에 대한 참조를 계산한다.
결과 참조의 기원 변수r의 기원 변수와 같다.
r: ref<AS,vecN<T>,AM> 또는
ptr<AS,vecN<T>,AM>
r.y: ref<AS,T,AM>
r.g: ref<AS,T,AM>
메모리 뷰 r이 참조하는 벡터의 두 번째 컴포넌트에 대한 참조를 계산한다.
결과 참조의 기원 변수r의 기원 변수와 같다.
r: ref<AS,vecN<T>,AM> 또는
ptr<AS,vecN<T>,AM>
N은 3 또는 4
r.z: ref<AS,T,AM>
r.b: ref<AS,T,AM>
메모리 뷰 r이 참조하는 벡터의 세 번째 컴포넌트에 대한 참조를 계산한다.
결과 참조의 기원 변수r의 기원 변수와 같다.
r: ref<AS,vec4<T>,AM> 또는
ptr<AS,vec4<T>,AM>
r.w: ref<AS,T,AM>
r.a: ref<AS,T,AM>
메모리 뷰 r이 참조하는 벡터의 네 번째 컴포넌트에 대한 참조를 계산한다.
결과 참조의 기원 변수r의 기원 변수와 같다.
r: ref<AS,vecN<T>,AM> 또는
ptr<AS,vecN<T>,AM>
i: i32 또는 u32
r[i] : ref<AS,T,AM>
메모리 뷰 r이 참조하는 벡터의 i번째 컴포넌트에 대한 참조를 계산한다.

i가 범위 [0,N-1] 밖에 있는 경우:

결과 참조의 기원 변수r의 기원 변수와 같다.

스위즐 뷰에서 컴포넌트에 대한 참조 얻기
전제 조건 결론 설명
sv : swizzle<AS,S,N,K>
sv.x : ref<AS,S,read_write>
sv.r : ref<AS,S,read_write>
sv스위즐 뷰(p, « Idx0,...,IdxK−1 »)라고 하자.

결과는 포인터 p에 대한 메모리 뷰 내부에서 인덱스가 Idx0인 컴포넌트에 대한 참조이다.

결과 참조의 기원 변수sv의 기원 변수와 같다.

sv : swizzle<AS,S,N,K>
sv.y : ref<AS,S,read_write>
sv.g : ref<AS,S,read_write>
sv스위즐 뷰(p, « Idx0,...,IdxK−1 »)라고 하자.

결과는 포인터 p에 대한 메모리 뷰 내부에서 인덱스가 Idx1인 컴포넌트에 대한 참조이다.

결과 참조의 기원 변수sv의 기원 변수와 같다.

sv : swizzle<AS,S,N,K>
여기서 K ≥ 3
sv.z : ref<AS,S,read_write>
sv.b : ref<AS,S,read_write>
sv스위즐 뷰(p, « Idx0,...,IdxK−1 »)라고 하자.

결과는 포인터 p에 대한 메모리 뷰 내부에서 인덱스가 Idx2인 컴포넌트에 대한 참조이다.

결과 참조의 기원 변수sv의 기원 변수와 같다.

sv : swizzle<AS,S,N,K>
여기서 K = 4
sv.w : ref<AS,S,read_write>
sv.a : ref<AS,S,read_write>
sv스위즐 뷰(p, « Idx0,...,IdxK−1 »)라고 하자.

결과는 포인터 p에 대한 메모리 뷰 내부에서 인덱스가 Idx3인 컴포넌트에 대한 참조이다.

결과 참조의 기원 변수sv의 기원 변수와 같다.

sv : swizzle<AS,S,N,K>
i : i32 또는 u32
sv[i] : ref<AS,S,read_write>
sv스위즐 뷰(p, « Idx0,...,IdxK−1 »)라고 하자.

i가 [0, K) 안에 있으면 식은 다음 참조이다.

(*p)[ Idxi ]

참고: sv유효하지 않은 스위즐 뷰이면 결과는 유효하지 않은 메모리 참조이다.

i가 [0,K) 밖에 있는 경우:

결과 참조의 기원 변수sv의 기원 변수와 같다.

8.5.2. 행렬 접근 식

열 벡터 추출
전제 조건 결론 설명
e: matCxR<T>
i: i32 또는 u32
T구체
e[i]: vecR<T> 결과는 ei번째 열 벡터이다.

i가 범위 [0,C-1] 밖에 있는 경우:

e: matCxR<T>
i: i32 또는 u32
T추상
i상수 식
e[i]: vecR<T> 결과는 ei번째 열 벡터이다.

i가 범위 [0,C-1] 밖에 있으면 셰이더 생성 오류이다.

참고: 추상 행렬 값 e상수 식이 아닌 식으로 인덱싱하면, 인덱스를 적용하기 전에 행렬이 구체화된다.

행렬에 대한 메모리 뷰에서 열 벡터에 대한 참조 얻기
전제 조건 결론 설명
r: ref<AS,matCxR<T>,AM> 또는
ptr<AS,matCxR<T>,AM>
i: i32 또는 u32
r[i] : ref<AS,vecR<T>,AM> 메모리 뷰 r이 참조하는 행렬의 i번째 열 벡터에 대한 참조를 계산한다.

i가 범위 [0,C-1] 밖에 있는 경우:

결과 참조의 기원 변수r의 기원 변수와 같다.

8.5.3. 배열 접근 식

배열 요소 추출
전제 조건 결론 설명
e: array<T,N>
i: i32 또는 u32
T구체
e[i] : T 결과는 배열 값 ei번째 요소 값이다.

i가 범위 [0,N-1] 밖에 있는 경우:

e: array<T,N>
i: i32 또는 u32
T추상
i상수 식
e[i] : T 결과는 배열 값 ei번째 요소 값이다.

i가 범위 [0,N-1] 밖에 있으면 셰이더 생성 오류이다.

참고: 추상 배열 값 e상수 식이 아닌 식으로 인덱싱하면, 인덱스를 적용하기 전에 배열이 구체화된다.

배열에 대한 메모리 뷰에서 배열 요소에 대한 참조 얻기
전제 조건 결론 설명
r: ref<AS,array<T,N>,AM> 또는
ptr<AS,array<T,N>,AM>
i: i32 또는 u32
r[i] : ref<AS,T,AM> 메모리 뷰 r이 참조하는 배열의 i번째 요소에 대한 참조를 계산한다.

i가 범위 [0,N-1] 밖에 있는 경우:

결과 참조의 기원 변수r의 기원 변수와 같다.

r: ref<AS,array<T>,AM> 또는
ptr<AS,array<T>,AM>
i: i32 또는 u32
r[i] : ref<AS,T,AM> 메모리 뷰 r이 참조하는 런타임 크기 배열의 i번째 요소에 대한 참조를 계산한다.

런타임에 배열에 N개의 요소가 있고 i가 범위 [0,N-1] 밖에 있으면 식은 유효하지 않은 메모리 참조로 평가된다.

i가 부호 있는 정수이고 i가 0보다 작은 경우:

결과 참조의 기원 변수r의 기원 변수와 같다.

8.5.4. 구조체 접근 식

구조체 멤버 추출
전제 조건 결론 설명
S는 구조체 타입
M은 타입이 TS 멤버의 식별자 이름
e: S
e.M: T 결과는 구조체 값 e에서 이름이 M인 멤버의 값이다.
구조체에 대한 메모리 뷰에서 구조체 멤버에 대한 참조 얻기
전제 조건 결론 설명
S는 구조체 타입
M은 타입이 TS 멤버의 식별자 이름
r: ref<AS,S,AM> 또는
ptr<AS,S,AM>
r.M: ref<AS,T,AM> 구조체에 대한 메모리 뷰가 주어지면 결과는 식별자 이름이 M인 구조체 멤버에 대한 참조이다.
결과 참조의 기원 변수r의 기원 변수와 같다.

8.6. 스위즐 뷰 식

스위즐 뷰 식은 swizzle_assignment 언어 확장으로 활성화된다.

스위즐 뷰는 다음과 같이 구성된다.

이러한 규칙에 따라 스위즐 뷰의 인덱스 목록 부분은 셰이더 생성 시점에 완전히 결정된다.

이 절에서는 스위즐 인덱스 함수 SI를 다음과 같이 정의한다.

다음 조건을 만족하면 스위즐 이름 ZK개의 인덱스 « Idx0, ..., IdxK−1 »를 나타낸다고 한다.

참고: 예를 들어 스위즐 wzyx는 네 인덱스 «3, 2, 1, 0»을 나타내고, 스위즐 rb는 두 인덱스 «0, 2»를 나타낸다. 스위즐 rgbzrgba 문자와 xyzw 문자를 혼합하므로 어떤 인덱스 시퀀스도 나타내지 않는다.

참조에서 스위즐 뷰 구성하기
전제 조건 결론 설명
swizzle_assignment가 지원됨

r: ref<AS,T,read_write>
T는 vecN<S>
스위즐 이름 ZK개의 인덱스 I = « Idx0, ..., IdxK−1 »를 나타냄
K는 {2,3,4}에 속함

r.Z : swizzle<AS,S,N,K> 결과는 스위즐 뷰(&r, I)이다.

I의 각 인덱스는 N보다 작아야 한다.

r유효하지 않은 메모리 참조이면 결과는 유효하지 않은 스위즐 뷰이다.

포인터에서 스위즐 뷰 구성하기
전제 조건 결론 설명
swizzle_assignment가 지원됨
pointer_composite_access가 지원됨

p: ptr<AS,T,read_write>
T는 vecN<S>
스위즐 이름 ZK개의 인덱스 I = « Idx0, ..., IdxK−1 »를 나타냄
K는 {2,3,4}에 속함

p.Z : swizzle<AS,S,N,K> 결과는 스위즐 뷰(p, I)이다.

I의 각 인덱스는 N보다 작아야 한다.

p유효하지 않은 포인터이면 결과는 유효하지 않은 스위즐 뷰이다.

스위즐 뷰에서 스위즐 뷰 구성하기
전제 조건 결론 설명
sv: swizzle<AS,S,N,Kin>
스위즐 이름 ZKZ개의 인덱스 IZ = « IZ [0], ..., IZ [KZ −1] »를 나타냄
KZ는 {2,3,4}에 속함
sv.Z : swizzle< AS,S,N,KZ > sv스위즐 뷰(p, Iin)라고 하자. 정의에 따라 시퀀스 Iin에는 Kin개의 항목이 있다.

Iout을 다음 시퀀스라고 하자.
« Iin [IZ [0]], ..., Iin [IZ [KZ -1]] »

식의 결과는 스위즐 뷰(p, Iout)이다.

IZ의 각 인덱스는 Kin보다 작아야 한다.

sv유효하지 않은 스위즐 뷰이면 결과는 유효하지 않은 스위즐 뷰이다.

8.7. 논리식

단항 논리 연산
전제 조건 결론 설명
e: T
T는 bool 또는 vecN<bool>
!e: T 논리 부정. efalse이면 결과는 true이고, etrue이면 결과는 false이다. T가 벡터이면 컴포넌트별로 적용된다.
이항 논리식
전제 조건 결론 설명
e1: bool
e2: bool
e1 || e2: bool 단락 평가 "or". e1 또는 e2 중 하나가 true이면 true를 생성한다. e1이 false인 경우에만 e2를 평가한다.
e1: bool
e2: bool
e1 && e2: bool 단락 평가 "and". e1e2가 모두 true이면 true를 생성한다. e1이 true인 경우에만 e2를 평가한다.
e1: T
e2: T
T는 bool 또는 vecN<bool>
e1 | e2: T 논리 "or". T가 벡터이면 컴포넌트별로 적용된다. e1e2를 모두 평가한다.
e1: T
e2: T
T는 bool 또는 vecN<bool>
e1 & e2: T 논리 "and". T가 벡터이면 컴포넌트별로 적용된다. e1e2를 모두 평가한다.

8.8. 산술식

단항 산술식
전제 조건 결론 설명
e: T
T는 AbstractInt, AbstractFloat, i32, f32, f16, vecN<AbstractInt>, vecN<AbstractFloat>, vecN<i32>, vecN<f32> 또는 vecN<f16>
-e: T 부정. T가 벡터이면 컴포넌트별로 적용된다. T정수 스칼라 타입이고 e가 가장 작은 음수 값으로 평가되면 결과는 e이다.
이항 산술식
전제 조건 결론 설명
e1 : T
e2 : T
S는 AbstractInt, AbstractFloat, i32, u32, f32 또는 f16
T는 S 또는 vecN<S>
e1 + e2 : T 덧셈. T가 벡터이면 컴포넌트별로 적용된다.

T가 부동 소수점 타입이면 스칼라 정의역은 다음을 제외한 확장 실수의 모든 순서쌍 (x,y)의 집합이다.

  • (−∞,+∞)

  • (+∞,−∞)

e1 : T
e2 : T
S는 AbstractInt, AbstractFloat, i32, u32, f32 또는 f16
T는 S 또는 vecN<S>
e1 - e2 : T 뺄셈. T가 벡터이면 컴포넌트별로 적용된다.

T가 부동 소수점 타입이면 스칼라 정의역은 다음을 제외한 확장 실수의 모든 순서쌍 (x,y)의 집합이다.

  • (−∞,−∞)

  • (+∞,+∞)

e1 : T
e2 : T
S는 AbstractInt, AbstractFloat, i32, u32, f32 또는 f16
T는 S 또는 vecN<S>
e1 * e2 : T 곱셈. T가 벡터이면 컴포넌트별로 적용된다.

T가 부동 소수점 타입이면 스칼라 정의역은 다음을 제외한 확장 실수의 모든 순서쌍 (x,y)의 집합이다.

  • (0,−∞)

  • (0,+∞)

  • (−∞, 0)

  • (+∞, 0)

e1 : T
e2 : T
S는 AbstractInt, AbstractFloat, i32, u32, f32 또는 f16
T는 S 또는 vecN<S>
e1 / e2 : T 나눗셈. T가 벡터이면 컴포넌트별로 적용된다.

T가 부호 있는 정수 스칼라 타입이면 다음과 같이 평가된다.

참고: 절단 동작을 보장해야 하므로 구현은 부호 없는 나눗셈을 계산할 때보다 더 많은 연산을 수행해야 할 수 있다. 두 피연산자의 부호가 같다고 알려져 있으면 부호 없는 나눗셈을 사용한다.

T가 부호 없는 정수 스칼라 타입이면 다음과 같이 평가된다.

T가 부동 소수점 타입이면 스칼라 정의역은 다음을 제외한 확장 실수의 모든 순서쌍 (x,y)의 집합이다.

  • (0,0)

  • (−∞,−∞)

  • (−∞,+∞)

  • (+∞,−∞)

  • (+∞,+∞)

e1 : T
e2 : T
S는 AbstractInt, AbstractFloat, i32, u32, f32 또는 f16
T는 S 또는 vecN<S>
e1 % e2 : T 나머지. T가 벡터이면 컴포넌트별로 적용된다.

T가 부호 있는 정수 스칼라 타입이면 e1e2를 한 번씩 평가하고 다음과 같이 평가된다.

참고: 0이 아닐 때 결과는 e1과 같은 부호를 갖는다.

참고: 일관된 동작을 보장해야 하므로 구현은 부호 없는 나머지를 계산할 때보다 더 많은 연산을 수행해야 할 수 있다.

T가 부호 없는 정수 스칼라 타입이면 다음과 같이 평가된다.

T가 부동 소수점 타입이면 결과는 다음과 같다.
e1 - e2 * trunc(e1 / e2).

T가 부동 소수점 타입이면 스칼라 정의역은 다음을 제외한 확장 실수의 모든 순서쌍 (x,y)의 집합이다.

  • x / y의 정의역 밖에 있는 경우:

    • (0,0)

    • (−∞,−∞)

    • (−∞,+∞)

    • (+∞,−∞)

    • (+∞,+∞)

  • y * trunc(x / y)의 정의역 밖에 추가로 존재하는 경우:

    • y가 무한대이고 x가 유한하여 trunc(x / y)가 0이 되는 경우.

    • y가 0이고 x가 무한대여서 trunc(x / y)가 무한대가 되는 경우.

스칼라와 벡터 피연산자가 혼합된 이항 산술식
전제 조건 결론 의미론
S는 AbstractInt, AbstractFloat, f32, f16, i32, u32 중 하나
V는 vecN<S>
es: S
ev: V
ev + es: V ev + V(es)
es + ev: V V(es) + ev
ev - es: V ev - V(es)
es - ev: V V(es) - ev
ev * es: V ev * V(es)
es * ev: V V(es) * ev
ev / es: V ev / V(es)
es / ev: V V(es) / ev
ev % es: V ev % V(es)
es % ev: V V(es) % ev
행렬 산술
전제 조건 결론 의미론
e1, e2: matCxR<T>
T는 AbstractFloat, f32 또는 f16
e1 + e2: matCxR<T>
행렬 덧셈: 결과는 컴포넌트별로 계산되며, 결과의 열 ie1[i] + e2[i]이다.
e1 - e2: matCxR<T> 행렬 뺄셈: 결과는 컴포넌트별로 계산되며, 결과의 열 ie1[i] - e2[i]이다.
m: matCxR<T>
s: T
T는 AbstractFloat, f32 또는 f16
m * s: matCxR<T>
컴포넌트별 스케일링: (m * s)[i][j]는 m[i][j] * s이다.
s * m: matCxR<T>
컴포넌트별 스케일링: (s * m)[i][j]는 m[i][j] * s이다.
m: matCxR<T>
v: vecC<T>
T는 AbstractFloat, f32 또는 f16
m * v: vecR<T>
선형대수의 행렬-열 벡터 곱: 결과의 컴포넌트 idot(transpose(m)[i],v)이다.
m: matCxR<T>
v: vecR<T>
T는 AbstractFloat, f32 또는 f16
v * m: vecC<T>
선형대수의 행 벡터-행렬 곱:
transpose(transpose(m) * transpose(v))
e1: matKxR<T>
e2: matCxK<T>
T는 AbstractFloat, f32 또는 f16
e1 * e2: matCxR<T>
선형대수의 행렬 곱.

8.9. 비교식

비교
전제 조건 결론 설명
e1: T
e2: T
S는 AbstractInt, AbstractFloat, bool, i32, u32, f32 또는 f16
TS 또는 vecN<S>
T가 벡터이면 TB는 vecN<bool>,
그렇지 않으면 TB는 bool
e1 == e2: TB 같음. T가 벡터이면 컴포넌트별로 적용된다.
e1: T
e2: T
S는 AbstractInt, AbstractFloat, bool, i32, u32, f32 또는 f16
TS 또는 vecN<S>
T가 벡터이면 TB는 vecN<bool>,
그렇지 않으면 TB는 bool
e1 != e2: TB 같지 않음. T가 벡터이면 컴포넌트별로 적용된다.
e1: T
e2: T
S는 AbstractInt, AbstractFloat, i32, u32, f32 또는 f16
T는 S 또는 vecN<S>
T가 벡터이면 TB는 vecN<bool>,
그렇지 않으면 TB는 bool
e1 < e2: TB 보다 작음. T가 벡터이면 컴포넌트별로 적용된다.
e1: T
e2: T
S는 AbstractInt, AbstractFloat, i32, u32, f32 또는 f16
T는 S 또는 vecN<S>
T가 벡터이면 TB는 vecN<bool>,
그렇지 않으면 TB는 bool
e1 <= e2: TB 보다 작거나 같음. T가 벡터이면 컴포넌트별로 적용된다.
e1: T
e2: T
S는 AbstractInt, AbstractFloat, i32, u32, f32 또는 f16
T는 S 또는 vecN<S>
T가 벡터이면 TB는 vecN<bool>,
그렇지 않으면 TB는 bool
e1 > e2: TB 보다 큼. T가 벡터이면 컴포넌트별로 적용된다.
e1: T
e2: T
S는 AbstractInt, AbstractFloat, i32, u32, f32 또는 f16
T는 S 또는 vecN<S>
T가 벡터이면 TB는 vecN<bool>,
그렇지 않으면 TB는 bool
e1 >= e2: TB 보다 크거나 같음. T가 벡터이면 컴포넌트별로 적용된다.

8.10. 비트 식

단항 비트 연산
전제 조건 결론 설명
e: T
S는 AbstractInt, i32 또는 u32
T는 S 또는 vecN<S>
~e : T e의 비트별 보수. 결과의 각 비트는 e의 대응하는 비트와 반대이다. T가 벡터이면 컴포넌트별로 적용된다.
이항 비트 연산
전제 조건 결론 설명
e1: T
e2: T
S는 AbstractInt, i32 또는 u32
T는 S 또는 vecN<S>
e1 | e2: T 비트별 OR. T가 벡터이면 컴포넌트별로 적용된다.
e1: T
e2: T
S는 AbstractInt, i32 또는 u32
T는 S 또는 vecN<S>
e1 & e2: T 비트별 AND. T가 벡터이면 컴포넌트별로 적용된다.
e1: T
e2: T
S는 AbstractInt, i32 또는 u32
T는 S 또는 vecN<S>
e1 ^ e2: T 비트별 배타적 OR. T가 벡터이면 컴포넌트별로 적용된다.
비트 시프트 식
전제 조건 결론 설명
e1: T
e2: TS
S는 i32 또는 u32
TS 또는 vecN<S>
TS이면 TS는 u32, 그렇지 않으면 TS는 vecN<u32>
e1 << e2: T 왼쪽 시프트(시프트되는 값이 구체 값임):

e1을 왼쪽으로 시프트하고 최하위 위치에 0 비트를 삽입하며 최상위 비트를 버린다.

시프트할 비트 수는 e2의 값을 e1의 비트 너비로 나눈 나머지이다.
e2e1의 비트 너비보다 크거나 같으면 다음이 적용된다.

e1e2가 모두 셰이더 실행 시작 전에 알려져 있으면 결과가 오버플로해서는 안 된다.

T가 벡터이면 컴포넌트별로 적용된다.

e1: T
e2: TS
T는 AbstractInt 또는 vecN<AbstractInt>
T가 AbstractInt이면 TS는 u32, 그렇지 않으면 TS는 vecN<u32>
e1 << e2: T 왼쪽 시프트(시프트되는 값이 추상 값임):

e1을 왼쪽으로 시프트하고 최하위 위치에 0 비트를 삽입하며 최상위 비트를 버린다.

시프트할 비트 수는 e2의 값이다.

e1의 최상위 e2+1개 비트는 같은 비트 값을 가져야 한다. 그렇지 않으면 오버플로가 발생한다.

참고: 이 조건은 버려지는 모든 비트가 원래 값의 부호 비트 및 최종 값의 부호 비트와 같아야 한다는 뜻이다.

T가 벡터이면 컴포넌트별로 적용된다.

e1: T
e2: TS
S는 i32 또는 u32
TS 또는 vecN<S>
TS이면 TS는 u32, 그렇지 않으면 TS는 vecN<u32>
e1 >> e2: T 오른쪽 시프트(시프트되는 값이 구체 값임).

e1을 오른쪽으로 시프트하고 최하위 비트를 버린다.

S가 부호 없는 타입이면 최상위 위치에 0 비트를 삽입한다.

S가 부호 있는 타입인 경우:

  • e1이 음수이면 삽입되는 각 비트는 1이며 결과도 음수이다.

  • 그렇지 않으면 삽입되는 각 비트는 0이다.

시프트할 비트 수는 e2의 값을 e1의 비트 너비로 나눈 나머지이다.

e2e1의 비트 너비보다 크거나 같으면 다음이 적용된다.

T가 벡터이면 컴포넌트별로 적용된다.

e1: T
e2: TS
T는 AbstractInt 또는 vecN<AbstractInt>
T가 AbstractInt이면 TS는 u32, 그렇지 않으면 TS는 vecN<u32>
e1 >> e2: T 오른쪽 시프트(추상 값).

e1을 오른쪽으로 시프트하고 최하위 비트를 버린다.

e1이 음수이면 삽입되는 각 비트는 1이며 결과도 음수이다. 그렇지 않으면 삽입되는 각 비트는 0이다.

시프트할 비트 수는 e2의 값이다.

T가 벡터이면 컴포넌트별로 적용된다.

8.11. 함수 호출 식

함수 호출 식은 호출되는 함수에 반환 타입이 있는 함수 호출을 실행한다. 호출되는 함수가 값을 반환하지 않으면 함수 호출 문을 대신 사용해야 한다. § 9.5 함수 호출 문을 참조한다.

8.12. 변수 식별자 식

변수 이름에서 참조 얻기
전제 조건 결론 설명
vAS 주소 공간에 선언되고 저장소 타입T이며 접근 모드AM범위 내 변수로 해석되는 식별자 v: ref<AS,T,AM> 결과는 이름이 지정된 변수 v의 메모리에 대한 참조이다.

8.13. 형식 매개변수 식

함수의 형식 매개변수로 선언된 식별자의 값 얻기
전제 조건 결론 설명
a는 타입이 T범위 내 형식 매개변수 선언으로 해석되는 식별자 a: T 결과는 이 함수 인스턴스를 호출하는 호출 지점에서 대응하는 함수 호출 피연산자로 제공된 값이다.

8.14. 주소 취득 식

주소 취득 연산자는 참조를 그에 대응하는 포인터로 변환한다.

참조에서 포인터 얻기
전제 조건 결론 설명
r: ref<AS,T,AM> &r: ptr<AS,T,AM> 결과는 참조 값 r과 동일한 메모리 뷰에 대응하는 포인터 값이다.

r유효하지 않은 메모리 참조이면 결과 포인터도 유효하지 않은 메모리 참조이다.

AShandle 주소 공간이면 셰이더 생성 오류이다.

r벡터 컴포넌트에 대한 참조이면 셰이더 생성 오류이다.

8.15. 간접 참조 식

간접 참조 연산자는 포인터를 그에 대응하는 참조로 변환한다.

포인터에서 참조 얻기
전제 조건 결론 설명
p: ptr<AS,T,AM> *p: ref<AS,T,AM> 결과는 포인터 값 p와 동일한 메모리 뷰에 대응하는 참조 값이다.

p유효하지 않은 메모리 참조이면 결과 참조도 유효하지 않은 메모리 참조이다.

8.16. 값 선언의 식별자 식

const, override 또는 let으로 선언된 식별자의 값 얻기
전제 조건 결론 설명
c는 타입이 Tconst 선언으로 해석되는 범위 내 식별자 c: T 결과는 이니셜라이저 식에 대해 계산된 값이다. 이 식은 상수 식이며 셰이더 생성 시점에 평가된다.
c는 타입이 T오버라이드 선언으로 해석되는 범위 내 식별자 c: T 파이프라인 생성에서 상수 ID의 값을 지정했다면 결과는 그 값이다. 이 값은 파이프라인 인스턴스마다 다를 수 있다.

그렇지 않으면 결과는 이니셜라이저 식에 대해 계산된 값이다. 파이프라인 오버라이드 가능 상수는 모듈 범위에 나타나므로 셰이더가 실행을 시작하기 전에 평가된다.

참고: API 호출에 초깃값이 지정되지 않았고 let 선언에 이니셜라이저 식이 없으면 파이프라인 생성에 실패한다.

c는 타입이 Tlet 선언으로 해석되는 범위 내 식별자 c: T 결과는 이니셜라이저 식에 대해 계산된 값이다. let 선언은 함수 본문 안에 나타나며, 제어 흐름이 선언에 도달할 때마다 그 이니셜라이저가 평가된다.

8.17. 열거형 식

열거형 식
전제 조건 결론 설명
e는 열거형 타입 E에 속하는 미리 선언된 열거자해석되는 식별자 e : E § 6.4.1 미리 선언된 열거자를 참조한다.

8.18. 타입 식

타입 식
전제 조건 결론 설명
t미리 선언된 타입으로 해석되는 식별자 t : AllTypes § 6.10 미리 선언된 타입 및 타입 생성기 요약을 참조한다.
a타입 별칭으로 해석되는 식별자. a : AllTypes 또한 a는 별칭을 부여받은 타입을 나타낸다.
s구조체 타입의 선언으로 해석되는 식별자. s : AllTypes 또한 s는 구조체 타입을 나타낸다.
tg타입 생성기해석되는 식별자

e1: T1
...
eN: TN

tg _template_args_start
e1,
...,
eN
_template_args_end
: AllTypes
타입 생성기에는 요구하고 허용하는 템플릿 매개변수에 대한 고유한 요구 사항이 있으며, 템플릿 매개변수가 결과 타입을 결정하는 방식을 정의한다.

e1부터 eN까지의 식은 타입 생성기의 템플릿 매개변수이다.

예를 들어 타입 식 vec2<f32>는 두 개의 f32 요소로 이루어진 벡터이다.

미리 선언된 타입 생성기의 목록은 § 6.10 미리 선언된 타입 및 타입 생성기 요약을 참조한다.

참고: 여기의 두 변형은 eN 뒤에 후행 쉼표가 있는지 여부만 다르다.

tg _template_args_start
e1,
...,
eN,
_template_args_end
: AllTypes

8.19. 식 문법 요약

식별자call_phrase의 첫 번째 토큰이면 다음 중 하나이다.

선언 및 범위 규칙은 이러한 이름이 항상 서로 다르도록 보장한다.

primary_expression :

template_elaborated_ident

| call_expression

| literal

| paren_expression

call_expression :

call_phrase

참고: call_expression 규칙은 호출 식에 타입 검사가 적용되도록 하기 위해 존재한다.
call_phrase :

template_elaborated_ident argument_expression_list

paren_expression :

'(' expression ')'

argument_expression_list :

'(' expression_comma_list ? ')'

expression_comma_list :

expression ( ',' expression ) * ',' ?

component_or_swizzle_specifier :

'[' expression ']' component_or_swizzle_specifier ?

| '.' member_ident component_or_swizzle_specifier ?

| '.' swizzle_name component_or_swizzle_specifier ?

unary_expression :

singular_expression

| '-' unary_expression

| '!' unary_expression

| '~' unary_expression

| '*' unary_expression

| '&' unary_expression

singular_expression :

primary_expression component_or_swizzle_specifier ?

lhs_expression :

core_lhs_expression component_or_swizzle_specifier ?

| '*' lhs_expression

| '&' lhs_expression

core_lhs_expression :

ident

| '(' lhs_expression ')'

| call_expression

multiplicative_expression :

unary_expression

| multiplicative_expression multiplicative_operator unary_expression

multiplicative_operator :

'*'

| '/'

| '%'

additive_expression :

multiplicative_expression

| additive_expression additive_operator multiplicative_expression

additive_operator :

'+'

| '-'

shift_expression :

additive_expression

| unary_expression _shift_left unary_expression

| unary_expression _shift_right unary_expression

relational_expression :

shift_expression

| shift_expression _less_than shift_expression

| shift_expression _greater_than shift_expression

| shift_expression _less_than_equal shift_expression

| shift_expression _greater_than_equal shift_expression

| shift_expression '==' shift_expression

| shift_expression '!=' shift_expression

short_circuit_and_expression :

relational_expression

| short_circuit_and_expression '&&' relational_expression

short_circuit_or_expression :

relational_expression

| short_circuit_or_expression '||' relational_expression

binary_or_expression :

unary_expression

| binary_or_expression '|' unary_expression

binary_and_expression :

unary_expression

| binary_and_expression '&' unary_expression

binary_xor_expression :

unary_expression

| binary_xor_expression '^' unary_expression

bitwise_expression :

binary_and_expression '&' unary_expression

| binary_or_expression '|' unary_expression

| binary_xor_expression '^' unary_expression

expression :

relational_expression

| short_circuit_or_expression '||' relational_expression

| short_circuit_and_expression '&&' relational_expression

| bitwise_expression

8.20. 연산자 우선순위 및 결합성

이 하위 절 전체는 비규범적이다.

오른쪽 WGSL 식의 연산자 우선순위와 결합성은 해당 문법에서 종합적으로 도출된다. 오른쪽 식은 다음 다이어그램과 같이 연산자를 그룹화하여 구성한다.

연산자 우선순위 및 결합성 그래프

명시성을 통해 가독성을 높이기 위해 다음 그룹은 다른 그룹과 결합되지 않는다.

그리고 다음 그룹은 자기 자신과 결합되지 않는다.

위 두 그룹 절을 결합하려면 관계를 명시적으로 설정하는 괄호가 필요하다. 다음 예제의 주석은 이러한 규칙으로 인해 식이 유효하지 않게 되는 경우를 보여준다.

예: 연산자 우선순위의 경계 사례
let a = x & (y ^ (z | w)); // 유효하지 않음: x & y ^ z | w
let b = (x + y) << (z >= w); // 유효하지 않음: x + y << z >= w
let c = x < (y > z); // 유효하지 않음: x < y > z
let d = x && (y || z); // 유효하지 않음: x && y || z

도출된 우선순위는 식의 암시적 괄호를 제어한다. 우선순위가 더 약한 연산자와 함께 있을 때 결합력이 더 강한 연산자는 괄호로 둘러싸인 것처럼 동작한다. 예를 들어 곱셈 연산자는 덧셈 연산자보다 결합력이 더 강하므로 식 a + b * c에서 (a + (b * c))가 추론된다. 마찬가지로 도출된 결합성은 이러한 암시적 괄호의 방향을 제어한다. 예를 들어 왼쪽에서 오른쪽으로 결합하면 식 a + b + c에서 ((a + b) + c)가 추론되는 반면, 오른쪽에서 왼쪽으로 결합하면 식 * * a에서 (* (* a))가 추론된다.

다음 표는 연산자 우선순위, 결합성 및 결합 대상을 가장 강한 것부터 가장 약한 것까지 정렬하여 요약한다. 결합 대상 열에는 주어진 연산자보다 강한 식이 표시된다. 예를 들어 값이 "위의 모든 항목"이면 해당 연산자가 더 강한 식 중 어느 것이든 포함할 수 있다는 뜻이다. 반면 값이 "단항식"이면 단항식보다 약하지만 해당 행의 연산자보다 강한 것은 이 연산자와 결합하기 위해 괄호가 필요하다. 이 열은 연산자를 선형적으로 나열하는 데 필요하다.

오른쪽 식의 연산자 우선순위, 결합성 및 결합 대상(강한 순서에서 약한 순서로 정렬)
이름 연산자 결합성 결합 대상
괄호식 (...)
기본식 a(), a[], a.b 왼쪽에서 오른쪽
단항식 -a, !a, ~a, *a, &a 오른쪽에서 왼쪽 위의 모든 항목
승산식 a*b, a/b, a%b 왼쪽에서 오른쪽 위의 모든 항목
가산식 a+b, a-b 왼쪽에서 오른쪽 위의 모든 항목
시프트식 a<<b, a>>b 괄호 필요 단항식
관계식 a<b, a>b, a<=b, a>=b, a==b, a!=b 괄호 필요 위의 모든 항목
이항 AND a&b 왼쪽에서 오른쪽 단항식
이항 XOR a^b 왼쪽에서 오른쪽 단항식
이항 OR a|b 왼쪽에서 오른쪽 단항식
단락 평가 AND a&&b 왼쪽에서 오른쪽 관계식
단락 평가 OR a||b 왼쪽에서 오른쪽 관계식

9.

은 실행을 제어하는 프로그램 조각이다. 문은 일반적으로 순차적으로 실행되지만 제어 흐름 문으로 인해 프로그램이 비순차적으로 실행될 수 있다.

9.1. 복합문

복합문은 중괄호로 둘러싸인 0개 이상의 문의 시퀀스입니다. 선언이 이러한 문 중 하나인 경우, 그 식별자는 다음 문의 시작부터 복합문의 끝까지 범위 안에 있습니다.

compound_statement :

attribute * '{' statement * '}'

continuing_compound_statementcontinuing 문의 본문을 구성하고 끝에 선택적 break-if 문을 허용하는 특수한 형태의 복합문입니다.

9.2. 할당문

할당은 식을 평가하고, 선택적으로 결과를 메모리에 저장합니다(따라서 변수의 내용을 갱신합니다).

assignment_statement :

lhs_expression ( '=' | compound_assignment_operator ) expression

| '_' '=' expression

연산자 토큰 왼쪽의 텍스트는 좌변이고, 연산자 토큰 오른쪽의 식은 우변입니다.

9.2.1. 단순 할당

할당좌변참조 식이고 연산자가 등호('=') 토큰인 경우 단순 할당입니다. 이 경우 우변의 값이 좌변이 참조하는 메모리에 기록됩니다.

전제 조건 설명
e: T,
T구체 생성 가능 타입,
r: ref<AS,T,AM>,
AS는 쓰기 가능한 주소 공간,
접근 모드 AMwrite 또는 read_write
r = e r을 평가한 다음 e를 평가하고, e에 대해 계산된 값을 r이 참조하는 메모리 위치에 기록합니다.

참고: 참조가 유효하지 않은 메모리 참조인 경우 쓰기가 실행되지 않거나 예상과 다른 메모리 위치에 쓸 수 있습니다.

가장 단순한 경우 좌변은 변수의 이름입니다. 다른 경우는 § 6.5.9 참조 및 포인터 값 형성을 참조하십시오.

예제: 할당
struct S {
    age: i32,
    weight: f32
}
var<private> person: S;

fn f() {
    var a: i32 = 20;
    a = 30;           // 'a'의 내용을 30으로 바꿉니다.

    person.age = 31;  // person 변수의 age 필드에 31을 씁니다.

    var uv: vec2<f32>;
    uv.y = 1.25;      // uv의 두 번째 컴포넌트에 1.25를 넣습니다.

    let uv_x_ptr: ptr<function,f32> = &uv.x;
    *uv_x_ptr = 2.5;  // uv의 첫 번째 컴포넌트에 2.5를 넣습니다.

    var sibling: S;
    // 'person' 변수의 내용을 'sibling' 변수로 복사합니다.
    sibling = person;
}

9.2.2. 스위즐 할당

이 절은 swizzle_assignment 언어 확장이 지원되는 경우에만 적용됩니다.

할당좌변스위즐 뷰이고 연산자가 등호('=') 토큰인 경우 스위즐 할당입니다. 이 경우 우변의 값을 갱신 벡터로 사용하여 좌변스위즐 뷰 쓰기를 수행합니다.

전제 조건 설명
sv : swizzle<AS,S,N,K>
e : vecK<S>
주소 공간 AS는 쓰기 가능,
sv = e 관례상 sv = (p, IndexList)

제약 조건:

  • IndexList의 인덱스는 반드시 모두 서로 달라야 합니다.

참고: 스위즐 뷰 식 규칙은 IndexList의 각 인덱스가 [0,N-1]에 속하도록 보장합니다.

다음 단계를 수행합니다.

  1. p를 평가합니다.

  2. e를 평가하여 벡터 update를 산출합니다.

  3. p가 참조하는 메모리를 읽어 vecN<S> 타입의 벡터 old_contents를 산출합니다.

  4. SwizzleViewWrite(p, IndexList, old_contents, update)를 수행합니다.

참고: 스위즐 뷰가 유효하지 않은 스위즐 뷰인 경우 3단계와 4단계는 범위를 벗어난 접근이므로 실행되지 않거나 예상과 다른 메모리 위치에 쓸 수 있습니다.

참고: p의 이전 내용을 읽기 전에 e를 평가하는 것은 부자연스럽게 보일 수 있습니다. 그러나 4단계의 스위즐 쓰기는 IndexList에 나열되지 않은 벡터 컴포넌트를 보존해야 하며, 그 컴포넌트들은 e 자체를 평가하는 동안 수정되었을 수도 있습니다.

예제: 스위즐 할당의 평가 순서
var<private> v: array<vec4u,1>;

fn update_and_index() -> u32 {
  v[0] += vec4u(2,4,8,10);
  return 0;
}

fn update_and_rhs() -> vec2u {
  v[0].x = 900;
  v[0].z = 100;
  return vec2u(55,66);
}

fn eval_order_swizzle_assignment() {
  v[0] = vec4u(0,0,0,0);

  // 1. 포인터 p를 평가합니다. 이 과정에서
  //    좌변의 인덱스를 평가하고,
  //    부수 효과로 v[0] = vec4u(2,4,8,10)을 설정하며
  //    인덱스로 0을 산출합니다.
  // 2. 우변을 평가하여
  //     v[0].x = 900
  //     v[0].z = 100
  //    을 설정하고 vec2u(55,66)을 산출합니다.
  // 3. 그런 다음 스위즐 할당은 v[0].x와 v[0].y만 갱신하고,
  //    v[0].z와 v[0].w를 보존합니다.

  v[update_and_index()].yx = update_and_rhs();

  // 이제 v[0]은 vec4u(66,55,100,10)과 같습니다.
}

9.2.3. 더미 할당

할당좌변이 밑줄('_') 토큰인 경우 더미 할당입니다. 이 경우 우변을 평가한 다음 무시합니다.

전제 조건 설명
e: T,
T생성 가능 타입, 포인터 타입, 텍스처 타입 또는 샘플러 타입
_ = e e를 평가합니다.

참고: 결과 값은 저장되지 않습니다. _ 토큰은 식별자가 아니므로 식에서 사용할 수 없습니다.

더미 할당은 다음과 같은 경우에 유용합니다.

예제: 불필요한 함수 결과를 버리기 위한 더미 할당 사용
var<private> counter: i32;

fn increment_and_yield_previous() -> i32 {
  let previous = counter;
  counter = counter + 1;
  return previous;
}

fn user() {
  // 카운터를 증가시키지만 결과는 사용하지 않습니다.
  _ = increment_and_yield_previous();
}
예제: 바인딩을 사용하지 않고 차지하기 위한 더미 할당 사용
struct BufferContents {
    counter: atomic<u32>,
    data: array<vec4<f32>>
}
@group(0) @binding(0) var<storage> buf: BufferContents;
@group(0) @binding(1) var t: texture_2d<f32>;
@group(0) @binding(2) var s: sampler;

@fragment
fn shade_it() -> @location(0) vec4<f32> {
  // buf, t, s를 어떤 용도로도 사용하지 않고 셰이더 인터페이스의
  // 일부로 선언합니다.
  _ = &buf;
  _ = t;
  _ = s;
  return vec4<f32>();
}

9.2.4. 복합 할당

할당좌변참조 식 또는 스위즐 뷰이고 연산자가 compound_assignment_operators 중 하나인 경우 복합 할당입니다.

compound_assignment_operator :

'+='

| '-='

| '*='

| '/='

| '%='

| '&='

| '|='

| '^='

| _shift_right_assign

| _shift_left_assign

각 문의 타입 요구 사항, 의미론 및 동작은 다음 표와 같이 복합 할당을 확장한 것처럼 정의되지만, 다음 사항은 예외입니다.

확장
e1 += e2 e1 = e1 + (e2)
e1 -= e2 e1 = e1 - (e2)
e1 *= e2 e1 = e1 * (e2)
e1 /= e2 e1 = e1 / (e2)
e1 %= e2 e1 = e1 % (e2)
e1 &= e2 e1 = e1 & (e2)
e1 |= e2 e1 = e1 | (e2)
e1 ^= e2 e1 = e1 ^ (e2)
e1 >>= e2 e1 = e1 >> (e2)
e1 <<= e2 e1 = e1 << (e2)

참고: 구문은 복합 할당이 동시에 더미 할당이 되는 것을 허용하지 않습니다.

참고: e1참조인 경우 한 번 평가되지만 그 기반 메모리에는 두 번 접근합니다. 먼저 읽기 접근으로 이전 값을 가져오고, 그다음 쓰기 접근으로 갱신된 값을 저장합니다.

예제: 복합 할당
var<private> next_item: i32 = 0;

fn advance_item() -> i32 {
   next_item += 1;   // next_item에 1을 더합니다.
   return next_item - 1;
}

fn bump_item() {
  var data: array<f32,10>;
  next_item = 0;
  // advance_item()을 한 번만 호출하면서 data[0]에 5.0을 더합니다.
  data[advance_item()] += 5.0;
  // 여기서 next_item은 1입니다.
}

fn precedence_example() {
  var value = 1;
  // 복합 할당의 우변은 그 자체로 하나의 식입니다.
  value *= 2 + 3; // value = value * (2 + 3);과 같습니다.
  // 이제 'value'에는 5가 들어 있습니다.
}
참고: e1스위즐 뷰인 경우 명시된 대로 e1은 대응하는 포인터를 계산하기 위해 한 번 평가되지만, 그 기반 메모리에는 세 번 접근합니다.
예제: 복합 스위즐 할당의 평가 순서
var<private> v: array<vec4u,1>;

fn update_and_index() -> u32 {
  v[0] += vec4u(2,4,8,10);
  return 0;
}

fn update_and_rhs() -> vec2u {
  v[0].x = 900;
  v[0].z = 100;
  return vec2u(55,66);
}

fn eval_order_compound_swizzle_assignment() {
  v[0] = vec4u(0,0,0,0);

  // 1. 포인터 p를 평가합니다. 이 과정에서
  //    좌변의 인덱스를 평가하고,
  //    부수 효과로 v[0] = vec4u(2,4,8,10)을 설정하며
  //    인덱스로 0을 산출합니다.
  // 2. 스위즐 이름은 .yx이므로 IndexList는 목록 1,0입니다.
  //    SwizzleViewRead(p,IndexList)를 수행하여
  //    view_contents = vec2u(4,2)를 산출합니다.
  // 3. 우변을 평가하여
  //     v[0].x = 900
  //     v[0].z = 100
  //    을 설정하고 vec2u(55,66)을 산출합니다.
  // 4. 다음과 같이 갱신 벡터를 계산합니다.
  //           view_contents + vec2u(55,66)
  //         = vec2u(4,2) + vec2u(55,66)
  //         = vec2u(59,68)
  // 5. 그런 다음 스위즐 할당은 v[0].x와 v[0].y만 갱신하고,
  //    v[0].z와 v[0].w를 보존합니다.

  v[update_and_index()].yx += update_and_rhs();

  // 이제 v[0]은 vec4u(68,59,100,10)과 같습니다.
}
참고: 참조에 대한 복합 할당은 대신 단순 할당을 사용하는 다른 WGSL 코드로 다시 작성할 수 있습니다. 핵심은 참조를 한 번 평가한 결과를 보관하기 위해 포인터를 사용하는 것입니다.
예를 들어, e1이 벡터 내부 컴포넌트에 대한 참조가 아닌 경우
e1+=e2;
는 다음과 같이 다시 작성할 수 있습니다.
{ let p = &(e1); *p = *p + (e2); }
여기서 식별자 p는 프로그램의 다른 모든 식별자와 다르게 선택합니다.
e1이 벡터 내부 컴포넌트에 대한 참조인 경우에는 WGSL이 이 경우 주소 가져오기를 허용하지 않으므로 위 기법을 수정해야 합니다. 예를 들어 ev가 벡터에 대한 참조인 경우 다음 문은
ev[c] += e2;
다음과 같이 다시 작성할 수 있습니다.
{ let p = &(ev); let c0 = c; (*p)[c0] = (*p)[c0] + (e2); }
여기서 식별자 c0p는 프로그램의 다른 모든 식별자와 다르게 선택합니다.

9.3. 증가문과 감소문

증가문은 변수의 내용에 1을 더합니다. 감소문은 변수의 내용에서 1을 뺍니다.

increment_statement :

lhs_expression '++'

decrement_statement :

lhs_expression '--'

식은 구체 정수 스칼라 저장소 타입read_write 접근 모드를 가진 참조로 반드시 평가되어야 합니다.

전제 조건 설명
r : ref<AS,T,read_write>,
T구체 정수 스칼라
r++ r이 참조하는 메모리의 내용에 1을 더합니다.
r += T(1)과 동일
r : ref<AS,T,read_write>,
T구체 정수 스칼라
r-- r이 참조하는 메모리의 내용에서 1을 뺍니다.
r -= T(1)과 동일
예제: 증가와 감소
fn f() {
    var a: i32 = 20;
    a++;
    // 이제 a에는 21이 들어 있습니다.
    a--;
    // 이제 a에는 20이 들어 있습니다.
}

9.4. 제어 흐름

제어 흐름 문은 프로그램이 비순차적 순서로 실행되게 할 수 있습니다.

9.4.1. If 문

if 문은 조건 식의 평가에 따라 최대 하나의 복합문을 조건부로 실행합니다.

if 문에는 if 절이 있고, 그 뒤에 0개 이상의 else if 절과 선택적 else 절이 이어집니다.

if_statement :

attribute * if_clause else_if_clause * else_clause ?

if_clause :

'if' expression compound_statement

else_if_clause :

'else' 'if' expression compound_statement

else_clause :

'else' compound_statement

타입 규칙 전제 조건: 각 ifelse if 절의 식은 bool 타입이어야 합니다.

if 문은 다음과 같이 실행됩니다.

9.4.2. Switch 문

switch 문은 선택자 식의 평가에 따라 case 절 집합 중 하나 또는 default 절로 제어를 이동합니다.

switch_statement :

attribute * 'switch' expression switch_body

switch_body :

attribute * '{' switch_clause + '}'

switch_clause :

case_clause

| default_alone_clause

case_clause :

'case' case_selectors ':' ? compound_statement

default_alone_clause :

'default' ':' ? compound_statement

case_selectors :

case_selector ( ',' case_selector ) * ',' ?

case_selector :

'default'

| expression

case 절'case' 토큰 뒤에 쉼표로 구분된 case 선택자 목록과 복합문 형태의 본문이 이어지는 것입니다.

독립 default 절'default' 토큰 뒤에 복합문 형태의 본문이 이어지는 것입니다.

default 절은 다음 중 하나입니다.

각 switch 문에는 정확히 하나의 default 절반드시 있어야 합니다.

'default' 토큰은 하나의 case_selector 목록에 두 번 이상 나타나서는 안 됩니다.

타입 규칙 전제 조건: 하나의 switch 문에서 선택자 식과 모든 case 선택자 식은 동일한 구체 정수 스칼라 타입이어야 합니다.

case_selectors의 식은 상수 식이어야 합니다.

동일한 switch 문에 있는 서로 다른 두 case 선택자 식은 같은 값을 가져서는 안 됩니다.

선택자 값이 case_selector 목록에 있는 식의 값과 같으면 제어가 해당 case 절의 본문으로 이동합니다. 선택자 값이 어느 case 선택자 값과도 같지 않으면 제어가 default 절의 본문으로 이동합니다.

제어가 절 본문의 끝에 도달하면 switch 문 다음의 첫 번째 문으로 이동합니다.

절 본문의 문 중 하나가 선언인 경우, 복합문 내부 선언의 일반적인 범위수명 규칙을 따릅니다. 즉, 본문은 문의 시퀀스이며 그중 하나가 선언이면 해당 선언의 범위는 시퀀스에서 다음 문의 시작부터 본문의 끝까지 이어집니다. 선언은 도달했을 때 실행되어 변수 또는 의 새 인스턴스를 생성하고 초기화합니다.

예제: WGSL Switch
var a : i32;
let x : i32 = generateValue();
switch x {
  case 0: {      // 콜론은 선택 사항입니다.
    a = 1;
  }
  default {      // default는 마지막에 나타날 필요가 없습니다.
    a = 2;
  }
  case 1, 2, {   // 여러 선택자 값을 사용할 수 있습니다.
    a = 3;
  }
  case 3, {      // 뒤쪽 쉼표는 선택 사항입니다.
    a = 4;
  }
  case 4 {
    a = 5;
  }
}
예제: default가 결합된 WGSL Switch
const c = 2;
var a : i32;
let x : i32 = generateValue();
switch x {
  case 0: {
    a = 1;
  }
  case 1, c {       // case 선택자에 상수 식을 사용할 수 있습니다.
    a = 3;
  }
  case 3, default { // default 키워드를 다른 절과 함께 사용할 수 있습니다.
    a = 4;
  }
}

9.4.3. Loop 문

loop_statement :

attribute * 'loop' attribute * '{' statement * continuing_statement ? '}'

loop 문은 루프 본문을 반복 실행합니다. 루프 본문은 복합문으로 지정됩니다. 루프 본문의 각 실행을 반복이라고 합니다.

이 반복은 break 또는 return 문으로 중단할 수 있습니다.

선택적으로 루프 본문의 마지막 문은 continuing 문일 수 있습니다.

loop가 무한한 수의 반복을 실행하게 되는 경우 동적 오류가 발생합니다. 이로 인해 루프가 조기에 종료되거나, 다른 비지역적 효과가 발생하거나, 심지어 기기 손실이 발생할 수도 있습니다.

루프 본문의 문 중 하나가 선언인 경우, 복합문 내부 선언의 일반적인 범위수명 규칙을 따릅니다. 즉, 루프 본문은 문의 시퀀스이며 그중 하나가 선언이면 해당 선언의 범위는 시퀀스에서 다음 문의 시작부터 루프 본문의 끝까지 이어집니다. 선언은 도달할 때마다 실행되므로 각각의 새로운 반복은 변수 또는 의 새 인스턴스를 생성하고 다시 초기화합니다.

참고: loop 문은 특수한 구문이므로 일반적으로는 for 또는 while 문을 사용하는 것이 좋습니다. loop 문은 다른 셰이더 언어와의 가장 큰 차이점 중 하나입니다.

이 설계는 컴파일된 코드에서 흔히 볼 수 있는 루프 관용구를 직접 표현합니다. 특히 루프 갱신문을 루프 본문의 끝에 배치하면 루프 본문에 정의된 값을 자연스럽게 사용할 수 있습니다.

예제: for 루프
var a: i32 = 2;
for (var i: i32 = 0; i < 4; i++) {
  a *= 2;
}
예제: loop
var a: i32 = 2;
var i: i32 = 0;      // <1>
loop {
  if i >= 4 { break; }

  a = a * 2;

  i++;
}
예제: continue가 있는 for 루프
var a: i32 = 2;
let step: i32 = 1;
for (var i: i32 = 0; i < 4; i += step) {
  if (i % 2 == 0) { continue; }
  a *= 2;
}
예제: continue가 있는 loop
var a: i32 = 2;
var i: i32 = 0;
loop {
  if i >= 4 { break; }

  let step: i32 = 1;

  i = i + step;
  if i % 2 == 0 { continue; }

  a = a * 2;
}
예제: continue와 continuing이 있는 loop
var a: i32 = 2;
var i: i32 = 0;
loop {
  if i >= 4 { break; }

  let step: i32 = 1;

  if i % 2 == 0 { continue; }

  a = a * 2;

  continuing {   // <2>
    i = i + step;
  }
}

9.4.4. For 문

for_statement :

attribute * 'for' '(' for_header ')' compound_statement

for_header :

for_init ? ';' expression ? ';' for_update ?

for_init :

variable_or_value_statement

| variable_updating_statement

| func_call_statement

for_update :

variable_updating_statement

| func_call_statement

for 문은 loop 문을 포함하는 복합문을 위한 구문 설탕입니다. 일반적으로 for 문은 다음 형식을 취합니다.

for ( initializer ; condition ; update_part ) { body }

조건 식이 있는 경우 for 문은 다음 형태의 루프로 역당화됩니다.

{
initializer ;
loop {
if !(condition) { break; }
body
continuing { update_part }
}
}
조건 식이 없는 경우 for 문은 다음 형태의 루프로 역당화됩니다.
{
initializer ;
loop {
body
continuing { update_part }
}
}

추가로:

for 루프의 initializer는 루프를 실행하기 전에 한 번 실행됩니다. 선언이 초기화 구문에 나타나는 경우 그 식별자body의 끝까지 범위 안에 있습니다. body의 선언과 달리 이 선언은 각 반복에서 다시 초기화되지 않습니다.

condition, body, update_part는 이 순서로 실행되어 하나의 루프 반복을 형성합니다. body는 특수한 형태의 복합문입니다. body에 있는 선언의 식별자는 다음 문의 시작부터 body의 끝까지 범위 안에 있습니다. 선언은 도달할 때마다 실행되므로 각각의 새로운 반복은 변수 또는 상수의 새 인스턴스를 생성하고 다시 초기화합니다.

예제: 조건이 있는 For에서 Loop로의 변환: 변환 전
var a: i32 = 2;
for (var i: i32 = 0; i < 4; i++) {
  if a == 0 {
    continue;
  }
  a = a + 2;
}

다음으로 변환됩니다.

예제: 조건이 있는 For에서 Loop로의 변환: 변환 후
var a: i32 = 2;
{ // 루프 변수 i를 위한 새 범위를 도입합니다.
  var i: i32 = 0;
  loop {
    if !(i < 4) {
      break;
    }

    if a == 0 {
      continue;
    }
    a = a + 2;

    continuing {
      i++;
    }
  }
}
예제: 조건이 없는 For에서 Loop로의 변환: 변환 전
var a: i32 = 2;
for (var i: i32 = 0; ; i++) {
  if a == 0 {
    continue;
  }
  if i == 4 { break; }
  a = a + 2;
}

다음으로 변환됩니다.

예제: 조건이 없는 For에서 Loop로의 변환: 변환 후
var a: i32 = 2;
{ // 루프 변수 i를 위한 새 범위를 도입합니다.
  var i: i32 = 0;
  loop {
    // 참고: 역당화는 여기에 if 절을 도입하지 않습니다.

    if a == 0 {
      continue;
    }
    if i == 4 { break; }
    a = a + 2;

    continuing {
      i++;
    }
  }
}

for 루프가 무한한 수의 반복을 실행하게 되는 경우 동적 오류가 발생합니다. 이로 인해 루프가 조기에 종료되거나, 다른 비지역적 효과가 발생하거나, 심지어 기기 손실이 발생할 수도 있습니다.

9.4.5. While 문

while_statement :

attribute * 'while' expression compound_statement

while 문은 조건으로 매개변수화된 루프의 한 종류입니다. 각 루프 반복의 시작에서 불리언 조건을 평가합니다. 조건이 false이면 while 루프의 실행이 끝납니다. 그렇지 않으면 반복의 나머지 부분을 실행합니다.

타입 규칙 전제 조건: 조건은 bool 타입이어야 합니다.

while 루프는 loop 또는 for 문을 위한 구문 설탕으로 볼 수 있습니다. 다음 문 형식은 동등합니다.

while 루프가 무한한 수의 반복을 실행하게 되는 경우 동적 오류가 발생합니다. 이로 인해 루프가 조기에 종료되거나, 다른 비지역적 효과가 발생하거나, 심지어 기기 손실이 발생할 수도 있습니다.

9.4.6. Break 문

break_statement :

'break'

break 문은 가장 가까이 둘러싸는 루프 또는 switch 문의 본문 바로 뒤로 제어를 이동하여 루프 또는 switch 문의 실행을 끝냅니다.

break 문은 loop, for, whileswitch 문 안에서만 반드시 사용해야 합니다.

break 문은 루프의 continuing 문에서 빠져나가게 되는 위치에 배치해서는 안 됩니다. 대신 break-if 문을 사용하십시오.

예제: continuing 절에서 루프를 빠져나가는 유효하지 않은 WGSL 코드
var a: i32 = 2;
var i: i32 = 0;
loop {
  let step: i32 = 1;

  if i % 2 == 0 { continue; }

  a = a * 2;

  continuing {
    i = i + step;
    if i >= 4 { break; } // 유효하지 않습니다. 대신 break-if를 사용하십시오.
  }
}

9.4.7. Break-If 문

break_if_statement :

'break' 'if' expression ';'

break-if 문은 불리언 조건을 평가합니다. 조건이 true이면 제어가 가장 가까이 둘러싸는 loop 문의 본문 바로 뒤로 이동하여 해당 루프의 실행을 끝냅니다.

타입 규칙 전제 조건: 조건은 bool 타입이어야 합니다.

참고: break-if 문은 continuing 문 본문의 마지막 문으로만 나타날 수 있습니다.

예제: continuing 절에서 유효하게 루프를 빠져나가는 WGSL break-if
var a: i32 = 2;
var i: i32 = 0;
loop {
  let step: i32 = 1;

  if i % 2 == 0 { continue; }

  a = a * 2;

  continuing {
    i = i + step;
    break if i >= 4;
  }
}

9.4.8. Continue 문

continue_statement :

'continue'

continue 문은 가장 가까이 둘러싸는 loop 안에서 다음과 같이 제어를 이동합니다.

continue 문은 loop, for 또는 while 문 안에서만 반드시 사용해야 합니다. continue 문은 제어를 둘러싸는 continuing 문으로 이동하게 되는 위치에 배치해서는 안 됩니다. (continuing 문으로 분기할 때는 전방 분기입니다.)

continue 문은 대상 continuing 문에서 사용하는 선언을 지나 제어를 이동하게 되는 위치에 배치해서는 안 됩니다.

참고: continuecontinuing 문 안에 중첩된 다른 루프 내부에서 제어 흐름을 이동하는 데 사용되는 경우에만 continuing 문 안에서 사용할 수 있습니다. 즉, continue는 현재 실행 중인 continuing 문의 시작으로 제어를 이동하는 데 사용할 수 없습니다.

예제: 선언을 우회하는 유효하지 않은 continue
var i: i32 = 0;
loop {
  if i >= 4 { break; }
  if i % 2 == 0 { continue; } // <3>

  let step: i32 = 2;

  continuing {
    i = i + step;
  }
}

9.4.9. Continuing 문

continuing_statement :

'continuing' continuing_compound_statement

continuing_compound_statement :

attribute * '{' statement * break_if_statement ? '}'

continuing 문은 루프 반복의 끝에서 실행할 복합문을 지정합니다. 이 구문은 선택 사항입니다.

복합문은 어느 복합문 중첩 수준에서도 return을 포함해서는 안 됩니다.

9.4.10. Return 문

return_statement :

'return' expression ?

return 문은 현재 함수의 실행을 끝냅니다. 함수가 진입점이면 현재 셰이더 호출이 종료됩니다. 그렇지 않으면 현재 함수 호출의 호출 지점 평가 뒤에 오는 다음 식 또는 문부터 평가가 계속됩니다.

함수에 반환 타입이 없으면 return 문은 선택 사항입니다. 이러한 함수에 return 문이 제공된 경우 값을 제공해서는 안 됩니다. 그렇지 않으면 식이 반드시 있어야 하며, 이를 반환 값이라고 합니다. 이 경우 이 함수 호출의 호출 지점은 반환 값으로 평가됩니다. 반환 값의 타입은 함수의 반환 타입과 반드시 일치해야 합니다.

9.4.11. Discard 문

discard 문은 호출을 보조 호출로 변환하고 프래그먼트 출력을 버립니다. discard 문은 프래그먼트 셰이더 스테이지에서만 반드시 사용해야 합니다.

더 정확히 말하면 discard 문을 실행하면 다음을 수행할 것입니다.

discard 문보다 먼저 실행된 문만 관찰 가능한 효과를 가질 것입니다.

참고: discard 문은 프래그먼트 스테이지의 함수라면 어느 함수에서든 실행할 수 있으며 효과는 동일합니다. 프래그먼트 출력이 버려집니다.

예제: 프래그먼트를 버리기 위한 discard 문 사용
@group(0) @binding(0)
var<storage, read_write> will_emit_color : u32;

fn discard_if_shallow(pos: vec4<f32>) {
  if pos.z < 0.001 {
    // 이것이 실행되면 보조 호출은 공유 메모리에 쓰지 않으므로
    // will_emit_color 변수는 절대로 1로 설정되지
    // 않습니다.
    discard;
  }
  will_emit_color = 1;
}

@fragment
fn main(@builtin(position) coord_in: vec4<f32>)
  -> @location(0) vec4<f32>
{
  discard_if_shallow(coord_in);

  // 보조 함수가 discard 문을 실행하지 않은 경우에만
  // 값을 1로 설정하고 빨간색을 출력합니다.
  will_emit_color = 1;
  return vec4<f32>(1.0, 0.0, 0.0, 1.0);
}

9.5. 함수 호출문

func_call_statement :

call_phrase

함수 호출문은 함수 호출을 실행합니다.

호출된 함수에 must_use 특성이 있으면 셰이더 생성 오류가 발생합니다.

참고: 함수가 값을 반환하고 함수에 must_use 특성이 없으면 해당 값은 무시됩니다.

9.6. 문 문법 요약

statement 규칙은 함수 본문 내부의 대부분 위치에서 사용할 수 있는 문과 일치합니다.

statement :

';'

| return_statement ';'

| if_statement

| switch_statement

| loop_statement

| for_statement

| while_statement

| func_call_statement ';'

| variable_or_value_statement ';'

| break_statement ';'

| continue_statement ';'

| 'discard' ';'

| variable_updating_statement ';'

| compound_statement

| assert_statement ';'

variable_updating_statement :

assignment_statement

| increment_statement

| decrement_statement

또한 일부 문은 매우 특정한 문맥에서만 사용할 수 있습니다.

9.7. 문 동작 분석

9.7.1. 규칙

제어 흐름에 영향을 주는 일부 문은 특정 문맥에서만 유효합니다. 예를 들어 continueloop, for 또는 while 외부에서는 유효하지 않습니다. 또한 균일성 분석(§ 15.2 균일성 참조)은 제어 흐름이 여러 가지 방식으로 문을 빠져나갈 수 있는 때를 알아야 합니다.

두 목표 모두 문의 실행 동작을 요약하는 체계를 통해 달성됩니다. 동작 분석은 각 문을 해당 문의 평가가 완료된 후 실행이 진행될 수 있는 방식의 집합에 매핑합니다. 값과 식의 타입 분석과 마찬가지로 동작 분석은 상향식으로 진행됩니다. 먼저 특정 기본 문의 동작을 결정하고, 결합 규칙을 적용하여 상위 수준 구문의 동작을 결정합니다.

동작은 집합이며, 그 원소는 다음 중 하나일 수 있습니다.

각 항목은 키워드를 통하거나 다음 문으로 자연스럽게 진행하는 방식("Next")으로 복합문을 빠져나가는 방법에 대응합니다.

"s: B"라는 표기는 s가 동작에 관한 규칙을 준수하고 동작 B를 가진다는 의미입니다.

각 함수에 대해:

각 함수에 동작을 할당합니다. 이는 본문을 일반적인 문으로 취급했을 때의 본문 동작에서 "Return"을 모두 "Next"로 바꾼 것입니다. 위 규칙의 결과로 함수 동작은 항상 {} 또는 {Next} 중 하나입니다.

동작 분석은 각 문과 함수에 대해 비어 있지 않은 동작을 결정할 수 있어야 합니다.

문의 동작을 분석하고 검증하기 위한 규칙
전제 조건 결과 동작
빈 문 {Next}
{s} s: B B
s1 s2

참고: s1은 흔히 세미콜론으로 끝납니다.

s1: B1
Next가 B1에 포함됨
s2: B2
(B1∖{Next}) ∪ B2
s1: B1
Next가 B1에 포함되지 않음
s2: B2
B1
var x:T; {Next}
let x = e; {Next}
var x = e; {Next}
x = e; {Next}
_ = e; {Next}
f(e1, ..., en); f는 동작 B를 가짐 B
return; {Return}
return e; {Return}
discard; {Next}
break; {Break}
break if e; {Break, Next}
continue; {Continue}
const_assert e; {Next}
if e s1 else s2 s1: B1
s2: B2
B1B2
loop {s1 continuing {s2}} s1: B1
s2: B2
B1 = {Return}
{Continue, Return} 중 어느 것도 B2에 포함되지 않음
{Return}
s1: B1
s2: B2
B1 ≠ {Return}
{Continue, Return} 중 어느 것도 B2에 포함되지 않음
Break가 (B1B2)에 포함되지 않음
(B1B2)∖{Continue, Next}
s1: B1
s2: B2
B1 ≠ {Return}
{Continue, Return} 중 어느 것도 B2에 포함되지 않음
Break가 (B1B2)에 포함됨
(B1B2 ∪ {Next})∖{Break, Continue}
switch e {case c1: s1 ... case cn: sn} s1: B1
...
sn: Bn
Break가 (B1 ∪ ... ∪ Bn)에 포함되지 않음
B1 ∪ ... ∪ Bn
s1: B1
...
sn: Bn
Break가 (B1 ∪ ... ∪ Bn)에 포함됨
(B1 ∪ ... ∪ Bn ∪ {Next})∖Break

참고: ∪는 집합 합집합 연산이고 ∖는 집합 차집합 연산입니다.

참고: 빈 문인 경우는 loop의 본문이 비어 있거나 for 루프에 초기화문 또는 갱신문이 없을 때 발생합니다.

이 분석에서는 다음과 같이 처리합니다.

내장 함수동작은 {Next}입니다. 또한 위 표에 나열되지 않은 각 연산자 적용은 동일한 피연산자를 사용하고 함수의 동작이 {Next}인 함수 호출과 동일한 동작을 가집니다.

함수의 동작은 위에 제시된 규칙을 충족해야 합니다.

참고: 위 규칙은 루프의 동작이 {Next}, {Return} 또는 {Next,Return}임을 뜻합니다.

참고: 식은 항상 {Next}이거나 이전에 분석한 함수에서 오류가 발생하므로 식의 동작을 분석할 필요가 없습니다.

9.7.2. 참고 사항

이 절은 정보 제공 목적이며 비규범적입니다.

동작 분석으로 인해 프로그램은 다음과 같은 방식으로 거부될 수 있습니다 (위의 요구 사항을 다시 기술함).

함수 호출의 동작은 함수의 코드에 따라 달라질 수 있으므로 호출 그래프를 상향식으로 분석하면 이 분석을 선형 시간에 실행할 수 있습니다.

9.7.3. 예제

다음은 이 분석이 실제로 적용되는 모습을 보여 주는 몇 가지 예제입니다.

예제: 자명한 죽은 코드는 허용됩니다
fn simple() -> i32 {
  var a: i32;
  return 0;  // 동작: {Return}
  a = 1;     // 유효한 정적으로 도달할 수 없는 코드입니다.
             //   문 동작: {Next}
             //   전체 동작(순차적 문으로 인함): {Return}
  return 2;  // 유효한 정적으로 도달할 수 없는 코드입니다. 동작: {Return}
} // 함수 동작: {Return}
예제: 복합문이 지원됩니다
fn nested() -> i32 {
  var a: i32;
  {             // 복합문의 시작입니다.
    a = 2;      // 동작: {Next}
    return 1;   // 동작: {Return}
  }             // 복합문 전체의 동작은 {Return}입니다.
  a = 1;        // 유효한 정적으로 도달할 수 없는 코드입니다.
                //   문 동작: {Next}
                //   전체 동작(순차적 문으로 인함): {Return}
  return 2;     // 유효한 정적으로 도달할 수 없는 코드입니다. 동작: {Return}
}
예제: if/then은 빈 else가 있는 것처럼 동작합니다
fn if_example() {
  var a: i32 = 0;
  loop {
    if a == 5 {
      break;      // 동작: {Break}
    }             // 전체 if 복합문의 동작: {Break, Next},
                  //   if에 암시적인 빈 else가 있기 때문입니다.
    a = a + 1;    // 이전 문의 동작에 "Next"가 있으므로 유효합니다.
  }
}
예제: if/then/else는 양쪽의 동작을 모두 가집니다
fn if_example() {
  var a: i32 = 0;
  loop {
    if a == 5 {
      break;      // 동작: {Break}
    } else {
      continue;   // 동작: {Continue}
    }             // 전체 if 복합문의 동작: {Break, Continue}
    a = a + 1;    // 유효한 정적으로 도달할 수 없는 코드입니다.
                  //   문 동작: {Next}
                  //   전체 동작: {Break, Continue}
  }
}
예제: if/else if/else는 중첩된 if/else처럼 동작합니다
fn if_example() {
  var a: i32 = 0;
  loop {
    // if e1 s1 else if e2 s2 else s3
    // 은 다음과 동일합니다.
    // if e1 else { if e2 s2 else s3 }
    if a == 5 {
      break;      // 동작: {Break}
    } else if a == 42 {
      continue;   // 동작: {Continue}
    } else {
      return;     // 동작 {Return}
    }             // 전체 if 복합문의 동작:
                  //   {Break, Continue, Return}
  }               // 전체 loop 복합문의 동작 {Next, Return}
}                 // 전체 함수의 동작 {Next}
예제: switch의 Break는 Next가 됩니다
fn switch_example() {
  var a: i32 = 0;
  switch a {
    default: {
      break;   // 동작: {Break}
    }
  }            // switch가 Break를 Next로 바꾸므로 동작은 {Next}입니다.
  a = 5;       // 이전 문의 동작에 Next가 있으므로 유효합니다.
}
예제: 명백한 무한 루프
fn invalid_infinite_loop() {
  loop { }     // 동작: { }. 비어 있으므로 유효하지 않습니다.
}
예제: Discard는 루프를 종료하지 않습니다
fn invalid_infinite_loop() {
  loop {
    discard; // 동작 { Next }.
  }          // 전체 루프의 동작이 { }이므로 유효하지 않습니다.
}
예제: continuing 문이 있는 조건부 continue
fn conditional_continue() {
  var a: i32;
  loop {
    if a == 5 { break; } // 동작: {Break, Next}
    if a % 2 == 1 {      // 이전 문의 동작에 Next가 있으므로 유효합니다.
      continue;          // 동작: {Continue}
    }                    // 동작: {Continue, Next}
    a = a * 2;           // 이전 문의 동작에 Next가 있으므로 유효합니다.
    continuing {         // continuing 문의 동작이 {Next}이므로 유효합니다.
                         //  다음 중 어느 것도 포함하지 않습니다.
                         //  {Break, Continue, Return}
      a = a + 1;
    }
  }                      // 루프 전체의 동작은 {Next}입니다.
                         //  "Continue"와 "Next"를 흡수한 다음
                         //  "Break"를 "Next"로 바꾸기 때문입니다.
}
예제: continuing 문이 있는 중복 continue
fn redundant_continue_with_continuing() {
  var a: i32;
  loop {
    if a == 5 { break; }
    continue;   // 유효합니다. 다음 문으로 분기하므로 중복입니다.
    continuing {
      a = a + 1;
    }
  }
}
예제: 루프 본문 끝의 continue
fn continue_end_of_loop_body() {
  for (var i: i32 = 0; i < 5; i++ ) {
    continue;   // 유효합니다. 중복이며,
                //   루프 본문의 끝으로 분기합니다.
  }             // 동작: {Next},
                //   루프는 "Continue"를 흡수하고
                //   "for" 루프는 항상 "Next"를 추가하기 때문입니다.
}
for 루프는 조건부 break가 있는 loop로 역당화됩니다. 이전 예제에서 본 것처럼 조건부 break의 동작은 {Break, Next}이며, 이로 인해 루프의 동작에 "Next"가 추가됩니다.
예제: 반환 타입이 있는 함수에는 return이 필요합니다
fn missing_return () -> i32 {
  var a: i32 = 0;
  if a == 42 {
    return a;       // 동작: {Return}
  }                 // 동작: {Next, Return}
}                   // 오류: 반환 타입이 있는 함수의 본문에서는
                    //   Next가 유효하지 않습니다.
예제: continue는 루프 안에 있어야 합니다
fn continue_out_of_loop () {
  var a: i32 = 0;
  if a > 0  {
    continue;       // 동작: {Continue}
  }                 // 동작: {Next, Continue}
}                   // 오류: 함수 본문에서는 Continue가 유효하지 않습니다.
같은 예제에서 continuebreak로 바꾸어도 동일한 이유로 유효하지 않습니다.

10. 단언

단언은 불리언 조건이 충족되는지 확인하는 검사입니다.

global_assert :

const_assert ';'

WGSL은 한 종류의 단언, 즉 상수 단언을 정의합니다.

const_assert :

'const_assert' expression

타입 규칙 전제 조건: 식은 bool 타입이어야 합니다.

10.1. 상수 단언문

상수 단언문은 식이 false로 평가되면 셰이더 생성 오류를 발생시키는 단언입니다. 식은 상수 식이어야 합니다. 이 문은 셰이더의 정적 접근 조건을 충족할 수 있지만 그 외에는 컴파일된 셰이더에 영향을 주지 않습니다. 상수 단언은 모듈 범위 또는 함수 범위 으로 나타날 수 있습니다.

assert_statement :

const_assert

예제: 정적 단언 예제
const x = 1;
const y = 2;
const_assert x < y; // 모듈 범위에서 유효합니다.
const_assert(y != 0); // 괄호는 선택 사항입니다.

fn foo() {
  const z = x + y - 2;
  const_assert z > 0; // 함수 안에서 유효합니다.
  let a  = 3;
  const_assert a != 0; // 유효하지 않습니다. 식은 상수 식이어야 합니다.
}

11. 함수

함수는 호출될 때 계산 작업을 수행합니다.

함수는 다음 방법 중 하나로 호출됩니다.

WGSL의 함수는 사용된 위치보다 소스에서 뒤에 정의되는 경우를 포함하여 어떤 순서로든 정의할 수 있습니다. 따라서 함수 프로토타입이나 전방 선언은 필요하지 않으며 이를 작성하는 방법도 없습니다.

함수에는 두 종류가 있습니다.

11.1. 사용자 정의 함수 선언

함수 선언은 다음을 지정하여 사용자 정의 함수를 생성합니다.

함수 선언은 모듈 범위에서만 반드시 나타나야 합니다. 함수 이름은 프로그램 전체에서 범위 안에 있습니다.

참고:사용자 정의 함수에는 하나의 오버로드만 있습니다.

형식 매개변수 선언은 함수를 호출할 때 반드시 제공해야 하는 값의 식별자 이름과 타입을 지정합니다. 진입점 함수의 형식 매개변수에는 특성을 적용할 수 있습니다. § 11.2 함수 호출을 참조하십시오. 식별자의 범위함수 본문입니다. 주어진 함수의 두 형식 매개변수는 같은 이름을 가져서는 안 됩니다.

참고: 일부 내장 함수는 매개변수에 추상 숫자 타입을 허용할 수 있습니다. 그러나 이 기능은 현재 사용자 선언 함수에서 지원되지 않습니다.

반환 타입을 지정한 경우 생성 가능해야 합니다.

WGSL은 함수 선언에 적용할 수 있는 다음 특성을 정의합니다.

function_decl :

attribute * function_header compound_statement

function_header :

'fn' ident '(' param_list ? ')' ( '->' attribute * template_elaborated_ident ) ?

param_list :

param ( ',' param ) * ',' ?

param :

attribute * ident ':' type_specifier

예제: 단순 함수
// add_two 함수를 선언합니다.
// 이 함수에는 두 형식 매개변수 i와 b가 있습니다.
// 반환 타입은 i32입니다.
// return 문이 있는 본문을 가집니다.
fn add_two(i: i32, b: f32) -> i32 {
  return i + 2;  // 형식 매개변수는 본문에서 사용할 수 있습니다.
}

// 컴퓨트 셰이더 진입점 함수 'main'입니다.
// 지정된 반환 타입이 없습니다.
// add_two 함수를 호출하고 결과 값을
// 이름 있는 값 'six'에 저장합니다.
@compute @workgroup_size(1)
fn main() {
   let six: i32 = add_two(4, 5.0);
}

11.2. 함수 호출

함수 호출은 함수를 호출하는 문 또는 식입니다.

함수 호출을 포함하는 함수는 호출 함수 또는 호출자입니다. 호출되는 함수는 피호출 함수 또는 피호출자입니다.

함수 호출은 다음을 수행합니다.

함수 호출은 피호출 함수에 있는 형식 매개변수와 동일한 수의 인수 값을 반드시 제공해야 합니다. 각 인수 값은 위치상 대응하는 형식 매개변수와 동일한 타입으로 반드시 평가되어야 합니다.

요약하면 함수를 호출할 때 다음이 수행됩니다.

  1. 호출 함수의 실행이 일시 중단됩니다.

  2. 피호출 함수반환할 때까지 실행됩니다.

  3. 호출 함수의 실행이 재개됩니다.

피호출 함수는 다음과 같이 반환합니다.

구체적으로 함수 호출이 실행될 때 다음 단계가 발생합니다.

  1. 함수 호출의 인수 값을 평가합니다. 상대적인 평가 순서는 왼쪽에서 오른쪽입니다.

  2. 호출 함수의 실행이 일시 중단됩니다. 모든 함수 범위 변수와 상수는 현재 값을 유지합니다.

  3. 피호출 함수가 사용자 정의 함수이면 피호출 함수의 각 함수 범위 변수에 메모리를 할당합니다.

  4. 피호출 함수의 형식 매개변수 값은 함수 호출의 인수 값을 위치별로 대응시켜 결정합니다. 예를 들어 피호출 함수의 첫 번째 형식 매개변수에는 호출 지점에 있는 첫 번째 인수의 값이 지정됩니다.

  5. 제어가 피호출 함수로 이동합니다. 피호출 함수가 사용자 정의 함수이면 본문의 첫 번째 문부터 실행을 진행합니다.

  6. 피호출 함수는 반환할 때까지 실행됩니다.

  7. 제어가 호출 함수로 다시 이동하고 피호출 함수 실행의 일시 중단 상태가 해제됩니다. 피호출 함수가 값을 반환하면 해당 값이 함수 호출 식의 값으로 제공됩니다.

함수 호출의 위치를 호출 지점이라고 하며, 구체적으로는 파싱된 call_phrase 문법 규칙 인스턴스의 첫 번째 토큰 위치입니다. 호출 지점은 동적 문맥입니다. 따라서 동일한 텍스트 위치가 여러 호출 지점을 나타낼 수 있습니다.

참고: 쿼드의 모든 호출이 폐기되면 프래그먼트 셰이더의 함수 호출이 반환하지 않을 수 있습니다. 이 경우 제어는 호출 함수로 다시 이동하지 않습니다.

11.3. const 함수

const 특성으로 선언된 함수는 셰이더 생성 시점에 평가할 수 있습니다. 이러한 함수를 const 함수라고 합니다. 이러한 함수의 호출은 상수 식의 일부가 될 수 있습니다.

함수에 상수 식이 아닌 식이나 const 선언이 아닌 선언이 포함되어 있으면 셰이더 생성 오류입니다.

참고: const 특성은 사용자 선언 함수에 적용할 수 없습니다.

예제: const 함수
const first_one = firstLeadingBit(1234 + 4567); // 12로 평가됩니다.
                                                // firstLeadingBit는 AbstractInt에서
                                                // 연산할 수 없으므로 first_one의
                                                // 타입은 i32입니다.

@id(1) override x : i32;
override y = firstLeadingBit(x); // 상수 식은 오버라이드 식에서
                                 // 사용할 수 있습니다.
                                 // 이 문맥에서 firstLeadingBit(x)는
                                 // 상수 식이 아닙니다.

fn foo() {
  var a : array<i32, firstLeadingBit(257)>; // 모든 매개변수가 상수 식이면
                                            // const 함수를 상수 식에서
                                            // 사용할 수 있습니다.
}

11.4. 함수에 대한 제한

참고: 어떤 종류의 선언 사이에서도 순환이 허용되지 않으므로 재귀가 허용되지 않습니다.

예제: 유효하거나 유효하지 않은 포인터 인수
fn bar(p : ptr<function, f32>) {
}

fn baz(p : ptr<private, i32>) {
}

fn bar2(p : ptr<function, f32>) {
  let a = &*&*(p);

  bar(p); // 유효함
  bar(a); // 유효함
}

fn baz2(p : ptr<storage, f32>) {
}

struct S {
  x : i32
}

@group(0) @binding(0)
var<storage> ro_storage : f32;
@group(0) @binding(1)
var<storage, read_write> rw_storage : f32;

var usable_priv : i32;
var unusable_priv : array<i32, 4>;
fn foo() {
  var usable_func : f32;
  var unusable_func : S;
  var i32_func : i32;

  let a_priv = &usable_priv;
  let b_priv = a_priv;
  let c_priv = &*&usable_priv;
  let d_priv = &(unusable_priv.x);
  let e_priv = d_priv;

  let a_func = &usable_func;
  let b_func = &unusable_func;
  let c_func = &(*b_func)[0];
  let d_func = c_func;
  let e_func = &*a_func;

  baz(&usable_priv); // 유효함, 변수의 주소 가져오기입니다.
  baz(a_priv);       // 유효함, 실질적으로 변수의 주소 가져오기입니다.
  baz(b_priv);       // 유효함, 실질적으로 변수의 주소 가져오기입니다.
  baz(c_priv);       // 유효함, 실질적으로 변수의 주소 가져오기입니다.
  baz(d_priv);       // 유효함, 메모리 뷰가 변경되었습니다.
  baz(e_priv);       // 유효함, 메모리 뷰가 변경되었습니다.
  baz(&i32_func);    // 유효하지 않음, 주소 공간이 일치하지 않습니다.

  bar(&usable_func); // 유효함, 변수의 주소 가져오기입니다.
  bar(c_func);       // 유효함, 메모리 뷰가 변경되었습니다.
  bar(d_func);       // 유효함, 메모리 뷰가 변경되었습니다.
  bar(e_func);       // 유효함, 실질적으로 변수의 주소 가져오기입니다.

  baz2(&ro_storage); // 유효함, 변수의 주소 가져오기입니다.
  baz2(&rw_storage); // 유효하지 않음, 접근 모드가 일치하지 않습니다.
}

11.4.1. 별칭 분석

11.4.1.1. 루트 식별자

함수를 실행하는 동안 메모리 뷰 또는 스위즐 뷰를 사용하여 메모리 위치에 접근할 수 있습니다. 함수 내에서 각 메모리 뷰에는 특정한 루트 식별자가 있습니다. 이 식별자는 해당 함수에서 그 메모리에 처음으로 접근을 제공하는 변수 또는 형식 매개변수의 이름입니다. 마찬가지로 스위즐 뷰루트 식별자는 스위즐 뷰 포인터의 루트 식별자입니다.

참조 또는 포인터 타입의 지역적으로 파생된 식은 특정 루트 식별자의 새 이름을 도입할 수 있지만 각 식에는 정적으로 결정할 수 있는 루트 식별자가 있습니다.

포인터 또는 참조 타입의 식 E가 주어졌을 때, 루트 식별자는 다음과 같이 찾은 기원 변수 또는 포인터 타입형식 매개변수입니다.

11.4.1.2. 별칭

루트 식별자기원 변수는 함수의 호출 지점에 따라 달라지는 동적 개념이지만, WGSL 모듈을 정적으로 분석하여 각 루트 식별자에 가능한 모든 기원 변수 집합을 결정할 수 있습니다.

루트 식별자는 같은 기원 변수를 가질 때 서로 별칭을 이룹니다. 한 접근은 쓰기이고 다른 접근은 읽기 또는 쓰기인 경우 WGSL 함수의 실행은 서로 별칭을 이루는 루트 식별자를 통해 메모리에 접근할 가능성이 있어서는 안 됩니다. 이는 호출 그래프의 리프부터 위쪽으로 프로그램을 분석하여 결정합니다 (즉, 위상 순서). 각 함수에 대해 분석은 다음 집합을 기록합니다.

함수의 각 호출 지점에서 다음 중 하나라도 발생하면 셰이더 생성 오류입니다.

예제: 별칭 분석
var<private> x : i32 = 0;

fn f1(p1 : ptr<function, i32>, p2 : ptr<function, i32>) {
  *p1 = *p2;
}

fn f2(p1 : ptr<function, i32>, p2 : ptr<function, i32>) {
  f1(p1, p2);
}

fn f3() {
  var a : i32 = 0;
  f2(&a, &a);  // 유효하지 않습니다. 하나 이상에 쓰기가 수행되는 경우
               // 같은 루트 식별자를 가진 두 포인터 매개변수를
               // 전달할 수 없습니다(하위 함수에서 쓰는 경우도 포함).
}

fn f4(p1 : ptr<function, i32>, p2 : ptr<function, i32>) -> i32 {
  return *p1 + *p2;
}

fn f5() {
  var a : i32 = 0;
  let b = f4(&a, &a); // 유효합니다. f4의 p1과 p2는 모두 읽기만 수행됩니다.
}

fn f6(p : ptr<private, i32>) {
  x = *p;
}

fn f7(p : ptr<private, i32>) -> i32 {
  return x + *p;
}

fn f8() {
  let a = f6(&x); // 유효하지 않습니다. x에는 전역 변수로서 쓰기가 수행되고
                  // 매개변수로서 읽기가 수행됩니다.
  let b = f7(&x); // 유효합니다. x는 매개변수와 변수 모두로서
                  // 읽기만 수행됩니다.
}

12. 특성

특성은 객체를 수정합니다. WGSL은 특성을 적용하기 위한 통합 구문을 제공합니다. 특성은 API와의 인터페이스 지정 등 다양한 목적으로 사용됩니다.

일반적으로 언어의 관점에서 특성은 타입 및 의미 검사를 수행할 때 무시할 수 있습니다. 또한 특성 이름은 문맥 의존적 이름이며, 일부 특성 매개변수도 문맥 의존적 이름입니다.

attribute :

'@' ident_pattern_token argument_expression_list ?

| align_attr

| binding_attr

| blend_src_attr

| builtin_attr

| const_attr

| diagnostic_attr

| group_attr

| id_attr

| interpolate_attr

| invariant_attr

| location_attr

| must_use_attr

| size_attr

| workgroup_size_attr

| subgroup_size_attr

| vertex_attr

| fragment_attr

| compute_attr

특성의 설명에서 명시적으로 허용하지 않는 한, 객체 또는 타입 하나에 동일한 특성을 두 번 이상 지정해서는 안 됩니다.

12.1. align

align_attr :

'@' 'align' '(' expression ',' ? ')'

align 특성
설명 메모리에서 구조체 멤버의 배치를 제한합니다.

반드시 구조체 타입의 멤버에만 적용해야 합니다.

이 특성은 이를 포함하는 구조체 타입의 값이 메모리에 나타나는 방식에 영향을 줍니다. 즉, 구조체 자체와 그 구성 멤버들이 나타날 수 있는 바이트 주소를 제한합니다.

align(n)이 타입 TS의 멤버에 적용되고, S가 주소 공간 AS에 있는 변수의 저장소 타입이 될 수 있으며, ASuniform이 아니라면, n반드시 다음을 충족해야 합니다.
어떤 양의 정수 k에 대해 n = k × RequiredAlignOf(T,AS)입니다.

정렬과 크기에 관한 규칙은 상호 재귀적입니다. 그러나 위 제약 조건은 중첩된 타입의 필수 정렬에 의존하고, 타입의 중첩 깊이에는 상한이 있으므로 명확하게 정의됩니다.

유니폼 또는 스토리지 버퍼에 바인딩된 메모리의 시작 주소가 특성에 지정된 값보다 낮은 정렬을 가지면, 결과 정렬은 두 값 중 작은 값이 됩니다. 구현은 변수의 기준 주소에 대해서만 이 특성을 충족합니다.

§ 14.4 메모리 레이아웃을 참조하십시오.

매개변수 반드시 상수 식이어야 하며, 그 식은 해석될 때 i32 또는 u32가 되어야 합니다.
반드시 양수여야 합니다.
반드시 2의 거듭제곱이어야 합니다.

12.2. binding

binding_attr :

'@' 'binding' '(' expression ',' ? ')'

binding 특성
설명 바인드 그룹에서 리소스의 바인딩 번호를 지정합니다. § 13.3.2 리소스 인터페이스를 참조하십시오.

반드시 리소스 변수에만 적용해야 합니다.

매개변수 반드시 상수 식이어야 하며, 그 식은 해석될 때 i32 또는 u32가 되어야 합니다.
반드시 음수가 아니어야 합니다.

12.3. blend_src

blend_src_attr :

'@' 'blend_src' '(' expression ',' ? ')'

blend_src 특성
설명 dual_source_blending 기능이 활성화되었을 때 프래그먼트 출력의 일부를 지정합니다. § 13.3.1.3 입출력 위치를 참조하십시오.

반드시 location 특성이 있는 구조체 타입의 멤버에만 적용해야 합니다. 반드시 숫자 스칼라 또는 숫자 벡터 타입인 객체의 선언에만 적용해야 합니다. 셰이더 스테이지 입력에 포함해서는 안 됩니다. 프래그먼트 셰이더 스테이지를 제외하고 셰이더 스테이지 출력에 포함해서는 안 됩니다.

매개변수 반드시 상수 식이어야 하며, 그 식은 해석될 때 값이 0 또는 1i32 또는 u32가 되어야 합니다.

12.4. builtin

builtin_attr :

'@' 'builtin' '(' builtin_value_name ',' ? ')'

builtin 특성
설명 지정된 토큰이 나타내는 대로 연결된 객체가 내장 값임을 지정합니다. § 13.3.1.1 내장 입력과 출력을 참조하십시오.

반드시 진입점 함수 매개변수, 진입점 반환 타입 또는 구조체의 멤버에만 적용해야 합니다.

매개변수 반드시 내장 값을 위한 내장 값 이름 토큰이어야 합니다.

12.5. const

const_attr :

'@' 'const'

const 특성
설명 함수를 상수 함수로 사용할 수 있음을 지정합니다. 이 특성을 사용자 정의 함수에 적용해서는 안 됩니다.

반드시 함수 선언에만 적용해야 합니다.

참고: 이 특성은 어떤 내장 함수를 상수 식에서 사용할 수 있는지 설명하는 표기 규약으로 사용됩니다.

매개변수 없음

12.6. diagnostic

diagnostic_attr :

'@' 'diagnostic' diagnostic_control

diagnostic_control :

'(' severity_control_name ',' diagnostic_rule_name ',' ? ')'

diagnostic 특성
설명 범위 진단 필터를 지정합니다. § 2.3 진단을 참조하십시오.

하나의 구문 형식에 둘 이상의 diagnostic 특성을 지정할 수 있지만, 서로 다른 트리거 규칙을 지정해야 합니다.

매개변수 첫 번째 매개변수는 severity_control_name입니다.

두 번째 매개변수는 트리거 규칙을 지정하는 diagnostic_rule_name 토큰입니다.

12.7. group

group_attr :

'@' 'group' '(' expression ',' ? ')'

group 특성
설명 리소스의 바인딩 그룹을 지정합니다. § 13.3.2 리소스 인터페이스를 참조하십시오.

반드시 리소스 변수에만 적용해야 합니다.

매개변수 반드시 상수 식이어야 하며, 그 식은 해석될 때 i32 또는 u32가 되어야 합니다.
반드시 음수가 아니어야 합니다.

12.8. id

id_attr :

'@' 'id' '(' expression ',' ? ')'

id 특성
설명 파이프라인 오버라이드 가능 상수의 대체 이름으로 사용할 숫자 식별자를 지정합니다.

반드시 스칼라 타입인 오버라이드 선언에만 적용해야 합니다.

매개변수 반드시 상수 식이어야 하며, 그 식은 해석될 때 i32 또는 u32가 되어야 합니다.
반드시 음수가 아니어야 합니다.

12.9. interpolate

interpolate_attr :

'@' 'interpolate' '(' interpolate_type_name ',' ? ')'

| '@' 'interpolate' '(' interpolate_type_name ',' interpolate_sampling_name ',' ? ')'

interpolate_type_name :

ident_pattern_token

interpolate 특성
설명 사용자 정의 IO를 어떻게 보간해야 하는지 지정합니다. § 13.3.1.4 보간을 참조하십시오.

반드시 location 특성이 적용된 선언에만 적용해야 합니다.

이 특성이 존재할 때는 사용자 정의 버텍스 출력과 프래그먼트 입력에만 의미가 있습니다.

매개변수 첫 번째 매개변수는 보간 타입을 위한 보간 타입 이름 토큰이어야 합니다.

두 번째 매개변수가 존재한다면 보간 샘플링을 위한 보간 샘플링 이름 토큰이어야 합니다.

12.10. invariant

invariant_attr :

'@' 'invariant'

invariant 특성
설명 버텍스 셰이더의 position 내장 출력값에 적용하면 결과 계산은 서로 다른 프로그램 및 동일한 진입점의 서로 다른 호출 전반에서 불변입니다. 즉, 서로 다른 진입점의 두 position 출력에서 데이터 흐름과 제어 흐름이 일치하면 결과 값이 동일함이 보장됩니다. position 내장 입력값에는 아무런 영향이 없습니다.

반드시 position 내장 값에만 적용해야 합니다.

참고: 이 특성은 HLSL의 precise 한정자 및 GLSL의 invariant 한정자에 대응합니다.

매개변수 없음

12.11. location

location_attr :

'@' 'location' '(' expression ',' ? ')'

location 특성
설명 진입점의 사용자 정의 IO 일부를 지정합니다. § 13.3.1.3 입출력 위치를 참조하십시오.

반드시 진입점 함수 매개변수, 진입점 반환 타입 또는 구조체 타입의 멤버에만 적용해야 합니다. 반드시 숫자 스칼라 또는 숫자 벡터 타입인 객체의 선언에만 적용해야 합니다. 컴퓨트 셰이더 스테이지 입력에 포함해서는 안 됩니다.

매개변수 반드시 상수 식이어야 하며, 그 식은 해석될 때 i32 또는 u32가 되어야 합니다.
반드시 음수가 아니어야 합니다.

12.12. must_use

must_use_attr :

'@' 'must_use'

must_use 특성
설명 이 함수에 대한 호출으로 사용해야 을 지정합니다. 즉, 이 함수에 대한 호출이 함수 호출문의 전부여서는 안 됩니다.

반드시 반환 타입이 있는 함수의 선언에만 적용해야 합니다.

참고: 많은 함수는 값을 반환하며 부수 효과가 없습니다. 그러한 함수에 대한 호출을 함수 호출문에서 유일한 요소로 사용하는 것은 흔히 프로그래밍 결함입니다. 이러한 속성을 가진 내장 함수는 @must_use로 선언됩니다. 사용자 정의 함수에도 @must_use 특성을 지정할 수 있습니다.

참고: @must_use 규칙을 의도적으로 우회하려면 더미 할당을 사용하거나, 함수 호출을 이니셜라이저로 사용하여 값을 선언하십시오.

매개변수 없음

12.13. size

size_attr :

'@' 'size' '(' expression ',' ? ')'

size 특성
설명 구조체 멤버를 위해 예약되는 바이트 수를 지정합니다.

이 수는 멤버 타입의 바이트 크기 이상이어야 합니다.

size(n)이 타입 T인 멤버에 적용되면 SizeOf(T) ≤ n입니다.

§ 14.4 메모리 레이아웃을 참조하십시오.

반드시 구조체 타입의 멤버에만 적용해야 합니다. 멤버 타입은 생성 시 고정된 풋프린트를 가져야 합니다.

매개변수 반드시 상수 식이어야 하며, 그 식은 해석될 때 i32 또는 u32가 되어야 합니다.
반드시 양수여야 합니다.

12.14. subgroup_size

subgroup_size_attr :

'@' 'subgroup_size' '(' expression ',' ? ')'

subgroup_size 특성
설명 컴퓨트 셰이더 호출의 서브그룹 크기를 지정합니다.

반드시 컴퓨트 셰이더 진입점 함수에만 적용해야 합니다.

요구 사항 반드시 subgroup_size_control 확장이 활성화된 경우에만 사용해야 합니다.
매개변수 상수 식 또는 오버라이드 식이어야 하며, 그 식은 해석될 때 i32 또는 u32가 되어야 합니다.

값이 2의 거듭제곱이 아니라면 다음과 같습니다.

진입점 workgroup_size의 x 차원이 subgroup_size 값의 배수가 아니면 파이프라인 생성 오류가 발생합니다.

값이 subgroupMaxSize보다 크거나 subgroupMinSize보다 작으면 파이프라인 생성 오류가 발생합니다.

값이 subgroupMinSizesubgroupMaxSize 사이에 있더라도, 레지스터 압박 또는 특정 하드웨어 제한으로 인해 파이프라인 생성 시 분류되지 않은 오류가 발생할 수 있습니다.

12.15. workgroup_size

workgroup_size_attr :

'@' 'workgroup_size' '(' expression ',' ? ')'

| '@' 'workgroup_size' '(' expression ',' expression ',' ? ')'

| '@' 'workgroup_size' '(' expression ',' expression ',' expression ',' ? ')'

workgroup_size 특성
설명 컴퓨트 셰이더의 워크그룹 그리드에 대한 x, y, z 차원을 지정합니다.

첫 번째 매개변수는 x 차원을 지정합니다. 두 번째 매개변수가 제공되면 y 차원을 지정하며, 그렇지 않으면 1로 간주됩니다. 세 번째 매개변수가 제공되면 z 차원을 지정하며, 그렇지 않으면 1로 간주됩니다.

반드시 컴퓨트 셰이더 진입점 함수에만 적용해야 합니다. 다른 객체에는 적용해서는 안 됩니다.

매개변수 하나, 둘 또는 세 개의 매개변수를 받습니다.

각 매개변수는 상수 식 또는 오버라이드 식이어야 합니다. 모든 매개변수는 i32 또는 u32 중 하나인 동일한 타입이어야 합니다.

지정된 매개변수 중 하나라도 양수가 아닌 값으로 평가되는 상수 식이면 셰이더 생성 오류가 발생합니다.

지정된 매개변수 중 하나라도 양수가 아닌 값으로 평가되거나 WebGPU API가 지정한 상한을 초과하는 경우, 또는 매개변수 값의 곱이 WebGPU API가 지정한 상한을 초과하는 경우 파이프라인 생성 오류가 발생합니다(WebGPU § 3.6.2 제한 참조).

12.16. 셰이더 스테이지 특성

아래의 셰이더 스테이지 특성은 함수를 특정 셰이더 스테이지진입점으로 지정합니다. 이러한 특성은 함수 선언에만 적용해야 하며, 지정된 함수에는 최대 하나만 존재할 수 있습니다. 매개변수는 받지 않습니다.

12.16.1. vertex

vertex_attr :

'@' 'vertex'

vertex 특성은 함수를 렌더 파이프라인버텍스 셰이더 스테이지를 위한 진입점으로 선언합니다.

12.16.2. fragment

fragment_attr :

'@' 'fragment'

fragment 특성은 함수를 렌더 파이프라인프래그먼트 셰이더 스테이지를 위한 진입점으로 선언합니다.

12.16.3. compute

compute_attr :

'@' 'compute'

compute 특성은 함수를 컴퓨트 파이프라인컴퓨트 셰이더 스테이지를 위한 진입점으로 선언합니다.

13. 진입점

진입점은 특정 셰이더 스테이지를 위한 작업을 수행하는 사용자 정의 함수입니다.

13.1. 셰이더 스테이지

WebGPU는 그리기 또는 디스패치 명령의 형태로 GPU에 작업을 지시합니다. 이러한 명령은 셰이더 스테이지 입력, 출력 및 연결된 리소스의 집합이라는 문맥에서 파이프라인을 실행합니다.

파이프라인은 GPU에서 수행할 작업을 일련의 스테이지로 설명하며, 이 중 일부는 프로그래밍할 수 있습니다. WebGPU에서는 그리기 또는 디스패치 명령의 실행을 예약하기 전에 파이프라인이 생성됩니다. 파이프라인에는 GPUComputePipeline과 GPURenderPipeline의 두 종류가 있습니다.

디스패치 명령GPUComputePipeline을 사용하여 제어 가능한 수준의 병렬 처리로 논리적 점 그리드 전체에서 컴퓨트 셰이더 스테이지를 실행하면서 버퍼 및 이미지 리소스를 읽고 필요에 따라 갱신합니다.

그리기 명령GPURenderPipeline을 사용하여 다른 고정 기능 스테이지들 사이에서 프로그래밍 가능한 두 스테이지가 포함된 다단계 처리를 실행합니다.

WebGPU 명세에는 파이프라인이 더 상세하게 설명되어 있습니다.

WGSL은 파이프라인의 프로그래밍 가능한 부분에 대응하는 세 가지 셰이더 스테이지를 정의합니다.

각 셰이더 스테이지에는 다른 곳에서 설명하는 고유한 기능과 제약 조건이 있습니다.

13.2. 진입점 선언

진입점을 생성하려면 셰이더 스테이지 특성이 있는 사용자 정의 함수를 선언합니다.

WebGPU API에서 파이프라인을 구성할 때 진입점의 함수 이름은 WebGPU GPUProgrammableStage 객체의 entryPoint 특성에 매핑됩니다.

진입점의 형식 매개변수는 해당 스테이지의 셰이더 스테이지 입력을 나타냅니다. 구조체 타입을 사용하여 사용자 정의 입력끼리 묶고, 선택적으로 내장 입력과 함께 묶을 수 있습니다. 각 매개변수는 셰이더 스테이지 입력이거나, 각 구조체 멤버가 셰이더 스테이지 입력인 구조체 타입으로 선언되어야 하며, 그렇지 않다면 그러한 구조체 타입으로 선언되어야 합니다.

지정된 경우 진입점의 반환 타입과 그 특성은 해당 스테이지의 셰이더 스테이지 출력을 나타냅니다. 구조체 타입을 사용하여 사용자 정의 출력끼리 묶고, 선택적으로 내장 출력과 함께 묶을 수 있습니다. 반환 타입과 그 특성이 존재하면 셰이더 스테이지 출력이거나, 각 구조체 멤버가 셰이더 스테이지 출력인 구조체 타입이어야 하며, 그렇지 않다면 그러한 구조체 타입이어야 합니다.

참고: 컴퓨트 진입점에는 반환 타입이 절대 없습니다.

예제: 진입점
@vertex
fn vert_main() -> @builtin(position) vec4<f32> {
  return vec4<f32>(0.0, 0.0, 0.0, 1.0);
}

@fragment
fn frag_main(@builtin(position) coord_in: vec4<f32>) -> @location(0) vec4<f32> {
  return vec4<f32>(coord_in.x, coord_in.y, 0.0, 1.0);
}

@compute @workgroup_size(1)
fn comp_main() { }

셰이더 스테이지의 함수 집합은 다음 항목의 합집합입니다.

합집합은 안정화될 때까지 반복해서 적용됩니다. 유한한 단계 내에 안정화됩니다.

13.2.1. 진입점을 위한 함수 특성

WGSL은 진입점 선언에 적용할 수 있는 다음과 같은 특성을 정의합니다.

예제: workgroup_size 특성
@compute @workgroup_size(8,4,1)
fn sorter() { }

@compute @workgroup_size(8u)
fn reverser() { }

// 파이프라인 오버라이드 가능 상수를 사용합니다.
@id(42) override block_width = 12u;
@compute @workgroup_size(block_width)
fn shuffler() { }

// 오류: workgroup_size는 컴퓨트 셰이더에 지정해야 합니다.
@compute
fn bad_shader() { }

13.3. 셰이더 인터페이스

셰이더 인터페이스는 셰이더가 읽거나 쓰기 위해 셰이더 스테이지 외부의 데이터에 접근할 때 사용하는 객체 집합과, 셰이더를 구성하는 데 사용되는 파이프라인 오버라이드 가능 상수로 이루어집니다. 인터페이스에는 다음이 포함됩니다.

선언 D는 다음과 같은 경우 셰이더에서 정적으로 접근됩니다.

참고:정적 접근은 다음 사항을 고려하여 재귀적으로 정의됩니다.

이제 셰이더의 인터페이스를 다음 항목으로 구성된 것으로 정확하게 정의할 수 있습니다.

13.3.1. 스테이지 간 입력 및 출력 인터페이스

셰이더 스테이지 입력은 파이프라인의 상류에서 셰이더 스테이지로 제공되는 데이터입니다. 각 데이터는 내장 입력값 또는 사용자 정의 입력입니다.

셰이더 스테이지 출력은 셰이더가 파이프라인 하류의 추가 처리를 위해 제공하는 데이터입니다. 각 데이터는 내장 출력값 또는 사용자 정의 출력입니다.

IO 특성은 객체를 셰이더 스테이지 입력 또는 셰이더 스테이지 출력으로 확립하거나, 입력 또는 출력의 속성을 추가로 설명하는 데 사용됩니다. IO 특성은 다음과 같습니다.

13.3.1.1. 내장 입력과 출력

내장 입력값은 시스템에서 생성된 제어 정보에 대한 접근을 제공합니다. 진입점에는 동일한 내장 값 이름을 가진 두 개의 내장 입력이 있어서는 안 됩니다.

스테이지 S에 대한 이름 X, 타입 TX인 내장 입력에는 다음 두 방법 중 하나로 셰이더 스테이지 S진입점에 대한 형식 매개변수를 통해 접근합니다.

  1. 매개변수에 builtin(X) 특성이 있고 타입이 TX입니다.

  2. 매개변수가 구조체 타입이며, 구조체 멤버 중 하나에 builtin(X) 특성이 있고 타입이 TX입니다.

반대로 진입점의 매개변수 또는 매개변수의 멤버에 builtin 특성이 있으면, 이에 대응하는 내장 값은 진입점의 셰이더 스테이지에 대한 입력이어야 합니다.

내장 출력값은 셰이더가 파이프라인의 후속 처리 단계에 제어 정보를 전달하는 데 사용됩니다. 진입점에는 동일한 내장 값 이름을 가진 두 개의 내장 출력이 있어서는 안 됩니다.

스테이지 S에 대한 이름 Y, 타입 TY인 내장 출력은 다음 두 방법 중 하나로 셰이더 스테이지 S진입점에 대한 반환 값을 통해 설정됩니다.

  1. 진입점 반환 타입builtin(Y) 특성이 있고 타입이 TY입니다.

  2. 진입점 반환 타입이 구조체 타입이며, 구조체 멤버 중 하나에 builtin(Y) 특성이 있고 타입이 TY입니다.

반대로 진입점의 반환 타입 또는 반환 타입의 멤버에 builtin 특성이 있으면, 이에 대응하는 내장 값은 진입점의 셰이더 스테이지에 대한 출력이어야 합니다.

참고: position 내장 값은 버텍스 셰이더의 출력이자 프래그먼트 셰이더의 입력입니다.

내장 입력값과 내장 출력값을 통틀어 내장 값이라고 합니다.

다음 표에는 사용 가능한 내장 값이 요약되어 있습니다. 각 항목은 내장 값을 위한 내장 값 이름 토큰입니다. 각 항목은 이후 절에서 자세히 설명합니다.

내장 입력값과 출력값
이름 스테이지 방향 타입 확장
vertex_index 버텍스 입력 u32
instance_index 버텍스 입력 u32
clip_distances 버텍스 출력 array<f32, N> (N8) clip_distances
position 버텍스 출력 vec4<f32>
프래그먼트 입력 vec4<f32>
front_facing 프래그먼트 입력 bool
frag_depth 프래그먼트 출력 f32
primitive_index 프래그먼트 입력 u32 primitive_index
sample_index 프래그먼트 입력 u32
sample_mask 프래그먼트 입력 u32
프래그먼트 출력 u32
local_invocation_id 컴퓨트 입력 vec3<u32>
local_invocation_index 컴퓨트 입력 u32
global_invocation_id 컴퓨트 입력 vec3<u32>
global_invocation_index 컴퓨트 입력 u32 linear_indexing
workgroup_id 컴퓨트 입력 vec3<u32>
workgroup_index 컴퓨트 입력 u32 linear_indexing
num_workgroups 컴퓨트 입력 vec3<u32>
subgroup_invocation_id 컴퓨트 입력 u32 subgroups
프래그먼트
subgroup_size 컴퓨트 입력 u32 subgroups
프래그먼트
subgroup_id 컴퓨트 입력 u32 subgroupssubgroup_id
num_subgroups 컴퓨트 입력 u32 subgroupssubgroup_id
예제: 내장 값 선언
 struct VertexOutput {
   @builtin(position) my_pos: vec4<f32>,
   @builtin(clip_distances) my_clip_distances: array<f32, 8>,
 }

 @vertex
 fn vs_main(
   @builtin(vertex_index) my_index: u32,
   @builtin(instance_index) my_inst_index: u32,
 ) -> VertexOutput {}

 struct FragmentOutput {
   @builtin(frag_depth) depth: f32,
   @builtin(sample_mask) mask_out: u32
 }

 @fragment
 fn fs_main(
   @builtin(front_facing) is_front: bool,
   @builtin(position) coord: vec4<f32>,
   @builtin(sample_index) my_sample_index: u32,
   @builtin(sample_mask) mask_in: u32,
 ) -> FragmentOutput {}

 @compute @workgroup_size(64)
 fn cs_main(
   @builtin(local_invocation_id) local_id: vec3<u32>,
   @builtin(local_invocation_index) local_index: u32,
   @builtin(global_invocation_id) global_id: vec3<u32>,
) {}
13.3.1.1.1. clip_distances
이름 clip_distances
스테이지 버텍스
타입 array<f32, N>
방향 출력
설명 배열의 각 값은 사용자 정의 클립 평면까지의 거리를 나타냅니다. 클립 거리가 0이면 버텍스가 평면 위에 있음을 의미하고, 양의 거리이면 버텍스가 클립 반공간 내부에 있음을 의미하며, 음의 거리이면 버텍스가 클립 반공간 외부에 있음을 의미합니다. clip_distances의 배열 크기는 8 이하여야 합니다. WebGPU § 23.2.4 프리미티브 클리핑을 참조하십시오.
13.3.1.1.2. frag_depth
이름 frag_depth
스테이지 프래그먼트
타입 f32
방향 출력
설명 뷰포트 깊이 범위에 있는 프래그먼트의 갱신된 깊이입니다.

WebGPU § 3.3 좌표계를 참조하십시오.

fragment_depth 기능이 지원되면 builtin 특성은 깊이 모드를 지정하는 선택적인 두 번째 매개변수를 가질 수 있습니다.

프래그먼트의 원래 깊이는 프래그먼트 RasterizationPoint의 depth 속성입니다.

셰이더가 깊이 모드 약속을 위반하는 깊이 값을 반환하면 그 대신 불확정 깊이 값이 사용될 수 있습니다.

@fragment
fn main() -> @builtin(frag_depth, greater) f32 {
    return 1.0f;
}
13.3.1.1.3. front_facing
이름 front_facing
스테이지 프래그먼트
타입 bool
방향 입력
설명 현재 프래그먼트가 앞면을 향한 프리미티브 위에 있으면 참입니다. 그렇지 않으면 거짓입니다.
13.3.1.1.4. global_invocation_id
이름 global_invocation_id
스테이지 컴퓨트
타입 vec3<u32>
방향 입력
설명 현재 호출의 전역 호출 ID, 즉 컴퓨트 셰이더 그리드 내 위치입니다. global_invocation_id의 값은 workgroup_id * workgroup_size + local_invocation_id와 같습니다.
13.3.1.1.5. global_invocation_index
이름 global_invocation_index
스테이지 컴퓨트
타입 u32;
방향 입력
설명 현재 호출의 전역 호출 인덱스, 즉 컴퓨트 셰이더 그리드 내 선형 위치입니다. global_invocation_index의 값은 다음과 같습니다.

global_invocation_id.x +
(global_invocation_id.y * workgroup_size.x * num_workgroups.x) +
(global_invocation_id.z * workgroup_size.x * num_workgroups.x * workgroup_size.y * num_workgroups.y)

참고: 디스패치된 워크그룹 수로 인해 이 값이 u32 타입의 범위를 초과하게 되면 디스패치가 실패합니다.
  • dispatchWorkgroups의 경우 GPUComputePassEncoder가 무효화됩니다.

  • dispatchWorkgroupsIndirect의 경우 디스패치가 실행되지 않습니다.

13.3.1.1.6. instance_index
이름 instance_index
스테이지 버텍스
타입 u32
방향 입력
설명 현재 API 수준 그리기 명령 내 현재 버텍스의 인스턴스 인덱스입니다.

직접 제공되었든 간접적으로 제공되었든 첫 번째 인스턴스의 인덱스는 그리기의 firstInstance 인수와 같습니다. 그리기에 추가되는 각 인스턴스마다 인덱스가 1씩 증가합니다.

13.3.1.1.7. local_invocation_id
이름 local_invocation_id
스테이지 컴퓨트
타입 vec3<u32>
방향 입력
설명 현재 호출의 로컬 호출 ID, 즉 워크그룹 그리드 내 위치입니다.
13.3.1.1.8. local_invocation_index
이름 local_invocation_index
스테이지 컴퓨트
타입 u32
방향 입력
설명 현재 호출의 로컬 호출 인덱스로, 워크그룹 그리드 내 호출 위치의 선형화된 인덱스입니다.
13.3.1.1.9. num_workgroups
이름 num_workgroups
스테이지 컴퓨트
타입 vec3<u32>
방향 입력
설명 API가 컴퓨트 셰이더를 디스패치할 때의 디스패치 크기, vec3<u32>(group_count_x, group_count_y, group_count_z)입니다.
13.3.1.1.10. position
이름 position
스테이지 버텍스
타입 vec4<f32>
방향 출력
설명 클립 공간 좌표로 나타낸 현재 버텍스의 클립 위치입니다.

출력 값 (x,y,z,w)은 WebGPU의 정규화된 장치 좌표에서 (x/w, y/w, z/w)에 매핑됩니다.

WebGPU § 3.3 좌표계WebGPU § 23.2.4 프리미티브 클리핑을 참조하십시오.

w 좌표가 0이면 동적 오류가 발생합니다.

이름 position
스테이지 프래그먼트
타입 vec4<f32>
방향 입력
설명
현재 프래그먼트 래스터화 지점의 입력 위치입니다.

rp를 프래그먼트의 RasterizationPoint라고 합니다.
vp를 그리기 명령에 적용되는 [[viewport]]라고 합니다.
그러면 fp는 프래그먼트 래스터화 지점의 계산된 입력 위치입니다.

개략적으로 다음과 같습니다.

fp.xy = rp.destination.position
fp.z = rp.depth
fp.w = rp.perspectiveDivisor

더 자세히 설명하면 다음과 같습니다.

  • fp.x와 fp.y는 프레임버퍼에서 현재 프래그먼트 래스터화 지점 위치의 보간된 x 및 y 좌표입니다.

    프레임버퍼는 왼쪽 위가 (0.0,0.0)이고 오른쪽 아래가 (vp.width, vp.height)인 2차원 픽셀 그리드입니다. 각 픽셀은 x 및 y 차원에서 각각 1.0 단위의 범위를 가지며, 픽셀 중심은 정수 좌표에서 (0.5,0.5)만큼 오프셋된 위치에 있습니다.

  • fp.z는 현재 프래그먼트 래스터화 지점의 보간된 깊이입니다. 예를 들면 다음과 같습니다.

    • 정규화된 장치 좌표에서 깊이 0은 fp.z = vp.minDepth에 매핑됩니다.

    • 정규화된 장치 좌표에서 깊이 1은 fp.z = vp.maxDepth에 매핑됩니다.

  • fp.w는 프래그먼트 래스터화 지점의 원근 제수이며, 1.0 ÷ vertex_w의 보간입니다. 여기서 vertex_w는 버텍스 셰이더의 position 출력의 w 컴포넌트입니다.

WebGPU § 3.3 좌표계WebGPU § 23.2.5 래스터화를 참조하십시오.

13.3.1.1.11. primitive_index
이름 primitive_index
스테이지 프래그먼트
타입 u32
방향 입력
설명 현재 그리기 작업을 시작한 후 현재 인스턴스에서 처리된 프리미티브 수를 바탕으로 한 프리미티브별 인덱스입니다. 0에서 시작하며 점, 선 또는 삼각형 프리미티브가 처리될 때마다 1씩 증가합니다. 그려지는 각 인스턴스 사이에서 0으로 재설정됩니다. 프리미티브 재시작 값으로 스트립 프리미티브를 다시 시작해도 프리미티브 인덱스에는 영향을 주지 않습니다. 인덱스는 프리미티브의 모든 프래그먼트에서 균일합니다.
13.3.1.1.12. sample_index
이름 sample_index
스테이지 프래그먼트
타입 u32
방향 입력
설명 현재 프래그먼트 래스터화 지점의 샘플 인덱스입니다. 값은 최소 0이고 최대 sampleCount-1입니다. 여기서 sampleCount는 GPU 렌더 파이프라인에 지정된 샘플 개수입니다. 이 특성이 적용된 경우 프래그먼트 셰이더의 효과가 sample_index 값에 따라 달라지면 프래그먼트 셰이더가 샘플당 한 번씩 호출됩니다.

WebGPU § 10.3 GPURenderPipeline을 참조하십시오.

13.3.1.1.13. sample_mask
이름 sample_mask
스테이지 프래그먼트
타입 u32
방향 입력
설명 현재 프래그먼트의 샘플 커버리지 비트마스크입니다.

비트는 반개구간 [0, sampleCount)에 속하는 샘플 인덱스로 지정됩니다. 여기서 sampleCount는 GPU 렌더 파이프라인에 지정된 샘플 개수입니다.

샘플이 렌더링 중인 프리미티브에 포함된 경우에만 비트가 1로 설정됩니다. 인덱스가 sampleCount 이상인 비트는 항상 0으로 설정됩니다.

비트마스크에는 다음 두 가지 값이 가능합니다.

  • 비트마스크에서는 프래그먼트가 포함하는 모든 샘플에 대해 1비트가 설정됩니다. 이 경우 비트마스크는 프래그먼트의 RasterizationPoint coverageMask와 같습니다.

  • 비트마스크에서는 현재 프래그먼트 셰이더 호출이 처리하는 샘플에 대응하는 1비트만 설정됩니다. 즉, sample_index 내장 입력을 사용한 것처럼 비트마스크는 (1 << sample_index)입니다.

참고: sampleCount = 1이면 이 두 경우는 동일합니다.

참고: sampleCount > 1이면 이는 알려진 이식성 위험 요소입니다. 일부 장치는 전체 커버리지 마스크를 생성하고, 다른 장치는 단일 비트 마스크를 생성합니다.

WebGPU § 23.2.10 샘플별 셰이딩WebGPU § 23.2.11 샘플 마스킹을 참조하십시오.

이름 sample_mask
스테이지 프래그먼트
타입 u32
방향 출력
설명 현재 프래그먼트의 샘플 커버리지 마스크 제어입니다. 이 변수에 마지막으로 기록된 값이 셰이더 출력 마스크가 됩니다. 기록된 값의 0비트는 색상 어태치먼트의 대응하는 샘플이 폐기되도록 합니다.

WebGPU § 23.2.11 샘플 마스킹을 참조하십시오.

13.3.1.1.14. vertex_index
이름 vertex_index
스테이지 버텍스
타입 u32
방향 입력
설명 그리기 인스턴싱과 무관한 현재 API 수준 그리기 명령 내 현재 버텍스의 인덱스입니다.

인덱싱되지 않은 그리기의 경우, 직접 제공되었든 간접적으로 제공되었든 첫 번째 버텍스의 인덱스는 그리기의 firstVertex 인수와 같습니다. 그리기 인스턴스에 추가되는 각 버텍스마다 인덱스가 1씩 증가합니다.

인덱싱된 그리기의 경우 인덱스는 해당 버텍스의 인덱스 버퍼 항목에, 직접 제공되었든 간접적으로 제공되었든 그리기의 baseVertex 인수를 더한 값입니다.

13.3.1.1.15. workgroup_id
이름 workgroup_id
스테이지 컴퓨트
타입 vec3<u32>
방향 입력
설명 현재 호출의 워크그룹 ID, 즉 전체 컴퓨트 셰이더 그리드 내 워크그룹의 위치입니다.

동일한 워크그룹의 모든 호출은 동일한 워크그룹 ID를 가집니다.

워크그룹 ID의 범위는 (0,0,0)에서 (group_count_x - 1, group_count_y - 1, group_count_z - 1)까지입니다.

13.3.1.1.16. workgroup_index
이름 workgroup_index
스테이지 컴퓨트
타입 u32
방향 입력
설명 현재 호출의 워크그룹 인덱스, 즉 전체 컴퓨트 셰이더 그리드 내 워크그룹의 선형 위치입니다.

동일한 워크그룹의 모든 호출은 동일한 워크그룹 인덱스를 가집니다.

참고: 디스패치된 워크그룹 수로 인해 이 값이 u32 타입의 범위를 초과하게 되면 디스패치가 실패합니다.
  • dispatchWorkgroups의 경우 GPUComputePassEncoder가 무효화됩니다.

  • dispatchWorkgroupsIndirect의 경우 디스패치가 실행되지 않습니다.

13.3.1.1.17. subgroup_invocation_id
이름 subgroup_invocation_id
스테이지 컴퓨트 또는 프래그먼트
타입 u32
방향 입력
설명 현재 호출의 서브그룹 호출 ID입니다.

ID는 [0, subgroup_size - 1] 범위에 있습니다.

컴퓨트 셰이더에서 ID는 0부터 시작하며 조밀합니다. 즉, 컴퓨트 셰이더가 실행을 시작할 때 각 서브그룹 내에서는 다음과 같습니다.

  • 하나의 호출이 subgroup_invocation_id = 0을 가지며,

  • 서브그룹에 subgroup_invocation_id = k인 호출이 있으면, 모든 0 ≤ j < k에 대해 서브그룹에는 subgroup_invocation_id = j인 호출이 있습니다.

참고: 프래그먼트 셰이더의 서브그룹 호출 인덱싱은 조밀하지 않을 수 있습니다. 구현은 번호가 더 작은 일부 ID를 보조 호출에 할당할 수 있습니다.

13.3.1.1.18. subgroup_size
이름 subgroup_size
스테이지 컴퓨트 또는 프래그먼트
타입 u32
방향 입력
설명 현재 호출이 속한 서브그룹의 서브그룹 크기입니다.

subgroup_size 특성이 있는 컴퓨트 셰이더의 경우 이 값은 지정된 특성 값과 같습니다.

13.3.1.1.19. subgroup_id
이름 subgroup_id
스테이지 컴퓨트
타입 u32
방향 입력
설명 워크그룹 내에서 현재 호출이 속한 서브그룹서브그룹 ID입니다.

ID는 [0, num_subgroups - 1] 범위에 있습니다.

13.3.1.1.20. num_subgroups
이름 num_subgroups
스테이지 컴퓨트
타입 u32
방향 입력
설명 현재 호출의 워크그룹에 있는 서브그룹의 수입니다.
13.3.1.2. 사용자 정의 입력과 출력

사용자 정의 데이터는 파이프라인 시작 부분에 입력으로 전달하거나, 파이프라인의 스테이지 사이에 전달하거나, 파이프라인 끝에서 출력할 수 있습니다.

사용자 정의 입력 데이터사용자 정의 출력 데이터반드시 다음을 충족해야 합니다.

컴퓨트 셰이더에는 사용자 정의 입력이나 출력이 있어서는 안 됩니다.

13.3.1.3. 입출력 위치

각 입출력 위치에는 최대 16바이트 크기의 값을 저장할 수 있습니다. 타입의 바이트 크기는 § 14.4.1 정렬 및 크기SizeOf 열을 사용하여 정의됩니다. 예를 들어 부동 소수점 값의 4컴포넌트 벡터는 단일 위치를 차지합니다.

IO 위치는 location 특성을 통해 지정됩니다.

각 사용자 정의 입력출력에는 명시적으로 지정된 IO 위치가 있어야 합니다. 진입점 IO의 각 구조체 멤버는 내장 값(§ 13.3.1.1 내장 입력과 출력 참조)이거나 위치가 할당되어야 합니다.

WGSL 모듈에 정의된 각 진입점에 대해 inputs를 해당 진입점의 셰이더 스테이지 입력 집합 (즉, 형식 매개변수의 위치 또는 구조체 타입인 형식 매개변수의 멤버 위치)이라고 합니다.
WGSL 모듈에 정의된 각 구조체 타입 S(셰이더 스테이지 입력 또는 출력에 사용되는 것만이 아님)에 대해, memberslocation 특성이 있는 S의 멤버 집합이라고 합니다.

참고: 위치 번호는 입력과 출력 사이에서 서로 구분됩니다. 진입점의 셰이더 스테이지 입력에 대한 위치 번호는 해당 진입점의 셰이더 스테이지 출력에 대한 위치 번호와 충돌하지 않습니다.

참고: 진입점의 출력 내 위치 중복을 방지하기 위한 추가 규칙은 필요하지 않습니다. 출력이 구조체이면 위의 첫 번째 규칙이 중복을 방지합니다. 그렇지 않으면 출력은 스칼라 또는 벡터이며 하나의 위치만 할당할 수 있습니다.

참고: 진입점에 사용할 수 있는 위치의 수는 WebGPU API에서 정의합니다.

예제: location 특성 적용
struct A {
  @location(0) x: f32,
  // 위치의 크기가 16바이트이더라도 x와 y는 위치를 공유할 수 없습니다.
  @location(1) y: f32
}

// in1은 위치 0과 1을 차지합니다.
// in2는 위치 2를 차지합니다.
// 반환 값은 위치 0을 차지합니다.
@fragment
fn fragShader(in1: A, @location(2) in2: f32) -> @location(0) vec4<f32> {
 // ...
}

사용자 정의 IO는 동일한 구조체에서 내장 값과 함께 사용할 수 있습니다. 예를 들면 다음과 같습니다.

예제: 내장 값과 사용자 정의 IO 혼합
// 내장 입력과 사용자 정의 입력을 혼합합니다.
struct MyInputs {
  @location(0) x: vec4<f32>,
  @builtin(front_facing) y: bool,
  @location(1) @interpolate(flat) z: u32
}

struct MyOutputs {
  @builtin(frag_depth) x: f32,
  @location(0) y: vec4<f32>
}

@fragment
fn fragShader(in1: MyInputs) -> MyOutputs {
  // ...
}
예제: 유효하지 않은 위치 할당
struct A {
  @location(0) x: f32,
  // 유효하지 않음: x와 y는 위치를 공유할 수 없습니다.
  @location(0) y: f32
}

struct B {
  @location(0) x: f32
}

struct C {
  // 유효하지 않음: 사용자 정의 IO가 있는 구조체는 중첩할 수 없습니다.
  b: B
}

struct D {
  x: vec4<f32>
}

@fragment
// 유효하지 않음: location은 구조체 타입에 적용할 수 없습니다.
fn fragShader1(@location(0) in1: D) {
  // ...
}

@fragment
// 유효하지 않음: in1과 in2는 위치를 공유할 수 없습니다.
fn fragShader2(@location(0) in1: f32, @location(0) in2: f32) {
  // ...
}

@fragment
// 유효하지 않음: location은 구조체에 적용할 수 없습니다.
fn fragShader3(@location(0) in1: vec4<f32>) -> @location(0) D {
  // ...
}
13.3.1.4. 보간

작성자는 interpolate 특성을 사용하여 사용자 정의 IO 데이터가 보간되는 방식을 제어할 수 있습니다. WGSL은 보간 타입과 보간 샘플링이라는 두 가지 보간 측면을 제어할 수 있도록 합니다.

보간 타입은 다음 보간 타입 이름 토큰 중 하나여야 합니다.

perspective

값이 원근 보정 방식으로 보간됩니다.

linear

값이 원근 보정 없이 선형 방식으로 보간됩니다.

flat

값이 보간되지 않습니다.

보간 샘플링은 다음 보간 샘플링 이름 토큰 중 하나여야 합니다.

center

픽셀 중심에서 보간이 수행됩니다.

centroid

현재 프리미티브 내에서 프래그먼트가 포함하는 모든 샘플의 내부에 있는 지점에서 보간이 수행됩니다. 이 값은 프리미티브의 모든 샘플에서 동일합니다.

sample

샘플별로 보간이 수행됩니다. 이 특성이 적용되면 프래그먼트 셰이더가 샘플당 한 번씩 호출됩니다.

first

프리미티브의 첫 번째 버텍스가 값을 제공합니다.

either

프리미티브의 첫 번째 또는 마지막 버텍스가 값을 제공합니다. 값이 첫 번째 버텍스에서 오는지 마지막 버텍스에서 오는지는 구현에 따라 다릅니다.

스칼라 또는 벡터 부동 소수점 타입의 사용자 정의 IO에는 다음이 적용됩니다.

스칼라 또는 벡터 정수 타입의 사용자 정의 버텍스 출력과 프래그먼트 입력에는 항상 보간 타입 flat을 지정해야 합니다.

스테이지 간 인터페이스 유효성 검사렌더 파이프라인 내에서 각 사용자 정의 프래그먼트 입력의 보간 속성이 동일한 location 할당을 가진 버텍스 출력의 보간 속성과 일치하는지 검사합니다. 일치하지 않으면 파이프라인 생성 오류발생합니다.

13.3.2. 리소스 인터페이스

리소스셰이더 스테이지 외부의 데이터에 대한 접근을 제공하며, 오버라이드 선언도 아니고, 즉시 데이터 변수도 아니며, 셰이더 스테이지 입력 또는 출력도 아닌 객체입니다. 리소스는 셰이더의 모든 호출에서 공유됩니다.

리소스에는 다음 네 종류가 있습니다.

셰이더의 리소스 인터페이스셰이더 스테이지의 함수에서 정적으로 접근되는 모듈 범위 리소스 변수 집합입니다.

각 리소스 변수는 groupbinding 특성을 모두 사용하여 선언해야 합니다. 이 특성들은 셰이더의 스테이지와 함께 셰이더 파이프라인에서 리소스의 바인딩 주소를 식별합니다. WebGPU § 8.3 GPUPipelineLayout을 참조하십시오.

즉시 데이터 변수는 group 또는 binding 특성을 사용하지 않습니다.

셰이더의 서로 다른 두 리소스 변수는 group 값과 binding 값을 한 쌍으로 간주했을 때 동일한 값을 가져서는 안 됩니다.

13.3.3. 리소스 레이아웃 호환성

WebGPU에서는 셰이더의 리소스 인터페이스가 해당 셰이더를 사용하는 파이프라인의 레이아웃과 일치해야 합니다.

리소스 인터페이스의 WGSL 변수가 호환되지 않는 WebGPU 바인딩 멤버 또는 바인딩 타입에 바인딩되면 파이프라인 생성 오류입니다. 호환성은 다음 표에 정의되어 있습니다.

WebGPU 바인딩 타입 호환성
WGSL 리소스 WebGPU 바인딩 멤버 WebGPU 바인딩 타입
유니폼 버퍼 buffer GPUBufferBindingType "uniform"
read_write 접근 권한을 가진 스토리지 버퍼 "storage"
read 접근 권한을 가진 스토리지 버퍼 "read-only-storage"
샘플러 sampler GPUSamplerBindingType "filtering"
"non-filtering"
sampler_comparison "comparison"
샘플링 텍스처, 깊이 텍스처 또는 다중 샘플링 텍스처 texture GPUTextureSampleType "float"
"unfilterable-float"
"sint"
"uint"
"depth"
쓰기 전용 스토리지 텍스처 storageTexture GPUStorageTextureAccess "write-only"
읽기-쓰기 스토리지 텍스처 "read-write"
읽기 전용 스토리지 텍스처 "read-only"
외부 텍스처 externalTexture (해당 없음)

인터페이스 유효성 검사 요구 사항은 WebGPU API 명세를 참조하십시오.

13.3.4. 버퍼 바인딩에 따른 런타임 크기 배열의 요소 수 결정

스토리지 버퍼 변수에 런타임 크기 배열이 포함되어 있으면 해당 배열의 요소 수는 대응하는 resource의 크기를 통해 결정됩니다.

더 자세히 설명하면 타입이 RAT인 런타임 크기 배열의 NRuntime은 다음과 같습니다.

truncate((EBBS − array_offset) ÷ array_stride). 여기서:

셰이더는 arrayLength 내장 함수를 통해 NRuntime을 계산할 수 있습니다.

참고: 이 알고리즘에는 모호함이 없습니다. 런타임 크기 배열이 더 큰 타입의 일부이면 구조체의 마지막 요소로만 나타날 수 있으며, 해당 구조체 자체는 이를 포함하는 배열 또는 구조체의 일부가 될 수 없습니다.

NRuntime은 대응하는 버퍼 바인딩의 크기에 의해 결정되며, 각 그리기 또는 디스패치 명령마다 달라질 수 있습니다.

WebGPU 유효성 검사 규칙은 1 ≤ NRuntime임을 보장합니다.

다음 코드 예제에서:
예제: 단순한 런타임 크기 배열의 요소 수
@group(0) @binding(1) var<storage> weights: array<f32>;

다음 표는 대응하는 유효 버퍼 바인딩 크기를 기준으로 weights 변수의 NRuntime 예를 보여 줍니다.

단순한 런타임 크기 배열의 요소 수 예
유효 버퍼 바인딩 크기 weights 변수의 NRuntime 계산
1024 256 truncate( 1024 ÷ 4 )
1025 256 truncate( 1025 ÷ 4 )
1026 256 truncate( 1026 ÷ 4 )
1027 256 truncate( 1027 ÷ 4 )
1028 257 truncate( 1028 ÷ 4 )
다음 코드 예제에서:
예제: 복합 런타임 크기 배열의 요소 수
struct PointLight {                          //             align(16) size(32)
  position : vec3f,                          // offset(0)   align(16) size(12)
  // -- 암시적 멤버 정렬 패딩 -- // offset(12)            size(4)
  color : vec3f,                             // offset(16)  align(16) size(12)
  // -- 암시적 구조체 크기 패딩 --      // offset(28)            size(4)
}

struct LightStorage {                        //             align(16)
  pointCount : u32,                          // offset(0)   align(4)  size(4)
  // -- 암시적 멤버 정렬 패딩 -- // offset(4)             size(12)
  point : array<PointLight>,                 // offset(16)  align(16) elementsize(32)
}

@group(0) @binding(1) var<storage> lights : LightStorage;

다음 표는 lights 변수의 point 멤버에 대한 NRuntime 예를 보여 줍니다.

복합 런타임 크기 배열의 요소 수 예
유효 버퍼 바인딩 크기 lights 변수의 point 멤버에 대한 NRuntime 계산
1024 31 truncate( ( 1024 - 16 ) ÷ 32) )
1025 31 truncate( ( 1025 - 16 ) ÷ 32) )
1039 31 truncate( ( 1039 - 16 ) ÷ 32) )
1040 32 truncate( ( 1040 - 16 ) ÷ 32) )

14. 메모리

WGSL에서 저장 가능 타입의 값은 나중에 가져올 수 있도록 메모리에 저장할 수 있습니다. 이 절에서는 메모리의 구조와 메모리에 접근하는 연산의 의미를 설명합니다. 메모리에 배치할 수 있는 값의 타입과 메모리 접근을 수행하는 데 사용되는 타입에 대해서는 § 6.5 메모리 뷰를 참조하십시오.

14.1. 메모리 위치

메모리는 서로 구분되는 메모리 위치 집합으로 구성됩니다. 각 메모리 위치의 크기는 8비트입니다. 메모리에 영향을 주는 연산은 하나 이상의 메모리 위치 집합과 상호 작용합니다. 복합 값에 대한 메모리 연산은 패딩 메모리 위치에 접근하지 않습니다. 따라서 연산이 접근하는 메모리 위치 집합은 연속적이지 않을 수 있습니다.

두 메모리 위치 집합의 교집합이 비어 있지 않으면 두 집합은 중첩됩니다.

14.2. 메모리 접근 모드

메모리 접근메모리 위치에 작용하는 연산입니다.

하나의 연산은 읽거나, 쓰거나, 읽기와 쓰기를 모두 수행할 수 있습니다.

특정 메모리 위치는 메모리의 접근 모드로 표현되는 특정 종류의 접근만 지원할 수 있습니다.

접근 모드
접근 모드 지원되는 접근
read 읽기 접근은 지원하지만 쓰기는 지원하지 않습니다.
write 쓰기 접근은 지원하지만 읽기는 지원하지 않습니다.
read_write 읽기와 쓰기 접근을 모두 지원합니다.

WGSL은 read, writeread_write 열거자미리 선언합니다.

14.3. 주소 공간

메모리 위치는 주소 공간으로 분할됩니다. 각 주소 공간에는 가변성, 가시성, 포함할 수 있는 값 및 그 공간의 변수를 사용하는 방법을 결정하는 고유한 속성이 있습니다. 자세한 내용은 § 7 변수 및 값 선언을 참조하십시오.

주어진 메모리 뷰의 접근 모드는 흔히 문맥에 따라 결정됩니다.

storage 주소 공간은 readread_write 접근 모드를 모두 지원합니다. 다른 각 주소 공간은 하나의 접근 모드만 지원합니다. 각 주소 공간의 기본 접근 모드는 다음 표에 설명되어 있습니다.

주소 공간
주소 공간 호출 간 공유 기본 접근 모드 참고
function 동일한 호출에만 해당 read_write
private 동일한 호출에만 해당 read_write
workgroup 동일한 컴퓨트 셰이더 워크그룹에 속한 호출 read_write 가장 바깥쪽 배열의 요소 수파이프라인 오버라이드 가능 상수일 수 있습니다.
uniform 동일한 셰이더 스테이지에 속한 호출 read 유니폼 버퍼 변수에 사용
storage 동일한 셰이더 스테이지에 속한 호출 read 스토리지 버퍼 변수에 사용
immediate 동일한 셰이더 스테이지에 속한 호출 read 즉시 데이터 변수에 사용.
진입점은 최대 하나의 immediate 변수에 정적으로 접근할 수 있습니다.
handle 동일한 셰이더 스테이지에 속한 호출 read 샘플러텍스처 변수에 사용.

WGSL은 handle 주소 공간을 제외하고 각 주소 공간에 대한 열거자미리 선언합니다.

workgroup 주소 공간의 변수에는 컴퓨트 셰이더 스테이지에서만 정적으로 접근해야 합니다.

storage 주소 공간의 변수(스토리지 버퍼)는 접근 모드가 read인 경우에만 버텍스 셰이더 스테이지에서 정적으로 접근할 수 있습니다. 저장소 타입write 또는 read_write 접근 모드를 가진 스토리지 텍스처인 변수에는 버텍스 셰이더 스테이지에서 정적으로 접근할 수 없습니다. WebGPU createBindGroupLayout()을 참조하십시오.

참고: 각 주소 공간의 성능 특성은 서로 다를 수 있습니다.

WGSL 소스에서 변수 선언 또는 포인터 타입을 작성할 때:

14.4. 메모리 레이아웃

WGSL에서 타입의 레이아웃은 주소 공간과 무관합니다. 그러나 엄밀히 말하면 해당 레이아웃은 호스트 공유 가능 버퍼를 통해서만 관찰할 수 있습니다. 유니폼 버퍼스토리지 버퍼 변수는 메모리에서 바이트 시퀀스로 구성된 대량 데이터를 공유하는 데 사용됩니다. 버퍼는 CPU와 GPU 사이, 파이프라인의 서로 다른 셰이더 스테이지 사이 또는 서로 다른 파이프라인 사이에서 공유됩니다.

버퍼 데이터는 재포맷이나 변환 없이 공유되므로 버퍼 생산자와 소비자가 메모리 레이아웃에 동의하지 않으면 동적 오류입니다. 메모리 레이아웃은 버퍼의 바이트가 타입이 지정된 WGSL 값으로 구성되는 방식을 설명합니다. 이러한 바이트는 공통 기준 위치를 기준으로 한 값의 메모리 위치입니다.

버퍼 변수의 저장소 타입은 아래에 설명된 것처럼 완전히 구체화된 메모리 레이아웃을 가진 호스트 공유 가능 타입이어야 합니다.

각 버퍼 변수는 uniform 또는 storage 주소 공간 중 하나에 선언되어야 합니다.

타입의 메모리 레이아웃은 다음을 사용하는 식을 평가할 때만 의미가 있습니다.

8비트 바이트는 호스트 공유 가능 메모리의 가장 기본적인 단위입니다. 이 절에서 정의하는 용어는 8비트 바이트의 수를 나타냅니다.

다음 표기법을 사용합니다. 여기서 T호스트 공유 가능 또는 고정 풋프린트 타입이고, S는 호스트 공유 가능 또는 고정 풋프린트 구조체 타입이며, A는 호스트 공유 가능 또는 고정 풋프린트 배열이나 런타임 크기 배열입니다.

14.4.1. 정렬 및 크기

호스트 공유 가능 또는 고정 풋프린트 데이터 타입 T에는 크기가 있습니다. 버퍼 타입을 제외하고 각 호스트 공유 가능 또는 고정 풋프린트 타입에는 정렬이 있습니다.

타입의 정렬은 해당 타입의 값을 메모리의 어디에 배치할 수 있는지에 관한 제약 조건이며 정수로 표현됩니다. 타입의 정렬은 해당 타입 값의 시작 메모리 위치의 바이트 주소를 나누어떨어지게 해야 합니다. 정렬을 사용하면 값에 접근하는 더 효율적인 하드웨어 명령을 사용하거나 특정 주소 공간의 더 엄격한 하드웨어 요구 사항을 충족할 수 있습니다. (주소 공간 레이아웃 제약 조건 참조).

참고: 구성 방식에 따라 각 정렬 값은 항상 2의 거듭제곱입니다.

타입 또는 구조체 멤버의 바이트 크기는 해당 타입 또는 구조체 멤버의 값을 저장하기 위해 호스트 공유 가능 메모리에 예약되는 연속 바이트의 수입니다. 크기에는 타입의 끝에 있는 주소 지정 불가능한 패딩이 포함될 수 있습니다. 따라서 값을 로드하고 저장할 때 해당 값의 크기보다 적은 메모리 위치에 접근할 수 있습니다.

호스트 공유 가능고정 풋프린트 타입의 정렬과 크기는 다음 표에서 재귀적으로 정의합니다.

호스트 공유 가능 및 고정 풋프린트 타입의 정렬과 크기
호스트 공유 가능 또는 고정 풋프린트 타입 T AlignOf(T) SizeOf(T)
bool
참고를 참조하십시오.
4 4
i32, u32 또는 f32 4 4
f16 2 2
atomic<T> 4 4
vec2<T>, Tbool, i32, u32 또는 f32 8 8
vec2<f16> 4 4
vec3<T>, Tbool, i32, u32 또는 f32 16 12
vec3<f16> 8 6
vec4<T>, Tbool, i32, u32 또는 f32 16 16
vec4<f16> 8 8
matCxR (열 우선)

(일반 형식)

AlignOf(vecR) SizeOf(array<vecR, C>)
mat2x2<f32> 8 16
mat2x2<f16> 4 8
mat3x2<f32> 8 24
mat3x2<f16> 4 12
mat4x2<f32> 8 32
mat4x2<f16> 4 16
mat2x3<f32> 16 32
mat2x3<f16> 8 16
mat3x3<f32> 16 48
mat3x3<f16> 8 24
mat4x3<f32> 16 64
mat4x3<f16> 8 32
mat2x4<f32> 16 32
mat2x4<f16> 8 16
mat3x4<f32> 16 48
mat3x4<f16> 8 24
mat4x4<f32> 16 64
mat4x4<f16> 8 32
멤버 M1...MN을 가진 struct S max(AlignOfMember(S,1), ... , AlignOfMember(S,N))
roundUp(AlignOf(S), justPastLastMember)

여기서 justPastLastMember = OffsetOfMember(S,N) + SizeOfMember(S,N)
array<E, N>
AlignOf(E) N × roundUp(AlignOf(E), SizeOf(E))
array<E>
AlignOf(E) NRuntime × roundUp(AlignOf(E),SizeOf(E))

여기서 NRuntime은 런타임에 결정되는 T의 요소 수입니다.
buffer<N> 해당 없음 N
buffer 해당 없음 연결된 WebGPU GPUBuffer의 크기

참고: 버퍼 타입은 다른 타입에 포함될 수 없으므로 정렬은 중요하지 않습니다.

참고: 많은 GPU는 잠재적인 데이터 경합을 일으키지 않고 단일 바이트 쓰기를 구현할 수 없습니다. bool 값이 4바이트 정렬로 4바이트를 차지하도록 지정하면 구현은 데이터 경합을 일으키지 않고 메모리에서 인접한 불리언 값을 지원할 수 있습니다.

14.4.2. 구조체 멤버 레이아웃

구조체의 내부 레이아웃은 멤버의 크기와 정렬을 바탕으로 계산됩니다. 기본적으로 멤버 정렬 요구 사항을 충족하면서 멤버가 중첩되지 않도록 순서대로 밀집 배치됩니다.

이 기본 내부 레이아웃은 다음과 같은 레이아웃 특성을 사용하여 재정의할 수 있습니다.

구조체 타입 Si번째 멤버에는 각각 SizeOfMember(S, i)와 AlignOfMember(S, i)로 나타내는 크기와 정렬이 있습니다. 멤버 크기와 정렬은 § 14.4.4 값의 내부 레이아웃에 설명된 대로 구조체 시작 지점에서 각 멤버까지의 바이트 오프셋을 계산하는 데 사용됩니다.

Si번째 멤버에 size(k) 특성이 있으면 SizeOfMember(S, i)는 k입니다. 그렇지 않으면 T가 멤버의 타입일 때 SizeOf(T)입니다.
Si번째 멤버에 align(k) 특성이 있으면 AlignOfMember(S, i)는 k입니다. 그렇지 않으면 T가 멤버의 타입일 때 AlignOf(T)입니다.

구조체 멤버에 size 특성이 적용된 경우 그 값은 멤버 타입의 크기 이상이어야 합니다.

SizeOfMember(S, i) ≥ SizeOf(T)
여기서 TSi번째 멤버의 타입입니다.

첫 번째 구조체 멤버는 항상 구조체의 시작 지점에서 바이트 오프셋 0에 있습니다.

OffsetOfMember(S, 1) = 0

그 이후의 각 멤버는 멤버 타입의 정렬을 충족하고 이전 멤버와의 중첩을 피하는 가장 낮은 오프셋에 배치됩니다. 각 멤버 인덱스 i > 1에 대해:

OffsetOfMember(S, i) = roundUp(AlignOfMember(S, i ), OffsetOfMember(S, i-1) + SizeOfMember(S, i-1))
예제: 암시적 멤버 크기와 정렬을 사용하는 구조체의 레이아웃
struct A {                                     //             align(8)  size(24)
    u: f32,                                    // offset(0)   align(4)  size(4)
    v: f32,                                    // offset(4)   align(4)  size(4)
    w: vec2<f32>,                              // offset(8)   align(8)  size(8)
    x: f32                                     // offset(16)  align(4)  size(4)
    // -- 암시적 구조체 크기 패딩 --      // offset(20)            size(4)
}

struct B {                                     //             align(16) size(160)
    a: vec2<f32>,                              // offset(0)   align(8)  size(8)
    // -- 암시적 멤버 정렬 패딩 -- // offset(8)             size(8)
    b: vec3<f32>,                              // offset(16)  align(16) size(12)
    c: f32,                                    // offset(28)  align(4)  size(4)
    d: f32,                                    // offset(32)  align(4)  size(4)
    // -- 암시적 멤버 정렬 패딩 -- // offset(36)            size(4)
    e: A,                                      // offset(40)  align(8)  size(24)
    f: vec3<f32>,                              // offset(64)  align(16) size(12)
    // -- 암시적 멤버 정렬 패딩 -- // offset(76)            size(4)
    g: array<A, 3>,    // element stride 24       offset(80)  align(8)  size(72)
    h: i32                                     // offset(152) align(4)  size(4)
    // -- 암시적 구조체 크기 패딩 --      // offset(156)           size(4)
}

@group(0) @binding(0)
var<storage,read_write> storage_buffer: B;
예제: 명시적 멤버 크기와 정렬을 사용하는 구조체의 레이아웃
struct A {                                     //             align(8)  size(32)
    u: f32,                                    // offset(0)   align(4)  size(4)
    v: f32,                                    // offset(4)   align(4)  size(4)
    w: vec2<f32>,                              // offset(8)   align(8)  size(8)
    @size(16) x: f32                           // offset(16)  align(4)  size(16)
}

struct B {                                     //             align(16) size(208)
    a: vec2<f32>,                              // offset(0)   align(8)  size(8)
    // -- 암시적 멤버 정렬 패딩 -- // offset(8)             size(8)
    b: vec3<f32>,                              // offset(16)  align(16) size(12)
    c: f32,                                    // offset(28)  align(4)  size(4)
    d: f32,                                    // offset(32)  align(4)  size(4)
    // -- 암시적 멤버 정렬 패딩 -- // offset(36)            size(12)
    @align(16) e: A,                           // offset(48)  align(16) size(32)
    f: vec3<f32>,                              // offset(80)  align(16) size(12)
    // -- 암시적 멤버 정렬 패딩 -- // offset(92)            size(4)
    g: array<A, 3>,    // element stride 32       offset(96)  align(8)  size(96)
    h: i32                                     // offset(192) align(4)  size(4)
    // -- 암시적 구조체 크기 패딩 --      // offset(196)           size(12)
}

@group(0) @binding(0)
var<uniform> uniform_buffer: B;

14.4.3. 배열 레이아웃 예

예제: 고정 크기 배열 레이아웃 예
// 다음과 같은 배열:
//   - 정렬은 4 = AlignOf(f32)
//   - 요소 스트라이드는 4 = roundUp(AlignOf(f32),SizeOf(f32)) = roundUp(4,4)
//   - 크기는 32 = stride * number_of_elements = 4 * 8
var small_stride: array<f32, 8>;

// 다음과 같은 배열:
//   - 정렬은 16 = AlignOf(vec3<f32>) = 16
//   - 요소 스트라이드는 16 = roundUp(AlignOf(vec3<f32>), SizeOf(vec3<f32>))
//                          = roundUp(16,12)
//   - 크기는 128 = stride * number_of_elements = 16 * 8
var bigger_stride: array<vec3<f32>, 8>;
예제: 런타임 크기 배열 레이아웃 예
// 다음과 같은 배열:
//   - 정렬은 4 = AlignOf(f32)
//   - 요소 스트라이드는 4 = roundUp(AlignOf(f32),SizeOf(f32)) = 4
// B가 그리기 또는 디스패치 명령의 바인딩에 대한
// 유효 버퍼 바인딩 크기라면 요소 수는 다음과 같습니다:
//   N_runtime = floor(B / element stride) = floor(B / 4)
@group(0) @binding(0)
var<storage> weights: array<f32>;

// 다음과 같은 배열:
//   - 정렬은 16 = AlignOf(vec3<f32>) = 16
//   - 요소 스트라이드는 16 = roundUp(AlignOf(vec3<f32>), SizeOf(vec3<f32>))
//                          = roundUp(16,12)
// B가 그리기 또는 디스패치 명령의 바인딩에 대한
// 유효 버퍼 바인딩 크기라면 요소 수는 다음과 같습니다:
//   N_runtime = floor(B / element stride) = floor(B / 16)
var<storage> directions: array<vec3<f32>>;

14.4.4. 값의 내부 레이아웃

이 절에서는 전체 값의 배치가 주어졌다고 가정할 때 호스트 공유 가능 값의 내부가 버퍼의 바이트 위치에 배치되는 방식을 설명합니다. 이러한 레이아웃은 값의 타입과 구조체 멤버에 적용된 alignsize 특성에 따라 달라집니다. 아래에서 설명하는 것처럼 이 규칙은 불투명하지 않은 타입에 적용됩니다. 버퍼 타입의 값에는 내부 구조가 없으며 이 규칙의 제약을 받지 않습니다.

값이 배치되는 버퍼 바이트 오프셋은 타입 정렬 요구 사항을 충족해야 합니다. 타입 T의 값이 버퍼 오프셋 k에 배치되면, 어떤 음이 아닌 정수 c에 대해 k = c × AlignOf(T)입니다.

데이터는 주소 공간과 관계없이 동일하게 나타납니다.

참고: bool 타입은 호스트 공유 가능 타입이 아닙니다. WGSL은 bool 값의 크기와 정렬이 4바이트라고 지정하지만 bool 값의 내부 레이아웃은 지정하지 않습니다.

타입이 u32 또는 i32인 값 V가 호스트 공유 버퍼의 바이트 오프셋 k에 배치되면:

참고: i32는 2의 보수 표현을 사용하므로 부호 비트는 비트 위치 31에 있습니다.

64비트 정수 레이아웃: WebGPU API의 일부 기능은 부호 없는 64비트 정수 값을 버퍼에 씁니다. 그러한 값 V가 호스트 공유 버퍼의 바이트 오프셋 k에 나타나면:

참고: WGSL에는 구체적 64비트 정수 타입이 없습니다.

타입이 f32인 값 VIEEE-754 binary32 형식으로 표현됩니다. 부호 비트 1개, 지수 비트 8개 및 가수 비트 23개를 가집니다. V가 호스트 공유 버퍼의 바이트 오프셋 k에 배치되면:

타입이 f16인 값 VIEEE-754 binary16 형식으로 표현됩니다. 부호 비트 1개, 지수 비트 5개 및 가수 비트 10개를 가집니다. V가 호스트 공유 버퍼의 바이트 오프셋 k에 배치되면:

참고: 위 규칙에 따라 호스트 공유 버퍼의 숫자 값은 리틀 엔디언 형식으로 저장됩니다.

원자 타입 atomic<T>인 값 V가 호스트 공유 버퍼에 배치되면 기반 타입 T 값과 동일한 내부 레이아웃을 가집니다.

벡터 타입 vecN<T>인 값 V가 호스트 공유 버퍼의 바이트 오프셋 k에 배치되면:

행렬 타입 matCxR<T>인 값 V가 호스트 공유 버퍼의 바이트 오프셋 k에 배치되면:

배열 타입 A의 값이 호스트 공유 메모리 버퍼의 바이트 오프셋 k에 배치되면:

구조체 타입 S의 값이 호스트 공유 메모리 버퍼의 바이트 오프셋 k에 배치되면:

14.4.5. 주소 공간 레이아웃 제약 조건

storageuniform 주소 공간에는 이 절에서 설명하는 서로 다른 레이아웃 제약 조건이 있습니다.

uniform을 제외한 모든 주소 공간에는 storage 주소 공간과 동일한 제약 조건이 적용됩니다.

변수가 직접 또는 간접적으로 참조하는 모든 구조체 및 배열 타입은 변수 주소 공간의 제약 조건을 준수해야 합니다. 주소 공간 제약 조건을 위반하면 셰이더 생성 오류가 발생합니다.

이 절에서는 RequiredAlignOf(S, C)를 호스트 공유 가능 또는 고정 풋프린트 타입 S의 값이 주소 공간 C에서 사용될 때 요구되는 바이트 오프셋 정렬로 정의합니다.

주소 공간 C에 있는 호스트 공유 가능 또는 고정 풋프린트 타입의 정렬 요구 사항
SC에 나타날 수 있다고 가정할 때, 호스트 공유 가능 또는 고정 풋프린트 타입 S RequiredAlignOf(S, C),
uniform_buffer_standard_layout이 지원되거나 Cuniform이 아닌 경우
RequiredAlignOf(S, C),
uniform_buffer_standard_layout이 지원되지 않고 Cuniform인 경우
bool, i32, u32, f32 또는 f16 AlignOf(S) AlignOf(S)
atomic<T> AlignOf(S) AlignOf(S)
vecN<T> AlignOf(S) AlignOf(S)
matCxR<T> AlignOf(S) AlignOf(S)
array<T, N> AlignOf(S) roundUp(16, AlignOf(S))
array<T> AlignOf(S)
Cuniform이면 buffer_view 내장 함수의 결과인 경우를 제외하고 허용되지 않음
roundUp(16, AlignOf(S))
buffer_view 내장 함수의 결과인 경우를 제외하고 허용되지 않음
struct S AlignOf(S) roundUp(16, AlignOf(S))

타입 T인 구조체 멤버는 주소 공간 C에 대한 RequiredAlignOf(T, C)의 배수인, 구조체 시작 지점으로부터의 바이트 오프셋을 가져야 합니다.

OffsetOfMember(S, i) = k × RequiredAlignOf(T, C)
여기서 k는 음이 아닌 정수이고 구조체 Si번째 멤버는 타입 T입니다.

요소 타입이 T인 배열은 주소 공간 C에 대한 RequiredAlignOf(T, C)의 배수인 요소 스트라이드를 가져야 합니다.

StrideOf(array<T, N>) = k × RequiredAlignOf(T, C)
StrideOf(array<T>) = k × RequiredAlignOf(T, C)
여기서 k는 양의 정수입니다.

uniform_buffer_standard_layout이 지원되지 않는 경우 uniform 주소 공간은 다음을 요구합니다.

참고: 다음 예제는 유니폼 버퍼의 레이아웃 요구 사항을 충족하도록 구조체 멤버에 alignsize 특성을 사용하는 방법을 보여 줍니다. 특히 이러한 기법을 사용하여 std140 레이아웃의 GLSL 버퍼를 WGSL로 기계적으로 변환할 수 있습니다.

예제: uniform 주소 공간의 오프셋 요구 사항 충족
struct S {
  x: f32
}
struct Invalid {
  a: S,
  b: f32 // 유효하지 않음: a와 b 사이의 오프셋은 4바이트이지만 최소 16바이트여야 합니다.
}
@group(0) @binding(0) var<uniform> invalid: Invalid;

struct Valid {
  a: S,
  @align(16) b: f32 // 유효함: a와 b 사이의 오프셋은 16바이트입니다.
}
@group(0) @binding(1) var<uniform> valid: Valid;
예제: uniform 주소 공간의 스트라이드 요구 사항 충족
struct small_stride {
  a: array<f32,8> // stride 4
}
// 유효하지 않음: 스트라이드는 16의 배수여야 합니다.
@group(0) @binding(0) var<uniform> invalid: small_stride;

struct wrapped_f32 {
  @size(16) elem: f32
}
struct big_stride {
  a: array<wrapped_f32,8> // stride 16
}
@group(0) @binding(1) var<uniform> valid: big_stride;     // 유효함

14.5. 메모리 모델

일반적으로 WGSL은 Vulkan 메모리 모델을 따릅니다. 이 절의 나머지 부분에서는 WGSL 프로그램이 Vulkan 메모리 모델에 매핑되는 방식을 설명합니다.

참고: Vulkan 메모리 모델은 형식 Alloy 모델의 텍스트 버전입니다.

14.5.1. 메모리 연산

WGSL에서 읽기 접근은 Vulkan 메모리 모델의 메모리 읽기 연산과 동일합니다. WGSL에서 쓰기 접근은 Vulkan 메모리 모델의 메모리 쓰기 연산과 동일합니다.

호출이 다음 중 하나를 실행하면 읽기 접근이 발생합니다.

호출이 다음 중 하나를 실행하면 쓰기 접근이 발생합니다.

원자적 읽기-수정-쓰기 내장 함수는 읽기 접근이면서 쓰기 접근인 단일 메모리 연산을 수행합니다.

그 밖의 상황에서는 읽기와 쓰기 접근이 발생하지 않습니다. 읽기와 쓰기 접근을 통틀어 Vulkan 메모리 모델에서 메모리 연산이라고 합니다.

메모리 뷰를 통한 메모리 연산은 일반적으로 해당 메모리 뷰와 연결된 위치 집합에 정확히 접근합니다. 예외적으로 벡터 컴포넌트에 대한 쓰기 접근은 해당 벡터와 연결된 모든 메모리 위치에 접근할 수 있습니다.

스위즐 뷰를 통한 메모리 연산은 기반 벡터와 연결된 모든 메모리 위치에 접근합니다. 자세한 내용은 스위즐 뷰 읽기스위즐 뷰 쓰기를 참조하십시오.

예제: 메모리 위치 접근
struct S {
  a : f32,
  b : u32,
  c : f32
}

@group(0) @binding(0)
var<storage> v : S;

fn foo() {
  let x = v.b; // v.a 또는 v.c의 메모리 위치에는 접근하지 않습니다.
}

14.5.2. 메모리 모델 참조

각 모듈 범위 리소스 변수는 고유한 groupbinding 쌍에 대한 메모리 모델 참조를 형성합니다. 다른 각 변수(즉, function, privateworkgroup 주소 공간의 변수)는 변수의 수명 동안 고유한 메모리 모델 참조를 형성합니다.

14.5.3. 범위 지정 연산

호출이 범위 지정 연산을 수행하면 하나 또는 두 개의 호출 집합에 영향을 줍니다. 이러한 집합은 메모리 범위와 실행 범위입니다. 메모리 범위는 연산의 영향을 받는 메모리 내용의 갱신을 확인하게 되는 호출 집합을 지정합니다. 동기화 내장 함수의 경우에는 함수보다 프로그램 순서상 앞에 있는 영향을 받는 모든 메모리 연산이 함수보다 프로그램 순서상 뒤에 있는 영향을 받는 연산에 표시됨을 의미하기도 합니다. 실행 범위는 연산에 참여할 수 있는 호출 집합을 지정합니다(§ 15.6 집합 연산 참조).

원자 내장 함수는 메모리 범위가 다음과 같은 원자 연산에 매핑됩니다.

동기화 내장 함수는 실행 및 메모리 범위Workgroup인 제어 장벽에 매핑됩니다.

암시적 및 명시적 미분에는 암시적인 쿼드 실행 범위가 있습니다.

참고: 생성된 셰이더에서 Vulkan 메모리 모델이 활성화되지 않은 경우 QueueFamily 대신 Device 범위를 사용해야 합니다.

14.5.4. 메모리 의미 체계

모든 원자 내장 함수Relaxed 메모리 의미 체계를 사용하므로 스토리지 클래스 의미 체계를 사용하지 않습니다.

참고: WGSL의 주소 공간은 SPIR-V의 스토리지 클래스와 동일합니다.

workgroupBarrierAcquireRelease 메모리 의미 체계WorkgroupMemory 의미 체계를 사용합니다. storageBarrierAcquireRelease 메모리 의미 체계UniformMemory 의미 체계를 사용합니다. textureBarrierAcquireRelease 메모리 의미 체계ImageMemory 의미 체계를 사용합니다.

참고: 결합된 workgroupBarrierstorageBarrierAcquireRelease 순서 의미 체계와 WorkgroupMemoryUniformMemory 메모리 의미 체계를 모두 사용합니다.

참고: 원자 또는 동기화 내장 함수는 MakeAvailable 또는 MakeVisible 의미 체계를 사용하지 않습니다.

14.5.5. Private와 Non-private

storage 또는 workgroup 주소 공간의 모든 비원자적 읽기 접근비프라이빗으로 간주되며, Workgroup 범위를 가진 NonPrivatePointer | MakePointerVisible 메모리 피연산자를 사용하는 읽기 연산에 대응합니다.

storage 또는 workgroup 주소 공간의 모든 비원자적 쓰기 접근비프라이빗으로 간주되며, Workgroup 범위를 가진 NonPrivatePointer | MakePointerAvailable 메모리 피연산자를 사용하는 쓰기 연산에 대응합니다.

handle 주소 공간의 모든 비원자적 읽기 접근비프라이빗으로 간주되며, Workgroup 범위를 가진 NonPrivateTexel | MakeTexelVisible 메모리 피연산자를 사용하는 읽기 연산에 대응합니다.

handle 주소 공간의 모든 비원자적 쓰기 접근비프라이빗으로 간주되며, Workgroup 범위를 가진 NonPrivateTexel | MakeTexelAvailable 메모리 피연산자를 사용하는 쓰기 연산에 대응합니다.

15. 실행

§ 1.1 개요에서는 셰이더가 호출되고 호출로 분할되는 방식을 설명합니다. 이 절에서는 호출이 개별적으로 그리고 집합적으로 실행되는 방식에 관한 추가 제약 조건을 설명합니다.

15.1. 호출 내 프로그램 순서

WGSL 모듈의 각 문은 실행 중 0회 이상 실행될 수 있습니다. 주어진 호출에서 특정 문의 각 실행은 고유한 동적 문 인스턴스를 나타냅니다.

문에 식이 포함된 경우 해당 문의 의미 체계는 다음을 결정합니다.

식의 중첩은 평가를 완료하기 위해 충족해야 하는 데이터 의존성을 정의합니다. 즉, 중첩된 식은 이를 포함하는 식을 평가하기 전에 평가해야 합니다. WGSL에서 식의 피연산자는 왼쪽에서 오른쪽 순서로 평가됩니다. 예를 들어 foo() + bar()에서는 bar()보다 foo()를 먼저 평가해야 합니다. § 8 식을 참조하십시오.

WGSL 모듈의 문은 제어 흐름 순서로 실행됩니다. § 9 문§ 11.2 함수 호출을 참조하십시오.

15.2. 균일성

집합 연산 (예: 장벽, 미분 또는 암시적으로 계산된 미분에 의존하는 텍스처 연산)은 GPU에서 동시에 실행되는 여러 호출 간의 조정을 요구합니다. 모든 호출이 연산을 동시에, 즉 균일 제어 흐름에서 실행할 때 연산이 정확하고 이식 가능하게 실행됩니다.

반대로 호출의 엄격한 부분집합이 연산을 실행할 때, 즉 비균일 제어 흐름에서는 부정확하거나 이식 불가능한 동작이 발생합니다. 비공식적으로 말하면 비균일 제어 의존성으로 인해 일부 호출은 집합 연산에 도달하지만 다른 호출은 도달하지 않거나 같은 시간에 도달하지 않습니다. 비균일 제어 의존성은 비균일 값에 따라 동작이 달라지는 제어 흐름문에서 발생합니다.

예를 들어 서로 다른 호출이 if, break-if, while 또는 for의 조건에 대해 서로 다른 값을 계산하거나, switch의 선택자 또는 단락 평가 이항 연산자 (&& 또는 ||)의 좌측 피연산자에 대해 서로 다른 값을 계산할 때 비균일 제어 의존성이 발생합니다.

이러한 비균일 값은 정적으로 균일하다고 입증되지 않은 특정 소스로 거슬러 올라가는 경우가 많습니다. 이러한 소스에는 다음이 포함되지만 이에 한정되지는 않습니다.

정확하고 이식 가능한 동작을 보장하기 위해 WGSL 구현은 정적 균일성 분석을 수행하여 각 집합 연산이 균일 제어 흐름에서 실행됨을 입증하려고 합니다. 이후 하위 절에서 분석을 설명합니다.

균일성 분석이 특정 집합 연산균일 제어 흐름에서 실행됨을 입증할 수 없으면 균일성 실패트리거됩니다.

15.2.1. 용어 및 개념

다음 정의는 단지 참고 정보이며, 다음 하위 절의 분석이 무엇을 계산하는지 직관적으로 설명하려는 것입니다. 실제로 이러한 개념과 프로그램이 유효한 경우 또는 균일성 규칙을 위반하는 경우를 정의하는 것은 분석입니다.

주어진 호출 그룹에 대해:

15.2.2. 균일성 분석 개요

나머지 하위 절에서는 집합 연산균일 제어 흐름에서만 실행되는지 검증하는 정적 분석을 지정합니다. subgroup_uniformity 기능이 지원되면 여러 균일성 범위가 존재합니다. 이 분석은 각 범위에 대해 한 번씩 수행됩니다.

참고: 분석은 범위마다 한 번씩 실행되는 것으로 설명되지만 구현은 각 범위를 포함하는 단일 분석을 수행할 수 있습니다. 워크그룹그리기 균일성 범위는 서로 다른 셰이더 스테이지에서 작동하고 셰이더 스테이지에서 가장 큰 균일성 범위를 나타내므로 실질적으로 동등합니다.

분석에서는 동적 오류가 발생하지 않는다고 가정합니다. 동적 오류가 있는 셰이더 스테이지는 균일성 분석 결과와 관계없이 이미 이식 가능하지 않습니다.

참고:이 분석에는 다음과 같은 바람직한 속성이 있습니다.

각 함수는 다음 두 가지를 보장하기 위해 분석됩니다.

이 두 검사 중 하나라도 실패하면 균일성 실패가 트리거됩니다.

이 작업의 일부로 분석은 함수에 관한 메타데이터를 계산하여 해당 함수의 호출자를 차례로 분석하는 데 활용합니다. 즉, 먼저 호출 그래프를 구축한 다음 리프부터 위쪽으로, 다시 말해 표준 라이브러리 외부의 함수를 호출하지 않는 함수부터 진입점 방향으로 함수를 분석해야 합니다. 이 방식에서는 함수를 분석할 때마다 모든 피호출자의 메타데이터가 이미 계산되어 있습니다. 언어에서 재귀가 금지되므로 순환에 갇힐 위험은 없습니다.

참고: 같은 내용을 다른 방식으로 표현하면, “(직접 또는 간접적인) 피호출자이다”라는 부분 순서에 따라 정렬된 함수의 위상 정렬을 수행하고 그 순서대로 분석합니다.

또한 각 함수 호출에 대해 분석은 해당 호출이 균일 제어 흐름에 있음을 입증할 수 없을 때 트리거되는 트리거 규칙 집합이 있다면 이를 계산하고 전파합니다. 이를 호출의 잠재적 트리거 집합이라고 합니다. 이 집합의 요소는 다음 가능성에서 선택됩니다.

15.2.3. 함수의 균일성 요구 사항 분석

각 함수는 두 단계로 분석됩니다.

첫 번째 단계에서는 다음 하위 절의 규칙에 따라 함수의 구문을 순회하면서 방향 그래프를 구축합니다. 두 번째 단계에서는 해당 그래프를 탐색하여 이 함수를 호출하는 데 관한 제약 조건을 계산하고 잠재적으로 균일성 실패를 트리거합니다.

참고:네 개의 특수 노드 RequiredToBeUniform.error, RequiredToBeUniform.warning, RequiredToBeUniform.infoMayBeNonUniform을 제외하면, 각 노드는 다음 문 중 하나의 참값을 포착하는 것으로 이해할 수 있습니다.

에지는 소스 노드에 대응하는 문에서 대상 노드에 대응하는 문으로의 함의로 이해할 수 있습니다.

예를 들어 균일성 요구 사항 중 하나는 workgroupBarrier 내장 함수를 균일 제어 흐름 내에서만 호출해야 한다는 것입니다. 이를 표현하기 위해 RequiredToBeUniform.error에서 workgroupBarrier 호출 지점에 대응하는 노드로 에지를 추가합니다. 이를 이해하는 한 가지 방법은 RequiredToBeUniform.error가 명제 참에 대응하므로 RequiredToBeUniform.error -> X는 X가 참이라고 말하는 것과 같다는 것입니다.

반대로 어떤 항목의 균일성을 보장할 수 없음을 표현하기 위해(예: 스레드 ID를 보유한 변수) 해당 노드에서 MayBeNonUniform으로 에지를 추가합니다. 이를 이해하는 한 가지 방법은 MayBeNonUniform이 명제 거짓에 대응하므로 X -> MayBeNonUniform은 X가 거짓이라고 말하는 것과 같다는 것입니다.

이 해석에 따르면 RequiredToBeUniform.error에서 도달 가능한 모든 노드는 프로그램이 유효하기 위해 균일해야 하는 항목에 대응하고, MayBeNonUniform에 도달할 수 있는 모든 노드는 균일성을 보장할 수 없는 항목에 대응합니다. 따라서 RequiredToBeUniform.error에서 MayBeNonUniform으로 가는 경로가 하나라도 있으면 균일성 위반이 발생하여 균일성 실패가 트리거됩니다.

RequiredToBeUniform.warningRequiredToBeUniform.info 노드도 비슷한 방식으로 사용되지만 경고 또는 정보 진단을 트리거해야 하는 시점을 결정하는 데 도움을 줍니다.

§ 2.3 진단에 설명된 대로 더 높은 심각도의 진단도 생성된 경우에는 더 낮은 심각도의 진단이 폐기될 수 있습니다.

각 함수에 대해 두 개의 태그를 계산합니다.

함수의 각 형식 매개변수에 대해 하나 또는 두 개의 태그를 계산합니다.

호출 지점 태그
호출 지점 태그 설명
CallSiteRequiredToBeUniform.S,
여기서 S오류, 경고 또는 정보 중 하나의 심각도입니다.
함수는 균일 제어 흐름에서만 호출해야 합니다. 그렇지 않으면 심각도가 S인 진단이 트리거됩니다.

잠재적 트리거 집합과 연결됩니다.

CallSiteNoRestriction 함수는 비균일 제어 흐름에서 호출할 수 있습니다.
함수 태그
함수 태그 설명
ReturnValueMayBeNonUniform 함수의 반환 값이 비균일할 수 있습니다.
NoRestriction 함수는 비균일성을 도입하지 않습니다.
매개변수 태그
매개변수 태그 설명
ParameterRequiredToBeUniform.S,
여기서 S오류, 경고 또는 정보 중 하나의 심각도입니다.
매개변수는 균일 값이어야 합니다. 매개변수 타입이 포인터이면 반드시 그 내용까지 균일할 필요는 없지만 메모리 뷰는 균일해야 합니다. 그렇지 않으면 심각도가 S인 진단이 트리거됩니다.

잠재적 트리거 집합과 연결됩니다.

ParameterContentsRequiredToBeUniform.S,
여기서 S오류, 경고 또는 정보 중 하나의 심각도입니다.
포인터 매개변수가 가리키는 메모리에 저장된 값은 균일 값이어야 합니다. 그렇지 않으면 심각도가 S인 진단이 트리거됩니다.

잠재적 트리거 집합과 연결됩니다.

ParameterNoRestriction 매개변수 값에는 균일성 요구 사항이 없습니다.
매개변수 반환 태그
매개변수 반환 태그 설명
ParameterReturnContentsRequiredToBeUniform 반환 값이 균일 값이 되려면 매개변수가 균일 값이어야 합니다. 매개변수가 포인터이면 포인터가 가리키는 메모리에 저장된 값도 균일해야 합니다.
ParameterReturnNoRestriction 매개변수 값에는 균일성 요구 사항이 없습니다.
포인터 매개변수 태그
포인터 매개변수 태그 설명
PointerParameterMayBeNonUniform 함수 호출 후 포인터 매개변수가 가리키는 메모리에 저장된 값이 비균일할 수 있습니다.
PointerParameterNoRestriction 포인터 매개변수가 가리키는 메모리에 저장된 값의 균일성은 함수 호출의 영향을 받지 않습니다.

다음 알고리즘은 주어진 함수에 대해 이러한 태그를 계산하는 방법을 설명합니다.

참고: 이 시점에서 전체 그래프를 폐기할 수 있습니다. 위에서 설명한 태그만 기억하면 이 함수의 호출자를 분석할 수 있습니다. 그러나 그래프에는 더 유용한 정보를 담은 진단을 제공하는 데 사용할 수 있는 정보가 포함되어 있습니다. 예를 들어 한 함수의 값이 균일하다고 입증되지 않을 수 있으며, 이 값이 다른 함수에서 균일성 실패를 트리거하는 데 기여할 수 있습니다. 유용한 정보를 담은 진단은 비균일 값과 함께 진단의 트리거 위치에 있는 함수 호출을 설명합니다.

15.2.4. 포인터 디슈거링

function 주소 공간에 있는 포인터 타입의 각 매개변수는 매개변수를 역참조하는 것과 동등한 초깃값을 갖는 지역 변수 선언으로 디슈거링됩니다. 즉, function 주소 공간 포인터는 지역 변수 선언에 대한 별칭으로 간주됩니다. 초깃값 할당은 i번째 매개변수에 대해 param_i_contents로 향하는 에지를 생성합니다 (즉, V(e)param_i_contents입니다).

포인터 타입유효 값 타입을 가진 각 let 선언 L은 다음과 같이 디슈거링됩니다.

이 디슈거링은 포인터가 사용되는 각 위치에 포인터의 루트 식별자를 직접 드러내어 후속 분석을 단순화합니다.

참고: 균일성 분석을 위해 타입 검사는 이 디슈거링이 수행되기 전과 후에 모두 발생하는 것으로 설명됩니다.

예제: 균일성 분석의 포인터
fn foo(p : ptr<function, array<f32, 4>>, i : i32) -> f32 {
  let p1 = p;
  var x = i;
  let p2 = &((*p1)[x]);
  x = 0;
  *p2 = 5;
  return (*p1)[x];
}

// 분석을 위해 foo와 동등한 버전입니다.
fn foo_for_analysis(p : ptr<function, array<f32, 4>>, i : i32) -> f32 {
  var p_var = *p;            // p를 위한 변수를 도입합니다.
  let p1 = &p_var;           // p1에 이 변수를 사용합니다
  var x = i;
  let x_tmp1 = x;            // x의 값을 캡처합니다
  let p2 = &(p_var[x_tmp1]); // p1의 초기화 식을 대입합니다
  x = 0;
  *(&(p_var[x_tmp1])) = 5;   // p2의 초기화 식을 대입합니다
  return (*(&p_var))[x];     // p1의 초기화 식을 대입합니다
}

15.2.5. 함수 범위 변수 값 분석

특정 문장에서 각 함수 범위 변수의 값은 그 위치에 도달하는 할당과 경우에 따라 해당 변수의 초깃값을 기준으로 분석할 수 있습니다.

다음을 만족하면 할당은 전체 할당입니다.

그렇지 않으면 할당은 부분 할당입니다.

전체 참조는 다음 중 하나인 참조 타입의 식입니다.

전체 포인터는 다음 중 하나인 포인터 타입의 식입니다.

참고: 이 분석에서는 포인터 타입의 형식 매개변수가 전체 포인터일 수 있는 경우가 필요하지 않습니다.

전체 참조와 마찬가지로 전체 포인터는 대응하는 기원 변수 x모든 메모리 위치에 대한 메모리 뷰입니다.

전체 참조가 아닌 참조는 부분 참조입니다. 따라서 부분 참조는 다음 중 하나입니다.

참고: 부분 참조도 전체 참조와 동일한 모든 메모리 위치, 즉 변수 선언에서 사용하는 모든 위치를 포괄할 수 있습니다. 저장소 타입이 멤버를 하나만 가진 구조체 타입이거나 저장소 타입이 요소를 하나만 가진 배열 타입일 때 이러한 상황이 발생할 수 있습니다.

단일 멤버를 가진 구조체 타입과 해당 타입을 저장하는 변수를 살펴보겠습니다.

struct S { member: i32; }
fn foo () {
   var v: S;
}

그러면 v는 전체 참조이고 v.member는 부분 참조입니다. 두 메모리 뷰는 동일한 메모리 위치를 포괄하지만 v의 저장소 타입은 S이고 v.s의 저장소 타입은 i32입니다.

요소를 하나만 가진 배열에서도 비슷한 상황이 발생합니다.

fn foo () {
   var arr: array<i32,1>;
}

그러면 arr는 전체 참조이고 arr[0]은 부분 참조입니다. 두 메모리 뷰는 동일한 메모리 위치를 포괄하지만 arr의 저장소 타입은 array<i32,1>이고 arr[0]의 저장소 타입은 i32입니다.

분석을 단순화하기 위해 어떤 종류의 부분 참조를 통한 할당도 연관된 기원 변수의 모든 메모리 위치를 수정하지 않는 것으로 취급됩니다. 이로 인해 분석이 보수적으로 이루어지며, 엄밀히 필요한 것보다 더 많은 프로그램에서 균일성 실패가 트리거될 수 있습니다.

전체 스위즐 뷰는 다음 조건을 만족하는 스위즐 뷰 sv = (p, IndexList)로 평가되는 식입니다.

참고: 전체 스위즐 뷰를 통해 할당하면 메모리에 있는 기반 벡터의 모든 요소를 덮어씁니다.

부분 스위즐 뷰전체 스위즐 뷰가 아닌 스위즐 뷰 타입의 식입니다.

참고: 전체 스위즐 뷰인지 여부는 기반 포인터 식의 전체성 및 IndexList에만 의존하고 이 둘은 모두 셰이더 생성 시점에 알려지므로, 셰이더 생성 시점에 판별할 수 있습니다. 이는 스위즐 뷰 식을 연쇄적으로 연결하는 경우에도 성립합니다.

전체 참조 또는 전체 스위즐 뷰를 통한 할당은 전체 할당입니다.

부분 참조 또는 부분 스위즐 뷰를 통한 할당은 부분 할당입니다.

후속 절의 균일성 규칙에서 RHSValue로 사용된 함수 범위 변수의 값을 언급하는 경우, 이는 RHSValue 식을 평가하기 전의 변수 값을 의미합니다. 후속 절의 균일성 규칙에서 LHSValue로 사용된 함수 범위 변수의 값을 언급하는 경우, 이는 해당 식이 나타나는 문장을 실행한 후의 변수 값을 의미합니다.

제어 흐름 문장이나 부분 할당으로 인해 변수에 대한 여러 할당이 해당 변수의 사용 위치에 도달할 수 있습니다. 분석에서는 각 제어 흐름 출구에 도달하는 할당 집합의 합집합을 구하여 제어 흐름 문장에서 빠져나오는 여러 할당을 결합합니다.

다음 표는 할당을 결합하는 규칙을 설명합니다. 균일성 그래프에서 각 결합은 결과 노드에서 값의 출처를 나타내는 노드로 향하는 에지입니다. 이 표는 임의의 변수 x를 기준으로 작성되었으며 다음 표기법을 사용합니다.

함수 범위 변수에 대한 여러 할당을 결합하는 규칙.
문장 결과 결과에서 나가는 에지
var x; Vin(next) V(0)
var x = e;
Vin(next) V(e)

참고: 이는 x에 대한 전체 할당입니다.

x = e;
r = e;
여기서 r은 변수 x에 대한 전체 참조입니다
sv = e;
여기서 sv는 기원 변수가 x전체 스위즐 뷰입니다
r = e;
여기서 r은 변수 x에 대한 부분 참조입니다
Vout(S) V(e), Vout(prev)

참고: 이는 x에 대한 부분 할당입니다.

참고: 부분 할당에는 이전 값이 포함됩니다. 할당은 저장된 컴포넌트의 일부에만 쓰거나, 기록되는 값의 타입이 기원 변수저장소 타입과 다릅니다.

sv = e;
여기서 sv는 기원 변수가 x부분 스위즐 뷰입니다
s1 s2
여기서 Nexts1의 동작에 포함됩니다.

참고: s1은 흔히 세미콜론으로 끝납니다.

Vin(s2) Vout(s1)
if e s1 else s2
여기서 Nexts1s2 모두의 동작에 포함됩니다
Vin(next) Vout(s1), Vout(s2)
if e s1 else s2
여기서 Nexts1의 동작에는 포함되지만 s2의 동작에는 포함되지 않습니다
Vin(next) Vout(s1)
if e s1 else s2
여기서 Nexts2의 동작에는 포함되지만 s1의 동작에는 포함되지 않습니다
Vin(next) Vout(s2)
loop { s1 continuing { s2 } } Vin(s1) Vout(prev),
s1의 동작이 {Next,Continue}와 교차하는 경우 Vout(s2)
loop { s1 continuing { s2 } } Vin(s2) Nexts1의 동작에 포함되는 경우 Vout(s1),
동작이 {Continue}이고 제어를 s2로 전달하는 s1 내부의 모든 si에 대한 Vout(si)
loop { s1 continuing { s2 } } Vin(next) Breaks1의 동작에 포함되는 경우 Vout(s2),
동작이 {Break}이고 제어를 next로 전달하는 s1 내부의 모든 si에 대한 Vout(si)
switch e {
case _: s1
case _: s2
...
case _: s3
}
Vin(si) Vout(prev)
switch e {
case _: s1
case _: s2
...
case _: s3
}
Vin(next) 동작에 Next 또는 Break가 포함되는 모든 si에 대한 Vout(si),
그리고
동작이 {Break}이고 제어를 next로 전달하는 sj 내부의 모든 문장에 대한 Vout(sj)

다른 모든 문장(함수 호출 제외)에서 Vin(next)는 Vout(prev)와 동등합니다.

참고: 문장 동작 분석과 동일한 디슈거링이 적용됩니다.

15.2.6. 문장에 대한 균일성 규칙

문장을 분석하는 규칙은 문장 자체와 문장 시작 시점의 제어 흐름에 해당하는 노드 (아래에서는 "CF"로 표기)를 인수로 받아 다음 두 가지를 모두 반환합니다.

아래 표에서 (CF1, S) => CF2는 "제어 흐름 CF1에서 시작하여 S에 대한 분석을 실행하고, 그래프에 필요한 변경 사항을 적용한 뒤, 결과 제어 흐름 노드의 이름을 CF2로 지정한다"라는 의미입니다. 마찬가지로 (CF1, E) => V는 "제어 흐름 CF1에서 시작하여 식 E에 대한 분석을 실행하고, 그래프에 필요한 변경 사항을 적용한 뒤, 결과 값 노드의 이름을 V로 지정한다"라는 의미입니다(식 분석은 다음 절 참조). 식에 대한 이러한 평가는 할당좌변에 속하지 않는 모든 식에 사용되며 RHSValue라고 합니다.

할당좌변에 속하는 식, 즉 LHSValue에 대해서도 유사한 규칙 집합이 있으며 이를 LHSValue: (CF, E) => L로 표기합니다. 이는 값의 균일성에 해당하는 노드를 계산하는 대신 할당 대상 변수의 균일성에 해당하는 노드를 계산합니다.

참고: LHSValue에는 증가감소 문장에 있는 식이 포함됩니다.

참고: RHSValue에는 할당 문의 우변에 속하는 식이나, 할당·증가·감소 문장에 속하지 않는 식이 포함됩니다.

여러 에지를 생성해야 할 때는 X -> Y, X -> Z의 축약 표기로 X -> {Y, Z}를 사용합니다.

루프를 분석할 때는 다음 패턴을 사용합니다.

문장에 대한 균일성 규칙
문장 새 노드 재귀 분석 결과 제어 흐름 노드 새 에지
빈 문장 CF
{s} (CF, s) => CF' CF'
s1 s2,
s1의 동작에 Next가 포함됨

참고: s1은 흔히 세미콜론으로 끝납니다.

(CF, s1) => CF1
(CF1, s2) => CF2
CF2
s1 s2,
s1의 동작에 Next가 포함되지 않음

참고: s1은 흔히 세미콜론으로 끝납니다.

(CF, s1) => CF1

참고: s2는 정적으로 도달할 수 없으며 재귀적으로 분석되지 않습니다. s2는 균일성 분석에 기여하지 않습니다.

CF1
if e s1 else s2
동작이 {Next}임
(CF, e) => V
(V, s1) => CF1
(V, s2) => CF2
CF
if e s1 else s2
다른 동작을 가짐
CFend CFend CFend -> {CF1, CF2}
loop {s1}
s1의 동작에 Return이 포함되지 않음
CF' (CF', s1) => CF1 CF CF' -> {CF1, CF},
s1의 동작이 {Next,Continue}와 교차하는 경우
CF' -> CF,
s1의 동작이 {Next,Continue}와 교차하지 않는 경우
loop {s1}
s1의 동작에 Return이 포함됨
CF' (CF', s1) => CF1 CF1 CF' -> {CF1, CF}
s1의 동작이 {Next,Continue}와 교차하는 경우
CF' -> CF
s1의 동작이 {Next,Continue}와 교차하지 않는 경우
loop {s1 continuing {s2}}
s1의 동작이 {Break}임
(CF, s1) => CF1 CF

참고: 루프는 단 한 번만 반복되므로 추가 에지가 필요하지 않습니다.

loop {s1 continuing {s2}}
s1의 동작이 {Return} 또는 {Break,Return}임
(CF, s1) => CF1 CF1
loop {s1 continuing {s2}}
s1의 동작이 {Next,Continue}와 교차함
CF' (CF', s1) => CF1
(CF1, s2) => CF2
CF
s1의 동작에 Return이 포함되지 않는 경우
CF' -> {CF2, CF}
CF'
s1의 동작에 Return이 포함되는 경우
switch e case _: s_1 .. case _: s_n
동작이 {Next}임
(CF, e) => V
(V, s_1) => CF_1
...
(V, s_n) => CF_n
CF
switch e case _: s_1 .. case _: s_n
다른 동작을 가짐
CFend CFend CFend -> {CF_1, ..., CF_n}
var x: T; CF

참고: x가 function 주소 공간 변수이면 CF값 분석에서 0 값 초기화 식으로 사용됩니다.

break;
continue;
break if e; CFend (CF, e) => V CFend CFend -> V

참고: CFend에서 V로 향하는 에지는 조건 값이 비균일하면 이 break if 문으로 인한 제어 흐름 역시 비균일하다는 사실을 나타냅니다.

return; CF function 주소 공간 포인터 매개변수 i에 대해, Value_return_i_contents -> Vin(prev) (§ 15.2.5 함수 범위 변수 값 분석 참조)
return e; (CF, e) => V CF Value_return -> V

function 주소 공간 포인터 매개변수 i에 대해, Value_return_i_contents -> Vin(prev) (§ 15.2.5 함수 범위 변수 값 분석 참조)

e1 = e2; LHSValue: (CF, e1) => LV
(CF, e2) => RV
CF LV -> RV

참고: LV값 분석의 결과 값입니다.

_ = e (CF, e) => V CF
let x = e; (CF, e) => V CF
var x = e; (CF, e) => V CF

참고: x가 function 주소 공간 변수이면 V값 분석의 결과 값으로 사용됩니다.

f()
인수가 없는 함수 호출 문장
함수 호출 분석을 호출합니다. (CF, f()) => Result CF
f(e1,...,eN)
인수가 있는 함수 호출 문장
함수 호출 분석을 호출합니다. (CF, f(e1,...,eN)) => Result CF

이 분석을 위해 다음과 같이 처리합니다.

성능을 극대화하기 위해 구현체는 흔히 비균일 제어 흐름의 양을 최소화하려고 합니다. 그러나 호출이 균일하다고 말할 수 있는 지점은 여러 요인에 따라 달라집니다. WGSL의 정적 분석은 문장의 동작이 {Next}인 경우 if, switch, loop 문이 끝날 때 균일 제어 흐름으로 돌아간다고 보수적으로 가정합니다. 앞의 표에서는 결과 제어 흐름 노드가 입력 제어 흐름 노드와 동일한 것으로 이를 모델링합니다.

15.2.7. 함수 호출에 대한 균일성 규칙

가장 복잡한 규칙은 함수 호출에 대한 규칙입니다.

참고: Vout(call)의 정의는 § 15.2.5 함수 범위 변수 값 분석을 참조하십시오.

대부분의 내장 함수에는 다음 태그가 있습니다.

예외 목록은 다음과 같습니다.

참고: WGSL 구현체는 함수 호출 전의 제어 흐름이 특정 범위에서 균일하면 함수 호출 후에도 균일하도록 보장합니다.

15.2.8. 식에 대한 균일성 규칙

식을 분석하는 규칙은 식 자체와 식 시작 시점의 제어 흐름에 대응하는 노드 (아래에서는 "CF"로 표기)를 인수로 받아 다음을 반환합니다.

RHSValue 식에 대한 균일성 규칙
새 노드 재귀 분석 결과 값 노드 새 에지
e1 || e2 (CF, e1) => V1
(V1, e2) => V2
V2
e1 && e2
리터럴 CF
함수 범위 변수 "x"로 해석되는 식별자이며, 해당 식별자가 메모리 뷰MVE루트 식별자로 나타나고 타입 검사 중에 MVE에 대해 로드 규칙이 호출되는 경우 Result X는 이 식을 포함하는 문장의 입력 시점에서 "x"의 값에 대응하는 노드입니다 Result Result -> {CF, X}

참고: "x"에 대해 XVout(prev)와 동등합니다
(§ 15.2.5 함수 범위 변수 값 분석 참조)

함수 범위 변수 "x"로 해석되는 식별자이며, 해당 식별자가 스위즐 뷰 식 SVE루트 식별자로 나타나고 타입 검사 중에 SVE에 대해 스위즐 뷰 로드 규칙이 호출되는 경우
함수 범위 변수 "x"로 해석되는 식별자이며, 여기서 "x"는 디슈거링된 포인터 매개변수 i이고, 해당 식별자가 메모리 뷰MVE루트 식별자로 나타나며 타입 검사 중에 MVE에 대해 로드 규칙이 호출되지 않는 경우 param_i
함수 범위 변수 "x"로 해석되는 식별자이며, 여기서 "x"는 디슈거링된 포인터 매개변수 i이고, 해당 식별자가 스위즐 뷰 식 SVE루트 식별자로 나타나며 타입 검사 중에 SVE에 대해 스위즐 뷰 로드 규칙이 호출되는 경우
함수 범위 변수 "x"로 해석되는 식별자이며, 해당 식별자가 메모리 뷰MVE루트 식별자로 나타나고 타입 검사 중에 MVE에 대해 로드 규칙이 호출되지 않는 경우 CF
함수 범위 변수 "x"로 해석되는 식별자이며, 해당 식별자가 스위즐 뷰 식 SVE루트 식별자로 나타나고 타입 검사 중에 SVE에 대해 스위즐 뷰 로드 규칙이 호출되지 않는 경우
const 선언, override 선언, let 선언 또는 비포인터 타입인 비내장 형식 매개변수 "x"로 해석되는 식별자 Result X는 "x"에 대응하는 노드입니다 Result Result -> {CF, X}
읽기 전용이 아닌 접근 모드를 갖는 storage, workgroup 또는 private 주소 공간에 있는 포인터 타입형식 매개변수해석되는 식별자이며, 해당 식별자가 메모리 뷰MVE루트 식별자로 나타나고 타입 검사 중에 MVE에 대해 로드 규칙이 호출되는 경우 MayBeNonUniform
읽기 전용이 아닌 접근 모드를 갖는 storage, workgroup 또는 private 주소 공간에 있는 포인터 타입형식 매개변수해석되는 식별자이며, 해당 식별자가 스위즐 뷰 식 SVE루트 식별자로 나타나고 타입 검사 중에 SVE에 대해 스위즐 뷰 로드 규칙이 호출되는 경우
읽기 전용이 아닌 접근 모드를 갖는 storage, workgroup 또는 private 주소 공간에 있는 포인터 타입형식 매개변수해석되는 식별자이며, 해당 식별자가 메모리 뷰MVE루트 식별자로 나타나고 타입 검사 중에 MVE에 대해 로드 규칙이 호출되지 않는 경우 CF
읽기 전용이 아닌 접근 모드를 갖는 storage, workgroup 또는 private 주소 공간에 있는 포인터 타입형식 매개변수해석되는 식별자이며, 해당 식별자가 스위즐 뷰 식 SVE루트 식별자로 나타나고 타입 검사 중에 SVE에 대해 스위즐 뷰 로드 규칙이 호출되지 않는 경우
function 이외의 주소 공간에 있으며 읽기 전용 접근 모드를 갖는 포인터 타입형식 매개변수해석되는 식별자 CF
균일한 내장 값 "x"로 해석되는 식별자 CF
비균일한 내장 값 "x"로 해석되는 식별자 MayBeNonUniform
읽기 전용 모듈 범위 변수 "x"로 해석되는 식별자 CF
읽기 전용이 아닌 모듈 범위 변수 "x"로 해석되는 식별자이며, 해당 식별자가 메모리 뷰MVE루트 식별자로 나타나고 타입 검사 중에 MVE에 대해 로드 규칙이 호출되는 경우 MayBeNonUniform
읽기 전용이 아닌 모듈 범위 변수 "x"로 해석되는 식별자이며, 해당 식별자가 스위즐 뷰 식 SVE루트 식별자로 나타나고 타입 검사 중에 SVE에 대해 스위즐 뷰 로드 규칙이 호출되는 경우
읽기 전용이 아닌 모듈 범위 변수 "x"로 해석되는 식별자이며, 해당 식별자가 메모리 뷰MVE루트 식별자로 나타나고 타입 검사 중에 MVE에 대해 로드 규칙이 호출되지 않는 경우 CF
읽기 전용이 아닌 모듈 범위 변수 "x"로 해석되는 식별자이며, 해당 식별자가 스위즐 뷰 식 SVE루트 식별자로 나타나고 타입 검사 중에 SVE에 대해 스위즐 뷰 로드 규칙이 호출되지 않는 경우
( e ) (CF, e) => V V
op e,
여기서 op는 단항 연산자입니다
e.field, 여기서 field는 구조체 멤버 이름입니다
e.swiz, 여기서 swiz스위즐 이름입니다
e1 op e2,
여기서 op는 단락 평가하지 않는 이항 연산자입니다
Result (CF, e1) => V1
(CF, e2) => V2
Result Result -> {V1, V2}
e2[e1]
f()
인수가 없는 함수 호출 식
함수 호출 분석을 호출합니다.
(CF, f()) => Result
Result
f(e1,...,eN)
인수가 있는 함수 호출 식
함수 호출 분석을 호출합니다. (CF, f(e1,...,eN)) => Result Result

다음 내장 입력 변수는 균일한 것으로 간주됩니다.

서브그룹 균일성 범위에서는 다음 내장 입력 변수도 균일한 것으로 간주됩니다.

다른 모든 변수(내장 값 참조)는 비균일한 것으로 간주됩니다.

참고: 분석은 복합 타입의 컴포넌트를 개별적으로 분석하지 않으므로, 작성자는 균일한 내장 값을 다른 비균일 입력과 함께 그룹화하지 않아야 합니다.

LHSValue 식에 대한 균일성 규칙
새 노드 재귀 분석 결과 변수 노드 새 에지
함수 범위 변수 "x"로 해석되는 식별자 Result X는 이 식을 포함하는 문장의 출력 시점에서 "x"의 값에 대응하는 노드입니다. Result Result -> {CF, X}

참고: "x"에 대해 XVin(next)와 동등합니다
(§ 15.2.5 함수 범위 변수 값 분석 참조)

const 선언, override 선언, let 선언 또는 형식 매개변수 "x"로 해석되는 식별자 X는 "x"에 대응하는 노드입니다 X
모듈 범위 변수 "x"로 해석되는 식별자 MayBeNonUniform
e.field, 여기서 field는 구조체 멤버 이름입니다 LHSValue: (CF, e) => L1 L1
e.swiz, 여기서 swiz스위즐 이름입니다
*e
&e
e2[e1] (CF, e1) => V1
LHSValue: (CF, e2) => L2
L2 L2 -> V1
f()
인수가 없는 함수 호출 식
함수 호출 분석을 호출합니다.
LHSValue: (CF, f()) => Result
Result
f(e1,...,eN)
인수가 있는 함수 호출 식
함수 호출 분석을 호출합니다. LHSValue: (CF, f(e1,...,eN)) => Result Result

15.2.9. 제어 흐름의 모든 지점에 균일성 주석 달기

이 하위 절 전체는 비규범적입니다.

구현자가 전체 셰이더 제어 흐름의 각 지점이 균일한지 여부 (따라서 해당 위치에서 균일성을 요구하는 함수를 호출하는 것이 유효한지 여부)를 보여 주는 진단 모드를 개발자에게 제공하려는 경우 다음 방법을 제안합니다.

이러한 도달 가능성 분석에서 방문하지 않은 모든 노드는 분석을 통해 균일하다고 입증할 수 있습니다 (따라서 해당 위치에서 도함수 또는 유사한 함수를 호출해도 안전합니다).

참고: 상향식 분석은 호출을 만났을 때 그래프에 어떤 에지를 추가할지 알려 주므로 여전히 필요합니다.

15.2.10. 예제

후속 예제의 그래프에서는 노드에 대해 다음 규칙을 사용합니다.

15.2.10.1. 유효하지 않은 textureSample 함수 호출

이 예제는 textureSample 내장 함수 호출의 유효하지 않은 사용을 보여 줍니다. 함수 호출은 조건이 비균일 값(즉, 내장 값 position)에 의존하는 if 문 내부에서 이루어집니다. 유효하지 않은 의존성 연쇄는 빨간색으로 강조됩니다.

예제: 유효하지 않은 WGSL textureSample
@group(0) @binding(0) var t : texture_2d<f32>;
@group(0) @binding(1) var s : sampler;

@fragment
fn main(@builtin(position) pos : vec4<f32>) {
  if (pos.x < 0.5) {
    // 유효하지 않은 textureSample 함수 호출입니다.
    _ = textureSample(t, s, pos.xy);
  }
}
균일성 그래프

이 예제는 if 문 이후의 제어 흐름 균일성이 if 문 이전의 균일성과 같다는 것도 보여 줍니다 (CF_return이 CF_start에 연결됨). 즉, 진입점 시작 시 균일 제어 흐름으로 시작한다고 보장되므로 if 문 이후에는 제어 흐름이 다시 균일해집니다. textureSample 함수 호출을 if 문 외부로 옮겼다면 프로그램은 유효했을 것입니다. 마찬가지로 if 문의 조건이 균일 값이었다면(예: 각 호출이 유니폼 버퍼에서 같은 값을 읽는 경우) 프로그램은 유효했을 것입니다.

15.2.10.2. 함수 범위 변수 균일성

이 예제는 함수 범위 변수의 값에 의존하는 유효한 배리어 함수 호출과 유효하지 않은 호출을 모두 보여 줍니다. x의 값이 가변 모듈 범위 변수 a에서 파생되므로 workgroupBarrier는 유효하지 않습니다. x의 값이 불변 모듈 범위 변수 b에서 파생되므로 storageBarrier는 유효합니다. 이 예제는 함수 범위 변수의 수명에서 서로 다른 균일성 기간을 구분하는 값 분석의 능력을 강조합니다. 또한 이 예제는 첫 번째 if 문이 끝난 후 제어 흐름이 다시 균일해짐을 명확히 보여 줍니다. 그래프의 해당 부분이 두 번째 if 문과 독립적이므로 이를 알 수 있습니다.

예제: 함수 변수를 사용하는 WGSL
@group(0) @binding(0) var<storage, read_write> a : i32;
@group(0) @binding(1) var<uniform> b : i32;

@compute @workgroup_size(16,1,1)
fn main() {
  var x : i32;
  x = a;
  if x > 0 {
    // 유효하지 않은 배리어 함수 호출입니다.
    workgroupBarrier();
  }
  x = b;
  if x < 0 {
    // 유효한 배리어 함수 호출입니다.
    storageBarrier();
  }
}
균일성 그래프

참고: 하위 그래프는 이해하기 쉽도록 예제에만 포함되었습니다.

15.2.10.3. 복합 값 분석의 한계

균일성 분석의 한 가지 한계는 복합 값의 컴포넌트를 독립적으로 추적하지 않는다는 것입니다. 즉, 비균일한 컴포넌트 값이 하나라도 있으면 분석은 전체 복합 값을 비균일한 것으로 취급하게 됩니다. 이 예제는 이 문제와 셰이더 작성자가 이 한계를 피하기 위해 사용할 수 있는 잠재적 해결 방법을 보여 줍니다.

예제: 유효하지 않은 복합 값 WGSL
struct Inputs {
  // workgroup_id는 균일한 내장 값입니다.
  @builtin(workgroup_id) wgid : vec3<u32>,
  // local_invocation_index는 비균일한 내장 값입니다.
  @builtin(local_invocation_index) lid : u32
}

@compute @workgroup_size(16,1,1)
fn main(inputs : Inputs) {
  // 이 비교는 항상 균일하지만,
  // 분석에서는 이를 판별할 수 없습니다.
  if inputs.wgid.x == 1 {
    workgroupBarrier();
  }
}
유효하지 않은 균일성 그래프

이 분석의 한계를 우회하는 가장 쉬운 방법은 균일하다고 알려진 값과 비균일하다고 알려진 값을 분리하도록 복합 값을 나누는 것입니다. 아래의 대체 WGSL에서는 두 내장 값을 별도의 매개변수로 분리하여 균일성 분석을 충족합니다. 그래프에서 RequiredToBeUniform.S에서 MayBeNonUniform으로 향하는 경로가 없다는 점에서 이를 확인할 수 있습니다.

예제: 유효한 대체 WGSL
@compute @workgroup_size(16,1,1)
fn main(@builtin(workgroup_id) wgid : vec3<u32>,
        @builtin(local_invocation_index) lid : u32) {
  // 이제 균일성 분석은 이 비교가 항상 균일함을
  // 올바르게 판별할 수 있습니다.
  if wgid.x == 1 {
    // 유효한 배리어 함수 호출입니다.
    workgroupBarrier();
  }
}
유효한 대체 균일성 그래프
15.2.10.4. 루프의 균일성

이 예제에는 루프 내의 유효하지 않은 workgroupBarrier 함수 호출이 있습니다. 비균일한 내장 값 local_invocation_index가 루프의 배리어 뒤에 나타나더라도 궁극적인 원인입니다. 후속 반복에서 워크그룹의 일부 호출은 루프를 조기에 빠져나간 반면 다른 호출은 배리어를 실행하려고 하기 때문에 이러한 상황이 발생합니다. 분석은 루프 본문 시작 시점의 제어(CF_loop_body)가 루프 본문 끝의 제어 흐름(CF_after_if)에 의존하는 에지로 반복 간 의존성을 모델링합니다.

예제: 루프 균일성 WGSL
@compute @workgroup_size(16,1,1)
fn main(@builtin(local_invocation_index) lid : u32) {
  for (var i = 0u; i < 10; i++) {
    workgroupBarrier();
    if (lid + i) > 7 {
      break;
    }
  }
}
균일성 그래프
15.2.10.5. 사용자 정의 함수 호출

이 예제는 첫 번째 예제를 수정한 것이지만 사용자 정의 함수 호출을 사용합니다. 분석은 scale의 두 매개변수에 대한 매개변수 반환 태그를 모두 ParameterReturnContentsRequiredToBeUniform으로 설정합니다. 이로 인해 main에서 scale 함수 호출의 반환 값과 position 내장 값 사이에 경로가 생깁니다. 이 경로는 RequiredToBeUniform.S에서 MayBeNonUniform으로 이어지는 전체 유효하지 않은 경로의 부분 경로입니다.

예제: 사용자 정의 함수 호출 균일성 WGSL
fn scale(in1 : f32, in2 : f32) -> f32 {
  let v = in1 / in2;
  return v;
}

@group(0) @binding(0) var t : texture_2d<f32>;
@group(0) @binding(1) var s : sampler;

@fragment
fn main(@builtin(position) pos : vec4<f32>) {
  let tmp = scale(pos.x, 0.5);
  if tmp > 1.0 {
    _ = textureSample(t, s, pos.xy);
  }
}
scale의 균일성 그래프
main의 균일성 그래프

참고: 하위 그래프는 이해하기 쉽도록 예제에만 포함되었습니다.

15.3. 컴퓨트 셰이더와 워크그룹

워크그룹컴퓨트 셰이더 스테이지 진입점을 동시에 실행하며 workgroup 주소 공간의 셰이더 변수에 대한 접근을 공유하는 호출 집합입니다.

컴퓨트 셰이더의 워크그룹 그리드는 다음을 만족하는 정수 좌표 (i,j,k)의 점 집합입니다.

여기서 (workgroup_size_x, workgroup_size_y, workgroup_size_z)는 진입점의 workgroup_size 특성에 지정된 값입니다.

워크그룹 그리드의 각 점에는 정확히 하나의 호출이 있습니다.

호출의 로컬 호출 ID는 해당 호출에 대응하는 워크그룹 그리드 점의 좌표 삼중항 (i,j,k)입니다.

호출에 로컬 호출 ID가 있을 때 해당 호출의 로컬 호출 인덱스는 다음과 같습니다.

i + (j × workgroup_size_x) + (k × workgroup_size_x × workgroup_size_y)

워크그룹에 W개의 호출이 있으면 워크그룹의 각 호출 I에는 0 ≤ L(I) < W를 만족하는 고유한 로컬 호출 인덱스 L(I)가 있으며, 이 범위 전체가 포괄됩니다.

컴퓨트 셰이더는 WebGPU 구현체가 큐에서 디스패치 명령을 제거하고 GPU에서 지정된 작업을 시작할 때 실행을 시작합니다. 디스패치 명령은 다음에 설명된 대로 실행할 워크그룹 수를 나타내는 정수 삼중항 (group_count_x, group_count_y, group_count_z)인 디스패치 크기를 지정합니다.

특정 디스패치에 대한 컴퓨트 셰이더 그리드는 다음을 만족하는 정수 좌표 (CSi,CSj,CSk)의 점 집합입니다.

여기서 workgroup_size_x, workgroup_size_yworkgroup_size_z는 위에서 설명한 컴퓨트 셰이더 진입점의 값입니다.

컴퓨트 셰이더 디스패치가 수행할 작업은 컴퓨트 셰이더 그리드의 각 점마다 진입점을 정확히 한 번 호출하는 것입니다.

호출의 전역 호출 ID는 해당 호출에 대응하는 컴퓨트 셰이더 그리드 점의 좌표 삼중항입니다.

호출은 워크그룹으로 구성되므로 각 호출의 전역 호출 ID (CSi, CSj, CSk)는 다음의 워크그룹 ID로 식별되는 단일 워크그룹에 매핑됩니다.

( ⌊ CSi ÷ workgroup_size_x ⌋, ⌊ CSj ÷ workgroup_size_y ⌋, ⌊ CSk ÷ workgroup_size_z ⌋)

또한 해당 워크그룹 내의 단일 호출은 다음 로컬 호출 ID로 식별됩니다.

( CSi mod workgroup_size_x , CSj mod workgroup_size_y , CSk mod workgroup_size_z ).

참고: 워크그룹 ID의 범위는 (0,0,0)부터 (group_count_x - 1, group_count_y - 1, group_count_z - 1)까지입니다.

linear_indexing 기능이 지원되고 워크그룹의 워크그룹 ID(WGi, WGj, WGk)이면 해당 워크그룹의 워크그룹 인덱스는 다음과 같습니다.

WGi + ( WGj × group_count_x ) + ( WGk × group_count_x × group_count_y )

linear_indexing 기능이 지원되고 호출의 전역 호출 ID(CSi, CSj, CSk)이면 해당 호출의 전역 호출 인덱스는 다음과 같습니다.

CSi + ( CSj × workgroup_size_x × group_count_x ) + ( CSk × workgroup_size_x × group_count_x × workgroup_size_y × group_count_y )

WebGPU는 다음 사항을 보장하지 않습니다.

15.4. 프래그먼트 셰이더와 보조 호출

프래그먼트 셰이더 스테이지의 호출은 X 및 Y 차원에서 서로 인접한 위치를 갖는 호출의 2x2 그리드로 나뉩니다. 이러한 각 그리드를 쿼드라고 합니다. 쿼드는 일부 집단 연산에서 협력할 수 있습니다(§ 15.6.2 도함수 참조). 호출의 쿼드 호출 ID는 쿼드 내의 고유 ID이며 다음과 같습니다.

참고: 쿼드 ID에 대한 내장 값 접근자는 없습니다.

일반적으로 프래그먼트 처리래스터화로 생성된 각 RasterizationPoint에 대해 프래그먼트 셰이더 호출을 하나 생성합니다. 그래픽 프리미티브의 가장자리 등에서는 쿼드를 완전히 채우기에 RasterizationPoint가 부족할 수 있습니다. 쿼드에 RasterizationPoint에 대응하는 호출이 1개, 2개 또는 3개뿐이면 프래그먼트 처리는 쿼드에서 채워지지 않은 각 위치에 대해 보조 호출을 생성하게 됩니다.

보조 호출은 관찰 가능한 효과가 제한됩니다. 보조 호출은 도함수 계산을 돕고 서브그룹 연산에 참여할 수 있습니다. 따라서 보조 호출에는 다음 제한이 적용됩니다.

쿼드의 모든 호출이 보조 호출이 되면(예: discard 문을 실행하여) 쿼드 실행이 종료될 수 있습니다. 그러나 이러한 종료는 비균일 제어 흐름을 생성하는 것으로 간주되지 않습니다.

15.5. 서브그룹

서브그룹컴퓨트 또는 프래그먼트 셰이더 스테이지 진입점을 동시에 실행하고 데이터를 효율적으로 공유하며 결과를 집단적으로 계산할 수 있는 호출 집합입니다. 컴퓨트 셰이더 또는 프래그먼트 셰이더의 각 호출은 정확히 하나의 서브그룹에 속합니다. 컴퓨트 셰이더에서 각 서브그룹은 특정 워크그룹의 부분집합입니다. 프래그먼트 셰이더에서 서브그룹은 여러 그리기 명령의 호출을 포함할 수 있습니다. 각 쿼드는 단일 서브그룹에 포함됩니다.

서브그룹 크기는 서브그룹의 최대 호출 수입니다. 셰이더 내에서 이 값은 subgroup_size 내장 값을 통해 접근할 수 있습니다. 서브그룹 크기는 디스패치 명령 내에서, 따라서 워크그룹 내에서 균일 값이지만, 그리기 명령 내에서는 균일 값이 아닐 수 있습니다. 모든 서브그룹 크기는 [4, 128] 범위에 있는 2의 거듭제곱이며, 특정 장치용으로 컴파일된 셰이더의 값은 WebGPU § 4.3 GPUAdapter에 대한 [subgroupMinSize, subgroupMaxSize] 범위 내에 있습니다. 실제 크기는 셰이더, 장치 속성 및 장치 컴파일러에 따라 달라집니다. 각 장치는 가능한 서브그룹 크기 범위의 부분집합(값 하나일 수도 있음)을 지원합니다. 장치 컴파일러는 다양한 휴리스틱을 사용하여 지원되는 크기 중 하나를 선택합니다. 각 서브그룹은 보고된 서브그룹 크기보다 적은 수의 호출을 포함할 수 있습니다 (예: 서브그룹 크기보다 적은 호출이 시작된 경우).

호출의 서브그룹 호출 ID는 서브그룹 내의 고유 ID입니다. 이 ID는 subgroup_invocation_id 내장 값을 통해 접근할 수 있으며 [0, subgroup_size - 1] 범위에 있습니다.

subgroup_id 기능이 지원되는 경우, 컴퓨트 셰이더 내에서 서브그룹 ID는 워크그룹 내 서브그룹의 고유 ID입니다. 이 ID는 subgroup_id 내장 값을 통해 접근할 수 있으며 [0, num_subgroups - 1] 범위에 있습니다.

서브그룹 값(즉, subgroup_invocation_idsubgroup_id)과 local_invocation_index 사이에는 정의된 관계가 없습니다. 이식 불가능한 코드를 방지하려면 셰이더 작성자는 두 값 사이에 특정 매핑이 있다고 가정해서는 안 됩니다.

같은 서브그룹의 호출이 서로 다른 제어 흐름 경로를 실행하면 서브그룹 실행이 분기되었다고 합니다. 이는 비균일 제어 흐름의 특수한 경우입니다. 분기는 서브그룹 연산의 의미 체계에 영향을 줍니다. 서브그룹 연산을 동시에 실행하는 서브그룹의 호출은 해당 연산에 대해 활성입니다. 서브그룹의 다른 호출은 해당 연산에 대해 비활성입니다. 서브그룹 크기가 서브그룹의 호출 수를 초과하면 추가적인 가상 호출은 비활성으로 간주됩니다. 보조 호출은 연산에서 활성일 수도 있고 비활성일 수도 있습니다. 즉, 일부 장치에서는 보조 호출이 서브그룹 연산에 참여할 수 있지만 다른 장치에서는 참여하지 않을 수 있습니다.

참고: 비균일 제어 흐름에서 작동할 때 기반 장치 간의 이식성 차이가 상당하며 장치 컴파일러는 이러한 코드를 흔히 공격적으로 최적화합니다. 그 결과 서브그룹은 셰이더 작성자가 예상하는 것과 다른 활성 호출 집합을 포함할 수 있습니다.

15.6. 집단 연산

15.6.1. 배리어

배리어는 프로그램의 메모리 연산 순서를 지정하는 동기화 내장 함수입니다. 제어 배리어는 같은 워크그룹의 모든 호출이 동시에 실행한 것처럼 실행됩니다. 따라서 제어 배리어는 컴퓨트 셰이더의 균일 제어 흐름에서만 실행되어야 합니다.

15.6.2. 도함수

편도함수는 한 축을 따른 값의 변화율입니다. 같은 쿼드 내의 프래그먼트 셰이더 호출은 근사 편도함수를 계산하기 위해 협력합니다.

도함수를 계산하는 내장 함수는 다음과 같습니다.

프래그먼트 좌표의 편도함수는 다음 내장 함수의 연산 일부로 암시적으로 계산됩니다.

이러한 함수에서 도함수는 샘플링할 텍셀의 밉 레벨을 결정하는 데 도움이 되며, textureSampleCompare의 경우에는 참조 값과 비교할 텍셀을 샘플링하는 데 도움이 됩니다.

호출에서 지정한 값의 편도함수는 § 17.6 도함수 내장 함수에 설명된 내장 함수로 계산됩니다.

인접한 호출이 도함수를 계산하기 위해 협력하므로 이러한 함수는 프래그먼트 셰이더의 균일 제어 흐름에서만 호출해야 합니다. 이러한 함수 중 하나를 호출할 때마다 균일성 분석에서 호출이 균일 제어 흐름 중에 발생함을 입증할 수 없으면 derivative_uniformity 진단이 트리거됩니다.

이러한 함수 중 하나가 비균일 제어 흐름에서 호출되면 결과는 불확정 값입니다.

참고: 도함수는 암시적인 유형의 쿼드 연산입니다. 도함수를 사용하는 데 subgroups 확장은 필요하지 않습니다.

15.6.3. 서브그룹 연산

서브그룹 내장 함수를 사용하면 서브그룹의 호출 간에 효율적으로 통신하고 계산할 수 있습니다. 서브그룹 연산은 단일 명령 다중 스레드(SIMT) 연산입니다.

서브그룹의 활성 호출은 결과를 결정하기 위해 서로 통신합니다. 따라서 모든 호출이 활성일 때(즉, 서브그룹 수준의 균일 제어 흐름에서) 이러한 함수를 호출하면 이식성이 극대화됩니다.

15.6.4. 쿼드 연산

쿼드 내장 함수는 호출의 쿼드에 대해 작동합니다. 이러한 함수는 쿼드 내의 데이터 통신에 유용합니다.

쿼드의 활성 호출은 결과를 결정하기 위해 서로 통신합니다. 따라서 모든 호출이 활성일 때(즉, 쿼드 수준의 균일 제어 흐름에서) 이러한 함수를 호출하면 이식성이 극대화됩니다.

15.7. 부동 소수점 평가

WGSL 부동 소수점 기능은 부동 소수점에 대한 IEEE-754 표준을 기반으로 하지만, GPU의 절충점을 반영하여 기능이 축소되었으며 이식성을 위한 몇 가지 추가 보호 장치가 있습니다.

15.7.1. IEEE-754 개요

WGSL 부동 소수점 타입은 IEEE-754 이진 부동 소수점 타입을 기반으로 합니다.

IEEE-754 이진 부동 소수점 타입은 확장 실수 수직선을 다음과 같이 근사합니다.

부동 소수점 타입의 유한 범위구간 [low, high]입니다. 여기서 low는 해당 타입에서 가장 낮은 유한 값이고 high는 해당 타입에서 가장 높은 유한 값입니다.

관심 대상인 IEEE-754 부동 소수점 타입은 다음과 같습니다.

다음 알고리즘은 부동 소수점 값의 비트 표현을 그에 대응하는 확장 실수 값 또는 NaN으로 매핑합니다.

알고리즘: 부동 소수점 비트 해석

입력: Bits, 이진 부동 소수점 타입 값의 비트 표현.

출력: F, Bits가 나타내는 부동 소수점 값.

절차:

부동 소수점 연산의 정의역은 연산이 잘 정의되는 확장 실수 입력의 집합입니다.

반올림확장 실수x를 부동 소수점 타입의 값 x'로 매핑합니다. x가 부동 소수점 타입에 속하면 반올림은 x를 자기 자신으로 매핑합니다. x = x'. x가 해당 타입의 유한 범위 밖에 있으면 반올림에서 오버플로가 발생할 수 있습니다. 그렇지 않으면 x'x보다 큰 가장 낮은 부동 소수점 값 또는 x보다 작은 가장 높은 부동 소수점 값 중 하나이며, 반올림 모드가 어느 값을 선택할지 결정합니다.

일반적으로 NaN 입력이 있는 연산은 NaN 출력을 산출합니다. 예외는 다음과 같습니다.

IEEE-754는 다음 다섯 종류의 예외를 정의합니다.

15.7.2. IEEE-754와의 차이점

WGSL은 IEEE-754 표준을 따르지만 다음과 같은 차이가 있습니다.

15.7.3. 부동 소수점 반올림 및 오버플로

오버플로가 발생하는 계산은 무한대 또는 가장 가까운 유한 값으로 반올림될 수 있습니다. 결과는 오버플로가 발생한 중간 결과 값의 크기와 평가가 셰이더 모듈 생성, 파이프라인 생성 또는 셰이더 실행 중 어느 시점에 발생하는지에 따라 달라집니다.

부동 소수점 타입 T에 대해 MAX(T)T의 가장 큰 양의 유한 값으로 정의하고, 2EMAX(T)T로 표현할 수 있는 가장 큰 2의 거듭제곱으로 정의합니다. 특히 EMAX(f32) = 127이고, EMAX(f16) = 15입니다.

X를 부동 소수점 계산에서 얻은 무한 정밀도의 중간 결과라고 합니다. 식의 최종 값은 다음과 같이 중간 결과X'X''를 거치는 두 단계로 결정됩니다.

X에서 반올림을 통해 TX'를 계산합니다.

X'에서 식의 최종 값 X''를 계산하거나 프로그램 오류를 감지합니다.

15.7.4. 부동 소수점 정확도

x를 무한한 정밀도로 계산한 연산의 정확한 실숫값 또는 무한대 결과라고 합니다. 부동 소수점 타입 T에 대한 연산의 정확히 반올림된 결과는 다음과 같습니다.

즉, 결과는 올림 또는 내림으로 반올림될 수 있습니다. WGSL은 반올림 모드를 지정하지 않습니다.

참고: 부동 소수점 타입에는 양의 무한대와 음의 무한대가 포함되므로 정확히 반올림된 결과는 유한하거나 무한할 수 있습니다.

참고: 무한한 정밀도로 계산한 연산 결과에는 배정밀도를 초과하는 정밀도가 필요할 수 있습니다. 이러한 사례의 예로 x=1.0 이고 y=1.17e-38(가장 작은 양의 정규 단정밀도 부동 소수점 수)인 x - y가 있습니다. 이 숫자들의 지수는 126만큼 떨어져 있습니다. IEEE-754 binary64(배정밀도) 형식의 유효 숫자에는 52비트만 있으므로 뺄셈을 수행할 때 y의 모든 유효 비트가 손실됩니다. 반올림 모드에 따라 이 사례와 y가 작지만 0이 아닌 여러 다른 사례에서 WGSL 식 x - yx와 같은 값을 산출할 수 있습니다. [ECMASCRIPT]IEEE-754 roundTiesToEven 반올림 모드와 동등한 방식을 사용한다는 점에 유의하십시오.

부동 소수점 수 x의 최하위 자리 단위인 ULP는 다음과 같이 정의됩니다 [Muller2005].

연산의 정확도는 다음 다섯 가지 중 하나로 제시됩니다.

연산의 정확도가 입력 범위에 대해 지정된 경우 해당 범위 밖의 입력 값에 대해서는 정확도가 정의되지 않습니다.

허용되는 결과가 결과 타입의 유한 범위 밖에 있으면 § 15.7.3 부동 소수점 반올림 및 오버플로의 규칙이 적용됩니다.

15.7.4.1. 구체 부동 소수점 식의 정확도
구체 부동 소수점 연산의 정확도
f32 정확도 f16 정확도
x + y 정확히 반올림됨
x - y 정확히 반올림됨
x * y 정확히 반올림됨
x / y |y|가 [2-126, 2126] 범위에 있을 때 2.5 ULP |y|가 [2-14, 214] 범위에 있을 때 2.5 ULP
x % y x - y * trunc(x/y)에서 상속됨
-x 정확히 반올림됨
x == y 정확한 결과
x != y 정확한 결과
x < y 정확한 결과
x <= y 정확한 결과
x > y 정확한 결과
x >= y 정확한 결과
구체 부동 소수점 내장 함수의 정확도
내장 함수 f32 정확도 f16 정확도
abs(x) 정확히 반올림됨
acos(x) 다음 중 더 나쁜 값:
  • 절대 오차 6.77×10-5

  • atan2(sqrt(1.0 - x * x), x)에서 상속됨

다음 중 더 나쁜 값:
  • 절대 오차 3.91×10-3

  • atan2(sqrt(1.0 - x * x), x)에서 상속됨

acosh(x) log(x + sqrt(x * x - 1.0))에서 상속됨
asin(x) 다음 중 더 나쁜 값:
  • 절대 오차 6.81×10-5

  • atan2(x, sqrt(1.0 - x * x))에서 상속됨

다음 중 더 나쁜 값:
  • 절대 오차 3.91×10-3

  • atan2(x, sqrt(1.0 - x * x))에서 상속됨

asinh(x) log(x + sqrt(x * x + 1.0))에서 상속됨
atan(x) 4096 ULP 5 ULP
atan2(y, x) |x|가 [2-126, 2126] 범위에 있고 y가 유한하며 정규일 때 4096 ULP |x|가 [2-14, 214] 범위에 있고 y가 유한하며 정규일 때 5 ULP
atanh(x) log( (1.0 + x) / (1.0 - x) ) * 0.5에서 상속됨
ceil(x) 정확히 반올림됨
clamp(x,low,high) 정확히 반올림됨.

무한 정밀도의 결과는 min(max(x,low),high) 또는 세 값의 중앙값 공식으로 계산됩니다. low > high이면 두 결과가 다를 수 있습니다.

xlow 또는 high 중 하나가 비정규이면 결과는 비정규 값 중 하나일 수 있습니다. 이는 비정규 입력에 대한 minmax 함수의 가능한 결과를 따릅니다.

cos(x) x가 구간 [-π, π]에 있을 때 절대 오차는 최대 2-11 x가 구간 [-π, π]에 있을 때 절대 오차는 최대 2-7
cosh(x) (exp(x) + exp(-x)) * 0.5에서 상속됨
cross(x, x) ij(x[i] * y[j] - x[j] * y[i])에서 상속됨
degrees(x) x * 57.295779513082322865에서 상속됨
determinant(m:mat2x2<T>)
determinant(m:mat3x3<T>)
determinant(m:mat4x4<T>)
무한 ULP.
참고:WebGPU 구현체는 실용적으로 유용한 determinant 함수를 제공해야 합니다.

이상적인 수학에서 행렬식은 덧셈, 뺄셈 및 곱셈 연산으로 계산됩니다.

그러나 GPU는 부동 소수점 수학을 사용하며 determinant의 GPU 구현은 오버플로와 오차에 대한 견고성보다 속도와 단순성을 선호합니다.

예를 들어 단순한 2x2 행렬식 계산 (m[0][0] * m[1][1] - m[1][0] * m[0][1])조차 치명적 상쇄를 방지하지 못합니다. 2x2 행렬식에 더 엄격한 오차 한계를 제공하는 것은 비교적 최근의 연구 [Jeannerod2013]의 주제입니다. 행렬 크기가 커질수록 난점은 빠르게 복합됩니다.

WGSL 행렬식에 유한한 오차 한계가 없다는 것은 기반 구현에도 동일한 한계가 없다는 점을 반영합니다.

distance(x, y) length(x - y)에서 상속됨
dot(x, y) x[i] * y[i]의 합에서 상속됨
dpdx(x)
dpdxCoarse(x)
dpdxFine(x)
dpdy(x)
dpdyCoarse(x)
dpdyFine(x)
fwidth(x)
fwidthCoarse(x)
fwidthFine(x)
무한 ULP.
참고:WebGPU 구현체는 실용적으로 유용한 도함수 함수를 제공해야 합니다.

GPU에서 도함수는 서로 다른 호출의 값 사이의 차이 (fwidth의 경우 절댓값의 차이)로 구현됩니다.

WGSL 도함수에 유한한 오차 한계가 없다는 것은 기반 구현에도 동일한 한계가 없다는 점을 반영합니다.

exp(x) 3 + 2 * |x| ULP 1 + 2 * |x| ULP
exp2(x) 3 + 2 * |x| ULP 1 + 2 * |x| ULP
faceForward(x, y, z) select(-x, x, dot(z, y) < 0.0)에서 상속됨
floor(x) 정확히 반올림됨
fma(x, y, z) x * y + z에서 상속됨
fract(x) x - floor(x)에서 상속됨
frexp(x) x가 0이거나 정규일 때 정확히 반올림됨.
inverseSqrt(x) 2 ULP
ldexp(x, y) 정확히 반올림됨
length(x) 벡터의 경우 sqrt(dot(x, x))에서, 스칼라의 경우 sqrt(x*x)에서 상속됨.
log(x) x가 구간 [0.5, 2.0]에 있을 때 절대 오차는 최대 2-21.
x가 구간 [0.5, 2.0] 밖에 있을 때 3 ULP.
x가 구간 [0.5, 2.0]에 있을 때 절대 오차는 최대 2-7.
x가 구간 [0.5, 2.0] 밖에 있을 때 3 ULP.
log2(x) x가 구간 [0.5, 2.0]에 있을 때 절대 오차는 최대 2-21.
x가 구간 [0.5, 2.0] 밖에 있을 때 3 ULP.
x가 구간 [0.5, 2.0]에 있을 때 절대 오차는 최대 2-7.
x가 구간 [0.5, 2.0] 밖에 있을 때 3 ULP.
max(x, y) 정확히 반올림됨

xy가 모두 비정규이면 결과는 둘 중 어느 입력이든 될 수 있습니다.

min(x, y) 정확히 반올림됨.

xy가 모두 비정규이면 결과는 둘 중 어느 입력이든 될 수 있습니다.

mix(x, y, z) x * (1.0 - z) + y * z에서 상속됨
modf(x) 정확히 반올림됨
normalize(x) x / length(x)에서 상속됨
pack4x8snorm(x) 정확히 반올림된 중간 결과 값. 정확한 결과.
pack4x8unorm(x) 정확히 반올림된 중간 결과 값. 정확한 결과.
pack2x16snorm(x) 정확히 반올림된 중간 결과 값. 정확한 결과.
pack2x16unorm(x) 정확히 반올림된 중간 결과 값. 정확한 결과.
pack2x16float(x) 정확히 반올림된 중간 결과 값. 정확한 결과.
pow(x, y) exp2(y * log2(x))에서 상속됨
quantizeToF16(x) 정확히 반올림됨
radians(x) x * 0.017453292519943295474에서 상속됨
reflect(x, y) x - 2.0 * dot(x, y) * y에서 상속됨
refract(x, y, z) z * x - (z * dot(y, x) + sqrt(k)) * y에서 상속됨.
여기서 k = 1.0 - z * z * (1.0 - dot(y, x) * dot(y, x))
k < 0.0이면 결과는 정확히 0.0입니다
round(x) 정확히 반올림됨
sign(x) 정확히 반올림됨
sin(x) x가 구간 [-π, π]에 있을 때 절대 오차는 최대 2-11 x가 구간 [-π, π]에 있을 때 절대 오차는 최대 2-7
sinh(x) (exp(x) - exp(-x)) * 0.5에서 상속됨
saturate(x) 정확히 반올림됨
smoothstep(edge0, edge1, x) t * t * (3.0 - 2.0 * t)에서 상속됨.
여기서 t = clamp((x - edge0) / (edge1 - edge0), 0.0, 1.0)
sqrt(x) 1.0 / inverseSqrt(x)에서 상속됨
step(edge, x) 정확히 반올림됨
tan(x) sin(x) / cos(x)에서 상속됨
tanh(x) 다음 중 더 나쁜 값:
  • 절대 오차 1.0×10-5

  • sinh(x) / cosh(x)에서 상속됨

transpose(x) 정확히 반올림됨
trunc(x) 정확히 반올림됨
unpack4x8snorm(x) 3 ULP 해당 없음
unpack4x8unorm(x) 3 ULP 해당 없음
unpack2x16snorm(x) 3 ULP 해당 없음
unpack2x16unorm(x) 3 ULP 해당 없음
unpack2x16float(x) 정확히 반올림됨 해당 없음
subgroupBroadcast(x, i) 정확히 반올림됨
subgroupBroadcastFirst(x) 정확히 반올림됨
subgroupAdd(x) 서브그룹의 모든 활성 호출에 대한 x의 합에서 상속됨
subgroupExclusiveAdd(x) 서브그룹 호출 ID가 현재 호출의 ID보다 작은 서브그룹의 모든 활성 호출에 대한 x의 합에서 상속됨.
subgroupInclusiveAdd(x) 서브그룹 호출 ID가 현재 호출의 ID보다 작거나 같은 서브그룹의 모든 활성 호출에 대한 x의 합에서 상속됨.
subgroupMul(x) 서브그룹의 모든 활성 호출에 대한 x의 곱에서 상속됨
subgroupExclusiveMul(x) 서브그룹 호출 ID가 i번째 호출의 ID보다 작은 서브그룹의 모든 활성 호출에 대한 xi의 곱에서 상속됨
subgroupInclusiveMul(x) 서브그룹 호출 ID가 i번째 호출의 ID보다 작거나 같은 서브그룹의 모든 활성 호출에 대한 xi의 곱에서 상속됨
subgroupMax(x) 서브그룹의 모든 활성 호출에 대한 max(x)에서 상속됨
subgroupMin(x) 서브그룹의 모든 활성 호출에 대한 min(x)에서 상속됨
subgroupShuffle(x, id) 정확히 반올림됨
subgroupShuffleDown(x, delta) 정확히 반올림됨
subgroupShuffleUp(x, delta) 정확히 반올림됨
subgroupShuffleXor(x, mask) 정확히 반올림됨
quadBroadcast(x, id) 정확히 반올림됨
quadSwapDiagonal(x) 정확히 반올림됨
quadSwapX(x) 정확히 반올림됨
quadSwapY(x) 정확히 반올림됨
15.7.4.2. AbstractFloat 식의 정확도

AbstractFloat 연산의 정확도는 다음과 같습니다.

참고:ULP로 정량화할 때 주어진 절대 오차 한계는 기반 부동 소수점 타입에 크게 의존합니다.

AbstractFloat 값의 ULP는 AbstractFloat가 IEEE-754 binary64 타입과 동일하다고 가정합니다.

binary64 형식의 유효 숫자가 f32 타입의 유효 숫자보다 29비트 더 길기 때문에 f32 값의 1 ULP는 IEEE-754 binary64 값의 1 ULP보다 229배 큽니다.

예를 들어 연산의 실제 결과 값이 x이지만 x'로 계산되었다고 가정합니다. 오차 x-x'가 f32에서 3 ULP이면 같은 절대 오차 x-x'는 AbstractFloat에서 3·229 ULP입니다.

15.7.5. 재결합 및 융합

재결합은 정확하게 계산했을 때 답이 같도록 식의 연산 순서를 변경하는 것입니다. 예를 들면 다음과 같습니다.

그러나 부동 소수점으로 계산하면 결과가 같지 않을 수 있습니다. 재결합된 결과는 근사로 인해 부정확할 수 있으며, 중간 결과를 계산할 때 오버플로 또는 NaN을 트리거할 수 있습니다.

구현체는 연산을 재결합할 수 있습니다.

변환된 식이 원래 공식만큼 정확하다면 구현체는 연산을 융합할 수 있습니다. 예를 들어 일부 융합 곱셈-덧셈 구현은 곱셈 후 덧셈을 수행하는 것보다 더 정확할 수 있습니다.

15.7.6. 부동 소수점 변환

이 절에서는 출발지 또는 목적지 중 하나가 부동 소수점 타입인 스칼라 변환의 세부 사항을 설명합니다.

이 절에서 부동 소수점 타입은 다음 중 하나일 수 있습니다.

참고: WGSL의 f32 타입은 IEEE-754 binary32 형식에 대응하고, WGSL의 f16 타입은 IEEE-754 binary16 형식에 대응한다는 점을 기억하십시오.

스칼라 부동 소수점에서 정수로 변환 알고리즘은 다음과 같습니다.

부동 소수점 스칼라 값 X정수 스칼라 타입 T로 변환하려면 다음을 수행합니다.

참고: 즉, NaN이 아닌 경우 부동 소수점에서 정수로 변환할 때는 값을 대상 타입의 범위 내로 제한한 다음 0을 향해 반올림합니다. 이 제한 요구 사항은 WGSL이 의미 있는 결과를 의무화하지만 C와 C++에서는 정의되지 않은 동작을 산출하고 IEEE-754에서는 유효하지 않은 연산 예외와 NaN 결과를 의무화하는 사례 중 하나입니다.

참고: 예를 들면 다음과 같습니다.

숫자 스칼라에서 부동 소수점으로 변환 알고리즘은 다음과 같습니다.

알고리즘: 부동 소수점으로의 숫자 스칼라 변환

입력:

출력: XOut, X를 타입 T로 변환한 결과. 또는 오류를 생성합니다.

절차:

참고: 정숫값은 표현 가능한 인접한 두 부동 소수점 값 사이에 있을 수 있습니다. 특히 f32 타입은 명시적인 소수부 비트 23개를 사용합니다. 또한 부동 소수점 값이 정규 범위에 있으면(지수가 어느 극단값도 아니면) 유효 숫자는 소수부 비트 집합과 비트 위치 23의 최상위 위치에 있는 추가 1비트로 구성됩니다. 그러면 예를 들어 정수 228과 1+228은 모두 같은 부동 소수점 값으로 매핑됩니다. 최하위의 1비트 차이는 부동 소수점 형식으로 표현할 수 없습니다. 이러한 종류의 충돌은 크기가 225 이상인 인접 정수 쌍에서 발생합니다.

참고: 원래 타입이 i32 또는 u32 중 하나이고 목적지 타입이 f32이면 원래 값은 항상 목적지 타입의 범위 내에 있습니다.

참고: 출발지 타입이 대상 부동 소수점 타입보다 지수 및 유효 숫자 비트가 적은 부동 소수점 타입이면 원래 값은 항상 목적지 타입의 범위 내에 있습니다.

15.7.7. 부동 소수점 식 및 내장 함수의 정의역

이전 절에서는 부동 소수점 식을 그 정의역 밖에서 평가할 때 예상되는 동작을 설명합니다.

§ 8.8 산술 식§ 17.5 숫자 내장 함수는 각각 부동 소수점 식과 내장 함수의 정의역을 정의합니다. 주어진 연산에 제한이 나열되지 않았다면 정의역은 전체입니다. 즉, 정의역은 모든 유한 입력과 무한 입력을 포함합니다. 그렇지 않으면 명시적인 정의역이 나열됩니다.

WGSL 연산이 IEEE-754에서 정의한 연산에 대응하는 여러 경우에는 두 연산의 정의역이 같습니다. 예를 들어 WGSL과 IEEE-754의 acos 연산은 모두 [−1,1]의 정의역을 가집니다.

명시적으로 나열된 정의역을 갖는 컴포넌트별 WGSL 연산에서는 스칼라 사례만 설명됩니다. 벡터 사례는 컴포넌트별 의미 체계에서 추론됩니다.

일부 WGSL 연산은 다른 WGSL 식을 사용하여 구현될 수 있습니다. § 15.7.4 부동 소수점 정확도에서는 이를 상속된 정확도를 갖는 것으로 나열합니다. 이러한 연산 중 하나의 정의역을 나열할 때는 다음 중 하나를 사용합니다.

예를 들어 2요소 벡터 ab에 대한 dot(a,b) 함수의 정확도는 식 a[0] * b[0] + a[1] * b[1]에서 상속됩니다. 이 식은 두 번의 부동 소수점 곱셈과 한 번의 부동 소수점 덧셈을 사용합니다.

16. 키워드 및 토큰 요약

16.1. 키워드 요약

16.2. 예약어

예약어는 향후 사용을 위해 예약된 토큰입니다. WGSL 모듈에는 예약어가 포함되어서는 안 됩니다.

다음은 예약어입니다.

_reserved :

| 'NULL'

| 'Self'

| 'abstract'

| 'active'

| 'alignas'

| 'alignof'

| 'as'

| 'asm'

| 'asm_fragment'

| 'async'

| 'attribute'

| 'auto'

| 'await'

| 'become'

| 'cast'

| 'catch'

| 'class'

| 'co_await'

| 'co_return'

| 'co_yield'

| 'coherent'

| 'column_major'

| 'common'

| 'compile'

| 'compile_fragment'

| 'concept'

| 'const_cast'

| 'consteval'

| 'constexpr'

| 'constinit'

| 'crate'

| 'debugger'

| 'decltype'

| 'delete'

| 'demote'

| 'demote_to_helper'

| 'do'

| 'dynamic_cast'

| 'enum'

| 'explicit'

| 'export'

| 'extends'

| 'extern'

| 'external'

| 'fallthrough'

| 'filter'

| 'final'

| 'finally'

| 'friend'

| 'from'

| 'fxgroup'

| 'get'

| 'goto'

| 'groupshared'

| 'highp'

| 'impl'

| 'implements'

| 'import'

| 'inline'

| 'instanceof'

| 'interface'

| 'layout'

| 'lowp'

| 'macro'

| 'macro_rules'

| 'match'

| 'mediump'

| 'meta'

| 'mod'

| 'module'

| 'move'

| 'mut'

| 'mutable'

| 'namespace'

| 'new'

| 'nil'

| 'noexcept'

| 'noinline'

| 'nointerpolation'

| 'non_coherent'

| 'noncoherent'

| 'noperspective'

| 'null'

| 'nullptr'

| 'of'

| 'operator'

| 'package'

| 'packoffset'

| 'partition'

| 'pass'

| 'patch'

| 'pixelfragment'

| 'precise'

| 'precision'

| 'premerge'

| 'priv'

| 'protected'

| 'pub'

| 'public'

| 'readonly'

| 'ref'

| 'regardless'

| 'register'

| 'reinterpret_cast'

| 'require'

| 'resource'

| 'restrict'

| 'self'

| 'set'

| 'shared'

| 'sizeof'

| 'smooth'

| 'snorm'

| 'static'

| 'static_assert'

| 'static_cast'

| 'std'

| 'subroutine'

| 'super'

| 'target'

| 'template'

| 'this'

| 'thread_local'

| 'throw'

| 'trait'

| 'try'

| 'type'

| 'typedef'

| 'typeid'

| 'typename'

| 'typeof'

| 'union'

| 'unless'

| 'unorm'

| 'unsafe'

| 'unsized'

| 'use'

| 'using'

| 'varying'

| 'virtual'

| 'volatile'

| 'wgsl'

| 'where'

| 'with'

| 'writeonly'

| 'yield'

16.3. 구문 토큰

구문 토큰은 다음 용도로 사용하는 특수 코드 포인트의 시퀀스입니다.

구문 토큰은 다음과 같습니다.

17. 내장 함수

일부 함수는 구현체에서 제공하는 미리 선언된 함수이므로 WGSL 모듈에서 언제나 사용할 수 있습니다. 이러한 함수를 내장 함수라고 합니다.

내장 함수는 모두 같은 이름을 갖지만 형식 매개변수의 개수, 순서 및 타입으로 구분되는 함수 패밀리입니다. 이러한 서로 다른 함수 변형 각각은 오버로드입니다.

참고:사용자 정의 함수에는 오버로드가 하나만 있습니다.

오버로드는 아래에서 다음 항목을 통해 설명됩니다.

내장 함수를 호출할 때 함수의 모든 인수는 함수 평가가 시작되기 전에 평가됩니다. § 11.2 함수 호출을 참조하십시오.

17.1. 생성자 내장 함수

값 생성자 내장 함수는 주어진 타입의 값을 명시적으로 생성합니다.

WGSL은 모든 미리 선언된 타입과 모든 생성 가능 구조체 타입에 값 생성자를 제공합니다. 이러한 생성자 내장 함수의 철자는 타입 또는 해당 타입의 타입 별칭과 같습니다. 이러한 내장 함수를 사용하는 모든 위치에서 식별자는 타입 또는 타입 별칭의 범위 내에 있어야 하며, 식별자는 다른 선언으로 해석되어서는 안 됩니다.

참고: frexp, modfatomicCompareExchangeWeak가 반환하는 구조체 타입은 WGSL 모듈에 작성할 수 없습니다.

참고: 해당 타입의 값 선언은 WGSL 텍스트의 그 문장에서 유효해야 합니다.

WGSL은 두 종류의 값 생성자를 제공합니다.

17.1.1. 0 값 내장 함수

구체 생성 가능 타입 T에는 고유한 0 값과, WGSL에서 타입 뒤에 빈 괄호 쌍을 붙여 작성하는 대응 내장 함수 T ()가 있습니다. 추상 숫자 타입에도 0 값이 있지만 이에 접근하는 내장 함수는 없습니다.

0 값은 다음과 같습니다.

참고: WGSL에는 원자 타입, 런타임 크기 배열, 버퍼 또는 기타 생성 가능하지 않은 타입을 위한 0 내장 함수가 없습니다.

오버로드
@const @must_use fn T() -> T
매개변수화 T구체 생성 가능 타입입니다.
설명 타입 T0 값을 생성합니다.

참고: AbstractInt의 0으로 채워진 벡터는 vec2(), vec3()vec4()로 작성할 수 있습니다.

예제: 0 값 벡터
vec2<f32>()                 // 두 f32 컴포넌트로 구성된 0 값 벡터입니다.
vec2<f32>(0.0, 0.0)         // 같은 값을 명시적으로 작성했습니다.

vec3<i32>()                 // 세 i32 컴포넌트로 구성된 0 값 벡터입니다.
vec3<i32>(0, 0, 0)          // 같은 값을 명시적으로 작성했습니다.
예제: 0 값 배열
array<bool, 2>()               // 두 불리언으로 구성된 0 값 배열입니다.
array<bool, 2>(false, false)   // 같은 값을 명시적으로 작성했습니다.
예제: 0 값 구조체
struct Student {
  grade: i32,
  GPA: f32,
  attendance: array<bool,4>
}

fn func() {
  var s: Student;

  // Student의 0 값
  s = Student();

  // 같은 값을 명시적으로 작성했습니다.
  s = Student(0, 0.0, array<bool,4>(false, false, false, false));

  // 같은 값을 0 값 멤버를 사용하여 작성했습니다.
  s = Student(i32(), f32(), array<bool,4>());
}

17.1.2. 값 생성자 내장 함수

다음 하위 절에 정의된 내장 함수는 다음 방법으로 생성 가능 값을 생성합니다.

벡터와 행렬 형식은 컴포넌트 타입이 일치하는 컴포넌트와 하위 벡터의 다양한 조합으로 벡터와 행렬 값을 생성합니다. 컴포넌트 타입을 지정하지 않고 대상 타입의 차원을 지정하여 벡터와 행렬을 생성하는 오버로드가 있습니다. 컴포넌트 타입은 생성자 인수에서 추론됩니다.

17.1.2.1. array
오버로드
@const @must_use fn array<T, N>(e1 : T, ..., eN : T) -> array<T, N>
매개변수화 T구체이고 생성 가능합니다
설명 요소로 배열을 생성합니다.

참고: array<T,N>의 요소 수는 생성자 인수의 수와 같아 셰이더 생성 시점에 완전히 결정되므로 생성 가능합니다.

오버로드
@const @must_use fn array(e1 : T, ..., eN : T) -> array<T, N>
매개변수화 T생성 가능합니다
설명 요소로 배열을 생성합니다.

컴포넌트 타입은 요소의 타입에서 추론됩니다. 배열의 크기는 요소 수로 결정됩니다.

17.1.2.2. bool
오버로드
@const @must_use fn bool(e : T) -> bool
매개변수화 T스칼라 타입입니다.
설명 bool 값을 생성합니다.

Tbool이면 이는 항등 연산입니다.
그렇지 않으면 불리언 강제 변환입니다. e0 값(부동 소수점 타입의 경우 -0.0)이면 결과는 false이고, 그렇지 않으면 true입니다.

17.1.2.3. f16
오버로드
@const @must_use fn f16(e : T) -> f16
매개변수화 T스칼라 타입입니다
설명 f16 값을 생성합니다.

Tf16이면 이는 항등 연산입니다.
Tf16 이외의 숫자 스칼라이면 ef16으로 변환됩니다(유효하지 않은 변환 포함).
Tbool이면 etrue일 때 결과는 1.0h이고, 그렇지 않으면 0.0h입니다.

17.1.2.4. f32
오버로드
@const @must_use fn f32(e : T) -> f32
매개변수화 T구체 스칼라 타입입니다
설명 f32 값을 생성합니다.

Tf32이면 이는 항등 연산입니다.
Tf32 이외의 숫자 스칼라이면 ef32로 변환됩니다(유효하지 않은 변환 포함).
Tbool이면 etrue일 때 결과는 1.0f이고, 그렇지 않으면 0.0f입니다.

17.1.2.5. i32
오버로드
@const @must_use fn i32(e : T) -> i32
매개변수화 T스칼라 타입입니다
설명 i32 값을 생성합니다.

Ti32이면 이는 항등 연산입니다.
Tu32이면 이는 비트 재해석입니다 (즉, 결과는 e와 같은 비트 패턴을 갖는 i32의 고유한 값입니다).
T부동 소수점 타입이면 e는 0을 향해 반올림하여 i32변환됩니다.
Tbool이면 etrue일 때 결과는 1i이고, 그렇지 않으면 0i입니다.
TAbstractInt이면 ei32로 표현할 수 있을 때는 항등 연산이고, 그렇지 않으면 셰이더 생성 오류를 생성합니다.

17.1.2.6. mat2x2
오버로드
@const @must_use fn mat2x2<T>(e : mat2x2<S>) -> mat2x2<T>
@const @must_use fn mat2x2(e : mat2x2<S>) -> mat2x2<S>
매개변수화 Tf16 또는 f32입니다
SAbstractFloat, f16 또는 f32입니다
설명 2x2 열 우선 행렬의 생성자입니다.

TS와 일치하지 않으면 변환이 발생합니다.

오버로드
@const @must_use fn mat2x2<T>(v1 : vec2<T>, v2 : vec2<T>) -> mat2x2<T>
@const @must_use fn mat2x2(v1 : vec2<T>, v2 : vec2<T>) -> mat2x2<T>
매개변수화 TAbstractFloat, f16 또는 f32입니다
설명 열 벡터로 2x2 열 우선 행렬을 생성합니다.
오버로드
@const @must_use fn mat2x2<T>(e1 : T, e2 : T, e3 : T, e4 : T) -> mat2x2<T>
@const @must_use fn mat2x2(e1 : T, e2 : T, e3 : T, e4 : T) -> mat2x2<T>
매개변수화 TAbstractFloat, f16 또는 f32입니다
설명 요소로 2x2 열 우선 행렬을 생성합니다.

mat2x2(vec2(e1,e2), vec2(e3,e4))와 같습니다.

17.1.2.7. mat2x3
오버로드
@const @must_use fn mat2x3<T>(e : mat2x3<S>) -> mat2x3<T>
@const @must_use fn mat2x3(e : mat2x3<S>) -> mat2x3<S>
매개변수화 Tf16 또는 f32입니다
SAbstractFloat, f16 또는 f32입니다
설명 2x3 열 우선 행렬의 생성자입니다.

TS와 일치하지 않으면 변환이 발생합니다.

오버로드
@const @must_use fn mat2x3<T>(v1 : vec3<T>, v2 : vec3<T>) -> mat2x3<T>
@const @must_use fn mat2x3(v1 : vec3<T>, v2 : vec3<T>) -> mat2x3<T>
매개변수화 TAbstractFloat, f16 또는 f32입니다
설명 열 벡터로 2x3 열 우선 행렬을 생성합니다.
오버로드
@const @must_use fn mat2x3<T>(e1 : T, ..., e6 : T) -> mat2x3<T>
@const @must_use fn mat2x3(e1 : T, ..., e6 : T) -> mat2x3<T>
매개변수화 TAbstractFloat, f16 또는 f32입니다
설명 요소로 2x3 열 우선 행렬을 생성합니다.

mat2x3(vec3(e1,e2,e3), vec3(e4,e5,e6))와 같습니다.

17.1.2.8. mat2x4
오버로드
@const @must_use fn mat2x4<T>(e : mat2x4<S>) -> mat2x4<T>
@const @must_use fn mat2x4(e : mat2x4<S>) -> mat2x4<S>
매개변수화 Tf16 또는 f32입니다
SAbstractFloat, f16 또는 f32입니다
설명 2x4 열 우선 행렬의 생성자입니다.

TS와 일치하지 않으면 변환이 발생합니다.

오버로드
@const @must_use fn mat2x4<T>(v1 : vec4<T>, v2 : vec4<T>) -> mat2x4<T>
@const @must_use fn mat2x4(v1 : vec4<T>, v2 : vec4<T>) -> mat2x4<T>
매개변수화 TAbstractFloat, f16 또는 f32입니다
설명 열 벡터로 2x4 열 우선 행렬을 생성합니다.
오버로드
@const @must_use fn mat2x4<T>(e1 : T, ..., e8 : T) -> mat2x4<T>
@const @must_use fn mat2x4(e1 : T, ..., e8 : T) -> mat2x4<T>
매개변수화 TAbstractFloat, f16 또는 f32입니다
설명 요소로 2x4 열 우선 행렬을 생성합니다.

mat2x4(vec4(e1,e2,e3,e4), vec4(e5,e6,e7,e8))와 같습니다.

17.1.2.9. mat3x2
오버로드
@const @must_use fn mat3x2<T>(e : mat3x2<S>) -> mat3x2<T>
@const @must_use fn mat3x2(e : mat3x2<S>) -> mat3x2<S>
매개변수화 Tf16 또는 f32입니다
SAbstractFloat, f16 또는 f32입니다
설명 3x2 열 우선 행렬의 생성자입니다.

TS와 일치하지 않으면 변환이 발생합니다.

오버로드
@const @must_use fn mat3x2<T>(v1 : vec2<T>,
                              v2 : vec2<T>,
                              v3 : vec2<T>) -> mat3x2<T>
@const @must_use fn mat3x2(v1 : vec2<T>,
                           v2 : vec2<T>,
                           v3 : vec2<T>) -> mat3x2<T>
매개변수화 TAbstractFloat, f16 또는 f32입니다
설명 열 벡터로 3x2 열 우선 행렬을 생성합니다.
오버로드
@const @must_use fn mat3x2<T>(e1 : T, ..., e6 : T) -> mat3x2<T>
@const @must_use fn mat3x2(e1 : T, ..., e6 : T) -> mat3x2<T>
매개변수화 TAbstractFloat, f16 또는 f32입니다
설명 요소로 3x2 열 우선 행렬을 생성합니다.

mat3x2(vec2(e1,e2), vec2(e3,e4), vec2(e5,e6))와 같습니다.

17.1.2.10. mat3x3
오버로드
@const @must_use fn mat3x3<T>(e : mat3x3<S>) -> mat3x3<T>
@const @must_use fn mat3x3(e : mat3x3<S>) -> mat3x3<S>
매개변수화 Tf16 또는 f32입니다
SAbstractFloat, f16 또는 f32입니다
설명 3x3 열 우선 행렬의 생성자입니다.

TS와 일치하지 않으면 변환이 발생합니다.

오버로드
@const @must_use fn mat3x3<T>(v1 : vec3<T>,
                              v2 : vec3<T>,
                              v3 : vec3<T>) -> mat3x3<T>
@const @must_use fn mat3x3(v1 : vec3<T>,
                           v2 : vec3<T>,
                           v3 : vec3<T>) -> mat3x3<T>
매개변수화 TAbstractFloat, f16 또는 f32입니다
설명 열 벡터로 3x3 열 우선 행렬을 생성합니다.
오버로드
@const @must_use fn mat3x3<T>(e1 : T, ..., e9 : T) -> mat3x3<T>
@const @must_use fn mat3x3(e1 : T, ..., e9 : T) -> mat3x3<T>
매개변수화 TAbstractFloat, f16 또는 f32입니다
설명 요소로 3x3 열 우선 행렬을 생성합니다.

mat3x3(vec3(e1,e2,e3), vec3(e4,e5,e6), vec3(e7,e8,e9))와 같습니다.

17.1.2.11. mat3x4
오버로드
@const @must_use fn mat3x4<T>(e : mat3x4<S>) -> mat3x4<T>
@const @must_use fn mat3x4(e : mat3x4<S>) -> mat3x4<S>
매개변수화 Tf16 또는 f32입니다
SAbstractFloat, f16 또는 f32입니다
설명 3x4 열 우선 행렬의 생성자입니다.

TS와 일치하지 않으면 변환이 발생합니다.

오버로드
@const @must_use fn mat3x4<T>(v1 : vec4<T>,
                              v2 : vec4<T>,
                              v3 : vec4<T>) -> mat3x4<T>
@const @must_use fn mat3x4(v1 : vec4<T>,
                           v2 : vec4<T>,
                           v3 : vec4<T>) -> mat3x4<T>
매개변수화 TAbstractFloat, f16 또는 f32입니다
설명 열 벡터로 3x4 열 우선 행렬을 생성합니다.
오버로드
@const @must_use fn mat3x4<T>(e1 : T, ..., e12 : T) -> mat3x4<T>
@const @must_use fn mat3x4(e1 : T, ..., e12 : T) -> mat3x4<T>
매개변수화 TAbstractFloat, f16 또는 f32입니다
설명 요소로 3x4 열 우선 행렬을 생성합니다.

mat3x4(vec4(e1,e2,e3,e4), vec4(e5,e6,e7,e8), vec4(e9,e10,e11,e12))와 같습니다.

17.1.2.12. mat4x2
오버로드
@const @must_use fn mat4x2<T>(e : mat4x2<S>) -> mat4x2<T>
@const @must_use fn mat4x2(e : mat4x2<S>) -> mat4x2<S>
매개변수화 Tf16 또는 f32입니다
SAbstractFloat, f16 또는 f32입니다
설명 4x2 열 우선 행렬의 생성자입니다.

TS와 일치하지 않으면 변환이 발생합니다.

오버로드
@const @must_use fn mat4x2<T>(v1 : vec2<T>,
                              v2 : vec2<T>,
                              v3 : vec2<T>,
                              v4: vec2<T>) -> mat4x2<T>
@const @must_use fn mat4x2(v1 : vec2<T>,
                           v2 : vec2<T>,
                           v3 : vec2<T>,
                           v4: vec2<T>) -> mat4x2<T>
매개변수화 TAbstractFloat, f16 또는 f32입니다
설명 열 벡터로 4x2 열 우선 행렬을 생성합니다.
오버로드
@const @must_use fn mat4x2<T>(e1 : T, ..., e8 : T) -> mat4x2<T>
@const @must_use fn mat4x2(e1 : T, ..., e8 : T) -> mat4x2<T>
매개변수화 TAbstractFloat, f16 또는 f32입니다
설명 요소로 4x2 열 우선 행렬을 생성합니다.

mat4x2(vec2(e1,e2), vec2(e3,e4), vec2(e5,e6), vec2(e7,e8))와 같습니다.

17.1.2.13. mat4x3
오버로드
@const @must_use fn mat4x3<T>(e : mat4x3<S>) -> mat4x3<T>
@const @must_use fn mat4x3(e : mat4x3<S>) -> mat4x3<S>
매개변수화 Tf16 또는 f32입니다
SAbstractFloat, f16 또는 f32입니다
설명 4x3 열 우선 행렬의 생성자입니다.

TS와 일치하지 않으면 변환이 발생합니다.

오버로드
@const @must_use fn mat4x3<T>(v1 : vec3<T>,
                              v2 : vec3<T>,
                              v3 : vec3<T>,
                              v4 : vec3<T>) -> mat4x3<T>
@const @must_use fn mat4x3(v1 : vec3<T>,
                           v2 : vec3<T>,
                           v3 : vec3<T>,
                           v4 : vec3<T>) -> mat4x3<T>
매개변수화 TAbstractFloat, f16 또는 f32입니다
설명 열 벡터로 4x3 열 우선 행렬을 생성합니다.
오버로드
@const @must_use fn mat4x3<T>(e1 : T, ..., e12 : T) -> mat4x3<T>
@const @must_use fn mat4x3(e1 : T, ..., e12 : T) -> mat4x3<T>
매개변수화 TAbstractFloat, f16 또는 f32입니다
설명 요소로 4x3 열 우선 행렬을 생성합니다.

mat4x3(vec3(e1,e2,e3), vec3(e4,e5,e6), vec3(e7,e8,e9), vec3(e10,e11,e12))와 같습니다.

17.1.2.14. mat4x4
오버로드
@const @must_use fn mat4x4<T>(e : mat4x4<S>) -> mat4x4<T>
@const @must_use fn mat4x4(e : mat4x4<S>) -> mat4x4<S>
매개변수화 Tf16 또는 f32입니다
SAbstractFloat, f16 또는 f32입니다
설명 4x4 열 우선 행렬의 생성자입니다.

TS와 일치하지 않으면 변환이 발생합니다.

오버로드
@const @must_use fn mat4x4<T>(v1 : vec4<T>,
                              v2 : vec4<T>,
                              v3 : vec4<T>,
                              v4 : vec4<T>) -> mat4x4<T>
@const @must_use fn mat4x4(v1 : vec4<T>,
                           v2 : vec4<T>,
                           v3 : vec4<T>,
                           v4 : vec4<T>) -> mat4x4<T>
매개변수화 TAbstractFloat, f16 또는 f32입니다
설명 열 벡터로 4x4 열 우선 행렬을 생성합니다.
오버로드
@const @must_use fn mat4x4<T>(e1 : T, ..., e16 : T) -> mat4x4<T>
@const @must_use fn mat4x4(e1 : T, ..., e16 : T) -> mat4x4<T>
매개변수화 TAbstractFloat, f16 또는 f32입니다
설명 요소로 4x4 열 우선 행렬을 생성합니다.

mat4x4(vec4(e1,e2,e3,e4), vec4(e5,e6,e7,e8), vec4(e9,e10,e11,e12), vec4(e13,e14,e15,e16))와 같습니다.

17.1.2.15. 구조체
오버로드
@const @must_use fn S(e1 : T1, ..., eN : TN) -> S
매개변수화 S는 타입이 T1 ... TN인 멤버를 가진 생성 가능 구조체 타입입니다.
설명 멤버로 타입 S구조체를 생성합니다.
17.1.2.16. u32
오버로드
@const @must_use fn u32(e : T) -> u32
매개변수화 T스칼라 타입입니다
설명 u32 값을 생성합니다.

Tu32이면 이는 항등 연산입니다.
Ti32이면 이는 비트 재해석입니다(즉, 결과는 e와 같은 비트 패턴을 갖는 u32의 고유한 값입니다).
T부동 소수점 타입이면 e는 0을 향해 반올림하여 u32변환됩니다.
Tbool이면 etrue일 때 결과는 1u이고, 그렇지 않으면 0u입니다.
TAbstractInt이면 eu32로 표현할 수 있을 때는 항등 연산이고, 그렇지 않으면 셰이더 생성 오류를 생성합니다.

참고: AbstractInt의 오버로드는 u32(4*1000*1000*1000)과 같은 표현식이 그렇지 않으면 i32 타입에서 오버플로되는 u32 값을 생성할 수 있도록 존재합니다. 이 오버로드가 없으면 오버로드 결정u32(i32) 오버로드를 선택하고, AbstractInt 표현식이 자동으로 i32로 변환되며, 이로 인해 오버플로 때문에 셰이더 생성 오류가 발생합니다.

17.1.2.17. vec2
오버로드
@const @must_use fn vec2<T>(e : T) -> vec2<T>
@const @must_use fn vec2(e : S) -> vec2<S>
매개변수화 T구체 스칼라입니다
S스칼라입니다
설명 e를 두 컴포넌트 모두로 사용하는 2컴포넌트 벡터를 생성합니다.
오버로드
@const @must_use fn vec2<T>(e : vec2<S>) -> vec2<T>
@const @must_use fn vec2(e : vec2<S>) -> vec2<S>
매개변수화 T구체 스칼라입니다
S스칼라입니다
설명 e.xe.y를 컴포넌트로 사용하는 2컴포넌트 벡터컴포넌트별로 생성합니다.

TS와 일치하지 않으면 변환이 사용되며 컴포넌트는 T(e.x)T(e.y)입니다.

오버로드
@const @must_use fn vec2<T>(e1 : T, e2 : T) -> vec2<T>
@const @must_use fn vec2(e1 : T, e2 : T) -> vec2<T>
매개변수화 T스칼라입니다
설명 e1e2를 컴포넌트로 사용하는 2컴포넌트 벡터컴포넌트별로 생성합니다.
오버로드
@const @must_use fn vec2() -> vec2<T>
매개변수화 T는 AbstractInt입니다
설명 vec2(0,0) 값을 반환합니다.
17.1.2.18. vec3
오버로드
@const @must_use fn vec3<T>(e : T) -> vec3<T>
@const @must_use fn vec3(e : S) -> vec3<S>
매개변수화 T구체 스칼라입니다
S스칼라입니다
설명 e를 모든 컴포넌트로 사용하는 3컴포넌트 벡터를 생성합니다.
오버로드
@const @must_use fn vec3<T>(e : vec3<S>) -> vec3<T>
@const @must_use fn vec3(e : vec3<S>) -> vec3<S>
매개변수화 T구체 스칼라입니다
S스칼라입니다
설명 e.x, e.y, e.z를 컴포넌트로 사용하는 3컴포넌트 벡터컴포넌트별로 생성합니다.

TS와 일치하지 않으면 변환이 사용되며 컴포넌트는 T(e.x), T(e.y), T(e.z)입니다.

오버로드
@const @must_use fn vec3<T>(e1 : T, e2 : T, e3 : T) -> vec3<T>
@const @must_use fn vec3(e1 : T, e2 : T, e3 : T) -> vec3<T>
매개변수화 T스칼라입니다
설명 e1, e2, e3를 컴포넌트로 사용하는 3컴포넌트 벡터컴포넌트별로 생성합니다.
오버로드
@const @must_use fn vec3<T>(v1 : vec2<T>, e1 : T) -> vec3<T>
@const @must_use fn vec3(v1 : vec2<T>, e1 : T) -> vec3<T>
매개변수화 T스칼라입니다
설명 v1.x, v1.y, e1을 컴포넌트로 사용하는 3컴포넌트 벡터컴포넌트별로 생성합니다.
오버로드
@const @must_use fn vec3<T>(e1 : T, v1 : vec2<T>) -> vec3<T>
@const @must_use fn vec3(e1 : T, v1 : vec2<T>) -> vec3<T>
매개변수화 T스칼라입니다
설명 e1, v1.x, v1.y를 컴포넌트로 사용하는 3컴포넌트 벡터컴포넌트별로 생성합니다.
오버로드
@const @must_use fn vec3() -> vec3<T>
매개변수화 T는 AbstractInt입니다
설명 vec3(0,0,0) 값을 반환합니다.
17.1.2.19. vec4
오버로드
@const @must_use fn vec4<T>(e : T) -> vec4<T>
@const @must_use fn vec4(e : S) -> vec4<S>
매개변수화 T구체 스칼라입니다
S스칼라입니다
설명 e를 모든 컴포넌트로 사용하는 4컴포넌트 벡터를 생성합니다.
오버로드
@const @must_use fn vec4<T>(e : vec4<S>) -> vec4<T>
@const @must_use fn vec4(e : vec4<S>) -> vec4<S>
매개변수화 T구체 스칼라입니다
S스칼라입니다
설명 e.x, e.y, e.z, e.w를 컴포넌트로 사용하는 4컴포넌트 벡터컴포넌트별로 생성합니다.

TS와 일치하지 않으면 변환이 사용되며 컴포넌트는 T(e.x), T(e.y), T(e.z), T(e.w)입니다.

오버로드
@const @must_use fn vec4<T>(e1 : T, e2 : T, e3 : T, e4 : T) -> vec4<T>
@const @must_use fn vec4(e1 : T, e2 : T, e3 : T, e4 : T) -> vec4<T>
매개변수화 T스칼라입니다
설명 e1, e2, e3, e4를 컴포넌트로 사용하는 4컴포넌트 벡터컴포넌트별로 생성합니다.
오버로드
@const @must_use fn vec4<T>(e1 : T, v1 : vec2<T>, e2 : T) -> vec4<T>
@const @must_use fn vec4(e1 : T, v1 : vec2<T>, e2 : T) -> vec4<T>
매개변수화 T스칼라입니다
설명 e1, v1.x, v1.y, e2를 컴포넌트로 사용하는 4컴포넌트 벡터컴포넌트별로 생성합니다.
오버로드
@const @must_use fn vec4<T>(e1 : T, e2 : T, v1 : vec2<T>) -> vec4<T>
@const @must_use fn vec4(e1 : T, e2 : T, v1 : vec2<T>) -> vec4<T>
매개변수화 T스칼라입니다
설명 e1, e2, v1.x, v1.y를 컴포넌트로 사용하는 4컴포넌트 벡터컴포넌트별로 생성합니다.
오버로드
@const @must_use fn vec4<T>(v1 : vec2<T>, v2 : vec2<T>) -> vec4<T>
@const @must_use fn vec4(v1 : vec2<T>, v2 : vec2<T>) -> vec4<T>
매개변수화 T스칼라입니다
설명 v1.x, v1.y, v2.x, v2.y를 컴포넌트로 사용하는 4컴포넌트 벡터컴포넌트별로 생성합니다.
오버로드
@const @must_use fn vec4<T>(v1 : vec2<T>, e1 : T, e2 : T) -> vec4<T>
@const @must_use fn vec4(v1 : vec2<T>, e1 : T, e2 : T) -> vec4<T>
매개변수화 T스칼라입니다
설명 컴포넌트별v1.x, v1.y, e1, e2를 컴포넌트로 사용하는 4컴포넌트 벡터를 생성합니다.
오버로드
@const @must_use fn vec4<T>(v1 : vec3<T>, e1 : T) -> vec4<T>
@const @must_use fn vec4(v1 : vec3<T>, e1 : T) -> vec4<T>
매개변수화 T스칼라입니다
설명 컴포넌트별v1.x, v1.y, v1.z, e1을 컴포넌트로 사용하는 4컴포넌트 벡터를 생성합니다.
오버로드
@const @must_use fn vec4<T>(e1 : T, v1 : vec3<T>) -> vec4<T>
@const @must_use fn vec4(e1 : T, v1 : vec3<T>) -> vec4<T>
매개변수화 T스칼라입니다
설명 컴포넌트별e1, v1.x, v1.y, v1.z를 컴포넌트로 사용하는 4컴포넌트 벡터를 생성합니다.
오버로드
@const @must_use fn vec4() -> vec4<T>
매개변수화 T는 AbstractInt입니다
설명 vec4(0,0,0,0) 값을 반환합니다.

17.2. 비트 재해석 내장 함수

17.2.1. bitcast

bitcast 내장 함수는 한 타입 값의 비트 표현을 다른 타입의 값으로 재해석하는 데 사용됩니다.

내부 레이아웃 규칙은 § 14.4.4 값의 내부 레이아웃에 설명되어 있습니다.

오버로드
@const @must_use fn bitcast<T>(e : T) -> T
매개변수화 T구체 숫자 스칼라 또는 구체 숫자 벡터입니다
설명 항등 변환입니다.
T벡터이면 컴포넌트별입니다.
결과는 e입니다.
오버로드
@const @must_use fn bitcast<T>(e : S) -> T
매개변수화 S는 i32, u32 또는 f32입니다
TS가 아니며 i32, u32 또는 f32입니다
설명 비트를 T로 재해석합니다.
결과는 e의 비트를 T 값으로 재해석한 것입니다.
오버로드
@const @must_use fn bitcast<vecN<T>>(e : vecN<S>) -> vecN<T>
매개변수화 S는 i32, u32 또는 f32입니다
TS가 아니며 i32, u32 또는 f32입니다
설명 비트를 T컴포넌트별 재해석합니다.
결과는 e의 비트를 vecN<T> 값으로 재해석한 것입니다.
오버로드
@const @must_use fn bitcast<u32>(e : AbstractInt) -> u32
@const @must_use fn bitcast<vecN<u32>>(e : vecN<AbstractInt>) -> vecN<u32>
매개변수화
설명 eu32로 표현할 수 있으면 항등 연산이고, 그렇지 않으면 셰이더 생성 오류를 생성합니다. 즉, u32(e)와 같은 결과를 생성합니다.

e가 벡터이면 컴포넌트별입니다.

오버로드
@const @must_use fn bitcast<T>(e : vec2<f16>) -> T
매개변수화 T는 i32, u32 또는 f32입니다
설명 비트를 T컴포넌트별 재해석합니다.
결과는 내부 레이아웃 규칙에 따라 e의 32비트를 T 값으로 재해석한 것입니다.
오버로드
@const @must_use fn bitcast<vec2<T>>(e : vec4<f16>) -> vec2<T>
매개변수화 T는 i32, u32 또는 f32입니다
설명 비트를 T컴포넌트별 재해석합니다.
결과는 내부 레이아웃 규칙에 따라 e의 64비트를 T 값으로 재해석한 것입니다.
오버로드
@const @must_use fn bitcast<vec2<f16>>(e : T) -> vec2<f16>
매개변수화 T는 i32, u32 또는 f32입니다
설명 비트를 f16으로 컴포넌트별 재해석합니다.
결과는 내부 레이아웃 규칙에 따라 e의 32비트를 f16 값으로 재해석한 것입니다.
오버로드
@const @must_use fn bitcast<vec4<f16>>(e : vec2<T>) -> vec4<f16>
매개변수화 T는 i32, u32 또는 f32입니다
설명 비트를 vec2<f16>으로 컴포넌트별 재해석합니다.
결과는 내부 레이아웃 규칙에 따라 e의 64비트를 f16 값으로 재해석한 것입니다.

17.3. 논리 내장 함수

17.3.1. all

오버로드
@const @must_use fn all(e: vecN<bool>) -> bool
설명 e의 각 컴포넌트가 true이면 true를 반환합니다.
오버로드
@const @must_use fn all(e: bool) -> bool
설명 e를 반환합니다.

17.3.2. any

오버로드
@const @must_use fn any(e: vecN<bool>) -> bool
설명 e의 컴포넌트 중 하나라도 true이면 true를 반환합니다.
오버로드
@const @must_use fn any(e: bool) -> bool
설명 e를 반환합니다.

17.3.3. select

오버로드
@const @must_use fn select(f: T,
                           t: T,
                           cond: bool) -> T
매개변수화 T스칼라 또는 벡터입니다
설명 cond가 true이면 t를 반환하고, 그렇지 않으면 f를 반환합니다.
오버로드
@const @must_use fn select(f: vecN<T>,
                           t: vecN<T>,
                           cond: vecN<bool>) -> vecN<T>
매개변수화 T스칼라입니다
설명 컴포넌트별 선택입니다. 결과 컴포넌트 iselect(f[i], t[i], cond[i])로 평가됩니다.

17.4. 배열 내장 함수

17.4.1. arrayLength

오버로드
@must_use fn arrayLength(p: ptr<AS, array<E>, AM>) -> u32
매개변수화 E런타임 크기 배열의 요소 타입입니다.
ASstorage, uniform 또는 workgroup 중 하나입니다.
액세스 모드 AMread 또는 read_write이며 AS에 유효해야 합니다.

참고: pbufferView 또는 bufferArrayView 내장 함수의 결과에서 파생된 경우에만 ASuniform 또는 workgroup일 수 있습니다.

설명 런타임 크기 배열의 요소 수인 NRuntime을 반환합니다.

§ 13.3.4 버퍼 바인딩이 런타임 크기 배열 요소 수를 결정함을 참조하십시오.

pbufferView 또는 bufferArrayView 내장 함수에서 파생된 경우, NRuntime§ 17.14 버퍼 뷰 내장 함수의 분석에서 결정된 버퍼 크기를 기반으로 합니다.

예제: 런타임 크기 배열의 요소 수 가져오기
struct PointLight {
  position : vec3f,
  color : vec3f,
}

struct LightStorage {
  pointCount : u32,
  point : array<PointLight>,
}

@group(0) @binding(1) var<storage> lights : LightStorage;

fn num_point_lights() -> u32 {
  return arrayLength( &lights.point );
}

17.5. 숫자 내장 함수

17.5.1. abs

오버로드
@const @must_use fn abs(e: T ) -> T
매개변수화 S는 AbstractInt, AbstractFloat, i32, u32, f32 또는 f16입니다
T는 S 또는 vecN<S>입니다
설명 e의 절댓값입니다. T가 벡터이면 컴포넌트별입니다.

e가 부동 소수점 타입이면 결과는 양의 부호 비트를 가진 e입니다. e가 부호 없는 정수 스칼라 타입이면 결과는 e입니다. e가 부호 있는 정수 스칼라 타입이고 가장 큰 음수 값으로 평가되면 결과는 e입니다.

17.5.2. acos

오버로드
@const @must_use fn acos(e: T) -> T
매개변수화 S는 AbstractFloat, f32 또는 f16입니다
T는 S 또는 vecN<S>입니다
설명 e의 역코사인(cos-1)의 주값을 라디안 단위로 반환합니다.
즉, cos(x) = e가 되도록 0 ≤ x ≤ π인 x를 근사합니다.

T가 벡터이면 컴포넌트별입니다.

스칼라 정의역 구간 [−1, 1]

17.5.3. acosh

오버로드
@const @must_use fn acosh(x: T) -> T
매개변수화 S는 AbstractFloat, f32 또는 f16입니다
T는 S 또는 vecN<S>입니다
설명 x의 역쌍곡코사인(cosh-1)을 쌍곡각으로 반환합니다.
즉, cosh(a) = x가 되도록 0 ≤ a ≤ +∞인 a를 근사합니다.

T가 벡터이면 컴포넌트별입니다.

스칼라 정의역 구간 [1, +∞]

17.5.4. asin

오버로드
@const @must_use fn asin(e: T) -> T
매개변수화 S는 AbstractFloat, f32 또는 f16입니다
T는 S 또는 vecN<S>입니다
설명 e의 역사인(sin-1)의 주값을 라디안 단위로 반환합니다.
즉, sin(x) = e가 되도록 -π/2 ≤ x ≤ π/2인 x를 근사합니다.

T가 벡터이면 컴포넌트별입니다.

스칼라 정의역 구간 [−1, 1]

17.5.5. asinh

오버로드
@const @must_use fn asinh(y: T) -> T
매개변수화 S는 AbstractFloat, f32 또는 f16입니다
T는 S 또는 vecN<S>입니다
설명 y의 역쌍곡사인(sinh-1)을 쌍곡각으로 반환합니다.
즉, sinh(y) = a가 되는 a를 근사합니다.

T가 벡터이면 컴포넌트별입니다.

17.5.6. atan

오버로드
@const @must_use fn atan(e: T) -> T
매개변수화 S는 AbstractFloat, f32 또는 f16입니다
T는 S 또는 vecN<S>입니다
설명 e의 역탄젠트(tan-1)의 주값을 라디안 단위로 반환합니다.
즉, tan(x) = e가 되도록 − π/2 ≤ x ≤ π/2인 x를 근사합니다.

T가 벡터이면 컴포넌트별입니다.

17.5.7. atanh

오버로드
@const @must_use fn atanh(t: T) -> T
매개변수화 S는 AbstractFloat, f32 또는 f16입니다
T는 S 또는 vecN<S>입니다
설명 t의 역쌍곡탄젠트(tanh-1)를 쌍곡각으로 반환합니다.
즉, tanh(a) = t가 되는 a를 근사합니다.

T가 벡터이면 컴포넌트별입니다.

스칼라 정의역 구간 [−1, 1]

17.5.8. atan2

오버로드
@const @must_use fn atan2(y: T,
                          x: T) -> T
매개변수화 S는 AbstractFloat, f32 또는 f16입니다
T는 S 또는 vecN<S>입니다
설명 탄젠트가 y÷x인 [-π, π] 구간의 을 라디안 단위로 반환합니다.

결과로 선택되는 사분면은 yx의 부호에 따라 달라집니다. 예를 들어 함수는 다음과 같이 구현할 수 있습니다.

  • x > 0일 때 atan(y/x)

  • (x < 0)이고 (y > 0)일 때 atan(y/x) + π

  • (x < 0)이고 (y < 0)일 때 atan(y/x) - π

참고: 다음의 경우 결과의 오차에는 상한이 없습니다.
  • abs(x)가 매우 작은 경우, 예를 들어 해당 타입에서 서브노멀인 경우,

  • 원점 (x,y) = (0,0)인 경우 또는

  • y가 서브노멀이거나 무한대인 경우입니다.

T가 벡터이면 컴포넌트별입니다.

17.5.9. ceil

오버로드
@const @must_use fn ceil(e: T) -> T
매개변수화 S는 AbstractFloat, f32 또는 f16입니다
T는 S 또는 vecN<S>입니다
설명 e올림값을 반환합니다. T가 벡터이면 컴포넌트별입니다.

17.5.10. clamp

오버로드
@const @must_use fn clamp(e: T,
                          low: T,
                          high: T) -> T
매개변수화 S는 AbstractInt, AbstractFloat, i32, u32, f32 또는 f16입니다
T는 S 또는 vecN<S>입니다
설명 e의 값을 범위 내로 제한합니다.

T가 정수 타입이면 결과는 min(max(e, low), high)입니다.

T가 부동 소수점 타입이면 결과는 min(max(e, low), high) 또는 세 값 e, low, high의 중앙값입니다.

T가 벡터이면 컴포넌트별입니다.

lowhigh보다 크면 다음과 같습니다.

17.5.11. cos

오버로드
@const @must_use fn cos(e: T) -> T
매개변수화 S는 AbstractFloat, f32 또는 f16입니다
T는 S 또는 vecN<S>입니다
설명 e가 라디안 단위일 때 e의 코사인을 반환합니다. T가 벡터이면 컴포넌트별입니다.
스칼라 정의역 구간 (−∞, +∞)

17.5.12. cosh

오버로드
@const @must_use fn cosh(a: T) -> T
매개변수화 S는 AbstractFloat, f32 또는 f16입니다
T는 S 또는 vecN<S>입니다
설명 a쌍곡각일 때 a의 쌍곡코사인을 반환합니다. 순수 수학 함수 (ea + e−a)÷2를 근사하지만, 반드시 이 방식으로 계산되는 것은 아닙니다.

T가 벡터이면 컴포넌트별입니다

17.5.13. countLeadingZeros

오버로드
@const @must_use fn countLeadingZeros(e: T) -> T
매개변수화 T는 i32, u32, vecN<i32> 또는 vecN<u32>입니다
설명 T가 스칼라 타입일 때 e의 최상위 비트에서 시작하는 연속된 0비트의 수입니다.
T가 벡터이면 컴포넌트별입니다.
일부 언어에서는 "clz"라고도 합니다.

17.5.14. countOneBits

오버로드
@const @must_use fn countOneBits(e: T) -> T
매개변수화 T는 i32, u32, vecN<i32> 또는 vecN<u32>입니다
설명 e의 표현에 포함된 1비트의 수입니다.
"population count"라고도 합니다.
T가 벡터이면 컴포넌트별입니다.

17.5.15. countTrailingZeros

오버로드
@const @must_use fn countTrailingZeros(e: T) -> T
매개변수화 T는 i32, u32, vecN<i32> 또는 vecN<u32>입니다
설명 T가 스칼라 타입일 때 e의 최하위 비트에서 시작하는 연속된 0비트의 수입니다.
T가 벡터이면 컴포넌트별입니다.
일부 언어에서는 "ctz"라고도 합니다.

17.5.16. cross

오버로드
@const @must_use fn cross(a: vec3<T>,
                          b: vec3<T>) -> vec3<T>
매개변수화 T는 AbstractFloat, f32 또는 f16입니다
설명 e1e2의 외적을 반환합니다.
정의역 가능한 구현으로 주어진 선형 항에서 유도됩니다.
  • a[1] × b[2] − a[2] × b[1]

  • a[2] × b[0] − a[0] × b[2]

  • a[0] × b[1] − a[1] × b[0]

17.5.17. degrees

오버로드
@const @must_use fn degrees(e1: T) -> T
매개변수화 S는 AbstractFloat, f32 또는 f16입니다
T는 S 또는 vecN<S>입니다
설명 e1 × 180 ÷ π를 근사하여 라디안을 도로 변환합니다. T가 벡터이면 컴포넌트별입니다

17.5.18. determinant

오버로드
@const @must_use fn determinant(e: matCxC<T>) -> T
매개변수화 T는 AbstractFloat, f32 또는 f16입니다
설명 e의 행렬식을 반환합니다.
정의역 행렬식의 표준 수학적 정의에 있는 선형 항에서 유도됩니다.

17.5.19. distance

오버로드
@const @must_use fn distance(e1: T,
                             e2: T) -> S
매개변수화 S는 AbstractFloat, f32 또는 f16입니다
T는 S 또는 vecN<S>입니다
설명 e1e2 사이의 거리(예: length(e1 - e2))를 반환합니다.

정의역은 뺄셈 e1e2가 유효한 모든 벡터 (e1,e2)입니다. 즉, 일부 컴포넌트 i에서 e1[i]e2[i]가 같은 무한대 값인 경우를 제외한 모든 벡터의 집합입니다.

17.5.20. dot

오버로드
@const @must_use fn dot(e1: vecN<T>,
                        e2: vecN<T>) -> T
매개변수화 T는 AbstractInt, AbstractFloat, i32, u32, f32 또는 f16입니다
설명 e1e2의 내적을 반환합니다.
정의역 e1[i] × e2[i] 항의 합에 있는 선형 항에서 유도됩니다.

17.5.21. dot4U8Packed

오버로드
@const @must_use fn dot4U8Packed(e1: u32,
                                 e2: u32) -> u32
설명 e1e2는 4개의 8비트 부호 없는 정수 컴포넌트를 가진 벡터로 해석됩니다. 이 두 벡터의 부호 없는 정수 내적을 반환합니다.

17.5.22. dot4I8Packed

오버로드
@const @must_use fn dot4I8Packed(e1: u32,
                                 e2: u32) -> i32
설명 e1e2는 4개의 8비트 부호 있는 정수 컴포넌트를 가진 벡터로 해석됩니다. 이 두 벡터의 부호 있는 정수 내적을 반환합니다. 곱셈을 수행하기 전에 각 컴포넌트를 i32로 부호 확장한 다음 WGSL i32에서 덧셈 연산을 수행합니다(결과가 수학적으로 -65024에서 65536까지의 범위에 있도록 보장되고, 이 범위는 i32로 표현할 수 있는 숫자의 범위 안에 있으므로 덧셈은 오버플로될 수 없습니다).

17.5.23. exp

오버로드
@const @must_use fn exp(e1: T) -> T
매개변수화 S는 AbstractFloat, f32 또는 f16입니다
T는 S 또는 vecN<S>입니다
설명 e1의 자연 지수(예: ee1)를 반환합니다. T가 벡터이면 컴포넌트별입니다.

17.5.24. exp2

오버로드
@const @must_use fn exp2(e: T) -> T
매개변수화 S는 AbstractFloat, f32 또는 f16입니다
T는 S 또는 vecN<S>입니다
설명 2를 e제곱한 값(예: 2e)을 반환합니다. T가 벡터이면 컴포넌트별입니다.

17.5.25. extractBits (부호 있음)

오버로드
@const @must_use fn extractBits(e: T,
                                offset: u32,
                                count: u32) -> T
매개변수화 T는 i32 또는 vecN<i32>입니다
설명 부호 확장을 사용하여 정수에서 비트를 읽습니다.

T가 스칼라 타입이면 다음과 같습니다.

  • wT의 비트 너비입니다
  • o = min(offset, w)
  • c = min(count, w - o)
  • c가 0이면 결과는 0입니다.
  • 그렇지 않으면 결과의 0..c - 1 비트는 eo..o + c - 1 비트에서 복사됩니다. 결과의 다른 비트는 결과의 c - 1 비트와 같습니다.
T가 벡터이면 컴포넌트별입니다.

count + offsetw보다 크면 다음과 같습니다.

17.5.26. extractBits (부호 없음)

오버로드
@const @must_use fn extractBits(e: T,
                                offset: u32,
                                count: u32) -> T
매개변수화 T는 u32 또는 vecN<u32>입니다
설명 부호 확장 없이 정수에서 비트를 읽습니다.

T가 스칼라 타입이면 다음과 같습니다.

  • wT의 비트 너비입니다
  • o = min(offset, w)
  • c = min(count, w - o)
  • c가 0이면 결과는 0입니다.
  • 그렇지 않으면 결과의 0..c - 1 비트는 eo..o + c - 1 비트에서 복사됩니다. 결과의 다른 비트는 0입니다.
T가 벡터이면 컴포넌트별입니다.

count + offsetw보다 크면 다음과 같습니다.

17.5.27. faceForward

오버로드
@const @must_use fn faceForward(e1: T,
                                e2: T,
                                e3: T) -> T
매개변수화 T는 vecN<AbstractFloat>, vecN<f32> 또는 vecN<f16>입니다
설명 dot(e2, e3)가 음수이면 e1을 반환하고, 그렇지 않으면 -e1을 반환합니다.
정의역 정의역 제한은 dot(e2,e3) 연산에서 발생하며, e2[i] × e3[i] 항의 합에 있는 선형 항에서 유도됩니다.

17.5.28. firstLeadingBit (부호 있음)

오버로드
@const @must_use fn firstLeadingBit(e: T) -> T
매개변수화 T는 i32 또는 vecN<i32>입니다
설명 스칼라 T의 결과는 다음과 같습니다.
  • e가 0 또는 -1이면 -1입니다.
  • 그렇지 않으면 e에서 e의 부호 비트와 다른 최상위 비트의 위치입니다.

T가 벡터이면 컴포넌트별입니다.

참고: 부호 있는 정수는 2의 보수 표현을 사용하므로 부호 비트가 최상위 비트 위치에 나타납니다.

17.5.29. firstLeadingBit (부호 없음)

오버로드
@const @must_use fn firstLeadingBit(e: T) -> T
매개변수화 T는 u32 또는 vecN<u32>입니다
설명 스칼라 T의 결과는 다음과 같습니다.
  • e가 0이면 T(-1)입니다.
  • 그렇지 않으면 e에서 최상위 1비트의 위치입니다.
T가 벡터이면 컴포넌트별입니다.

17.5.30. firstTrailingBit

오버로드
@const @must_use fn firstTrailingBit(e: T) -> T
매개변수화 T는 i32, u32, vecN<i32> 또는 vecN<u32>입니다
설명 스칼라 T의 결과는 다음과 같습니다.
  • e가 0이면 T(-1)입니다.
  • 그렇지 않으면 e에서 최하위 1비트의 위치입니다.
T가 벡터이면 컴포넌트별입니다.

17.5.31. floor

오버로드
@const @must_use fn floor(e: T) -> T
매개변수화 S는 AbstractFloat, f32 또는 f16입니다
T는 S 또는 vecN<S>입니다
설명 e내림값을 반환합니다. T가 벡터이면 컴포넌트별입니다.

17.5.32. fma

오버로드
@const @must_use fn fma(e1: T,
                        e2: T,
                        e3: T) -> T
매개변수화 S는 AbstractFloat, f32 또는 f16입니다
T는 S 또는 vecN<S>입니다
설명 e1 * e2 + e3을 반환합니다. T가 벡터이면 컴포넌트별입니다.

참고: fma라는 이름은 "융합 곱셈 덧셈"의 약자입니다.

참고: IEEE-754 fusedMultiplyAdd 연산은 범위와 정밀도가 무제한인 것처럼 중간 결과를 계산하며, 최종 결과만 대상 타입의 값으로 반올림됩니다. 그러나 fma에 대한 § 15.7.4 부동 소수점 정확도 규칙은 대상 타입에 대한 일반적인 곱셈을 수행한 후 일반적인 덧셈을 수행하는 구현을 허용합니다. 이 경우 중간 결과 값이 오버플로되거나 정확도를 잃을 수 있으며, 전체 연산은 전혀 "융합"되지 않습니다.

정의역 e2 × e2 + e3 표현식의 선형 항에서 유도됩니다.

17.5.33. fract

오버로드
@const @must_use fn fract(e: T) -> T
매개변수화 S는 AbstractFloat, f32 또는 f16입니다
T는 S 또는 vecN<S>입니다
설명 e - floor(e)로 계산된 e의 소수 부분을 반환합니다.
T가 벡터이면 컴포넌트별입니다.

참고: 유효한 결과는 닫힌 구간 [0, 1.0]에 있습니다. 예를 들어 e가 매우 작은 음수이면 fract(e)는 1.0일 수 있습니다.

17.5.34. frexp

오버로드
@const @must_use fn frexp(e: T) -> __frexp_result_f32
매개변수화 T는 f32입니다
설명 e를 분수와 지수로 분할합니다.
  • e가 0이면 분수는 0입니다.

  • e가 0이 아니고 정규 값이면 e = fraction * 2exponent이며, 분수는 [0.5, 1.0) 또는 (-1.0, -0.5] 범위에 있습니다.

  • 그렇지 않으면 e서브노멀, NaN 또는 무한대입니다. 결과 분수와 지수는 부정 값입니다.

다음과 같이 정의된 __frexp_result_f32 내장 구조체를 반환합니다.

struct __frexp_result_f32 {
  fract : f32, // 분수 부분
  exp : i32    // 지수 부분
}

참고: frexp라는 이름은 "fraction and exponent"를 기억하기 위한 것입니다.

예제: frexp 사용법
// 결과 타입을 추론합니다
let fraction_and_exponent = frexp(1.5);
// fraction_only를 0.75로 설정합니다
let fraction_only = frexp(1.5).fract;

참고: __frexp_result_f32 타입으로 값을 명시적으로 선언할 수는 없지만, 값이 타입을 추론할 수는 있습니다.

오버로드
@const @must_use fn frexp(e: T) -> __frexp_result_f16
매개변수화 T는 f16입니다
설명 e를 분수와 지수로 분할합니다.
  • e가 0이면 분수는 0입니다.

  • e가 0이 아니고 정규 값이면 e = fraction * 2exponent이며, 분수는 [0.5, 1.0) 또는 (-1.0, -0.5] 범위에 있습니다.

  • 그렇지 않으면 e서브노멀, NaN 또는 무한대입니다. 결과 분수와 지수는 부정 값입니다.

다음과 같이 정의된 것으로 간주되는 __frexp_result_f16 내장 구조체를 반환합니다.

struct __frexp_result_f16 {
  fract : f16, // 분수 부분
  exp : i32    // 지수 부분
}

참고: frexp라는 이름은 "fraction and exponent"를 기억하기 위한 것입니다.

참고: __frexp_result_f16 타입으로 값을 명시적으로 선언할 수는 없지만, 값이 타입을 추론할 수는 있습니다.

오버로드
@const @must_use fn frexp(e: T) -> __frexp_result_abstract
매개변수화 T는 AbstractFloat입니다
설명 e를 분수와 지수로 분할합니다.
  • e가 0이면 분수는 0입니다.

  • e가 0이 아니고 정규 값이면 e = fraction * 2exponent이며, 분수는 [0.5, 1.0) 또는 (-1.0, -0.5] 범위에 있습니다.

  • e서브노멀이면 분수와 지수의 오차에는 상한이 없습니다. 분수는 임의의 AbstractFloat 값일 수 있고, 지수는 임의의 AbstractInt 값일 수 있습니다.

참고: 무한대 또는 NaN이 되는 AbstractFloat 표현식은 셰이더 생성 오류를 발생시킵니다.

다음과 같이 정의된 __frexp_result_abstract 내장 구조체를 반환합니다.

struct __frexp_result_abstract {
  fract : AbstractFloat, // 분수 부분
  exp : AbstractInt      // 지수 부분
}

참고: frexp라는 이름은 "fraction and exponent"를 기억하기 위한 것입니다.

예제: 추상 frexp 사용법
// 결과 타입을 추론합니다
const fraction_and_exponent = frexp(1.5);
// fraction_only를 0.75로 설정합니다
const fraction_only = frexp(1.5).fract;

참고: __frexp_result_abstract 타입으로 값을 명시적으로 선언할 수는 없지만, 값이 타입을 추론할 수는 있습니다.

오버로드
@const @must_use fn frexp(e: T) -> __frexp_result_vecN_f32
매개변수화 T는 vecN<f32>입니다
설명 e의 컴포넌트 ei를 분수와 지수로 분할합니다.
  • ei가 0이면 분수는 0입니다.

  • ei가 0이 아니고 정규 값이면 ei = fraction * 2exponent이며, 분수는 [0.5, 1.0) 또는 (-1.0, -0.5] 범위에 있습니다.

  • 그렇지 않으면 ei는 NaN 또는 무한대입니다. 결과 분수와 지수는 부정 값입니다.

다음과 같이 정의된 __frexp_result_vecN_f32 내장 구조체를 반환합니다.

struct __frexp_result_vecN_f32 {
  fract : vecN<f32>, // 분수 부분
  exp : vecN<i32>    // 지수 부분
}

참고: frexp라는 이름은 "fraction and exponent"를 기억하기 위한 것입니다.

참고: __frexp_result_vecN_f32 타입으로 값을 명시적으로 선언할 수는 없지만, 값이 타입을 추론할 수는 있습니다.

오버로드
@const @must_use fn frexp(e: T) -> __frexp_result_vecN_f16
매개변수화 T는 vecN<f16>입니다
설명 e의 컴포넌트 ei를 분수와 지수로 분할합니다.
  • ei가 0이면 분수는 0입니다.

  • ei가 0이 아니고 정규 값이면 ei = fraction * 2exponent이며, 분수는 [0.5, 1.0) 또는 (-1.0, -0.5] 범위에 있습니다.

  • 그렇지 않으면 ei는 NaN 또는 무한대입니다. 결과 분수와 지수는 부정 값입니다.

다음과 같이 정의된 것으로 간주되는 __frexp_result_vecN_f16 내장 구조체를 반환합니다.

struct __frexp_result_vecN_f16 {
  fract : vecN<f16>, // 분수 부분
  exp : vecN<i32>    // 지수 부분
}

참고: frexp라는 이름은 "fraction and exponent"를 기억하기 위한 것입니다.

참고: __frexp_result_vecN_f16 타입으로 값을 명시적으로 선언할 수는 없지만, 값이 타입을 추론할 수는 있습니다.

오버로드
@const @must_use fn frexp(e: T) -> __frexp_result_vecN_abstract
매개변수화 T는 vecN<AbstractFloat>입니다
설명 e의 컴포넌트 ei를 분수와 지수로 분할합니다.
  • ei가 0이면 분수는 0입니다.

  • ei가 0이 아니고 정규 값이면 ei = fraction * 2exponent이며, 분수는 [0.5, 1.0) 또는 (-1.0, -0.5] 범위에 있습니다.

  • ei서브노멀이면 분수와 지수의 오차에는 상한이 없습니다. 분수는 임의의 AbstractFloat 값일 수 있고, 지수는 임의의 AbstractInt 값일 수 있습니다.

참고: 무한대 또는 NaN이 되는 AbstractFloat 표현식은 셰이더 생성 오류를 발생시킵니다.

다음과 같이 정의된 __frexp_result_vecN_abstract 내장 구조체를 반환합니다.

struct __frexp_result_vecN_abstract {
  fract : vecN<AbstractFloat>, // 분수 부분
  exp : vecN<AbstractInt>      // 지수 부분
}

참고: frexp라는 이름은 "fraction and exponent"를 기억하기 위한 것입니다.

참고: __frexp_result_vecN_abstract 타입으로 값을 명시적으로 선언할 수는 없지만, 값이 타입을 추론할 수는 있습니다.

17.5.35. insertBits

오버로드
@const @must_use fn insertBits(e: T,
                              newbits: T,
                              offset: u32,
                              count: u32) -> T
매개변수화 T는 i32, u32, vecN<i32> 또는 vecN<u32>입니다
설명 정수의 비트를 설정합니다.

T가 스칼라 타입이면 다음과 같습니다.

  • wT의 비트 너비입니다
  • o = min(offset, w)
  • c = min(count, w - o)
  • c가 0이면 결과는 e입니다.
  • 그렇지 않으면 결과의 o..o + c - 1 비트는 newbits0..c - 1 비트에서 복사됩니다. 결과의 다른 비트는 e에서 복사됩니다.
T가 벡터이면 컴포넌트별입니다.

count + offsetw보다 크면 다음과 같습니다.

17.5.36. inverseSqrt

오버로드
@const @must_use fn inverseSqrt(e: T) -> T
매개변수화 S는 AbstractFloat, f32 또는 f16입니다
T는 S 또는 vecN<S>입니다
설명 sqrt(e)의 역수를 반환합니다. T가 벡터이면 컴포넌트별입니다.
스칼라 정의역 구간 [0, +∞]

17.5.37. ldexp

오버로드
@const @must_use fn ldexp(e1: T,
                          e2: I) -> T
매개변수화 S는 AbstractFloat, f32 또는 f16입니다
T는 S 또는 vecN<S>입니다
I는 AbstractInt, i32, vecN<AbstractInt> 또는 vecN<i32>입니다
T가 벡터인 경우에만 I가 벡터입니다
I추상인 경우에만 T추상일 수 있으며 그 반대도 같습니다

참고: 어느 한 매개변수가 구체이면 다른 매개변수는 해당되는 경우 자동 변환을 거쳐 구체 타입이 되고, 결과는 구체 타입이 됩니다.

설명 다음 경우를 제외하고 e1 * 2e2를 반환합니다.

여기서 bias는 부동 소수점 형식의 지수 바이어스입니다.

  • f16의 경우 15

  • f32의 경우 127

  • AbstractFloat가 IEEE-754 binary64인 경우 AbstractFloat는 1023입니다

x가 해당 타입의 0 또는 유한 정규 값이면 다음과 같습니다.

x = ldexp(frexp(x).fract, frexp(x).exp)

T가 벡터이면 컴포넌트별입니다.

참고: ldexp라는 이름은 "지수 로드"를 기억하기 위한 것입니다. 이 이름은 PDP-11 부동 소수점 장치의 해당 명령어에서 가져온 것일 수 있습니다.

17.5.38. length

오버로드
@const @must_use fn length(e: T) -> S
매개변수화 S는 AbstractFloat, f32 또는 f16입니다
T는 S 또는 vecN<S>입니다
설명 e의 길이를 반환합니다.
T스칼라이면 e의 절댓값으로 평가됩니다.
T가 벡터 타입이면 sqrt(e[0]2 + e[1]2 + ...)로 평가됩니다.

참고: 스칼라의 경우 sqrt(e * e)로 평가될 수 있으며, 이로 인해 불필요하게 오버플로되거나 정확도를 잃을 수 있습니다.

17.5.39. log

오버로드
@const @must_use fn log(e: T) -> T
매개변수화 S는 AbstractFloat, f32 또는 f16입니다
T는 S 또는 vecN<S>입니다
설명 e의 자연로그를 반환합니다. T가 벡터이면 컴포넌트별입니다.
스칼라 정의역 구간 [0, +∞]

17.5.40. log2

오버로드
@const @must_use fn log2(e: T) -> T
매개변수화 S는 AbstractFloat, f32 또는 f16입니다
T는 S 또는 vecN<S>입니다
설명 e의 밑이 2인 로그를 반환합니다. T가 벡터이면 컴포넌트별입니다.
스칼라 정의역 구간 [0, +∞]

17.5.41. max

오버로드
@const @must_use fn max(e1: T,
                        e2: T) -> T
매개변수화 S는 AbstractInt, AbstractFloat, i32, u32, f32 또는 f16입니다
T는 S 또는 vecN<S>입니다
설명 e1e2보다 작으면 e2를 반환하고, 그렇지 않으면 e1을 반환합니다. T가 벡터이면 컴포넌트별입니다.

e1e2가 부동 소수점 값이면 다음과 같습니다.

  • e1e2가 모두 서브노멀이면 결과는 두 값 중 어느 것이든 될 수 있습니다.

17.5.42. min

오버로드
@const @must_use fn min(e1: T,
                        e2: T) -> T
매개변수화 S는 AbstractInt, AbstractFloat, i32, u32, f32 또는 f16입니다
T는 S 또는 vecN<S>입니다
설명 e2e1보다 작으면 e2를 반환하고, 그렇지 않으면 e1을 반환합니다. T가 벡터이면 컴포넌트별입니다.

e1e2가 부동 소수점 값이면 다음과 같습니다.

  • e1e2가 모두 서브노멀이면 결과는 두 값 중 어느 것이든 될 수 있습니다.

17.5.43. mix

오버로드
@const @must_use fn mix(e1: T,
                        e2: T,
                        e3: T) -> T
매개변수화 S는 AbstractFloat, f32 또는 f16입니다
T는 S 또는 vecN<S>입니다
설명 e1e2의 선형 혼합(예: e1 * (T(1) - e3) + e2 * e3)을 반환합니다. T가 벡터이면 컴포넌트별입니다.
정의역 다음 표현식의 선형 항에서 유도됩니다. e1[i] × (1 − e3[i]) + e2[i] × e3[i]. e2[i] × e2[i] + e3[i].
오버로드
@const @must_use fn mix(e1: T2,
                        e2: T2,
                        e3: T) -> T2
매개변수화 T는 AbstractFloat, f32 또는 f16입니다
T2는 vecN<T>입니다
설명 각 컴포넌트에 스칼라 혼합 계수 e3을 사용하여 e1e2를 컴포넌트별로 선형 혼합한 값을 반환합니다.
mix(e1, e2, T2(e3))와 같습니다.
정의역 다음 표현식의 선형 항에서 유도됩니다. e1[i] × (1 − e3) + e2[i] × e3.

17.5.44. modf

오버로드
@const @must_use fn modf(e: T) -> __modf_result_f32
매개변수화 T는 f32입니다
설명 e를 소수 부분과 정수 부분으로 분할합니다.

정수 부분은 trunc(e)이고, 소수 부분은 e - trunc(e)입니다.

다음과 같이 정의된 __modf_result_f32 내장 구조체를 반환합니다.

struct __modf_result_f32 {
  fract : f32, // 소수 부분
  whole : f32  // 정수 부분
}
예제: modf 사용법
// 결과 타입을 추론합니다
let fract_and_whole = modf(1.5);
// fract_only를 0.5로 설정합니다
let fract_only = modf(1.5).fract;
// whole_only를 1.0으로 설정합니다
let whole_only = modf(1.5).whole;

참고: __modf_result_f32 타입으로 값을 명시적으로 선언할 수는 없지만, 값이 타입을 추론할 수는 있습니다.

오버로드
@const @must_use fn modf(e: T) -> __modf_result_f16
매개변수화 T는 f16입니다
설명 e를 소수 부분과 정수 부분으로 분할합니다.

정수 부분은 trunc(e)이고, 소수 부분은 e - trunc(e)입니다.

다음과 같이 정의된 것으로 간주되는 __modf_result_f16 내장 구조체를 반환합니다.

struct __modf_result_f16 {
  fract : f16, // 소수 부분
  whole : f16  // 정수 부분
}

참고: __modf_result_f16 타입으로 값을 명시적으로 선언할 수는 없지만, 값이 타입을 추론할 수는 있습니다.

오버로드
@const @must_use fn modf(e: T) -> __modf_result_abstract
매개변수화 T는 AbstractFloat입니다
설명 e를 소수 부분과 정수 부분으로 분할합니다.

정수 부분은 trunc(e)이고, 소수 부분은 e - trunc(e)입니다.

다음과 같이 정의된 __modf_result_abstract 내장 구조체를 반환합니다.

struct __modf_result_abstract {
  fract : AbstractFloat, // 소수 부분
  whole : AbstractFloat  // 정수 부분
}
예제: 추상 modf 사용법
// 결과 타입을 추론합니다
const fract_and_whole = modf(1.5);
// fract_only를 0.5로 설정합니다
const fract_only = modf(1.5).fract;
// whole_only를 1.0으로 설정합니다
const whole_only = modf(1.5).whole;

참고: __modf_result_abstract 타입으로 값을 명시적으로 선언할 수는 없지만, 값이 타입을 추론할 수는 있습니다.

오버로드
@const @must_use fn modf(e: T) -> __modf_result_vecN_f32
매개변수화 T는 vecN<f32>입니다
설명 e의 컴포넌트를 소수 부분과 정수 부분으로 분할합니다.

정수 부분과 소수 부분의 i번째 컴포넌트는 modf(e[i])의 정수 부분 및 소수 부분과 각각 같습니다.

다음과 같이 정의된 __modf_result_vecN_f32 내장 구조체를 반환합니다.

struct __modf_result_vecN_f32 {
  fract : vecN<f32>, // 소수 부분
  whole : vecN<f32>  // 정수 부분
}

참고: __modf_result_vecN_f32 타입으로 값을 명시적으로 선언할 수는 없지만, 값이 타입을 추론할 수는 있습니다.

오버로드
@const @must_use fn modf(e: T) -> __modf_result_vecN_f16
매개변수화 T는 vecN<f16>입니다
설명 e의 컴포넌트를 소수 부분과 정수 부분으로 분할합니다.

정수 부분과 소수 부분의 i번째 컴포넌트는 modf(e[i])의 정수 부분 및 소수 부분과 각각 같습니다.

다음과 같이 정의된 것으로 간주되는 __modf_result_vecN_f16 내장 구조체를 반환합니다.

struct __modf_result_vecN_f16 {
  fract : vecN<f16>, // 소수 부분
  whole : vecN<f16>  // 정수 부분
}

참고: __modf_result_vecN_f16 타입으로 값을 명시적으로 선언할 수는 없지만, 값이 타입을 추론할 수는 있습니다.

오버로드
@const @must_use fn modf(e: T) -> __modf_result_vecN_abstract
매개변수화 T는 vecN<AbstractFloat>입니다
설명 e의 컴포넌트를 소수 부분과 정수 부분으로 분할합니다.

정수 부분과 소수 부분의 i번째 컴포넌트는 modf(e[i])의 정수 부분 및 소수 부분과 각각 같습니다.

다음과 같이 정의된 __modf_result_vecN_abstract 내장 구조체를 반환합니다.

struct __modf_result_vecN_abstract {
  fract : vecN<AbstractFloat>, // 소수 부분
  whole : vecN<AbstractFloat>  // 정수 부분
}

참고: __modf_result_vecN_abstract 타입으로 값을 명시적으로 선언할 수는 없지만, 값이 타입을 추론할 수는 있습니다.

17.5.45. normalize

오버로드
@const @must_use fn normalize(e: vecN<T> ) -> vecN<T>
매개변수화 T는 AbstractFloat, f32 또는 f16입니다
설명 e와 같은 방향의 단위 벡터를 반환합니다.

정의역은 영벡터를 제외한 모든 벡터입니다.

17.5.46. pow

오버로드
@const @must_use fn pow(e1: T,
                        e2: T) -> T
매개변수화 S는 AbstractFloat, f32 또는 f16입니다
T는 S 또는 vecN<S>입니다
설명 e1e2제곱한 값을 반환합니다. T가 벡터이면 컴포넌트별입니다.
스칼라 정의역 다음을 제외한 모든 확장 실수 쌍 (x,y)의 집합입니다.
  • x < 0입니다.

  • x가 1이고 y가 무한대입니다.

  • x가 무한대이고 y가 0입니다.

이 규칙은 결과가 exp2(y * log2(x))로 계산될 수 있다는 사실에서 비롯됩니다.

17.5.47. quantizeToF16

오버로드
@const @must_use fn quantizeToF16(e: T) -> T
매개변수화 T는 f32 또는 vecN<f32>입니다
설명 32비트 부동 소수점 값 eeIEEE-754 binary16 값으로 변환된 다음 다시 IEEE-754 binary32 값으로 변환된 것처럼 양자화합니다.

e가 binary16의 유한 범위 밖에 있으면 다음과 같습니다.

중간 binary16 값은 0으로 플러시될 수 있습니다. 즉, 중간 binary16 값이 서브노멀이면 최종 결과가 0일 수 있습니다.

§ 15.7.6 부동 소수점 변환을 참조하십시오.

T가 벡터이면 컴포넌트별입니다.

참고: vec2<f32>의 경우는 unpack2x16float(pack2x16float(e))와 같습니다.

17.5.48. radians

오버로드
@const @must_use fn radians(e1: T) -> T
매개변수화 S는 AbstractFloat, f32 또는 f16입니다
T는 S 또는 vecN<S>입니다
설명 e1 × π ÷ 180을 근사하여 도를 라디안으로 변환합니다. T가 벡터이면 컴포넌트별입니다

17.5.49. reflect

오버로드
@const @must_use fn reflect(e1: T,
                            e2: T) -> T
매개변수화 T는 vecN<AbstractFloat>, vecN<f32> 또는 vecN<f16>입니다
설명 입사 벡터 e1과 표면 방향 e2에 대해 반사 방향 e1 - 2 * dot(e2, e1) * e2를 반환합니다.

17.5.50. refract

오버로드
@const @must_use fn refract(e1: T,
                            e2: T,
                            e3: I) -> T
매개변수화 T는 vecN<I>입니다
I는 AbstractFloat, f32 또는 f16입니다
설명 입사 벡터 e1, 표면 법선 e2 및 굴절률의 비율 e3에 대해 k = 1.0 - e3 * e3 * (1.0 - dot(e2, e1) * dot(e2, e1))라고 합니다. k < 0.0이면 굴절 벡터 0.0을 반환하고, 그렇지 않으면 굴절 벡터 e3 * e1 - (e3 * dot(e2, e1) + sqrt(k)) * e2를 반환합니다. 스넬의 법칙에 따라 원하는 결과를 얻으려면 입사 벡터 e1과 법선 e2를 정규화해야 합니다. 그렇지 않으면 결과가 예상되는 물리적 동작과 일치하지 않을 수 있습니다.

17.5.51. reverseBits

오버로드
@const @must_use fn reverseBits(e: T) -> T
매개변수화 T는 i32, u32, vecN<i32> 또는 vecN<u32>입니다
설명 e의 비트를 역순으로 바꿉니다. 결과의 k 위치에 있는 비트는 e31 -k 위치에 있는 비트와 같습니다.
T가 벡터이면 컴포넌트별입니다.

17.5.52. round

오버로드
@const @must_use fn round(e: T) -> T
매개변수화 S는 AbstractFloat, f32 또는 f16입니다
T는 S 또는 vecN<S>입니다
설명 결과는 부동 소수점 값으로 나타낸 e에 가장 가까운 정수 k입니다.
e가 정수 kk + 1의 정확히 중간에 있으면 k가 짝수일 때 결과는 k이고, k가 홀수일 때 결과는 k + 1입니다.
T가 벡터이면 컴포넌트별입니다.

17.5.53. saturate

오버로드
@const @must_use fn saturate(e: T) -> T
매개변수화 S는 AbstractFloat, f32 또는 f16입니다
T는 S 또는 vecN<S>입니다
설명 clamp(e, 0.0, 1.0)을 반환합니다. T가 벡터이면 컴포넌트별입니다.

17.5.54. sign

오버로드
@const @must_use fn sign(e: T) -> T
매개변수화 S는 AbstractInt, AbstractFloat, i32, f32 또는 f16입니다
T는 S 또는 vecN<S>입니다
설명 결과는 다음과 같습니다.
  • e > 0일 때 1
  • e = 0일 때 0
  • e < 0일 때 -1

T가 벡터이면 컴포넌트별입니다.

17.5.55. sin

오버로드
@const @must_use fn sin(e: T) -> T
매개변수화 S는 AbstractFloat, f32 또는 f16입니다
T는 S 또는 vecN<S>입니다
설명 e가 라디안 단위일 때 e의 사인을 반환합니다. T가 벡터이면 컴포넌트별입니다.
스칼라 정의역 구간 (−∞, +∞)

17.5.56. sinh

오버로드
@const @must_use fn sinh(a: T) -> T
매개변수화 S는 AbstractFloat, f32 또는 f16입니다
T는 S 또는 vecN<S>입니다
설명 a쌍곡각일 때 a의 쌍곡사인을 반환합니다. 순수 수학 함수 (eae−a)÷2를 근사하지만, 반드시 이 방식으로 계산되는 것은 아닙니다.

T가 벡터이면 컴포넌트별입니다.

17.5.57. smoothstep

오버로드
@const @must_use fn smoothstep(edge0: T,
                               edge1: T,
                               x: T) -> T
매개변수화 S는 AbstractFloat, f32 또는 f16입니다
T는 S 또는 vecN<S>입니다
설명 0과 1 사이의 부드러운 에르미트 보간을 반환합니다. T가 벡터이면 컴포넌트별입니다.

스칼라 T의 결과는 t * t * (3.0 - 2.0 * t)이며,
여기서 t = clamp((x - edge0) / (edge1 - edge0), 0.0, 1.0)입니다.

정성적으로는 다음과 같습니다.

  • edge0 < edge1이면 함수는 edge0보다 작은 x에 대해 0이고, xedge1에 도달할 때까지 부드럽게 상승한 다음 이후에는 1로 유지됩니다.

  • edge0 > edge1이면 함수는 edge1보다 작은 x에 대해 1이고, xedge0에 도달할 때까지 부드럽게 하강한 다음 이후에는 0으로 유지됩니다.

edge0 = edge1이면 다음과 같습니다.

17.5.58. sqrt

오버로드
@const @must_use fn sqrt(e: T) -> T
매개변수화 S는 AbstractFloat, f32 또는 f16입니다
T는 S 또는 vecN<S>입니다
설명 e의 제곱근을 반환합니다. T가 벡터이면 컴포넌트별입니다.
스칼라 정의역 구간 [0, +∞]

17.5.59. step

오버로드
@const @must_use fn step(edge: T,
                         x: T) -> T
매개변수화 S는 AbstractFloat, f32 또는 f16입니다
T는 S 또는 vecN<S>입니다
설명 edgex이면 1.0을 반환하고, 그렇지 않으면 0.0을 반환합니다. T가 벡터이면 컴포넌트별입니다.

17.5.60. tan

오버로드
@const @must_use fn tan(e: T) -> T
매개변수화 S는 AbstractFloat, f32 또는 f16입니다
T는 S 또는 vecN<S>입니다
설명 e가 라디안 단위일 때 e의 탄젠트를 반환합니다. T가 벡터이면 컴포넌트별입니다.
스칼라 정의역 구간 (−∞, +∞)

17.5.61. tanh

오버로드
@const @must_use fn tanh(a: T) -> T
매개변수화 S는 AbstractFloat, f32 또는 f16입니다
T는 S 또는 vecN<S>입니다
설명 a쌍곡각일 때 a의 쌍곡탄젠트를 반환합니다. 순수 수학 함수 (eae−a) ÷ (ea + e−a)를 근사하지만, 반드시 이 방식으로 계산되는 것은 아닙니다.

T가 벡터이면 컴포넌트별입니다.

17.5.62. transpose

오버로드
@const @must_use fn transpose(e: matRxC<T>) -> matCxR<T>
매개변수화 T는 AbstractFloat, f32 또는 f16입니다
설명 e의 전치 행렬을 반환합니다.

17.5.63. trunc

오버로드
@const @must_use fn trunc(e: T) -> T
매개변수화 S는 AbstractFloat, f32 또는 f16입니다
T는 S 또는 vecN<S>입니다
설명 truncate(e), 즉 절댓값이 e의 절댓값보다 작거나 같은 가장 가까운 정수를 반환합니다. T가 벡터이면 컴포넌트별입니다.

17.6. 도함수 내장 함수

§ 15.6.2 도함수를 참조하십시오.

이러한 함수의 호출은 다음과 같습니다.

17.6.1. dpdx

오버로드
@must_use fn dpdx(e: T) -> T
매개변수화 T는 f32 또는 vecN<f32>입니다
설명 창 x 좌표에 대한 e의 편미분입니다. 결과는 dpdxFine(e) 또는 dpdxCoarse(e) 중 하나와 같습니다.

비균일 제어 흐름에서 호출하면 부정 값을 반환합니다.

17.6.2. dpdxCoarse

오버로드
@must_use fn dpdxCoarse(e: T) -> T
매개변수화 T는 f32 또는 vecN<f32>입니다
설명 국소 차이를 사용하여 창 x 좌표에 대한 e의 편미분을 반환합니다. 이로 인해 dpdxFine(e)보다 고유한 위치가 더 적을 수 있습니다.

비균일 제어 흐름에서 호출하면 부정 값을 반환합니다.

17.6.3. dpdxFine

오버로드
@must_use fn dpdxFine(e: T) -> T
매개변수화 T는 f32 또는 vecN<f32>입니다
설명 창 x 좌표에 대한 e의 편미분을 반환합니다.

비균일 제어 흐름에서 호출하면 부정 값을 반환합니다.

17.6.4. dpdy

오버로드
@must_use fn dpdy(e: T) -> T
매개변수화 T는 f32 또는 vecN<f32>입니다
설명 창 y 좌표에 대한 e의 편미분입니다. 결과는 dpdyFine(e) 또는 dpdyCoarse(e) 중 하나와 같습니다.

비균일 제어 흐름에서 호출하면 부정 값을 반환합니다.

17.6.5. dpdyCoarse

오버로드
@must_use fn dpdyCoarse(e: T) -> T
매개변수화 T는 f32 또는 vecN<f32>입니다
설명 국소 차이를 사용하여 창 y 좌표에 대한 e의 편미분을 반환합니다. 이로 인해 dpdyFine(e)보다 고유한 위치가 더 적을 수 있습니다.

비균일 제어 흐름에서 호출하면 부정 값을 반환합니다.

17.6.6. dpdyFine

오버로드
@must_use fn dpdyFine(e: T) -> T
매개변수화 T는 f32 또는 vecN<f32>입니다
설명 창 y 좌표에 대한 e의 편미분을 반환합니다.

비균일 제어 흐름에서 호출하면 부정 값을 반환합니다.

17.6.7. fwidth

오버로드
@must_use fn fwidth(e: T) -> T
매개변수화 T는 f32 또는 vecN<f32>입니다
설명 abs(dpdx(e)) + abs(dpdy(e))를 반환합니다.

비균일 제어 흐름에서 호출하면 부정 값을 반환합니다.

17.6.8. fwidthCoarse

오버로드
@must_use fn fwidthCoarse(e: T) -> T
매개변수화 T는 f32 또는 vecN<f32>입니다
설명 abs(dpdxCoarse(e)) + abs(dpdyCoarse(e))를 반환합니다.

비균일 제어 흐름에서 호출하면 부정 값을 반환합니다.

17.6.9. fwidthFine

오버로드
@must_use fn fwidthFine(e: T) -> T
매개변수화 T는 f32 또는 vecN<f32>입니다
설명 abs(dpdxFine(e)) + abs(dpdyFine(e))를 반환합니다.

비균일 제어 흐름에서 호출하면 부정 값을 반환합니다.

17.7. 텍스처 내장 함수

매개변수 값은 해당 텍스처 타입에 유효해야 합니다.

17.7.1. textureDimensions

텍스처 또는 텍셀 단위 텍스처의 밉 레벨 크기를 반환합니다.

매개변수화 오버로드
STi32, u32 또는 f32입니다
F텍셀 형식입니다
A액세스 모드입니다

Ttexture_1d<ST> 또는 texture_storage_1d<F,A>입니다
@must_use fn textureDimensions(t: T) -> u32
STi32, u32 또는 f32입니다

Ttexture_1d<ST>입니다

Li32 또는 u32입니다

@must_use fn textureDimensions(t: T,
                               level: L) -> u32
STi32, u32 또는 f32입니다
F텍셀 형식입니다
A액세스 모드입니다

Ttexture_2d<ST>, texture_2d_array<ST>, texture_cube<ST>, texture_cube_array<ST>, texture_multisampled_2d<ST>, texture_depth_2d, texture_depth_2d_array, texture_depth_cube, texture_depth_cube_array, texture_depth_multisampled_2d, texture_storage_2d<F,A>, texture_storage_2d_array<F,A> 또는 texture_external입니다
@must_use fn textureDimensions(t: T) -> vec2<u32>
STi32, u32 또는 f32입니다

Ttexture_2d<ST>, texture_2d_array<ST>, texture_cube<ST>, texture_cube_array<ST>, texture_depth_2d, texture_depth_2d_array, texture_depth_cube 또는 texture_depth_cube_array입니다

Li32 또는 u32입니다

@must_use fn textureDimensions(t: T,
                               level: L) -> vec2<u32>
STi32, u32 또는 f32입니다
F텍셀 형식입니다
A액세스 모드입니다

Ttexture_3d<ST> 또는 texture_storage_3d<F,A>입니다
@must_use fn textureDimensions(t: T) -> vec3<u32>
STi32, u32 또는 f32입니다

Ttexture_3d<ST>입니다

Li32 또는 u32입니다

@must_use fn textureDimensions(t: T,
                               level: L) -> vec3<u32>

매개변수:

t 샘플링된, 멀티샘플링된, 깊이, 스토리지 또는 외부 텍스처입니다.
level 밉 레벨이며, 레벨 0은 텍스처의 전체 크기 버전을 포함합니다.
생략하면 레벨 0의 크기를 반환합니다.

반환값:

텍스처의 좌표 크기입니다.

즉, 결과는 밉 레벨 수, 배열 크기샘플 수를 제외한 논리적 텍셀 주소 좌표의 정수 경계를 제공합니다.

큐브 기반 텍스처의 경우 결과는 큐브 각 면의 크기입니다. 큐브 면은 정사각형이므로 결과의 x 및 y 컴포넌트는 같습니다.

level[0, textureNumLevels(t)) 범위 밖에 있으면 반환 타입의 부정 값이 반환될 수 있습니다.

17.7.2. textureGather

텍스처 수집 연산은 2D, 2D 배열, 큐브 또는 큐브 배열 텍스처에서 읽어 다음과 같이 4컴포넌트 벡터를 계산합니다.

4개의 텍셀은 WebGPU 샘플러 설명자에 설명된 샘플링 영역을 형성합니다.

매개변수화 오버로드
Ci32 또는 u32입니다
STi32, u32 또는 f32입니다
@must_use fn textureGather(component: C,
                           t: texture_2d<ST>,
                           s: sampler,
                           coords: vec2<f32>) -> vec4<ST>
Ci32 또는 u32입니다
STi32, u32 또는 f32입니다
@must_use fn textureGather(component: C,
                           t: texture_2d<ST>,
                           s: sampler,
                           coords: vec2<f32>,
                           offset: vec2<i32>) -> vec4<ST>
Ci32 또는 u32입니다
Ai32 또는 u32입니다
STi32, u32 또는 f32입니다
@must_use fn textureGather(component: C,
                           t: texture_2d_array<ST>,
                           s: sampler,
                           coords: vec2<f32>,
                           array_index: A) -> vec4<ST>
Ci32 또는 u32입니다
Ai32 또는 u32입니다
STi32, u32 또는 f32입니다
@must_use fn textureGather(component: C,
                           t: texture_2d_array<ST>,
                           s: sampler,
                           coords: vec2<f32>,
                           array_index: A,
                           offset: vec2<i32>) -> vec4<ST>
Ci32 또는 u32입니다
STi32, u32 또는 f32입니다
@must_use fn textureGather(component: C,
                           t: texture_cube<ST>,
                           s: sampler,
                           coords: vec3<f32>) -> vec4<ST>
Ci32 또는 u32입니다
Ai32 또는 u32입니다
STi32, u32 또는 f32입니다
@must_use fn textureGather(component: C,
                           t: texture_cube_array<ST>,
                           s: sampler,
                           coords: vec3<f32>,
                           array_index: A) -> vec4<ST>
@must_use fn textureGather(t: texture_depth_2d,
                           s: sampler,
                           coords: vec2<f32>) -> vec4<f32>
@must_use fn textureGather(t: texture_depth_2d,
                           s: sampler,
                           coords: vec2<f32>,
                           offset: vec2<i32>) -> vec4<f32>
@must_use fn textureGather(t: texture_depth_cube,
                           s: sampler,
                           coords: vec3<f32>) -> vec4<f32>
Ai32 또는 u32입니다
@must_use fn textureGather(t: texture_depth_2d_array,
                           s: sampler,
                           coords: vec2<f32>,
                           array_index: A) -> vec4<f32>
Ai32 또는 u32입니다
@must_use fn textureGather(t: texture_depth_2d_array,
                           s: sampler,
                           coords: vec2<f32>,
                           array_index: A,
                           offset: vec2<i32>) -> vec4<f32>
Ai32 또는 u32입니다
@must_use fn textureGather(t: texture_depth_cube_array,
                           s: sampler,
                           coords: vec3<f32>,
                           array_index: A) -> vec4<f32>

매개변수:

component 깊이 텍스처가 아닌 경우에만 적용됩니다.
선택한 텍셀에서 읽을 채널의 인덱스입니다.
제공된 경우 component 표현식은 상수 표현식 (예: 1)이어야 합니다.
값은 0 이상 3 이하여야 합니다. 이 범위를 벗어난 값은 셰이더 생성 오류를 발생시킵니다.
t 읽을 샘플링된 또는 깊이 텍스처입니다.
s 샘플러 타입입니다.
coords 텍스처 좌표입니다.
array_index 0 기반 텍스처 배열 인덱스입니다.
이 값은 [0, textureNumLayers(t) - 1] 범위로 제한됩니다.
offset 텍스처를 샘플링하기 전에 정규화되지 않은 텍스처 좌표에 적용되는 선택적 텍셀 오프셋입니다. 이 오프셋은 모든 텍스처 래핑 모드를 적용하기 전에 적용됩니다.
offset 표현식은 상수 표현식(예: vec2<i32>(1, 2))이어야 합니다.
offset 컴포넌트는 -8 이상 7 이하여야 합니다. 이 범위를 벗어난 값은 셰이더 생성 오류를 발생시킵니다.

반환값:

위에서 설명한 대로 선택한 텍셀의 지정된 채널에서 추출한 컴포넌트를 가진 4컴포넌트 벡터입니다.

예제: 2D 텍스처의 텍셀에서 컴포넌트 수집
@group(0) @binding(0) var t: texture_2d<f32>;
@group(0) @binding(1) var dt: texture_depth_2d;
@group(0) @binding(2) var s: sampler;

fn gather_x_components(c: vec2<f32>) -> vec4<f32> {
  return textureGather(0,t,s,c);
}
fn gather_y_components(c: vec2<f32>) -> vec4<f32> {
  return textureGather(1,t,s,c);
}
fn gather_z_components(c: vec2<f32>) -> vec4<f32> {
  return textureGather(2,t,s,c);
}
fn gather_depth_components(c: vec2<f32>) -> vec4<f32> {
  return textureGather(dt,s,c);
}

17.7.3. textureGatherCompare

텍스처 수집 비교 연산은 깊이 텍스처의 4개 텍셀에 대해 깊이 비교를 수행하고 다음과 같이 결과를 단일 벡터로 수집합니다.

매개변수화 오버로드
@must_use fn textureGatherCompare(t: texture_depth_2d,
                                  s: sampler_comparison,
                                  coords: vec2<f32>,
                                  depth_ref: f32) -> vec4<f32>
@must_use fn textureGatherCompare(t: texture_depth_2d,
                                  s: sampler_comparison,
                                  coords: vec2<f32>,
                                  depth_ref: f32,
                                  offset: vec2<i32>) -> vec4<f32>
Ai32 또는 u32입니다
@must_use fn textureGatherCompare(t: texture_depth_2d_array,
                                  s: sampler_comparison,
                                  coords: vec2<f32>,
                                  array_index: A,
                                  depth_ref: f32) -> vec4<f32>
Ai32 또는 u32입니다
@must_use fn textureGatherCompare(t: texture_depth_2d_array,
                                  s: sampler_comparison,
                                  coords: vec2<f32>,
                                  array_index: A,
                                  depth_ref: f32,
                                  offset: vec2<i32>) -> vec4<f32>
@must_use fn textureGatherCompare(t: texture_depth_cube,
                                  s: sampler_comparison,
                                  coords: vec3<f32>,
                                  depth_ref: f32) -> vec4<f32>
Ai32 또는 u32입니다
@must_use fn textureGatherCompare(t: texture_depth_cube_array,
                                  s: sampler_comparison,
                                  coords: vec3<f32>,
                                  array_index: A,
                                  depth_ref: f32) -> vec4<f32>

매개변수:

t 읽을 깊이 텍스처입니다.
s 비교 샘플러입니다.
coords 텍스처 좌표입니다.
array_index 0 기반 텍스처 배열 인덱스입니다.
이 값은 [0, textureNumLayers(t) - 1] 범위로 제한됩니다.
depth_ref 샘플링된 깊이 값과 비교할 참조 값입니다.
offset 텍스처를 샘플링하기 전에 정규화되지 않은 텍스처 좌표에 적용되는 선택적 텍셀 오프셋입니다. 이 오프셋은 모든 텍스처 래핑 모드를 적용하기 전에 적용됩니다.
offset 표현식은 상수 표현식(예: vec2<i32>(1, 2))이어야 합니다.
offset 컴포넌트는 -8 이상 7 이하여야 합니다. 이 범위를 벗어난 값은 셰이더 생성 오류를 발생시킵니다.

반환값:

위에서 설명한 대로 선택한 텍셀의 비교 결과를 가진 4컴포넌트 벡터입니다.

예제: 깊이 비교 수집
@group(0) @binding(0) var dt: texture_depth_2d;
@group(0) @binding(1) var s: sampler;

fn gather_depth_compare(c: vec2<f32>, depth_ref: f32) -> vec4<f32> {
  return textureGatherCompare(dt,s,c,depth_ref);
}

17.7.4. textureLoad

샘플링이나 필터링 없이 텍스처에서 단일 텍셀을 읽습니다.

매개변수화 오버로드
Ci32 또는 u32입니다
Li32 또는 u32입니다
STi32, u32 또는 f32입니다
@must_use fn textureLoad(t: texture_1d<ST>,
                         coords: C,
                         level: L) -> vec4<ST>
Ci32 또는 u32입니다
Li32 또는 u32입니다
STi32, u32 또는 f32입니다
@must_use fn textureLoad(t: texture_2d<ST>,
                         coords: vec2<C>,
                         level: L) -> vec4<ST>
Ci32 또는 u32입니다
Ai32 또는 u32입니다
Li32 또는 u32입니다
STi32, u32 또는 f32입니다
@must_use fn textureLoad(t: texture_2d_array<ST>,
                        coords: vec2<C>,
                        array_index: A,
                        level: L) -> vec4<ST>
Ci32 또는 u32입니다
Li32 또는 u32입니다
STi32, u32 또는 f32입니다
@must_use fn textureLoad(t: texture_3d<ST>,
                         coords: vec3<C>,
                         level: L) -> vec4<ST>
Ci32 또는 u32입니다
Si32 또는 u32입니다
STi32, u32 또는 f32입니다
@must_use fn textureLoad(t: texture_multisampled_2d<ST>,
                         coords: vec2<C>,
                         sample_index: S)-> vec4<ST>
Ci32 또는 u32입니다
Li32 또는 u32입니다
@must_use fn textureLoad(t: texture_depth_2d,
                         coords: vec2<C>,
                         level: L) -> f32
Ci32 또는 u32입니다
Ai32 또는 u32입니다
Li32 또는 u32입니다
@must_use fn textureLoad(t: texture_depth_2d_array,
                         coords: vec2<C>,
                         array_index: A,
                         level: L) -> f32
Ci32 또는 u32입니다
Si32 또는 u32입니다
@must_use fn textureLoad(t: texture_depth_multisampled_2d,
                         coords: vec2<C>,
                         sample_index: S)-> f32
Ci32 또는 u32입니다
@must_use fn textureLoad(t: texture_external,
                         coords: vec2<C>) -> vec4<f32>
Ci32 또는 u32입니다
AMread 또는 read_write입니다
CF는 스토리지 텍셀 형식 F에 따라 달라집니다. 텍셀 형식과 채널 형식의 매핑은 텍셀 형식 표를 참조하십시오.
@must_use fn textureLoad(t : texture_storage_1d<F, AM>,
                         coords : C) -> vec4<CF>
Ci32 또는 u32입니다
AMread 또는 read_write입니다
CF는 스토리지 텍셀 형식 F에 따라 달라집니다. 텍셀 형식과 채널 형식의 매핑은 텍셀 형식 표를 참조하십시오.
@must_use fn textureLoad(t : texture_storage_2d<F, AM>,
                         coords : vec2<C>) -> vec4<CF>
Ci32 또는 u32입니다
AMread 또는 read_write입니다
Ai32 또는 u32입니다
CF는 스토리지 텍셀 형식 F에 따라 달라집니다. 텍셀 형식과 채널 형식의 매핑은 텍셀 형식 표를 참조하십시오.
@must_use fn textureLoad(t : texture_storage_2d_array<F, AM>,
                         coords : vec2<C>,
                         array_index : A) -> vec4<CF>
Ci32 또는 u32입니다
AMread 또는 read_write입니다
CF는 스토리지 텍셀 형식 F에 따라 달라집니다. 텍셀 형식과 채널 형식의 매핑은 텍셀 형식 표를 참조하십시오.
@must_use fn textureLoad(t : texture_storage_3d<F, AM>,
                         coords : vec3<C>) -> vec4<CF>

매개변수:

t 샘플링된, 멀티샘플링된, 깊이, 스토리지 또는 외부 텍스처입니다
coords 0 기반 텍셀 좌표입니다.
array_index 0 기반 텍스처 배열 인덱스입니다.
level 밉 레벨이며, 레벨 0은 텍스처의 전체 크기 버전을 포함합니다.
sample_index 멀티샘플링된 텍스처의 0 기반 샘플 인덱스입니다.

반환값:

필터링되지 않은 텍셀 데이터입니다.

다음의 경우 논리적 텍셀 주소가 유효하지 않습니다.

논리적 텍셀 주소가 유효하지 않으면 내장 함수는 다음 중 하나를 반환합니다.

17.7.5. textureNumLayers

배열 텍스처의 레이어(요소) 수를 반환합니다.

매개변수화 오버로드
F텍셀 형식입니다
A액세스 모드입니다
STi32, u32 또는 f32입니다

Ttexture_2d_array<ST>, texture_cube_array<ST>, texture_depth_2d_array, texture_depth_cube_array 또는 texture_storage_2d_array<F,A>입니다
@must_use fn textureNumLayers(t: T) -> u32

매개변수:

t 샘플링된, 깊이 또는 스토리지 텍스처 배열 텍스처입니다.

반환값:

텍스처가 큐브 기반이면 큐브 배열 텍스처의 큐브 수를 반환합니다.

그렇지 않으면 배열 텍스처의 레이어(동질적인 텍셀 격자) 수를 반환합니다.

17.7.6. textureNumLevels

텍스처의 밉 레벨 수를 반환합니다.

매개변수화 오버로드
STi32, u32 또는 f32입니다

Ttexture_1d<ST>, texture_2d<ST>, texture_2d_array<ST>, texture_3d<ST>, texture_cube<ST>, texture_cube_array<ST>, texture_depth_2d, texture_depth_2d_array, texture_depth_cube 또는 texture_depth_cube_array입니다
@must_use fn textureNumLevels(t: T) -> u32

매개변수:

t 샘플링된 또는 깊이 텍스처입니다.

반환값:

텍스처의 밉 레벨 수입니다.

17.7.7. textureNumSamples

멀티샘플링된 텍스처에서 텍셀당 샘플 수를 반환합니다.

매개변수화 오버로드
STi32, u32 또는 f32입니다

Ttexture_multisampled_2d<ST> 또는 texture_depth_multisampled_2d입니다
@must_use fn textureNumSamples(t: T) -> u32

매개변수:

t 멀티샘플링된 텍스처입니다.

반환값:

멀티샘플링된 텍스처샘플 수입니다.

17.7.8. textureSample

텍스처를 샘플링합니다.

프래그먼트 셰이더 단계에서만 사용해야 합니다.

균일성 분석이 이 함수의 호출이 균일 제어 흐름에 있음을 증명할 수 없으면 derivative_uniformity 진단트리거됩니다.

매개변수화 오버로드
@must_use fn textureSample(t: texture_1d<f32>,
                           s: sampler,
                           coords: f32) -> vec4<f32>
@must_use fn textureSample(t: texture_2d<f32>,
                           s: sampler,
                           coords: vec2<f32>) -> vec4<f32>
@must_use fn textureSample(t: texture_2d<f32>,
                           s: sampler,
                           coords: vec2<f32>,
                           offset: vec2<i32>) -> vec4<f32>
Ai32 또는 u32입니다
@must_use fn textureSample(t: texture_2d_array<f32>,
                           s: sampler,
                           coords: vec2<f32>,
                           array_index: A) -> vec4<f32>
Ai32 또는 u32입니다
@must_use fn textureSample(t: texture_2d_array<f32>,
                           s: sampler,
                           coords: vec2<f32>,
                           array_index: A,
                           offset: vec2<i32>) -> vec4<f32>
Ttexture_3d<f32> 또는 texture_cube<f32>입니다
@must_use fn textureSample(t: T,
                           s: sampler,
                           coords: vec3<f32>) -> vec4<f32>
@must_use fn textureSample(t: texture_3d<f32>,
                           s: sampler,
                           coords: vec3<f32>,
                           offset: vec3<i32>) -> vec4<f32>
Ai32 또는 u32입니다
@must_use fn textureSample(t: texture_cube_array<f32>,
                           s: sampler,
                           coords: vec3<f32>,
                           array_index: A) -> vec4<f32>
@must_use fn textureSample(t: texture_depth_2d,
                           s: sampler,
                           coords: vec2<f32>) -> f32
@must_use fn textureSample(t: texture_depth_2d,
                           s: sampler,
                           coords: vec2<f32>,
                           offset: vec2<i32>) -> f32
Ai32 또는 u32입니다
@must_use fn textureSample(t: texture_depth_2d_array,
                           s: sampler,
                           coords: vec2<f32>,
                           array_index: A) -> f32
Ai32 또는 u32입니다
@must_use fn textureSample(t: texture_depth_2d_array,
                           s: sampler,
                           coords: vec2<f32>,
                           array_index: A,
                           offset: vec2<i32>) -> f32
@must_use fn textureSample(t: texture_depth_cube,
                           s: sampler,
                           coords: vec3<f32>) -> f32
Ai32 또는 u32입니다
@must_use fn textureSample(t: texture_depth_cube_array,
                           s: sampler,
                           coords: vec3<f32>,
                           array_index: A) -> f32

매개변수:

t 샘플링할 샘플링된 또는 깊이 텍스처입니다.
s 샘플러 타입입니다.
coords 샘플링에 사용되는 텍스처 좌표입니다.
array_index 샘플링할 0 기반 텍스처 배열 인덱스입니다.
이 값은 [0, textureNumLayers(t) - 1] 범위로 제한됩니다.
offset 텍스처를 샘플링하기 전에 정규화되지 않은 텍스처 좌표에 적용되는 선택적 텍셀 오프셋입니다. 이 오프셋은 모든 텍스처 래핑 모드를 적용하기 전에 적용됩니다.
offset 표현식은 상수 표현식(예: vec2<i32>(1, 2))이어야 합니다.
offset 컴포넌트는 -8 이상 7 이하여야 합니다. 이 범위를 벗어난 값은 셰이더 생성 오류를 발생시킵니다.

반환값:

샘플링된 값입니다.

비균일 제어 흐름에서 호출하면 부정 값이 됩니다.

17.7.9. textureSampleBias

밉 레벨에 바이어스를 적용하여 텍스처를 샘플링합니다.

반드시 프래그먼트 셰이더 스테이지에서만 사용해야 합니다.

균일성 분석에서 이 함수 호출이 균일 제어 흐름에 있음을 증명할 수 없으면, derivative_uniformity 진단트리거됩니다.

매개변수화 오버로드
@must_use fn textureSampleBias(t: texture_2d<f32>,
                               s: sampler,
                               coords: vec2<f32>,
                               bias: f32) -> vec4<f32>
@must_use fn textureSampleBias(t: texture_2d<f32>,
                               s: sampler,
                               coords: vec2<f32>,
                               bias: f32,
                               offset: vec2<i32>) -> vec4<f32>
Ai32 또는 u32입니다
@must_use fn textureSampleBias(t: texture_2d_array<f32>,
                               s: sampler,
                               coords: vec2<f32>,
                               array_index: A,
                               bias: f32) -> vec4<f32>
Ai32 또는 u32입니다
@must_use fn textureSampleBias(t: texture_2d_array<f32>,
                               s: sampler,
                               coords: vec2<f32>,
                               array_index: A,
                               bias: f32,
                               offset: vec2<i32>) -> vec4<f32>
Ttexture_3d<f32> 또는 texture_cube<f32>입니다
@must_use fn textureSampleBias(t: T,
                               s: sampler,
                               coords: vec3<f32>,
                               bias: f32) -> vec4<f32>
@must_use fn textureSampleBias(t: texture_3d<f32>,
                               s: sampler,
                               coords: vec3<f32>,
                               bias: f32,
                               offset: vec3<i32>) -> vec4<f32>
Ai32 또는 u32입니다
@must_use fn textureSampleBias(t: texture_cube_array<f32>,
                               s: sampler,
                               coords: vec3<f32>,
                               array_index: A,
                               bias: f32) -> vec4<f32>

매개변수:

t 샘플링할 샘플링된 텍스처입니다.
s 샘플러 타입입니다.
coords 샘플링에 사용되는 텍스처 좌표입니다.
array_index 샘플링할 0 기반 텍스처 배열 인덱스입니다.
이 값은 [0, textureNumLayers(t) - 1] 범위로 제한됩니다.
bias 샘플링 전에 밉 레벨에 적용할 바이어스입니다.
이 값은 [-16.0, 15.99] 범위로 제한됩니다.
offset 텍스처를 샘플링하기 전에 정규화되지 않은 텍스처 좌표에 적용되는 선택적 텍셀 오프셋입니다. 이 오프셋은 모든 텍스처 래핑 모드를 적용하기 전에 적용됩니다.
offset 표현식은 반드시 상수 표현식이어야 합니다(예: vec2<i32>(1, 2)).
offset 컴포넌트는 반드시 -8 이상이고 7 이하여야 합니다. 이 범위를 벗어난 값은 셰이더 생성 오류를 발생시킵니다.

반환:

샘플링된 값입니다.

17.7.10. textureSampleCompare

깊이 텍스처를 샘플링하고 샘플링된 깊이 값을 참조 값과 비교합니다.

반드시 프래그먼트 셰이더 스테이지에서만 사용해야 합니다.

균일성 분석에서 이 함수 호출이 균일 제어 흐름에 있음을 증명할 수 없으면, derivative_uniformity 진단트리거됩니다.

매개변수화 오버로드
@must_use fn textureSampleCompare(t: texture_depth_2d,
                                  s: sampler_comparison,
                                  coords: vec2<f32>,
                                  depth_ref: f32) -> f32
@must_use fn textureSampleCompare(t: texture_depth_2d,
                                  s: sampler_comparison,
                                  coords: vec2<f32>,
                                  depth_ref: f32,
                                  offset: vec2<i32>) -> f32
Ai32 또는 u32입니다
@must_use fn textureSampleCompare(t: texture_depth_2d_array,
                                  s: sampler_comparison,
                                  coords: vec2<f32>,
                                  array_index: A,
                                  depth_ref: f32) -> f32
Ai32 또는 u32입니다
@must_use fn textureSampleCompare(t: texture_depth_2d_array,
                                  s: sampler_comparison,
                                  coords: vec2<f32>,
                                  array_index: A,
                                  depth_ref: f32,
                                  offset: vec2<i32>) -> f32
@must_use fn textureSampleCompare(t: texture_depth_cube,
                                  s: sampler_comparison,
                                  coords: vec3<f32>,
                                  depth_ref: f32) -> f32
Ai32 또는 u32입니다
@must_use fn textureSampleCompare(t: texture_depth_cube_array,
                                  s: sampler_comparison,
                                  coords: vec3<f32>,
                                  array_index: A,
                                  depth_ref: f32) -> f32

매개변수:

t 샘플링할 깊이 텍스처입니다.
s sampler_comparison 타입입니다.
coords 샘플링에 사용되는 텍스처 좌표입니다.
array_index 샘플링할 0 기반 텍스처 배열 인덱스입니다.
이 값은 [0, textureNumLayers(t) - 1] 범위로 제한됩니다.
depth_ref 샘플링된 깊이 값과 비교할 참조 값입니다.
offset 텍스처를 샘플링하기 전에 정규화되지 않은 텍스처 좌표에 적용되는 선택적 텍셀 오프셋입니다. 이 오프셋은 모든 텍스처 래핑 모드를 적용하기 전에 적용됩니다.
offset 표현식은 반드시 상수 표현식이어야 합니다(예: vec2<i32>(1, 2)).
offset 컴포넌트는 반드시 -8 이상이고 7 이하여야 합니다. 이 범위를 벗어난 값은 셰이더 생성 오류를 발생시킵니다.

반환:

[0.0..1.0] 범위의 값입니다.

샘플링된 각 텍셀은 sampler_comparison에 정의된 비교 연산자를 사용하여 참조 값과 비교되며, 그 결과 각 텍셀에 대해 0 또는 1 값이 생성됩니다.

샘플러가 이중 선형 필터링을 사용하는 경우 반환 값은 이러한 값의 필터링된 평균이고, 그렇지 않으면 단일 텍셀의 비교 결과가 반환됩니다.

비균일 제어 흐름에서 호출하면 부정 값이 됩니다.

17.7.11. textureSampleCompareLevel

깊이 텍스처를 샘플링하고 샘플링된 깊이 값을 참조 값과 비교합니다.

매개변수화 오버로드
@must_use fn textureSampleCompareLevel(t: texture_depth_2d,
                                       s: sampler_comparison,
                                       coords: vec2<f32>,
                                       depth_ref: f32) -> f32
@must_use fn textureSampleCompareLevel(t: texture_depth_2d,
                                       s: sampler_comparison,
                                       coords: vec2<f32>,
                                       depth_ref: f32,
                                       offset: vec2<i32>) -> f32
Ai32 또는 u32입니다
@must_use fn textureSampleCompareLevel(t: texture_depth_2d_array,
                                       s: sampler_comparison,
                                       coords: vec2<f32>,
                                       array_index: A,
                                       depth_ref: f32) -> f32
Ai32 또는 u32입니다
@must_use fn textureSampleCompareLevel(t: texture_depth_2d_array,
                                       s: sampler_comparison,
                                       coords: vec2<f32>,
                                       array_index: A,
                                       depth_ref: f32,
                                       offset: vec2<i32>) -> f32
@must_use fn textureSampleCompareLevel(t: texture_depth_cube,
                                       s: sampler_comparison,
                                       coords: vec3<f32>,
                                       depth_ref: f32) -> f32
Ai32 또는 u32입니다
@must_use fn textureSampleCompareLevel(t: texture_depth_cube_array,
                                       s: sampler_comparison,
                                       coords: vec3<f32>,
                                       array_index: A,
                                       depth_ref: f32) -> f32

매개변수:

t 샘플링할 깊이 텍스처입니다.
s sampler_comparison 타입입니다.
coords 샘플링에 사용되는 텍스처 좌표입니다.
array_index 샘플링할 0 기반 텍스처 배열 인덱스입니다.
이 값은 [0, textureNumLayers(t) - 1] 범위로 제한됩니다.
depth_ref 샘플링된 깊이 값과 비교할 참조 값입니다.
offset 텍스처를 샘플링하기 전에 정규화되지 않은 텍스처 좌표에 적용되는 선택적 텍셀 오프셋입니다. 이 오프셋은 모든 텍스처 래핑 모드를 적용하기 전에 적용됩니다.
offset 표현식은 반드시 상수 표현식이어야 합니다(예: vec2<i32>(1, 2)).
offset 컴포넌트는 반드시 -8 이상이고 7 이하여야 합니다. 이 범위를 벗어난 값은 셰이더 생성 오류를 발생시킵니다.

반환:

[0.0..1.0] 범위의 값입니다.

textureSampleCompareLevel 함수는 다음 사항을 제외하면 textureSampleCompare와 같습니다.

17.7.12. textureSampleGrad

명시적 그래디언트를 사용하여 텍스처를 샘플링합니다.

매개변수화 오버로드
@must_use fn textureSampleGrad(t: texture_2d<f32>,
                               s: sampler,
                               coords: vec2<f32>,
                               ddx: vec2<f32>,
                               ddy: vec2<f32>) -> vec4<f32>
@must_use fn textureSampleGrad(t: texture_2d<f32>,
                               s: sampler,
                               coords: vec2<f32>,
                               ddx: vec2<f32>,
                               ddy: vec2<f32>,
                               offset: vec2<i32>) -> vec4<f32>
Ai32 또는 u32입니다
@must_use fn textureSampleGrad(t: texture_2d_array<f32>,
                               s: sampler,
                               coords: vec2<f32>,
                               array_index: A,
                               ddx: vec2<f32>,
                               ddy: vec2<f32>) -> vec4<f32>
Ai32 또는 u32입니다
@must_use fn textureSampleGrad(t: texture_2d_array<f32>,
                               s: sampler,
                               coords: vec2<f32>,
                               array_index: A,
                               ddx: vec2<f32>,
                               ddy: vec2<f32>,
                               offset: vec2<i32>) -> vec4<f32>
Ttexture_3d<f32> 또는 texture_cube<f32>입니다
@must_use fn textureSampleGrad(t: T,
                               s: sampler,
                               coords: vec3<f32>,
                               ddx: vec3<f32>,
                               ddy: vec3<f32>) -> vec4<f32>
@must_use fn textureSampleGrad(t: texture_3d<f32>,
                               s: sampler,
                               coords: vec3<f32>,
                               ddx: vec3<f32>,
                               ddy: vec3<f32>,
                               offset: vec3<i32>) -> vec4<f32>
Ai32 또는 u32입니다
@must_use fn textureSampleGrad(t: texture_cube_array<f32>,
                               s: sampler,
                               coords: vec3<f32>,
                               array_index: A,
                               ddx: vec3<f32>,
                               ddy: vec3<f32>) -> vec4<f32>

매개변수:

t 샘플링할 샘플링된 텍스처입니다.
s 샘플러입니다.
coords 샘플링에 사용되는 텍스처 좌표입니다.
array_index 샘플링할 0 기반 텍스처 배열 인덱스입니다.
이 값은 [0, textureNumLayers(t) - 1] 범위로 제한됩니다.
ddx 샘플링 위치를 계산하는 데 사용되는 x 방향 도함수 벡터입니다.
ddy 샘플링 위치를 계산하는 데 사용되는 y 방향 도함수 벡터입니다.
offset 텍스처를 샘플링하기 전에 정규화되지 않은 텍스처 좌표에 적용되는 선택적 텍셀 오프셋입니다. 이 오프셋은 모든 텍스처 래핑 모드를 적용하기 전에 적용됩니다.
offset 표현식은 반드시 상수 표현식이어야 합니다(예: vec2<i32>(1, 2)).
offset 컴포넌트는 반드시 -8 이상이고 7 이하여야 합니다. 이 범위를 벗어난 값은 셰이더 생성 오류를 발생시킵니다.

반환:

샘플링된 값입니다.

17.7.13. textureSampleLevel

명시적 밉 레벨을 사용하여 텍스처를 샘플링합니다.

매개변수화 오버로드
@must_use fn textureSampleLevel(t: texture_1d<f32>,
                                s: sampler,
                                coords: f32,
                                level: f32) -> vec4<f32>
@must_use fn textureSampleLevel(t: texture_2d<f32>,
                                s: sampler,
                                coords: vec2<f32>,
                                level: f32) -> vec4<f32>
@must_use fn textureSampleLevel(t: texture_2d<f32>,
                                s: sampler,
                                coords: vec2<f32>,
                                level: f32,
                                offset: vec2<i32>) -> vec4<f32>
Ai32 또는 u32입니다
@must_use fn textureSampleLevel(t: texture_2d_array<f32>,
                                s: sampler,
                                coords: vec2<f32>,
                                array_index: A,
                                level: f32) -> vec4<f32>
Ai32 또는 u32입니다
@must_use fn textureSampleLevel(t: texture_2d_array<f32>,
                                s: sampler,
                                coords: vec2<f32>,
                                array_index: A,
                                level: f32,
                                offset: vec2<i32>) -> vec4<f32>
Ttexture_3d<f32> 또는 texture_cube<f32>입니다
@must_use fn textureSampleLevel(t: T,
                                s: sampler,
                                coords: vec3<f32>,
                                level: f32) -> vec4<f32>
@must_use fn textureSampleLevel(t: texture_3d<f32>,
                                s: sampler,
                                coords: vec3<f32>,
                                level: f32,
                                offset: vec3<i32>) -> vec4<f32>
Ai32 또는 u32입니다
@must_use fn textureSampleLevel(t: texture_cube_array<f32>,
                                s: sampler,
                                coords: vec3<f32>,
                                array_index: A,
                                level: f32) -> vec4<f32>
Li32 또는 u32입니다
@must_use fn textureSampleLevel(t: texture_depth_2d,
                                s: sampler,
                                coords: vec2<f32>,
                                level: L) -> f32
Li32 또는 u32입니다
@must_use fn textureSampleLevel(t: texture_depth_2d,
                                s: sampler,
                                coords: vec2<f32>,
                                level: L,
                                offset: vec2<i32>) -> f32
Ai32 또는 u32입니다
Li32 또는 u32입니다
@must_use fn textureSampleLevel(t: texture_depth_2d_array,
                                s: sampler,
                                coords: vec2<f32>,
                                array_index: A,
                                level: L) -> f32
Ai32 또는 u32입니다
Li32 또는 u32입니다
@must_use fn textureSampleLevel(t: texture_depth_2d_array,
                                s: sampler,
                                coords: vec2<f32>,
                                array_index: A,
                                level: L,
                                offset: vec2<i32>) -> f32
Li32 또는 u32입니다
@must_use fn textureSampleLevel(t: texture_depth_cube,
                                s: sampler,
                                coords: vec3<f32>,
                                level: L) -> f32
Ai32 또는 u32입니다
Li32 또는 u32입니다
@must_use fn textureSampleLevel(t: texture_depth_cube_array,
                                s: sampler,
                                coords: vec3<f32>,
                                array_index: A,
                                level: L) -> f32

매개변수:

t 샘플링할 샘플링된 또는 깊이 텍스처입니다.
s 샘플러 타입입니다.
coords 샘플링에 사용되는 텍스처 좌표입니다.
array_index 샘플링할 0 기반 텍스처 배열 인덱스입니다.
이 값은 [0, textureNumLayers(t) - 1] 범위로 제한됩니다.
level 밉 레벨이며, 레벨 0에는 텍스처의 전체 크기 버전이 포함됩니다. levelf32인 함수에서는 형식이 텍스처 형식 기능에 따라 필터링 가능한 경우 소수 값이 두 레벨 사이를 보간할 수 있습니다.
offset 텍스처를 샘플링하기 전에 정규화되지 않은 텍스처 좌표에 적용되는 선택적 텍셀 오프셋입니다. 이 오프셋은 모든 텍스처 래핑 모드를 적용하기 전에 적용됩니다.
offset 표현식은 반드시 상수 표현식이어야 합니다(예: vec2<i32>(1, 2)).
offset 컴포넌트는 반드시 -8 이상이고 7 이하여야 합니다. 이 범위를 벗어난 값은 셰이더 생성 오류를 발생시킵니다.

반환:

샘플링된 값입니다.

17.7.14. textureSampleBaseClampToEdge

아래 설명과 같이 텍스처 좌표를 가장자리로 제한하여 기본 레벨에서 텍스처 뷰를 샘플링합니다.

매개변수화 오버로드
Ttexture_2d<f32> 또는 texture_external입니다
@must_use fn textureSampleBaseClampToEdge(t: T,
                                          s: sampler,
                                          coords: vec2<f32>) -> vec4<f32>

매개변수:

t 샘플링할 샘플링된 또는 외부 텍스처입니다.
s 샘플러 타입입니다.
coords 샘플링에 사용되는 텍스처 좌표입니다.

샘플링 전에 주어진 좌표는 다음 직사각형으로 제한됩니다.

[ half_texel, 1 - half_texel ]

여기서

half_texel = vec2(0.5) / vec2<f32>(textureDimensions(t))

참고: 반 텍셀 조정은 샘플러의 주소 지정필터 모드와 관계없이 래핑이 발생하지 않도록 보장합니다. 즉, 가장자리 근처를 샘플링할 때 샘플링되는 텍셀은 해당 가장자리에 있거나 인접하며 반대편 가장자리에서 선택되지 않습니다.

반환:

샘플링된 값입니다.

17.7.15. textureStore

단일 텍셀을 텍스처에 씁니다.

매개변수화 오버로드
F텍셀 형식입니다
Ci32 또는 u32입니다
AMwrite 또는 read_write입니다
CF는 스토리지 텍셀 형식 F에 따라 달라집니다. 텍셀 형식에서 채널 형식으로의 매핑은 텍셀 형식 표를 참조하십시오.
fn textureStore(t: texture_storage_1d<F,AM>,
                coords: C,
                value: vec4<CF>)
F텍셀 형식입니다
Ci32 또는 u32입니다
AMwrite 또는 read_write입니다
CF는 스토리지 텍셀 형식 F에 따라 달라집니다. 텍셀 형식에서 채널 형식으로의 매핑은 텍셀 형식 표를 참조하십시오.
fn textureStore(t: texture_storage_2d<F,AM>,
                coords: vec2<C>,
                value: vec4<CF>)
F텍셀 형식입니다
Ci32 또는 u32입니다
AMwrite 또는 read_write입니다
Ai32 또는 u32입니다
CF는 스토리지 텍셀 형식 F에 따라 달라집니다. 텍셀 형식에서 채널 형식으로의 매핑은 텍셀 형식 표를 참조하십시오.
fn textureStore(t: texture_storage_2d_array<F,AM>,
                coords: vec2<C>,
                array_index: A,
                value: vec4<CF>)
F텍셀 형식입니다
Ci32 또는 u32입니다
AMwrite 또는 read_write입니다
CF는 스토리지 텍셀 형식 F에 따라 달라집니다. 텍셀 형식에서 채널 형식으로의 매핑은 텍셀 형식 표를 참조하십시오.
fn textureStore(t: texture_storage_3d<F,AM>,
                coords: vec3<C>,
                value: vec4<CF>)

매개변수:

t 쓰기 전용 스토리지 텍스처 또는 읽기-쓰기 스토리지 텍스처입니다
coords 0 기반 텍셀 좌표입니다.
array_index 0 기반 텍스처 배열 인덱스입니다.
value 새 텍셀 값입니다. value역 채널 전달 함수를 사용하여 변환됩니다.

참고:

논리적 텍셀 주소는 다음 경우 유효하지 않습니다.

논리적 텍셀 주소가 유효하지 않으면 내장 함수는 실행되지 않습니다.

17.8. 원자 내장 함수

원자 내장 함수는 원자 객체를 읽거나, 쓰거나, 읽기-수정-쓰기 하는 데 사용할 수 있습니다. 이는 § 6.2.8 원자 타입에 허용되는 유일한 연산입니다.

모든 원자 내장 함수는 relaxed 메모리 순서를 사용합니다. 이는 동기화 및 순서 보장이 동일한 메모리 위치에서 작동하는 원자 연산 사이에만 적용됨을 의미합니다. 원자 메모리 액세스와 비원자 메모리 액세스 사이 또는 서로 다른 메모리 위치에서 작동하는 원자 액세스 사이에는 동기화나 순서 보장이 적용되지 않습니다.

원자 내장 함수는 버텍스 셰이더 스테이지에서 사용해서는 안 됩니다.

모든 원자 내장 함수의 atomic_ptr 매개변수에 대한 주소 공간 AS반드시 storage 또는 workgroup이어야 합니다.

T반드시 u32 또는 i32여야 합니다

17.8.1. atomicLoad

fn atomicLoad(atomic_ptr: ptr<AS, atomic<T>, read_write>) -> T

atomic_ptr이 가리키는 값을 원자적으로 로드하여 반환합니다. 객체를 수정하지 않습니다.

17.8.2. atomicStore

fn atomicStore(atomic_ptr: ptr<AS, atomic<T>, read_write>, v: T)

atomic_ptr이 가리키는 원자 객체에 값 v를 원자적으로 저장합니다.

17.8.3. 원자 읽기-수정-쓰기 산술 및 논리 함수

각 함수는 다음 단계를 원자적으로 수행합니다.

  1. atomic_ptr이 가리키는 원래 값을 로드합니다.

  2. 함수 이름에 해당하는 연산(예: 최댓값)을 값 v와 수행하여 새 값을 얻습니다.

  3. atomic_ptr을 사용하여 새 값을 저장합니다.

각 함수는 연산 전에 원자 객체에 저장되어 있던 원래 값을 반환합니다.

17.8.3.1. atomicAdd
fn atomicAdd(atomic_ptr: ptr<AS, atomic<T>, read_write>, v: T) -> T

atomic_ptr이 가리키는 원자 객체에 값 v를 사용하여 덧셈 연산을 원자적으로 수행하고, 연산 전에 원자 객체에 저장되어 있던 원래 값을 반환합니다.

예제: 함수로 표현한 원자 덧셈 연산
// 모든 연산은 원자적으로 수행됩니다
fn atomicAdd(atomic_ptr: ptr<AS, atomic<T>, read_write>, v : T) -> T {
  let old = *atomic_ptr;
  *atomic_ptr = old + v;
  return old;
}
17.8.3.2. atomicSub
fn atomicSub(atomic_ptr: ptr<AS, atomic<T>, read_write>, v: T) -> T

atomic_ptr이 가리키는 원자 객체에 값 v를 사용하여 뺄셈 연산을 원자적으로 수행하고, 연산 전에 원자 객체에 저장되어 있던 원래 값을 반환합니다.

예제: 함수로 표현한 원자 뺄셈 연산
// 모든 연산은 원자적으로 수행됩니다
fn atomicSub(atomic_ptr: ptr<AS, atomic<T>, read_write>, v : T) -> T {
  let old = *atomic_ptr;
  *atomic_ptr = old - v;
  return old;
}
17.8.3.3. atomicMax
fn atomicMax(atomic_ptr: ptr<AS, atomic<T>, read_write>, v: T) -> T

atomic_ptr이 가리키는 원자 객체에 값 v를 사용하여 최댓값 연산을 원자적으로 수행하고, 연산 전에 원자 객체에 저장되어 있던 원래 값을 반환합니다.

예제: 함수로 표현한 원자 최댓값 연산
// 모든 연산은 원자적으로 수행됩니다
fn atomicMax(atomic_ptr: ptr<AS, atomic<T>, read_write>, v : T) -> T {
  let old = *atomic_ptr;
  *atomic_ptr = max(old, v);
  return old;
}
17.8.3.4. atomicMin
fn atomicMin(atomic_ptr: ptr<AS, atomic<T>, read_write>, v: T) -> T

atomic_ptr이 가리키는 원자 객체에 값 v를 사용하여 최솟값 연산을 원자적으로 수행하고, 연산 전에 원자 객체에 저장되어 있던 원래 값을 반환합니다.

예제: 함수로 표현한 원자 최솟값 연산
// 모든 연산은 원자적으로 수행됩니다
fn atomicMin(atomic_ptr: ptr<AS, atomic<T>, read_write>, v : T) -> T {
  let old = *atomic_ptr;
  *atomic_ptr = min(old, v);
  return old;
}
17.8.3.5. atomicAnd
fn atomicAnd(atomic_ptr: ptr<AS, atomic<T>, read_write>, v: T) -> T

atomic_ptr이 가리키는 원자 객체에 값 v를 사용하여 비트 AND 연산을 원자적으로 수행하고, 연산 전에 원자 객체에 저장되어 있던 원래 값을 반환합니다.

예제: 함수로 표현한 원자 비트 AND 연산
// 모든 연산은 원자적으로 수행됩니다
fn atomicAnd(atomic_ptr: ptr<AS, atomic<T>, read_write>, v : T) -> T {
  let old = *atomic_ptr;
  *atomic_ptr = old & v;
  return old;
}
17.8.3.6. atomicOr
fn atomicOr(atomic_ptr: ptr<AS, atomic<T>, read_write>, v: T) -> T

atomic_ptr이 가리키는 원자 객체에 값 v를 사용하여 비트 OR 연산을 원자적으로 수행하고, 연산 전에 원자 객체에 저장되어 있던 원래 값을 반환합니다.

예제: 함수로 표현한 원자 비트 OR 연산
// 모든 연산은 원자적으로 수행됩니다
fn atomicOr(atomic_ptr: ptr<AS, atomic<T>, read_write>, v : T) -> T {
  let old = *atomic_ptr;
  *atomic_ptr = old | v;
  return old;
}
17.8.3.7. atomicXor
fn atomicXor(atomic_ptr: ptr<AS, atomic<T>, read_write>, v: T) -> T

atomic_ptr이 가리키는 원자 객체에 값 v를 사용하여 비트 XOR 연산을 원자적으로 수행하고, 연산 전에 원자 객체에 저장되어 있던 원래 값을 반환합니다.

예제: 함수로 표현한 원자 비트 XOR 연산
// 모든 연산은 원자적으로 수행됩니다
fn atomicXor(atomic_ptr: ptr<AS, atomic<T>, read_write>, v : T) -> T {
  let old = *atomic_ptr;
  *atomic_ptr = old ^ v;
  return old;
}

17.8.4. atomicExchange

fn atomicExchange(atomic_ptr: ptr<AS, atomic<T>, read_write>, v: T) -> T

atomic_ptr이 가리키는 원자 객체에 값 v를 원자적으로 저장하고 연산 전에 원자 객체에 저장되어 있던 원래 값을 반환합니다.

예제: 함수로 표현한 원자 교환 연산
// 모든 연산은 원자적으로 수행됩니다
fn atomicExchange(atomic_ptr: ptr<AS, atomic<T>, read_write>, v : T) -> T {
  let old = *atomic_ptr;
  *atomic_ptr = v;
  return old;
}

17.8.5. atomicCompareExchangeWeak

fn atomicCompareExchangeWeak(
      atomic_ptr: ptr<AS, atomic<T>, read_write>,
      cmp: T,
      v: T) -> __atomic_compare_exchange_result<T>

struct __atomic_compare_exchange_result<T> {
  old_value : T,   // 원자 객체에 저장되어 있던 이전 값
  exchanged : bool // 교환이 수행되었으면 true
}

참고: __atomic_compare_exchange_result 타입으로 값을 명시적으로 선언할 수는 없지만, 값에서 이 타입을 추론할 수 있습니다.

다음 단계를 원자적으로 수행합니다.

  1. atomic_ptr이 가리키는 원래 값을 로드합니다.

  2. 동등 연산을 사용하여 원래 값과 값 cmp를 비교합니다.

  3. 동등 비교 결과가 true인 경우에만 값 v를 저장합니다.

두 멤버로 구성된 구조체를 반환합니다. 첫 번째 멤버 old_value는 연산 전 원자 객체의 원래 값이고, 두 번째 멤버 exchanged는 비교가 성공했는지를 나타냅니다.

예제: 함수로 표현한 원자 비교 교환 연산
// 모든 연산은 원자적으로 수행됩니다
fn atomicCompareExchangeWeak(atomic_ptr: ptr<AS, atomic<T>, read_write>, cmp : T, v : T) ->
  _atomic_compare_exchange_result<T> {
  let old = *atomic_ptr;
  // 이 비교는 허위로 실패할 수 있습니다.
  let comparison = old == cmp;
  if comparison {
    *atomic_ptr = v;
  }
  return _atomic_compare_exchange_result<T>(old, comparison);
}

참고: 일부 구현에서는 동등 비교가 허위로 실패할 수 있습니다. 즉, 결과 벡터의 첫 번째 컴포넌트가 cmp와 같더라도 결과 벡터의 두 번째 컴포넌트가 false일 수 있습니다.

17.9. 데이터 패킹 내장 함수

데이터 패킹 내장 함수는 WGSL의 타입에 직접 대응하지 않는 데이터 형식을 사용하여 값을 인코딩하는 데 사용할 수 있습니다. 이를 통해 프로그램이 조밀하게 패킹된 여러 값을 메모리에 쓸 수 있으므로 셰이더의 메모리 대역폭 요구량을 줄일 수 있습니다.

각 내장 함수는 여러 입력 값에 채널 전달 함수역함수를 적용한 다음 그 결과를 하나의 출력 값으로 결합합니다.

참고: unorm 값을 패킹할 때 정규화된 부동 소수점 값은 구간 [0.0, 1.0]에 있습니다.

참고: snorm 값을 패킹할 때 정규화된 부동 소수점 값은 구간 [-1.0, 1.0]에 있습니다.

17.9.1. pack4x8snorm

오버로드
@const @must_use fn pack4x8snorm(e: vec4<f32>) -> u32
설명 정규화된 네 개의 부동 소수점 값을 8비트 부호 있는 정수로 변환한 다음 하나의 u32 값으로 결합합니다.

입력의 컴포넌트 e[i]는 8비트 2의 보수 정숫값 ⌊ 0.5 + 127 × min(1, max(-1, e[i])) ⌋로 변환된 다음 결과의 8 × i번 비트부터 8 × i + 7번 비트까지 배치됩니다.

17.9.2. pack4x8unorm

오버로드
@const @must_use fn pack4x8unorm(e: vec4<f32>) -> u32
설명 정규화된 네 개의 부동 소수점 값을 8비트 부호 없는 정수로 변환한 다음 하나의 u32 값으로 결합합니다.

입력의 컴포넌트 e[i]는 8비트 부호 없는 정숫값 ⌊ 0.5 + 255 × min(1, max(0, e[i])) ⌋로 변환된 다음 결과의 8 × i번 비트부터 8 × i + 7번 비트까지 배치됩니다.

17.9.3. pack4xI8

오버로드
@const @must_use fn pack4xI8(e: vec4<i32>) -> u32
설명 e의 각 컴포넌트에서 하위 8비트를 u32 값으로 패킹하고 사용하지 않는 모든 비트를 버립니다.

입력의 컴포넌트 e[i]는 결과의 8 × i번 비트부터 8 × i + 7번 비트까지 매핑됩니다.

17.9.4. pack4xU8

오버로드
@const @must_use fn pack4xU8(e: vec4<u32>) -> u32
설명 e의 각 컴포넌트에서 하위 8비트를 u32 값으로 패킹하고 사용하지 않는 모든 비트를 버립니다.

입력의 컴포넌트 e[i]는 결과의 8 × i번 비트부터 8 × i + 7번 비트까지 매핑됩니다.

17.9.5. pack4xI8Clamp

오버로드
@const @must_use fn pack4xI8Clamp(e: vec4<i32>) -> u32
설명 e의 각 컴포넌트를 [-128, 127] 범위로 제한한 다음 각 컴포넌트의 하위 8비트를 u32 값으로 패킹합니다.

입력의 컴포넌트 e[i]는 결과의 8 × i번 비트부터 8 × i + 7번 비트까지 매핑됩니다.

17.9.6. pack4xU8Clamp

오버로드
@const @must_use fn pack4xU8Clamp(e: vec4<u32>) -> u32
설명 e의 각 컴포넌트를 [0, 255] 범위로 제한한 다음 각 컴포넌트의 하위 8비트를 u32 값으로 패킹합니다.

입력의 컴포넌트 e[i]는 결과의 8 × i번 비트부터 8 × i + 7번 비트까지 매핑됩니다.

17.9.7. pack2x16snorm

오버로드
@const @must_use fn pack2x16snorm(e: vec2<f32>) -> u32
설명 정규화된 두 부동 소수점 값을 16비트 부호 있는 정수로 변환한 다음 하나의 u32 값으로 결합합니다.
입력의 컴포넌트 e[i]는 16비트 2의 보수 정숫값 ⌊ 0.5 + 32767 × min(1, max(-1, e[i])) ⌋로 변환된 다음 결과의 16 × i번 비트부터 16 × i + 15번 비트까지 배치됩니다.

17.9.8. pack2x16unorm

오버로드
@const @must_use fn pack2x16unorm(e: vec2<f32>) -> u32
설명 정규화된 두 부동 소수점 값을 16비트 부호 없는 정수로 변환한 다음 하나의 u32 값으로 결합합니다.
입력의 컴포넌트 e[i]는 16비트 부호 없는 정숫값 ⌊ 0.5 + 65535 × min(1, max(0, e[i])) ⌋로 변환된 다음 결과의 16 × i번 비트부터 16 × i + 15번 비트까지 배치됩니다.

17.9.9. pack2x16float

오버로드
@const @must_use fn pack2x16float(e: vec2<f32>) -> u32
설명 두 부동 소수점 값을 반정밀도 부동 소수점 수로 변환한 다음 하나의 u32 값으로 결합합니다.
입력의 컴포넌트 e[i]IEEE-754 binary16 값으로 변환된 다음 결과의 16 × i번 비트부터 16 × i + 15번 비트까지 배치됩니다. § 15.7.6 부동 소수점 변환을 참조하십시오.

e[0] 또는 e[1]이 binary16의 유한 범위를 벗어나면:

17.10. 데이터 언패킹 내장 함수

데이터 언패킹 내장 함수는 WGSL의 타입에 직접 대응하지 않는 데이터 형식의 값을 디코딩하는 데 사용할 수 있습니다. 이를 통해 프로그램이 조밀하게 패킹된 여러 값을 메모리에서 읽을 수 있으므로 셰이더의 메모리 대역폭 요구량을 줄일 수 있습니다.

각 내장 함수는 입력 값을 채널로 분할한 다음 각 채널에 채널 전달 함수를 적용합니다.

참고: unorm 값을 언패킹할 때 정규화된 부동 소수점 결과는 구간 [0.0, 1.0]에 있습니다.

참고: snorm 값을 언패킹할 때 정규화된 부동 소수점 결과는 구간 [-1.0, 1.0]에 있습니다.

17.10.1. unpack4x8snorm

오버로드
@const @must_use fn unpack4x8snorm(e: u32) -> vec4<f32>
설명 32비트 값을 네 개의 8비트 청크로 분해한 다음 각 청크를 부호 있는 정규화 부동 소수점 값으로 재해석합니다.
결과의 컴포넌트 i는 max(v ÷ 127, -1)입니다. 여기서 ve의 8×i번 비트부터 8×i + 7번 비트까지를 2의 보수 부호 있는 정수로 해석한 값입니다.

17.10.2. unpack4x8unorm

오버로드
@const @must_use fn unpack4x8unorm(e: u32) -> vec4<f32>
설명 32비트 값을 네 개의 8비트 청크로 분해한 다음 각 청크를 부호 없는 정규화 부동 소수점 값으로 재해석합니다.
결과의 컴포넌트 iv ÷ 255입니다. 여기서 ve의 8×i번 비트부터 8×i + 7번 비트까지를 부호 없는 정수로 해석한 값입니다.

17.10.3. unpack4xI8

오버로드
@const @must_use fn unpack4xI8(e: u32) -> vec4<i32>
설명 e는 네 개의 8비트 부호 있는 정수 컴포넌트로 구성된 벡터로 해석됩니다. e를 부호 확장하여 vec4<i32>로 언패킹합니다.

17.10.4. unpack4xU8

오버로드
@const @must_use fn unpack4xU8(e: u32) -> vec4<u32>
설명 e는 네 개의 8비트 부호 없는 정수 컴포넌트로 구성된 벡터로 해석됩니다. e를 0 확장하여 vec4<u32>로 언패킹합니다.

17.10.5. unpack2x16snorm

오버로드
@const @must_use fn unpack2x16snorm(e: u32) -> vec2<f32>
설명 32비트 값을 두 개의 16비트 청크로 분해한 다음 각 청크를 부호 있는 정규화 부동 소수점 값으로 재해석합니다.
결과의 컴포넌트 i는 max(v ÷ 32767, -1)입니다. 여기서 ve의 16×i번 비트부터 16×i + 15번 비트까지를 2의 보수 부호 있는 정수로 해석한 값입니다.

17.10.6. unpack2x16unorm

오버로드
@const @must_use fn unpack2x16unorm(e: u32) -> vec2<f32>
설명 32비트 값을 두 개의 16비트 청크로 분해한 다음 각 청크를 부호 없는 정규화 부동 소수점 값으로 재해석합니다.
결과의 컴포넌트 iv ÷ 65535입니다. 여기서 ve의 16×i번 비트부터 16×i + 15번 비트까지를 부호 없는 정수로 해석한 값입니다.

17.10.7. unpack2x16float

오버로드
@const @must_use fn unpack2x16float(e: u32) -> vec2<f32>
설명 32비트 값을 두 개의 16비트 청크로 분해하고 각 청크를 부동 소수점 값으로 재해석합니다.
결과의 컴포넌트 iv의 f32 표현입니다. 여기서 ve의 16×i번 비트부터 16×i + 15번 비트까지를 IEEE-754 binary16 값으로 해석한 것입니다. § 15.7.6 부동 소수점 변환을 참조하십시오.

17.11. 동기화 내장 함수

모든 동기화 함수는 획득/해제 메모리 순서를 사용하는 제어 배리어를 실행합니다. 즉, 모든 동기화 함수와 영향을 받는 메모리 및 원자 연산은 동기화 함수를 기준으로 프로그램 순서에 따라 정렬됩니다. 또한 동기화 함수보다 프로그램 순서상 앞에 있는 영향을 받는 메모리 및 원자 연산은 동기화 함수보다 프로그램 순서상 뒤에 있는 영향을 받는 메모리 또는 원자 연산이 워크그룹의 멤버에 의해 실행되기 전에 워크그룹의 다른 모든 스레드에 표시되어야 합니다.

모든 동기화 함수는 Workgroup 메모리 범위를 사용합니다.
모든 동기화 함수의 실행 범위Workgroup입니다.
모든 동기화 함수는 반드시 컴퓨트 셰이더 스테이지에서만 사용해야 합니다. 모든 동기화 함수는 반드시 균일 제어 흐름에서만 호출해야 합니다.

17.11.1. storageBarrier

오버로드
fn storageBarrier()
설명 storage 주소 공간의 메모리 및 원자 연산에 영향을 주는 제어 배리어 동기화 함수를 실행합니다.

17.11.2. textureBarrier

오버로드
fn textureBarrier()
설명 handle 주소 공간의 메모리 연산에 영향을 주는 제어 배리어 동기화 함수를 실행합니다.

17.11.3. workgroupBarrier

오버로드
fn workgroupBarrier()
설명 workgroup 주소 공간의 메모리 및 원자 연산에 영향을 주는 제어 배리어 동기화 함수를 실행합니다.

17.11.4. workgroupUniformLoad

오버로드
@must_use fn workgroupUniformLoad(p : ptr<workgroup, T>) -> T
매개변수화 T구체 생성 가능 타입입니다.
설명 p가 가리키는 값을 워크그룹의 모든 호출에 반환합니다. 반환 값은 균일합니다. p반드시 균일 값이어야 합니다.

workgroup 주소 공간의 메모리 및 원자 연산에 영향을 주는 제어 배리어 동기화 함수를 실행합니다.

오버로드
@must_use fn workgroupUniformLoad(p : ptr<workgroup, atomic<T>, read_write>) -> T
설명 p가 가리키는 값을 원자적으로 로드하여 워크그룹의 모든 호출에 반환합니다. 반환 값은 균일합니다. p반드시 균일 값이어야 합니다.

workgroup 주소 공간의 메모리 및 원자 연산에 영향을 주는 제어 배리어 동기화 함수를 실행합니다.

17.12. 서브그룹 내장 함수

§ 15.6.3 서브그룹 연산을 참조하십시오.

이러한 함수 호출은:

참고: 컴퓨트 셰이더 스테이지에서 균일 제어 흐름의 범위는 워크그룹입니다. 프래그먼트 셰이더 스테이지에서 균일 제어 흐름의 범위는 드로 명령입니다. 이 두 범위는 모두 서브그룹보다 큽니다.

17.12.1. subgroupAdd

오버로드
@must_use fn subgroupAdd(e : T) -> T
전제 조건 T구체 숫자 스칼라 또는 구체 숫자 벡터입니다
설명 축약 연산입니다.

서브그룹의 모든 활성 호출에 대한 e의 합을 반환합니다.

17.12.1.1. subgroupExclusiveAdd
오버로드
@must_use fn subgroupExclusiveAdd(e : T) -> T
전제 조건 T구체 숫자 스칼라 또는 구체 숫자 벡터입니다
설명 배타적 접두사 스캔 연산입니다.

서브그룹활성 호출 중 서브그룹 호출 ID가 현재 호출의 ID보다 작은 모든 호출에 대한 e의 합을 반환합니다.

활성 호출 중 ID가 가장 작은 호출에 대해 반환되는 값은 T(0)입니다.

17.12.1.2. subgroupInclusiveAdd
오버로드
@must_use fn subgroupInclusiveAdd(e : T) -> T
전제 조건 T구체 숫자 스칼라 또는 구체 숫자 벡터입니다
설명 포괄적 접두사 스캔 연산입니다.

서브그룹활성 호출 중 서브그룹 호출 ID가 현재 호출의 ID보다 작거나 같은 모든 호출에 대한 e의 합을 반환합니다.

참고: subgroupExclusiveAdd(x) + x와 같습니다.

17.12.2. subgroupAll

오버로드
@must_use fn subgroupAll(e : bool) -> bool
설명 서브그룹의 모든 활성 호출에서 etrue이면 true를 반환합니다.

17.12.3. subgroupAnd

오버로드
@must_use fn subgroupAnd(e : T) -> T
전제 조건 T는 i32, u32, vecN<i32> 또는 vecN<u32>입니다
설명 축약 연산입니다.

서브그룹의 모든 활성 호출에 대한 e의 비트 AND(&)를 반환합니다.

17.12.4. subgroupAny

오버로드
@must_use fn subgroupAny(e : bool) -> bool
설명 서브그룹활성 호출 중 하나라도 etrue이면 true를 반환합니다.

17.12.5. subgroupBallot

오버로드
@must_use fn subgroupBallot(pred : bool) -> vec4<u32>
설명 서브그룹에서 predtrue활성 호출의 비트 마스크를 반환합니다.

반환 값의 x 컴포넌트에는 호출 0부터 31까지가 포함됩니다.
반환 값의 y 컴포넌트에는 호출 32부터 63까지가 포함됩니다.
반환 값의 z 컴포넌트에는 호출 64부터 95까지가 포함됩니다.
반환 값의 w 컴포넌트에는 호출 96부터 127까지가 포함됩니다.

각 컴포넌트에서 ID는 비트 위치를 기준으로 오름차순입니다 (예: ID 32는 y 컴포넌트의 비트 위치 0에 있습니다).

17.12.6. subgroupBroadcast

오버로드
@must_use fn subgroupBroadcast(e : T, id : I) -> T
전제 조건 T구체 숫자 스칼라 또는 구체 숫자 벡터입니다
Iu32 또는 i32입니다
설명 서브그룹에서 서브그룹 호출 IDid와 일치하는 호출의 e 값을 서브그룹의 모든 활성 호출에 반환합니다.

id반드시 [0, 128) 범위의 상수 표현식이어야 합니다.

id활성 호출을 선택하지 않으면 동적 오류입니다.

참고: 상수가 아닌 버전의 id가 필요한 경우 대신 subgroupShuffle을 사용하십시오.

17.12.6.1. subgroupBroadcastFirst
오버로드
@must_use fn subgroupBroadcastFirst(e : T) -> T
전제 조건 T구체 숫자 스칼라 또는 구체 숫자 벡터입니다
설명 서브그룹활성 호출 중 서브그룹 호출 ID가 가장 작은 호출의 e 값을 서브그룹의 모든 활성 호출에 반환합니다.

17.12.7. subgroupElect

오버로드
@must_use fn subgroupElect() -> bool
설명 현재 호출이 서브그룹활성 호출 중 가장 작은 서브그룹 호출 ID를 가지면 true를 반환합니다.

17.12.8. subgroupMax

오버로드
@must_use fn subgroupMax(e : T) -> T
전제 조건 T구체 숫자 스칼라 또는 구체 숫자 벡터입니다
설명 축약 연산입니다.

서브그룹의 모든 활성 호출에서 e의 최댓값을 반환합니다.

17.12.9. subgroupMin

오버로드
@must_use fn subgroupMin(e : T) -> T
전제 조건 T구체 숫자 스칼라 또는 구체 숫자 벡터입니다
설명 축약 연산입니다.

서브그룹의 모든 활성 호출에서 e의 최솟값을 반환합니다.

17.12.10. subgroupMul

오버로드
@must_use fn subgroupMul(e : T) -> T
전제 조건 T구체 숫자 스칼라 또는 구체 숫자 벡터입니다
설명 축약 연산입니다.

서브그룹의 모든 활성 호출에 대한 e의 곱을 반환합니다.

17.12.10.1. subgroupExclusiveMul
오버로드
@must_use fn subgroupExclusiveMul(e : T) -> T
전제 조건 T구체 숫자 스칼라 또는 구체 숫자 벡터입니다
설명 배타적 접두사 스캔 연산입니다.

서브그룹활성 호출 중 서브그룹 호출 ID가 현재 호출의 ID보다 작은 모든 호출에 대한 e의 곱을 반환합니다.

활성 호출 중 ID가 가장 작은 호출에 대해 반환되는 값은 T(1)입니다.

17.12.10.2. subgroupInclusiveMul
오버로드
@must_use fn subgroupInclusiveMul(e : T) -> T
전제 조건 T구체 숫자 스칼라 또는 구체 숫자 벡터입니다
설명 포괄적 접두사 스캔 연산입니다.

서브그룹활성 호출 중 서브그룹 호출 ID가 현재 호출의 ID보다 작거나 같은 모든 호출에 대한 e의 곱을 반환합니다.

참고: subgroupExclusiveMul(x) * x와 같습니다.

17.12.11. subgroupOr

오버로드
@must_use fn subgroupOr(e : T) -> T
전제 조건 T는 i32, u32, vecN<i32> 또는 vecN<u32>입니다
설명 축약 연산입니다.

서브그룹의 모든 활성 호출에 대한 e의 비트 OR(|)을 반환합니다.

17.12.12. subgroupShuffle

오버로드
@must_use fn subgroupShuffle(e : T, id : I) -> T
전제 조건 T구체 숫자 스칼라 또는 구체 숫자 벡터입니다
Iu32 또는 i32입니다
설명 서브그룹 호출 IDid와 일치하는 호출의 e를 반환합니다.

id가 [0, 128) 범위를 벗어나면:

id활성 호출을 선택하지 않으면 부정 값이 반환됩니다.

17.12.12.1. subgroupShuffleDown
오버로드
@must_use fn subgroupShuffleDown(e : T, delta : u32) -> T
전제 조건 T구체 숫자 스칼라 또는 구체 숫자 벡터입니다
설명 현재 호출에 대해 서브그룹 호출 IDsubgroup_invocation_id + delta와 일치하는 호출의 e를 반환합니다.

delta가 127보다 크면:

delta균일 값이 아니면 subgroup_uniformity 진단트리거됩니다. subgroup_invocation_id + delta활성 호출을 선택하지 않거나 delta가 서브그룹 내에서 균일 값이 아니면 부정 값이 반환됩니다.

17.12.12.2. subgroupShuffleUp
오버로드
@must_use fn subgroupShuffleUp(e : T, delta : u32) -> T
전제 조건 T구체 숫자 스칼라 또는 구체 숫자 벡터입니다
설명 현재 호출에 대해 서브그룹 호출 IDsubgroup_invocation_id - delta와 일치하는 호출의 e를 반환합니다.

delta가 127보다 크면:

delta균일 값이 아니면 subgroup_uniformity 진단트리거됩니다. subgroup_invocation_id - delta활성 호출을 선택하지 않거나 delta가 서브그룹 내에서 균일 값이 아니면 부정 값이 반환됩니다.

17.12.12.3. subgroupShuffleXor
오버로드
@must_use fn subgroupShuffleXor(e : T,  mask : u32) -> T
전제 조건 T구체 숫자 스칼라 또는 구체 숫자 벡터입니다
설명 현재 호출에 대해 서브그룹 호출 IDsubgroup_invocation_id ^ mask와 일치하는 호출의 e를 반환합니다.

mask가 127보다 크면:

mask균일 값이 아니면 subgroup_uniformity 진단트리거됩니다. mask활성 호출을 선택하지 않거나 mask가 서브그룹 내에서 균일 값이 아니면 부정 값이 반환됩니다.

17.12.13. subgroupXor

오버로드
@must_use fn subgroupXor(e : T) -> T
전제 조건 T는 i32, u32, vecN<i32> 또는 vecN<u32>입니다
설명 축약 연산입니다.

서브그룹의 모든 활성 호출에 대한 e의 비트 XOR(^)을 반환합니다.

17.13. 쿼드 연산

§ 15.6.4 쿼드 연산을 참조하십시오.

이러한 함수 호출은:

참고: 컴퓨트 셰이더 스테이지에서 균일 제어 흐름의 범위는 워크그룹입니다. 프래그먼트 셰이더 스테이지에서 균일 제어 흐름의 범위는 드로 명령입니다. 이 두 범위는 모두 쿼드보다 큽니다.

17.13.1. quadBroadcast

오버로드
@must_use fn quadBroadcast(e : T, id : I) -> T
전제 조건 T구체 숫자 스칼라 또는 구체 숫자 벡터입니다
Iu32 또는 i32입니다
설명 쿼드에서 쿼드 호출 IDid와 일치하는 호출의 e 값을 쿼드의 모든 활성 호출에 반환합니다.

id반드시 [0, 4) 범위의 상수 표현식이어야 합니다.

id활성 호출을 선택하지 않으면 부정 값이 반환됩니다.

참고: subgroupBroadcast와 달리 현재는 상수가 아닌 대안이 없습니다.

17.13.2. quadSwapDiagonal

오버로드
@must_use fn quadSwapDiagonal(e : T) -> T
전제 조건 T구체 숫자 스칼라 또는 구체 숫자 벡터입니다
설명 반대 좌표에 있는 쿼드 호출의 e 값을 반환합니다. 즉:
  • ID 0과 3을 교환합니다.

  • ID 1과 2를 교환합니다.

17.13.3. quadSwapX

오버로드
@must_use fn quadSwapX(e : T) -> T
전제 조건 T구체 숫자 스칼라 또는 구체 숫자 벡터입니다
설명 같은 X 차원을 공유하는 쿼드 호출의 e 값을 반환합니다. 즉:
  • ID 0과 1을 교환합니다.

  • ID 2와 3을 교환합니다.

17.13.4. quadSwapY

오버로드
@must_use fn quadSwapY(e : T) -> T
전제 조건 T구체 숫자 스칼라 또는 구체 숫자 벡터입니다
설명 같은 Y 차원을 공유하는 쿼드 호출의 e 값을 반환합니다. 즉:
  • ID 0과 2를 교환합니다.

  • ID 1과 3을 교환합니다.

17.14. 버퍼 뷰 내장 함수

이러한 함수에는 모두 buffer_view 언어 기능이 필요합니다.

이러한 함수는 버퍼에 대한 포인터에서 작동합니다. bufferViewbufferArrayView는 버퍼의 불투명한 데이터를 다른 호스트 공유 가능 데이터 타입으로 재해석합니다. 결과 포인터는 다른 포인터처럼 사용할 수 있습니다.

ArrayOffset(T)을 다음과 같이 정의합니다.

MinTypeSize(T)을 다음과 같이 정의합니다.

함수 호출에 대한 버퍼 포인터 인수는 매개변수 타입으로 자동 변환될 수 있으므로, 구현은 유효하지 않은 메모리 참조를 검사하고 올바른 결과를 보장하기 위해 프로시저 간 분석을 사용합니다. 모든 버퍼 뷰 내장 함수에 사용되는 버퍼 크기는 호출에 사용된 특정 원본 변수에서 발견되는 최소 버퍼 크기입니다. 이는 동적 개념이므로 구현은 내장 함수의 특정 인스턴스에 대해 이 값이 올바르게 결정되도록 보장합니다. 크기는 다음 중 최솟값입니다.

참고: 구현이 unrestricted_pointer_parameters 언어 기능을 지원하지 않으면 내장 함수 인수의 루트 식별자원본 변수여야 합니다.

참고: 버퍼 크기는 함수에 전달될 때 더 크게 만들 수 없습니다.

17.14.1. bufferView

오버로드
@must_use fn bufferView<T>(p : ptr<AS, buffer, AM>, offset: I) -> ptr<AS, T, AM>
전제 조건 ASstorage, uniform 또는 workgroup 중 하나입니다.
AMAS에 유효한 액세스 모드입니다.

T호스트 공유 가능 타입입니다.
T원자 또는 버퍼 타입이거나 이를 포함해서는 안 됩니다.
TAS에 대한 주소 공간 레이아웃 제약 조건충족해야 합니다.

Iu32 또는 i32입니다.

설명 p 시작 지점에서 offset바이트 떨어진 메모리 뷰T 타입으로 재해석합니다. 즉, p와 연결된 메모리 위치가 [0, bufferLength(p)) 범위에 있으면 결과와 연결된 메모리 위치는 저장 타입이 T인 [offset, bufferLength(p)) 범위에 있습니다.

Ii32이면:

MinTypeSize(T) + offset > bufferLength(p)이면 유효하지 않은 포인터가 반환됩니다.

offset % RequiredAlignOf(T, AS) != 0 이면:

참고: 이는 uniform_buffer_standard_layout 언어 기능과 상호작용합니다.

오버로드
@must_use fn bufferView<T>(p : ptr<AS, buffer<N>, AM>, offset: I) -> ptr<AS, T, AM>
전제 조건 ASstorage, uniform 또는 workgroup 중 하나입니다.
AMAS에 유효한 액세스 모드입니다.

T호스트 공유 가능 타입입니다.
T원자 또는 버퍼 타입이거나 이를 포함해서는 안 됩니다.
TAS에 대한 주소 공간 레이아웃 제약 조건충족해야 합니다.

Iu32 또는 i32입니다.

설명 p 시작 지점에서 offset바이트 떨어진 메모리 뷰T 타입으로 재해석합니다. 즉, p와 연결된 메모리 위치가 [0, bufferLength(p)) 범위에 있으면 결과와 연결된 메모리 위치는 저장 타입이 T인 [offset, bufferLength(p)) 범위에 있습니다.

Ii32이면:

MinTypeSize(T) + offset > N이면 유효하지 않은 메모리 참조가 반환됩니다.

offset % RequiredAlignOf(T, AS) != 0이면:

참고: 이는 uniform_buffer_standard_layout 언어 기능과 상호작용합니다.

예제: WGSL bufferView 사용법
requires buffer_view;

@group(0) @binding(0) var<storage> in : buffer;
@group(0) @binding(1) var<storage, read_write> out : buffer;

struct S {
  a : mat3x3f,
  b : vec2f,
}

fn foo(offsets : array<u32, 4>) {
  // 데이터의 일부를 vec4u로 읽고 씁니다.
  let p1 = bufferView<vec4u>(&in, offsets[0]);
  *bufferView<vec4u>(&out, offsets[1]) = *p1;

  // 다른 데이터의 일부를 구조체를 통해 읽고 씁니다.
  let p2 = bufferView<array<S, 2>>(&in, offsets[2]);
  let v = (*p2)[1].a;
  *bufferView<mat3x3f>(&out, offsets[3]) = v;
}

17.14.2. bufferArrayView

오버로드
@must_use fn bufferArrayView<T>(p : ptr<AS, buffer, AM>,
                                offset: OI, size: SI) -> ptr<AS, T, AM>
전제 조건 ASstorage, uniform 또는 workgroup 중 하나입니다.
AMAS에 유효한 액세스 모드입니다.

T고정 풋프린트가 없는 호스트 공유 가능 타입입니다.
T원자 또는 버퍼 타입이거나 이를 포함해서는 안 됩니다.
TAS에 대한 주소 공간 레이아웃 제약 조건충족해야 합니다.

OIu32 또는 i32입니다.
SIu32 또는 i32입니다.

설명 p 시작 지점에서 offset바이트 떨어진 곳부터 size바이트에 해당하는 메모리 뷰T 타입으로 재해석합니다. 즉, p와 연결된 메모리 위치가 [0, bufferLength(p)) 범위에 있으면 결과와 연결된 메모리 위치는 저장 타입이 T인 [offset, offset + size) 범위에 있습니다.

OIi32이면:

SIi32이면:

MinTypeSize(T) > size이면 유효하지 않은 메모리 참조가 반환됩니다.

offset + size > bufferLength(p)이면 유효하지 않은 메모리 참조가 반환됩니다.

offset % RequiredAlignOf(T, AS) != 0이면:

참고: 이는 uniform_buffer_standard_layout 언어 기능과 상호작용합니다.

(size - ArrayOffset(T)) % StrideOf(array<E>) != 0이면:

오버로드
@must_use fn bufferArrayView<T>(p : ptr<AS, buffer<N>, AM>,
                                offset: OI, size: SI) -> ptr<AS, T, AM>
전제 조건 ASstorage, uniform 또는 workgroup 중 하나입니다.
AMAS에 유효한 액세스 모드입니다.

T고정 풋프린트가 없는 호스트 공유 가능 타입입니다.
T원자 또는 버퍼 타입이거나 이를 포함해서는 안 됩니다.
TAS에 대한 주소 공간 레이아웃 제약 조건충족해야 합니다.

OIu32 또는 i32입니다.
SIu32 또는 i32입니다.

설명 p 시작 지점에서 offset바이트 떨어진 곳부터 size바이트에 해당하는 메모리 뷰T 타입으로 재해석합니다. 즉, p와 연결된 메모리 위치가 [0, bufferLength(p)) 범위에 있으면 결과와 연결된 메모리 위치는 저장 타입이 T인 [offset, offset + size) 범위에 있습니다.

OIi32이면:

SIi32이면:

MinTypeSize(T) > size이면 유효하지 않은 메모리 참조가 반환됩니다.

offset + size > N이면 유효하지 않은 메모리 참조가 반환됩니다.

MinTypeSize(T) > N이면:

offset % RequiredAlignOf(T, AS) != 0이면:

참고: 이는 uniform_buffer_standard_layout 언어 기능과 상호작용합니다.

(size - ArrayOffset(T)) % StrideOf(array<E>) != 0이면:

예제: WGSL bufferArrayView 사용법
requires buffer_view;

const stride = 32;
const N = 4;
const size = 2048;
const_assert stride * N < size;

struct strided_u32 {
  @size(stride) a : u32,
}

@group(0) @binding(0) var<uniform> in : buffer<size>;
@group(0) @binding(1) var<storage, read_write> out: array<u32, N>;

fn foo(offsets : u32) {
  // in에서 스트라이드 배열을 읽고 스트라이드를 제거하여 out으로 복사합니다.
  var tmp : array<u32, N>;
  let view = bufferArrayView<array<strided_u32>>(&in, offset, stride * N);
  for (var i = 0; i < N; i++) {
    tmp[i] = (*view)[i];
  }
  out = tmp;
}

17.14.3. bufferLength

오버로드
@must_use fn bufferLength(p : ptr<AS, buffer,    AM>) -> u32
@must_use fn bufferLength(p : ptr<AS, buffer<N>, AM>) -> u32
전제 조건 ASstorage, uniform 또는 workgroup 중 하나입니다.
AMAS에 유효한 액세스 모드입니다.
설명 프로시저 간 분석 중 발견된 p가 가리키는 버퍼의 최소 크기를 반환하거나, 런타임 크기 버퍼만 발견된 경우 WebGPU GPUBuffer의 크기를 반환합니다.
예제: bufferLength 값
requires buffer_view;
requires unrestricted_pointer_parameters;

@group(0) @binding(0) var<storage> b1 : buffer<2048>;
@group(0) @binding(0) var<storage> b2 : buffer<4096>;

fn foobar(p : ptr<storage, buffer>) -> u32 {
  return bufferLength(p);
}
fn bar(p : ptr<storage, buffer<1024>>) -> u32 {
  return foobar(p);
}
fn foo(p : ptr<storage, buffer<256>>) -> u32 {
  return bufferLength(p);
}

@compute @workgroup_size(1)
fn main() {
  let len1 = bufferLength(&b1); // 2048
  let len2 = bufferLength(&b2); // 4096

  let len3 = foo(&b1); // 256
  let len4 = foo(&b2); // 256

  let len5 = bar(&b1); // 1024
  let len6 = bar(&b2); // 1024

  let len7 = foobar(&b1); // 2048
  let len8 = foobar(&b2); // 4096
}

18. 재귀 하강 파싱을 위한 문법

이 절은 비규범적입니다.

WGSL 문법은 LALR(1) 파서에 적합한 형식으로 지정됩니다. 구현에서는 대신 재귀 하강 파서를 사용할 수 있습니다.

여러 규칙이 좌재귀이므로 규범 문법을 재귀 하강 파서에서 직접 사용할 수 없습니다. 정의되는 비종단 기호가 생성 규칙 중 하나의 맨 처음에 나타나면 해당 문법 규칙은 직접 좌재귀입니다.

다음은 WGSL 문법을 기계적으로 변환하여 다음을 수행한 것입니다.

그러나 LL(1)은 아닙니다. 일부 비종단 기호에서는 여러 생성 규칙이 공통 미리보기 집합을 갖습니다. 예를 들어 attribute 비종단 기호의 모든 생성 규칙은 attr 토큰으로 시작합니다. 더 미묘한 예는 global_decl입니다. 여기서는 세 생성 규칙이 attribute * 구문으로 시작하지만 이후 fn, override, var 토큰으로 구분됩니다.

간결성을 위해 많은 토큰 정의는 반복하지 않습니다. 명세 본문의 토큰 정의를 사용하십시오.

additive_operator:

'+'

| '-'

argument_expression_list:

'(' ( expression ( ',' expression )* ',' ? )? ')'

assignment_statement/0.1:

compound_assignment_operator

| '='

attribute:

compute_attr

| const_attr

| fragment_attr

| interpolate_attr

| invariant_attr

| must_use_attr

| vertex_attr

| workgroup_size_attr

| '@' ident_pattern_token ( '(' ( expression ( ',' expression )* ',' ? )? ')' )?

| '@' 'align' '(' expression ',' ? ')'

| '@' 'binding' '(' expression ',' ? ')'

| '@' 'blend_src' '(' expression ',' ? ')'

| '@' 'builtin' '(' builtin_value_name ',' ? ')'

| '@' 'diagnostic' diagnostic_control

| '@' 'group' '(' expression ',' ? ')'

| '@' 'id' '(' expression ',' ? ')'

| '@' 'location' '(' expression ',' ? ')'

| '@' 'size' '(' expression ',' ? ')'

| '@' 'subgroup_size' '(' expression ',' ? ')'

bitwise_expression.post.unary_expression:

'&' unary_expression ( '&' unary_expression )*

| '^' unary_expression ( '^' unary_expression )*

| '|' unary_expression ( '|' unary_expression )*

bool_literal:

'false'

| 'true'

builtin_value_name: ident_pattern_token
call_expression.post.ident:

template_elaborated_ident.post.ident '(' ( expression ( ',' expression )* ',' ? )? ')'

case_selector:

expression

| 'default'

component_or_swizzle_specifier:

'.' member_ident component_or_swizzle_specifier ?

| '.' swizzle_name component_or_swizzle_specifier ?

| '[' expression ']' component_or_swizzle_specifier ?

compound_assignment_operator:

shift_left_assign

| shift_right_assign

| '%='

| '&='

| '*='

| '+='

| '-='

| '/='

| '^='

| '|='

compound_statement:

attribute * '{' statement * '}'

compute_attr:

'@' 'compute'

const_attr:

'@' 'const'

core_lhs_expression:

ident

| ident call_expression.post.ident

| '(' lhs_expression ')'

decimal_int_literal:

/0[iu]?/

| /[1-9][0-9]*[iu]?/

diagnostic_control:

'(' ident_pattern_token ',' diagnostic_rule_name ',' ? ')'

diagnostic_rule_name:

ident_pattern_token

| ident_pattern_token '.' ident_pattern_token

expression:

unary_expression bitwise_expression.post.unary_expression

| unary_expression relational_expression.post.unary_expression

| unary_expression relational_expression.post.unary_expression '&&' unary_expression relational_expression.post.unary_expression ( '&&' unary_expression relational_expression.post.unary_expression )*

| unary_expression relational_expression.post.unary_expression '||' unary_expression relational_expression.post.unary_expression ( '||' unary_expression relational_expression.post.unary_expression )*

float_literal:

decimal_float_literal

| hex_float_literal

for_init:

ident call_expression.post.ident

| variable_or_value_statement

| variable_updating_statement

for_update:

ident call_expression.post.ident

| variable_updating_statement

fragment_attr:

'@' 'fragment'

global_assert:

'const_assert' ';'

global_decl:

attribute * 'fn' ident '(' ( attribute * ident ':' type_specifier ( ',' param )* ',' ? )? ')' ( '->' attribute * ident template_elaborated_ident.post.ident )? attribute * '{' statement * '}'

| attribute * 'var' ( _template_args_start expression ( ',' expression )* ',' ? _template_args_end )? optionally_typed_ident ( '=' expression )? ';'

| global_value_decl ';'

| 'alias' ident '=' ident template_elaborated_ident.post.ident ';'

| 'struct' ident '{' attribute * member_ident ':' type_specifier ( ',' attribute * member_ident ':' type_specifier )* ',' ? '}'

global_directive:

'diagnostic' '(' ident_pattern_token ',' diagnostic_rule_name ',' ? ')' ';'

| 'enable' ident_pattern_token ( ',' ident_pattern_token )* ',' ? ';'

| 'requires' ident_pattern_token ( ',' ident_pattern_token )* ',' ? ';'

global_value_decl:

attribute * 'override' optionally_typed_ident ( '=' expression )?

| 'const' optionally_typed_ident '=' expression

ident:

ident_pattern_token

int_literal:

decimal_int_literal

| hex_int_literal

interpolate_attr:

'@' 'interpolate' '(' ident_pattern_token ',' ? ')'

| '@' 'interpolate' '(' ident_pattern_token ',' ident_pattern_token ',' ? ')'

invariant_attr:

'@' 'invariant'

lhs_expression:

core_lhs_expression component_or_swizzle_specifier ?

| '&' lhs_expression

| '*' lhs_expression

literal:

bool_literal

| float_literal

| int_literal

member_ident: ident_pattern_token
multiplicative_operator:

'%'

| '*'

| '/'

must_use_attr:

'@' 'must_use'

optionally_typed_ident:

ident ( ':' type_specifier )?

param:

attribute * ident ':' type_specifier

primary_expression:

ident template_elaborated_ident.post.ident

| ident template_elaborated_ident.post.ident argument_expression_list

| literal

| '(' expression ')'

relational_expression.post.unary_expression:

shift_expression.post.unary_expression

| shift_expression.post.unary_expression greater_than unary_expression shift_expression.post.unary_expression

| shift_expression.post.unary_expression greater_than_equal unary_expression shift_expression.post.unary_expression

| shift_expression.post.unary_expression less_than unary_expression shift_expression.post.unary_expression

| shift_expression.post.unary_expression less_than_equal unary_expression shift_expression.post.unary_expression

| shift_expression.post.unary_expression '!=' unary_expression shift_expression.post.unary_expression

| shift_expression.post.unary_expression '==' unary_expression shift_expression.post.unary_expression

shift_expression.post.unary_expression:

( multiplicative_operator unary_expression )* ( additive_operator unary_expression ( multiplicative_operator unary_expression )* )*

| shift_left unary_expression

| shift_right unary_expression

statement:

attribute * 'for' '(' for_init ? ';' expression ? ';' for_update ? ')' compound_statement

| attribute * 'if' expression compound_statement ( 'else' 'if' expression compound_statement )* ( 'else' compound_statement )?

| attribute * 'loop' attribute * '{' statement * ( 'continuing' attribute * '{' statement * ( 'break' 'if' expression ';' )? '}' )? '}'

| attribute * 'switch' expression attribute * '{' switch_clause * '}'

| attribute * 'while' expression compound_statement

| compound_statement

| ident template_elaborated_ident.post.ident argument_expression_list ';'

| variable_or_value_statement ';'

| variable_updating_statement ';'

| assert_statement ';'

| break_statement ';'

| continue_statement ';'

| ';'

| 'discard' ';'

| 'return' expression ? ';'

switch_clause:

'case' case_selector ( ',' case_selector )* ',' ? ':' ? compound_statement

| 'default' ':' ? compound_statement

swizzle_name:

/[rgba]/

| /[rgba][rgba]/

| /[rgba][rgba][rgba]/

| /[rgba][rgba][rgba][rgba]/

| /[xyzw]/

| /[xyzw][xyzw]/

| /[xyzw][xyzw][xyzw]/

| /[xyzw][xyzw][xyzw][xyzw]/

template_arg_expression: expression
template_elaborated_ident.post.ident:

( _template_args_start template_arg_expression ( ',' expression )* ',' ? _template_args_end )?

translation_unit:

global_directive * ( global_decl | global_assert | ';' ) *

translation_unit/0.1/0/0.0:

global_assert

| global_decl

| ';'

type_specifier:

ident ( _template_args_start template_arg_expression ( ',' expression )* ',' ? _template_args_end )?

unary_expression:

primary_expression component_or_swizzle_specifier ?

| '!' unary_expression

| '&' unary_expression

| '*' unary_expression

| '-' unary_expression

| '~' unary_expression

variable_decl:

'var' ( _template_args_start expression ( ',' expression )* ',' ? _template_args_end )? optionally_typed_ident

variable_or_value_statement:

variable_decl

| variable_decl '=' expression

| 'const' optionally_typed_ident '=' expression

| 'let' optionally_typed_ident '=' expression

variable_updating_statement:

lhs_expression ( '=' | compound_assignment_operator ) expression

| lhs_expression '++'

| lhs_expression '--'

| '_' '=' expression

vertex_attr:

'@' 'vertex'

workgroup_size_attr:

'@' 'workgroup_size' '(' expression ',' ? ')'

| '@' 'workgroup_size' '(' expression ',' expression ',' ? ')'

| '@' 'workgroup_size' '(' expression ',' expression ',' expression ',' ? ')'

부록 A: text/wgsl 미디어 타입

인터넷 할당 번호 관리 기관(IANA)은 [IANA-MEDIA-TYPES]에서 미디어 타입 레지스트리를 관리합니다.

다음은 WGSL 모듈을 위한 text/wgsl 미디어 타입의 정의입니다. 이 미디어 타입은 IANA에 등록되어 있으며, https://www.iana.org/assignments/media-types/text/wgsl에서 확인할 수 있습니다.

타입 이름

text

하위 타입 이름

wgsl

필수 매개변수

해당 없음

선택적 매개변수

없음

인코딩 고려사항

binary

WGSL은 바이트 순서 표시(BOM) 없이 UTF-8 인코딩을 사용하는 유니코드 텍스트입니다. § 3 텍스트 구조를 참조하십시오.

보안 고려사항:

WebGPU 셰이딩 언어(WGSL)는 WebGPU API의 문맥에서 실행되는 GPU 코드를 위한 프로그래밍 언어입니다. 보안 고려사항은 [WebGPU] 2.1절 보안 고려사항을 참조하십시오. 개인정보 보호 고려사항은 [WebGPU] 2.2절 개인정보 보호 고려사항을 참조하십시오.

상호운용성 고려사항:

WebGPU 구현은 서로 다른 기능을 가질 수 있으며, 이러한 차이는 WGSL 프로그램에서 사용할 수 있는 기능에 영향을 줄 수 있습니다. [WebGPU] 3.6절 선택적 기능과 § 4.1.2 언어 확장을 참조하십시오.

구현은 이 등록이 이후 버전의 WGSL에도 적용되는 것처럼 동작할 것으로 예상되며, 공개된 명세 참조도 이에 따라 수시로 갱신될 수 있습니다. 이러한 기대는 미디어 타입 등록에서는 이례적이지만 널리 사용되는 업계 관행과 일치합니다.

공개된 명세:

WebGPU 셰이딩 언어

이 미디어 타입을 사용하는 애플리케이션:

WebGPU 구현입니다. 웹 브라우저가 포함될 것으로 예상됩니다.

프래그먼트 식별자 고려사항

없음

추가 정보:

매직 넘버: 없음

파일 확장자: .wgsl

Macintosh 파일 타입 코드: TEXT

추가 정보를 문의할 사람 및 이메일 주소:

David Neto, dneto@google.com 또는 WGSL에 나열된 편집자입니다.

의도된 용도

COMMON

작성자

W3C. WGSL에 나열된 편집자를 참조하십시오.

변경 관리자

W3C

규범적 참고문헌

[WebGPU] W3C, “WebGPU” W3C 작업 초안, 2023년 1월. https://w3.org/TR/webgpu

WebGPU 셰이딩 언어 W3C, “WebGPU 셰이딩 언어” W3C 작업 초안, 2023년 1월. https://w3.org/TR/WGSL

적합성

문서 규칙

적합성 요구사항은 설명적 단언과 RFC 2119 용어의 조합으로 표현됩니다. 이 문서의 규범적 부분에 사용된 핵심어 “MUST”, “MUST NOT”, “REQUIRED”, “SHALL”, “SHALL NOT”, “SHOULD”, “SHOULD NOT”, “RECOMMENDED”, “MAY”, “OPTIONAL”은 RFC 2119에 설명된 대로 해석해야 합니다. 그러나 가독성을 위해 이 명세에서는 이러한 단어가 모두 대문자로 표시되지는 않습니다.

명시적으로 비규범적이라고 표시된 절, 예제 및 참고를 제외한 이 명세의 모든 텍스트는 규범적입니다. [RFC2119]

이 명세의 예제는 “예를 들어”라는 말로 소개되거나 다음과 같이 class="example"을 사용하여 규범적 텍스트와 구분됩니다.

정보 제공용 예제의 예입니다.

정보 제공용 참고는 “참고”라는 말로 시작하며 다음과 같이 class="note"을 사용하여 규범적 텍스트와 구분됩니다.

참고: 이는 정보 제공용 참고입니다.

적합한 알고리즘

알고리즘의 일부로 명령형으로 표현된 요구사항 (예: "앞쪽의 모든 공백 문자를 제거한다" 또는 "false를 반환하고 이 단계를 중단한다")은 해당 알고리즘을 소개할 때 사용된 핵심어 ("must", "should", "may" 등)의 의미로 해석해야 합니다.

알고리즘이나 구체적인 단계로 표현된 적합성 요구사항은 최종 결과가 동등하다면 어떤 방식으로든 구현할 수 있습니다. 특히 이 명세에 정의된 알고리즘은 이해하기 쉽도록 작성되었으며 성능을 목표로 하지 않습니다. 구현자는 최적화하는 것이 권장됩니다.

색인

이 명세에서 정의하는 용어

참조 문헌에서 정의하는 용어

참고문헌

규범적 참고문헌

[DeRemer1969]
LR(k) 언어를 위한 실용적 번역기. 1969년 10월 24일. URL: http://publications.csail.mit.edu/lcs/pubs/pdf/MIT-LCS-TR-065.pdf
[ECMASCRIPT]
ECMAScript 언어 명세. URL: https://tc39.es/ecma262/multipage/
[IEEE-754]
부동 소수점 산술을 위한 IEEE 표준. 2008년 8월 29일. URL: http://ieeexplore.ieee.org/servlet/opac?punumber=4610933
[Muller2005]
ulp(x)의 정의에 관하여. 2005년 2월. URL: https://inria.hal.science/inria-00070503
[RFC2119]
S. Bradner. 요구 수준을 나타내기 위해 RFC에서 사용하는 핵심어. 1997년 3월. 현행 모범 사례. URL: https://datatracker.ietf.org/doc/html/rfc2119
[UAX14]
Robin Leroy. 유니코드 줄 바꿈 알고리즘. 2025년 9월 5일. 유니코드 표준 부록 #14. URL: https://www.unicode.org/reports/tr14/tr14-55.html
[UAX31]
Mark Davis; Robin Leroy. 유니코드 식별자와 구문. 2025년 8월 20일. 유니코드 표준 부록 #31. URL: https://www.unicode.org/reports/tr31/tr31-43.html
[UnicodeVersion14]
유니코드 표준 버전 14.0.0. URL: http://www.unicode.org/versions/Unicode14.0.0/
[VanWyk2007]
Eric R. Van Wyk; August C. Schwerdfeger. 확장 가능한 언어 파싱을 위한 문맥 인식 스캐닝. 2007년. URL: https://dl.acm.org/doi/10.1145/1289971.1289983
[VulkanMemoryModel]
Jeff Bolz 외. Vulkan 메모리 모델. URL: https://www.khronos.org/registry/vulkan/specs/1.2-extensions/html/vkspec.html#memory-model
[WebGPU]
Kai Ninomiya; Brandon Jones; Myles C. Maxfield. WebGPU. 작업 초안. URL: https://w3.org/TR/webgpu

비규범적 참고문헌

[CHARMOD-NORM]
Addison Phillips 외. 월드 와이드 웹의 문자 모델: 문자열 일치. 2026년 7월 16일. 최초 공개 작업 초안. URL: https://www.w3.org/TR/charmod-norm/
[IANA-MEDIA-TYPES]
미디어 타입. URL: https://www.iana.org/assignments/media-types/
[Jeannerod2013]
Claude-Pierre Jeannerod; Nicolas Louvet; Jean-Michel Muller. 2x2 행렬식의 정확한 계산을 위한 Kahan 알고리즘의 추가 분석. URL: https://www.ams.org/journals/mcom/2013-82-284/S0025-5718-2013-02679-8/S0025-5718-2013-02679-8.pdf
[WASM-CORE-2]
Andreas Rossberg. WebAssembly 코어 명세. 2026년 8월 12일. 후보 권고 초안. URL: https://www.w3.org/TR/wasm-core-2/