WebGPU 셰이딩 언어

W3C 후보 권고안 초안,

이 문서에 대한 자세한 정보
이 버전:
https://www.w3.org/TR/2026/CRD-WGSL-20261026/
최신 공개 버전:
https://www.w3.org/TR/WGSL/
편집자 초안:
https://gpuweb.github.io/gpuweb/wgsl/
이전 버전:
이력:
https://www.w3.org/standards/history/WGSL/
피드백:
public-gpu@w3.org 제목 줄을 “[WGSL] … 메시지 주제 …”로 설정해 보내 주십시오. (보관함)
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를 사용하는 애플리케이션은 GPU에서 실행되는 셰이더라고 하는 프로그램을 WGSL을 사용하여 표현합니다.

// 점 광원으로 텍스처가 적용된 지오메트리를 조명하는 프래그먼트 셰이더입니다.

// 스토리지 버퍼 바인딩의 광원입니다.
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은 스칼라 유형을 벡터 유형으로 승격하는 제한적인 기능을 제공합니다. 이는 복합 유형에도 적용됩니다.

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

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

셰이더 스테이지 내의 호출은 동시에 실행되며 흔히 병렬로 실행될 수 있습니다. 셰이더 작성자는 셰이더 스테이지의 호출이 동적으로 다음을 수행하도록 보장할 책임이 있습니다.

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

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

1.2. 구문 표기법

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

1.3. 수학 용어 및 표기법

각도:

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

그러면 면적 a는 x가 a의 쌍곡코사인이고 y가 a의 쌍곡사인인 쌍곡각입니다.

양의 무한대는 +∞로 나타내며 모든 실수보다 엄격히 큰 고유한 값입니다.

음의 무한대는 −∞로 나타내며 모든 실수보다 엄격히 작은 고유한 값입니다.

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

구간은 하한과 상한을 가진 연속적인 숫자 집합입니다. 컨텍스트에 따라 정수, 부동 소수점 수, 실수 또는 확장 실수의 집합입니다.

바닥 함수 표현식은 확장 실수 x에 대해 다음과 같이 정의됩니다.

천장 함수 표현식은 확장 실수 x에 대해 다음과 같이 정의됩니다.

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

roundUp 함수는 양의 정수 k 및 n에 대해 다음과 같이 정의됩니다.

roundDown 함수는 양의 정수 k 및 n에 대해 다음과 같이 정의됩니다.

c열 r행 행렬 A의 전치는 A의 행을 AT의 열로 복사하여 만든 r열 c행 행렬 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. off 심각도를 가진 진단을 버립니다.

  3. 남은 진단 중 적어도 하나인 DI의 심각도가 info인 경우 다음을 수행합니다.

    • 트리거 규칙이 동일한 다른 info 진단은 원래 진단 DI만 남기고 버릴 수 있습니다.

  4. 남은 진단 중 적어도 하나인 DW의 심각도가 warning인 경우 다음을 수행합니다.

    • 트리거 규칙이 동일한 다른 info 또는 warning 진단은 원래 진단 DW만 남기고 버릴 수 있습니다.

  5. 남은 진단 중 적어도 하나의 심각도가 error인 경우 다음을 수행합니다.

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

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

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

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

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

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

§ 15.2 균일성을 참조하십시오.

subgroup_uniformity error 서브그룹 또는 쿼드 내장 함수에 대한 호출 위치. 서브그룹 또는 쿼드 내장 함수 호출이지만 균일성 분석이 해당 호출이 균일한 제어 흐름에서 발생함을 증명할 수 없습니다. 또한 균일성 분석이 다음 매개변수 값이 균일함을 증명할 수 없는 경우도 포함됩니다.

§ 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_clause 및 else_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 절, while 및 for 루프의 본문, 그리고 if_clause, else_if_clause 및 else_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 문에 대해 default 절을 포함한 case 값 수의 합입니다. 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) 파서(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 사용자 정의 불가능한 줄 바꿈 규칙의 LB4 및 LB5에 정의된 "강제 줄 바꿈"을 나타내는 공백으로 정의됩니다. 즉, 줄 바꿈은 다음 중 하나입니다.

참고: 소스 텍스트 위치를 줄 번호로 보고하는 진단은 줄을 계산할 때 줄 바꿈을 사용하는 것이 좋습니다.

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이 아닌 정수 리터럴 앞의 0(예: 012)은 금지됩니다. 이는 다른 언어의 선행 0이 8진수를 의미하는 표기법과의 혼동을 방지하기 위한 것입니다.

int_literal :

decimal_int_literal

| hex_int_literal

decimal_int_literal :

/0[iu]?/

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

예: 십진 정수 리터럴
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;

부동 소수점 리터럴은 십진 부동 소수점 리터럴 또는 16진 부동 소수점 리터럴입니다.

float_literal :

decimal_float_literal

| hex_float_literal

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

십진 부동 소수점 리터럴은 다음과 같습니다.

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]?/

예: 십진 부동 소수점 리터럴
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;
십진 부동 소수점 리터럴의 수학적 값은 다음과 같이 계산합니다.

참고: 십진 가수는 20개의 십진 숫자 이후에 잘리며 분수에 약 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_Start 및 XID_Continue의 모든 유효한 코드 포인트를 나열한 비규범적 목록이 포함되어 있습니다.

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

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 개념을 템플릿 매개변수 storage 및 read_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처럼 문자로 끝나기 때문에 알고리즘은 리터럴을 명시적으로 건너뜁니다. 끝의 f가 ident_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+003E) 코드 포인트(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 지시문은 하나 이상의 활성화 확장 지원을 켜는 지시문입니다. 구현이 나열된 모든 활성화 확장을 지원하지 않으면 셰이더 생성 오류가 발생합니다.

enable_directive :

'enable' enable_extension_list ';'

enable_extension_list :

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

다른 지시문과 마찬가지로 enable 지시문이 존재하는 경우 모든 선언 및 const 어설션보다 먼저 나타나야 합니다. 확장 이름은 식별자가 아닙니다: 선언으로 해석되지 않습니다.

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

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

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

// arbitrary_precision_float가 다음 사용을 활성화한다고 가정합니다:
//    - 유형 f<E,M>
//    - 함수 반환, 형식 매개변수 및 let 선언의 유형으로 사용
//    - AbstractFloat로부터의 값 생성자로 사용
//    - 나눗셈 연산자 /의 피연산자로 사용
// @rounding_mode 속성이 rounding_mode enable 지시문에 의해 활성화된다고 가정합니다.
@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 스토리지 텍스처와 함께 read 및 read_write 접근 모드를 사용할 수 있게 합니다. 또한 textureBarrier 내장 함수를 추가합니다.
packed_4x8_integer_dot_product dot4U8Packed 및 dot4I8Packed 내장 함수를 사용한 내적 명령의 입력으로 8비트 정수의 4구성요소 벡터를 패킹하는 32비트 정수 스칼라 사용을 지원합니다. 또한 pack4xI8, pack4xU8, pack4xI8Clamp, pack4xU8Clamp, unpack4xI8, 및 unpack4xU8 내장 함수를 사용하여 패킹된 8비트 정수의 4구성요소 벡터를 패킹 및 언패킹하는 명령을 추가합니다.
unrestricted_pointer_parameters 사용자 정의 함수에서 다음 제한을 제거합니다:

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

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

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

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

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

uniform_buffer_standard_layout uniform 주소 공간의 버퍼가 다른 주소 공간과 동일한 메모리 레이아웃 제약 조건을 사용할 수 있게 합니다.
subgroup_id subgroups 확장이 활성화된 경우 subgroup_id 및 num_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_index 및 workgroup_index 내장 값을 지원합니다.
immediate_address_space immediate 주소 공간을 활성화하여 변수를 var<immediate>로 선언하고 WebGPU API를 통해 명령 인코더에서 직접 전달되는 자주 갱신되는 소량의 데이터에 바인딩할 수 있게 합니다.
fragment_depth frag-depth 내장에 새로운 depth_mode 내장 매개변수를 도입하며, 모드로 less 및 greater를 제공합니다. 이는 프래그먼트 셰이더가 기존 깊이보다 작거나(또는 크거나) 하다고 보장되는 깊이 값만 기록한다고 선언할 때 사용됩니다.
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;의 축약형입니다.

atomic_vec2u_min_max atomic<vec2<u32>> 객체에서 atomicStoreMin 및 atomicStoreMax 내장 함수를 지원합니다.

참고: 의도는 시간이 지남에 따라 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 is bool or vecN<bool>
!e: T

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

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

규칙의 다른 조건을 만족하는 어떤 대입을 적용하여 매개변수화된 규칙에서 생성할 수 있는 각각의 완전히 구체화된 규칙을 매개변수화된 규칙의 오버로드라고 합니다. 예를 들어 불리언 부정 규칙에는 네 개의 오버로드가 있습니다. 이는 유형 매개변수 T에 유형을 할당하는 방법이 네 가지이기 때문입니다.

참고: 즉, 매개변수화된 유형 규칙은 완전히 구체화된 유형 규칙 집합을 위한 패턴을 제공하며, 각각은 매개변수화된 규칙에 서로 다른 대입을 적용하여 생성됩니다.

유형 규칙이 구문 구문에 적용된다고 하는 경우는 다음과 같습니다:

매개변수화된 유형 규칙은 표현식에 적용되는 완전히 구체화된 유형 규칙을 생성하는 대입이 존재하는 경우 그 표현식에 적용됩니다.

표현식 1u+2u를 생각해 보십시오. 여기에는 두 개의 리터럴 하위 표현식인 1u와 2u가 있으며, 둘 다 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 부동 소수점 평가에 설명된 제한 사항을 전제로 값을 보존합니다.

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

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

참고: 변환이 수행되지 않는 경우 변환 순위는 0입니다.

한 유형에서 다른 유형으로의 ConversionRank
Src Dest ConversionRank(Src,Dest) 설명
T T 0 항등 변환. 변환이 수행되지 않습니다.
ref<AS,T,AM>
주소 공간 AS에 대해, 그리고 접근 모드 AM이 read 또는 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>
여기서 N1과 N2는 모두 const 표현식이고 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_parameters 및 buffer_view 언어 기능이 필요합니다.

다음 조건을 만족하면 T 유형은 S 유형의 구체화입니다:

T 유형의 값 e의 값 구체화는 T를 T의 구체화로 매핑하는 실행 가능한 변환을 e에 적용한 결과 값입니다.

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

6.1.3. 오버로드 해석

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

구문 구문 P와 P에 적용되는 모든 유형 규칙을 고려합니다. 오버로드 해석 알고리즘은 이러한 유형 규칙을 오버로드 후보라고 합니다. 각 후보에 대해:

P에 대한 오버로드 해석은 하나의 가장 선호되는 오버로드 후보를 찾는 것을 목표로 다음과 같이 진행됩니다:

  1. 각 후보 C에 대해 구문 구문의 하위 표현식에 대한 변환 순위를 열거합니다. 후보의 전제 조건은 충족되었으므로 P의 i번째 하위 표현식에 대해 다음이 성립합니다:

    • 정적 유형이 계산되어 있습니다.

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

  2. 실행 가능한 자동 변환 후 하위 표현식 중 하나가 추상 유형으로 해석되지만 다른 하위 표현식 중 하나가 const 표현식이 아닌 모든 후보를 제거합니다.

    참고: 결과적으로 구문의 하위 표현식 중 하나라도 const 표현식이 아니라면, 구문의 모든 하위 표현식은 구체적 유형이어야 합니다.

  3. 후보의 순위를 매깁니다. 두 오버로드 후보 C1과 C2가 주어졌을 때, 다음 조건을 만족하면 C1은 C2보다 선호됩니다:

    • P의 각 표현식 위치 i에 대해 C1.R(i) ≤ C2.R(i).

      • 즉, C1을 P에 적용하는 데 필요한 각 표현식 변환이 C2를 P에 적용하는 데 필요한 해당 표현식 변환보다 적어도 같은 정도로 선호됩니다.

    • 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

// 접미사가 없는 정수 리터럴은 필요한 경우 부동 소수점으로 변환될 수 있습니다:
//   AbstractInt를 f32로 자동 변환하며 변환 순위는 5입니다.
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 유형은 true 및 false 값을 포함합니다.

불리언 리터럴 유형 규칙
전제 조건 결론 설명
true: bool true 값.
false: bool false 값.

6.2.3. 정수 유형

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

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

오버플로되는 구체적 정수 유형에 대한 표현식은 2bitwidth를 법으로 한 결과를 생성합니다.

정수 유형의 극값
유형 최솟값 최댓값
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> T 유형의 C열 R행 행렬이며, C와 R은 모두 {2, 3, 4} 중 하나이고 T는 f32, f16, 또는 AbstractFloat여야 합니다. 동등하게 vecR<T> 유형의 C개 열 벡터로 볼 수 있습니다.

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

곱셈 연산자(*)는 다음 중 하나에 사용됩니다:

§ 8.8 산술 표현식을 참조하십시오.

예: 행렬
mat2x3<f32>  // 32비트 부동 소수점의 2열 3행 행렬입니다.
             // 동등하게 vec3<f32> 유형의 열 벡터 2개입니다.

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 유형의 원자적 유형입니다. T는 u32 또는 i32 중 하나여야 합니다.
atomic<vec2<u32>> vec2<u32> 유형의 원자적 유형입니다. 이 유형의 값은 부호 없는 64비트 정수 유형을 나타내며, 하위 32비트는 벡터 구성 요소 0에, 상위 32비트는 벡터 구성 요소 1에 있습니다.

atomic_vec2u_min_max 확장으로 활성화됩니다.

표현식은 원자적 유형으로 평가되어서는 안 됩니다.

원자적 유형은 workgroup 주소 공간의 변수 또는 read_write 접근 모드를 가진 스토리지 버퍼 변수에 의해서만 인스턴스화될 수 있습니다. 저장 유형이 atomic<vec2<u32>>이거나 이를 포함하는 경우 변수는 storage 주소 공간에 있어야 합니다.

해당 유형에 대한 연산의 메모리 범위는 유형이 인스턴스화된 주소 공간에 따라 결정됩니다. workgroup 주소 공간의 원자적 유형은 Workgroup의 메모리 범위를 가지며, storage 주소 공간의 원자적 유형은 QueueFamily의 메모리 범위를 가집니다.

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

WGSL에서 원자적 수정은 각 객체별로 상호 순서가 정해집니다. 즉, 셰이더 스테이지 실행 중 각 원자적 객체 A에 대해 모든 에이전트는 A에 적용되는 수정 연산의 동일한 순서를 관찰합니다. 서로 다른 원자적 객체의 순서는 어떤 방식으로도 연관되지 않을 수 있으며, 인과 관계가 암시되지 않습니다. workgroup 공간의 변수는 워크그룹 내에서 공유되지만 서로 다른 워크그룹 간에는 공유되지 않는다는 점에 유의하십시오.

6.2.9. 배열 유형

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

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

배열의 첫 번째 요소는 인덱스 0에 있으며, 이후의 각 요소는 다음 정수 인덱스에 있습니다. § 8.5.3 배열 접근 표현식을 참조하십시오.

표현식은 런타임 크기 배열 유형으로 평가되어서는 안 됩니다.

고정 크기 배열의 요소 수 표현식 N에는 다음 제약 조건이 적용됩니다:

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

참고: 유형 동등성을 충족하려면 const 표현식이 아닌 모든 override 표현식은 식별자여야 합니다. 재정의 가능한 상수로 크기가 지정된 워크그룹 변수를 참조하십시오.

런타임 크기 배열의 요소 수는 해당 스토리지 버퍼 변수와 연결된 버퍼 바인딩의 크기에 따라 결정됩니다. § 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 스테이지 간 입력 및 출력 인터페이스를 참조하십시오.

align 및 size 속성은 레이아웃 속성이며, 구조체 유형이 유니폼 버퍼 또는 스토리지 버퍼를 정의하는 데 사용되는 경우 필요할 수 있습니다. § 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. 고정 풋프린트 유형

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

유형의 구체화 크기가 셰이더 생성 시점에 완전히 결정되면 해당 유형은 생성 시 고정 풋프린트를 가집니다.

유형의 크기가 파이프라인 생성 시점에 완전히 결정되면 해당 유형은 고정 풋프린트를 가집니다.

참고: 모든 구체적 생성 시 고정 풋프린트 및 고정 풋프린트 유형은 저장 가능합니다.

참고: 파이프라인 생성은 셰이더 생성에 의존하므로, 생성 시 고정 풋프린트를 가진 유형은 고정 풋프린트도 가집니다.

생성 시 고정 풋프린트를 가진 유형은 다음과 같습니다:

참고: 구성 가능한 유형은 생성 시 고정 풋프린트를 가집니다.

고정 풋프린트를 가진 유형은 다음 중 하나입니다:

참고: 요소 수가 const 표현식이 아닌 override 표현식인 고정 크기 배열의 유일한 유효한 사용은 workgroup 주소 공간의 메모리 뷰입니다. 여기에는 워크그룹 변수의 저장 유형이 포함됩니다.

참고: 고정 풋프린트 유형은 원자적 유형을 직접 또는 간접적으로 포함할 수 있지만 구성 가능한 유형은 그럴 수 없습니다.

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

6.3. 버퍼 유형

이러한 유형에는 buffer_view 언어 기능이 필요합니다.

버퍼 값은 내용이 다른 호스트 공유 가능 유형으로 해석될 수 있는 메모리를 나타냅니다. 그 외에는 버퍼 값은 불투명합니다. 변수의 데이터에 여러 다른 유형으로 접근해야 하거나 셰이더 작성자가 하나의 변수를 여러 논리 변수로 세분화하려는 경우에 유용합니다.

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

유형 설명
buffer<N> N바이트의 저장 공간을 가진 고정 크기 버퍼입니다.
N은 override 표현식이어야 합니다.
buffer 런타임 크기 버퍼입니다.

표현식은 버퍼 유형으로 평가되어서는 안 됩니다.

고정 크기 버퍼는 storage, uniform, 그리고 workgroup 주소 공간의 변수로만 인스턴스화할 수 있습니다. storage 및 uniform 주소 공간에서는 크기가 const 표현식이어야 합니다. 런타임 크기 버퍼는 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에 대응하며, 그 반대도 성립합니다. 여기서 p와 r은 동일한 메모리 뷰를 설명합니다.

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의 구성 요소 i는 u의 구성 요소 Idxi의 값과 같습니다. 인덱싱 구문을 사용하면: v[i] = u[Idxi]

알고리즘: SwizzleViewWrite

update 벡터의 구성 요소를 포인터 p가 참조하는 메모리의 벡터에서 지정된 구성 요소에 씁니다.

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

스위즐 뷰 쓰기가 균일성 분석 및 메모리 모델과 상호작용하는 방식에 대한 논의는 아래를 참조하십시오.

입력:

IndexList의 모든 인덱스는 서로 달라야 합니다. 이 요구 사항에 따라 K ≤ N입니다.

변수:

절차:

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

  2. 변수 new를 old_contents로 초기화합니다.

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

    • new의 구성 요소 Idxi를 update의 구성 요소 i 값으로 설정합니다. 인덱싱 구문을 사용하면: new[Idxi] = update[i].

  4. new를 p가 참조하는 메모리에 씁니다.

참고: 모든 Idxi가 서로 다르도록 요구하면 3단계에서 new의 각 구성 요소가 최대 한 번만 갱신됨이 보장됩니다.

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

vecN<S> 유형의 벡터 new를 형성합니다. 여기서 new의 구성 요소 i는 다음과 같습니다:

  • 0...K−1의 어떤 j에 대해 i = Idxj이면, update의 구성 요소 j.

  • 그렇지 않으면 old_contents의 구성 요소 i.

스위즐 뷰에는 스위즐 뷰 유형이 있습니다:

제약 조건 유형 설명
S는 구체적 스칼라 유형이고,
N과 K는 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 선언의 effective-value-type은 구체적인 구성 가능 유형
  // 또는 포인터 유형이어야 합니다. 따라서 스위즐 뷰 로드 규칙을 호출하여
  // 스위즐 뷰를 자동으로 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 {
  // return 문의 표현식 유형은 함수의 선언된 반환 유형과
  // 일치해야 하므로 'i32'여야 합니다.
  // 'age' 표현식의 유형은 ref<private,i32,read_write>입니다.
  // 참조의 저장 유형이 표현식에 필요한 유형과 일치하고
  // 다른 유형 규칙이 적용되지 않으므로 로드 규칙을 적용합니다.
  // 이 컨텍스트에서 'age'의 평가는 return 문이 실행되는 시점에
  // '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() {
  // 스토리지 메모리의 특정 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이 산출됩니다.
    // f32 값 1.0을 uv.x가 참조하는 스토리지 메모리 위치에 저장합니다.
    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이 산출됩니다.
    // f32 값 2.0을 uv[1]이 참조하는 스토리지 메모리 위치에 저장합니다.
    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)이 산출됩니다.
    // 값 (1.0, 2.0)을 uv가 참조하는 스토리지 메모리 위치에 저장합니다.
    *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이 산출됩니다.
    // f32 값 1.0을 uv.x가 참조하는 스토리지 메모리 위치에 저장합니다.
    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이 산출됩니다.
    // f32 값 2.0을 uv[1]이 참조하는 스토리지 메모리 위치에 저장합니다.
    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. 텍스처 및 샘플러 유형

텍셀은 텍스처의 독립적으로 접근 가능한 가장 작은 요소로 사용되는 스칼라 또는 벡터입니다. texel이라는 단어는 texture element의 줄임말입니다.

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

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

텍스처에는 다음 기능이 있습니다:

텍셀 형식

각 텍셀의 데이터 표현입니다. § 6.6.1 텍셀 형식을 참조하십시오.

차원성

그리드 좌표의 차원 수와 좌표를 해석하는 방식입니다. 차원 수는 1, 2 또는 3입니다. 대부분의 텍스처는 데카르트 좌표를 사용합니다. 큐브 텍스처에는 정사각형 면이 6개 있으며, 원점에서 원점을 중심으로 하는 큐브를 향하는 방향 벡터로 해석되는 3차원 좌표를 사용하여 샘플링됩니다.

GPUTextureViewDimension을 참조하십시오.

크기

각 차원에 따른 그리드 좌표의 범위입니다. 이는 밉 레벨의 함수입니다.

밉 레벨 수

밉 레벨 수는 샘플링된 텍스처 및 깊이 텍스처의 경우 최소 1이고, 스토리지 텍스처의 경우 1입니다.
밉 레벨 0에는 텍스처의 전체 크기 버전이 포함됩니다. 이후의 각 밉 레벨에는 이전 밉 레벨의 절반 크기(반올림 범위 내)로 필터링된 이전 밉 레벨 버전이 포함됩니다.
텍스처를 샘플링할 때 명시적 또는 암시적으로 계산된 세부 수준을 사용하여 텍셀 데이터를 읽을 밉 레벨을 선택합니다. 그런 다음 필터링을 통해 이를 결합하여 샘플링된 값을 생성합니다.

배열형

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

  • 비배열형 텍스처는 텍셀의 그리드입니다.

  • 배열형 텍스처는 텍셀 그리드의 동종 배열입니다.

배열 크기

텍스처가 배열형인 경우 동종 그리드의 수입니다.

샘플 수

텍스처가 멀티샘플링된 경우 샘플 수입니다.

텍스처의 각 텍셀은 고유한 논리적 텍셀 주소와 연결되며, 이는 다음을 가지는 정수 튜플입니다:

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

그 결과 셰이더는 텍스처 변수 내부의 텍셀 메모리에 직접 접근할 수 없습니다. 대신 불투명 핸들을 통해 접근이 중개됩니다:

이 방식으로 텍스처 유형에서 지원되는 연산 집합은 해당 텍스처 유형의 형식 매개변수를 가진 텍스처 내장 함수의 사용 가능 여부에 따라 결정됩니다.

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

텍스처 유형은 다음에 정의된 유형의 집합입니다:

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

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

텍셀 접근은 샘플러의 여러 속성을 통해 제어됩니다:

주소 지정 모드

텍스처 경계 및 범위를 벗어난 좌표를 처리하는 방식을 제어합니다. 각 텍스처 차원의 주소 지정 모드는 독립적으로 설정할 수 있습니다. WebGPU GPUAddressMode를 참조하십시오.

필터 모드

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

LOD 클램프

접근할 세부 수준의 최솟값과 최댓값을 제어합니다.

비교

비교 샘플러에 대해 수행할 비교 유형을 제어합니다. WebGPU GPUCompareFunction을 참조하십시오.

최대 이방성

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

샘플러는 WGSL 모듈에서 생성할 수 없으며, 해당 상태(예: 위에 나열된 속성)는 셰이더 내에서 불변이고 WebGPU API를 통해서만 설정할 수 있습니다.

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

참고: 샘플러 변수에 저장된 핸들은 셰이더에서 변경할 수 없습니다.

6.6.1. 텍셀 형식

WGSL에서 특정 텍스처 유형은 텍셀 형식으로 매개변수화됩니다.

텍셀 형식은 다음으로 특징지어집니다:

채널

각 채널에는 스칼라가 포함됩니다. 텍셀 형식에는 최대 네 개의 채널이 있습니다: r, g, b, 그리고 a. 일반적으로 각각 빨강, 초록, 파랑 및 알파 채널 개념에 대응합니다.

채널 형식

채널의 비트 수와 해당 비트를 해석하는 방식입니다.

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. 샘플링된 텍스처 유형

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

텍셀 형식은 텍스처 변수에 바인딩된 GPUTexture의 format 속성입니다. 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 이상입니다. 이름과 달리 샘플러와 함께 사용할 수 없습니다. 샘플 인덱스를 무시하면 각 논리적 텍셀 주소마다 사실상 여러 텍셀에 해당하는 데이터를 저장합니다.

텍셀 형식은 텍스처 변수에 바인딩된 GPUTexture의 format 속성입니다. 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, modf 및 atomicCompareExchangeWeak 내장 함수의 반환 유형도 미리 선언합니다. 그러나 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 불변 모듈 또는 함수 구성 가능 (구체적 또는 추상) 필수 const 표현식 아니요
override 불변 모듈 구체적 스칼라 선택 사항3 const 표현식 또는 override 표현식 아니요4
let 불변 함수 구체적 구성 가능 또는 포인터 유형. 또한 texture_and_sampler_let 기능이 지원되는 경우 텍스처 또는 샘플러 유형. 필수 const 표현식, override 표현식, 또는 런타임 표현식 아니요
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 const 표현식 또는 override 표현식 아니요
var<function>
var
가변 함수 구체적 구성 가능 선택 사항10 const 표현식, override 표현식, 또는 런타임 표현식 아니요
  1. const 선언만 추상 유형일 수 있으며, 이는 유형이 명시적으로 지정되지 않은 경우에만 가능합니다.

  2. 표현식의 유형은 유효 값 유형으로 실행 가능하게 변환될 수 있어야 합니다.

  3. 초기화자가 지정되지 않은 경우 파이프라인 생성 시점에 값을 제공해야 합니다.

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

  5. 스토리지 버퍼 및 스토리지 텍스처 중 read 이외의 접근 모드를 가진 것은 버텍스 셰이더 스테이지에서 정적으로 접근할 수 없습니다. WebGPU createBindGroupLayout()을 참조하십시오.

  6. 원자적 유형은 가변 스토리지 버퍼 또는 워크그룹 변수에만 나타날 수 있습니다.

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

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

  9. 가장 바깥쪽 배열의 요소 수 또는 버퍼의 크기는 override 표현식일 수 있습니다.

  10. 초기화자가 없으면 변수는 기본 초기화됩니다.

7.1. 변수와 값

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

변수 사용은 일반적으로 값 선언 사용보다 비용이 더 큽니다. 변수를 사용하려면 변수와 연결된 메모리 위치를 읽거나 쓰기 위한 추가 연산이 필요하기 때문입니다.

일반적으로 작성자는 다음 순서로 선언 사용을 선호하는 것이 좋으며, 가장 선호되는 옵션을 먼저 나열합니다:

이는 일반적으로 셰이더의 전반적인 성능을 가장 좋게 만듭니다.

7.2. 값 선언

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

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

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

7.2.1. const 선언

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);  // 4개 구성 요소를 가진 AbstractFloat 배열입니다:
                              // (4.0, 2.0, 4.0, 2.0).

7.2.2. override 선언

override 선언은 파이프라인 재정의 가능 상수 값의 이름을 지정합니다. override 선언은 모듈 범위에서만 선언되어야 합니다. 파이프라인 재정의 가능 상수의 값은 파이프라인 생성 시점에 고정됩니다. 값이 지정된 경우 WebGPU 파이프라인 생성 메서드가 제공한 값을 사용하고, 그렇지 않으면 구체화된 초기화 표현식의 값을 사용합니다. override 선언의 유효 값 유형은 구체적 스칼라 유형이어야 합니다.

초기화 표현식은 선택 사항입니다. 존재하는 경우 override 표현식이어야 하며 파이프라인 재정의 가능 상수 기본값을 나타냅니다. 초기화자가 지정되지 않았고 파이프라인 생성 시점에 값도 제공되지 않으면 파이프라인 생성 오류입니다.

선언에 id 속성이 적용된 경우 리터럴 피연산자를 파이프라인 상수 ID라고 하며, 0 이상 65535 이하의 고유한 정수여야 합니다. 즉, 두 override 선언은 동일한 파이프라인 상수 ID를 사용해서는 안 됩니다.

애플리케이션은 파이프라인 생성 시점에 override 선언에 자체 값을 지정할 수 있습니다. 파이프라인 생성 API는 재정의 가능한 상수에서 해당 상수 유형의 값으로의 매핑을 받습니다. 상수는 파이프라인 재정의 가능 상수 식별자 문자열로 식별됩니다. 이는 파이프라인 상수 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, workgroup 및 handle 주소 공간의 변수는 모듈 범위에서만 선언해야 하며, 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 리소스 인터페이스에 설명된 대로 유니폼 버퍼, 스토리지 버퍼, 텍스처 및 샘플러는 셰이더의 리소스 인터페이스를 구성합니다.

변수의 수명은 셰이더 실행 중 메모리 위치가 변수와 연결되는 기간입니다. 모듈 범위 변수의 수명은 셰이더 스테이지 실행 전체입니다. 각 호출에는 private 및 function 주소 공간의 변수에 대해 독립적인 버전이 있습니다. 함수 범위 변수는 동적 컨텍스트입니다. 함수 범위 변수의 수명은 그 범위에 따라 결정됩니다:

두 리소스 변수의 메모리 위치가 겹칠 수 있지만, 두 변수 중 하나라도 가변이면 동적 오류입니다. 수명이 겹치는 다른 변수들은 메모리 위치가 서로 겹치지 않습니다. 변수의 수명이 끝나면 해당 메모리를 다른 변수에 사용할 수 있습니다.

참고: 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. 표현식

표현식은 값이 계산되는 방식을 지정합니다.

서로 다른 종류의 값 표현식은 평가되는 시점과 표현력 사이에 절충 관계를 제공합니다. 평가 시점이 빠를수록 연산에 더 많은 제약이 있지만, 값을 사용할 수 있는 위치도 더 많아집니다. 이러한 절충 관계로 인해 각 종류의 값 선언마다 서로 다른 유연성을 갖게 됩니다. const 표현식과 override 표현식은 GPU에서 실행되기 전에 평가되므로 최종 GPU 코드에는 표현식 계산 결과만 필요합니다. 또한 const 표현식은 셰이더 생성 시점에 평가되므로 override 표현식보다 더 많은 상황에서 사용할 수 있습니다. 예를 들어 함수 범위 변수의 배열 크기를 지정할 수 있습니다. 런타임 표현식은 const 표현식도 override 표현식도 아닌 표현식입니다. 런타임 표현식은 셰이더 실행 중 GPU에서 계산됩니다. 런타임 표현식은 더 적은 문법 요소에서 사용할 수 있지만, 다른 런타임 값과 같은 더 광범위한 표현식에서 계산될 수 있습니다.

8.1. 조기 평가 표현식

WGSL은 런타임 전에 평가할 수 있는 두 종류의 표현식을 정의합니다:

8.1.1. const 표현식

셰이더 생성 시점에 평가할 수 있는 표현식을 const 표현식이라고 합니다. 표현식의 모든 식별자가 다음으로 해석되면 해당 표현식은 const 표현식입니다:

const 표현식의 유형은 생성 시 고정 풋프린트를 가진 유형으로 해석되어야 합니다.

참고: 추상 유형은 const 표현식의 추론된 유형이 될 수 있습니다.

const 표현식 E는 다음 중 하나인 경우에만 평가됩니다:

참고: 평가 규칙은 하위 표현식 중 정적 유형을 결정하기 위해 평가해야 하는 것이 없는 한, 단락 평가 연산자 && 및 ||가 오른쪽 피연산자 하위 표현식의 평가를 차단함을 의미합니다.

const 표현식은 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 표현식

파이프라인 생성 시점에 평가할 수 있는 표현식을 override 표현식이라고 합니다. 표현식의 모든 식별자가 다음으로 해석되면 해당 표현식은 override 표현식입니다:

참고: 모든 const 표현식은 override 표현식이기도 합니다.

const 표현식이 아닌 override 표현식은 파이프라인 생성 중에만 검증되거나 평가되며, API가 제공한 값이 override 선언에 대입된 후에만 처리됩니다. override 선언의 값이 API를 통해 대입된 경우, 초기화 표현식이 있더라도 평가되지 않습니다. 그렇지 않으면 override 표현식 E는 다음 조건을 만족하는 경우에만 평가됩니다:

참고: 모든 override 표현식을 override 선언의 초기화자로 사용할 수 있는 것은 아닙니다. 이러한 초기화자는 해석 결과가 구체적 스칼라 유형이어야 하기 때문입니다.

예: override x = 42;는 다음과 같이 분석됩니다:

예: let y = x + 1;은 다음과 같이 분석됩니다:

예: vec3(x,x,x)는 다음과 같이 분석됩니다:

예: override 표현식으로 인한 셰이더 생성 오류
override a : i32 = 0;
override b = a / 0; // 셰이더 생성 오류이며,
                    // c 재정의를 시도하는지 여부와 관계없습니다.
예: override 표현식으로 인한 파이프라인 생성 오류
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 추상 부동 소수점 리터럴 값.
e가 i 접미사가 있는 정수 리터럴 e: i32 32비트 부호 있는 정수 리터럴 값.
e가 u 접미사가 있는 정수 리터럴 e: u32 32비트 부호 없는 정수 리터럴 값.
e가 f 접미사가 있는 부동 소수점 리터럴 e: f32 32비트 부동 소수점 리터럴 값.
e가 h 접미사가 있는 부동 소수점 리터럴 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는 const 표현식
e[i]: T 벡터의 i번째 구성 요소를 선택합니다.
첫 번째 구성 요소의 인덱스는 i=0입니다.

i가 [0,N-1] 범위를 벗어나면 셰이더 생성 오류입니다.

참고: 추상 벡터 값 e를 const 표현식이 아닌 표현식으로 인덱싱하면, 인덱스를 적용하기 전에 벡터가 구체화됩니다.

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구성요소 벡터를 계산합니다.
문자 z는 N이 3 또는 4일 때만 유효합니다.
문자 w는 N이 4일 때만 유효합니다.
e: vecN<T>
I는 문자 r, g, b 또는 a
J는 문자 r, g, b 또는 a
e.IJ: vec2<T>
첫 번째 구성 요소가 e.I, 두 번째 구성 요소가 e.J인 2구성요소 벡터를 계산합니다.
문자 b는 N이 3 또는 4일 때만 유효합니다.
문자 a는 N이 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구성요소 벡터를 계산합니다.
문자 z는 N이 3 또는 4일 때만 유효합니다.
문자 w는 N이 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구성요소 벡터를 계산합니다.
문자 b는 N이 3 또는 4일 때만 유효합니다.
문자 a는 N이 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구성요소 벡터를 계산합니다.
문자 z는 N이 3 또는 4일 때만 유효합니다.
문자 w는 N이 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구성요소 벡터를 계산합니다.
문자 b는 N이 3 또는 4일 때만 유효합니다.
문자 a는 N이 4일 때만 유효합니다.
벡터 메모리 뷰 분해: 스위즐 대입이 지원되지 않을 때의 다중 구성 요소 선택
전제 조건 결론 설명
swizzle_assignment가 지원되지 않음

pr: ref<AS,vecN<T,AM>> 또는 ptr<AS,vecN<T,AM>>
I는 문자 x, y, z 또는 w
J는 문자 x, y, z 또는 w
AM은 read 또는 read_write

pr.IJ: vec2<T>
평가 시점에 pr이 참조하는 메모리 위치에 저장된 벡터를 e라고 할 때, e.IJ를 계산합니다.

문자 z는 N이 3 또는 4일 때만 유효합니다.
문자 w는 N이 4일 때만 유효합니다.

swizzle_assignment가 지원되지 않음

pr: ref<AS,vecN<T,AM>> 또는 ptr<AS,vecN<T,AM>>
I는 문자 r, g, b 또는 a
J는 문자 r, g, b 또는 a
AM은 read 또는 read_write

pr.IJ: vec2<T>
평가 시점에 pr이 참조하는 메모리 위치에 저장된 벡터를 e라고 할 때, e.IJ를 계산합니다.

문자 b는 N이 3 또는 4일 때만 유효합니다.
문자 a는 N이 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
AM은 read 또는 read_write

pr.IJK: vec3<T>
평가 시점에 pr이 참조하는 메모리 위치에 저장된 벡터를 e라고 할 때, e.IJK를 계산합니다.

문자 z는 N이 3 또는 4일 때만 유효합니다.
문자 w는 N이 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
AM은 read 또는 read_write

pr.IJK: vec3<T>
평가 시점에 pr이 참조하는 메모리 위치에 저장된 벡터를 e라고 할 때, e.IJK를 계산합니다.

문자 b는 N이 3 또는 4일 때만 유효합니다.
문자 a는 N이 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
AM은 read 또는 read_write

pr.IJKL: vec4<T>
평가 시점에 pr이 참조하는 메모리 위치에 저장된 벡터를 e라고 할 때, e.IJKL를 계산합니다.

문자 z는 N이 3 또는 4일 때만 유효합니다.
문자 w는 N이 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
AM은 read 또는 read_write

pr.IJKL: vec4<T>
평가 시점에 pr이 참조하는 메모리 위치에 저장된 벡터를 e라고 할 때, e.IJKL를 계산합니다.

문자 b는 N이 3 또는 4일 때만 유효합니다.
문자 a는 N이 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> 결과는 e의 i번째 열 벡터입니다.

i가 [0,C-1] 범위를 벗어나면:

e: matCxR<T>
i: i32 또는 u32
T는 추상
i는 const 표현식
e[i]: vecR<T> 결과는 e의 i번째 열 벡터입니다.

i가 [0,C-1] 범위를 벗어나면 셰이더 생성 오류입니다.

참고: 추상 행렬 값 e를 const 표현식이 아닌 표현식으로 인덱싱하면, 인덱스를 적용하기 전에 행렬이 구체화됩니다.

행렬에 대한 메모리 뷰에서 열 벡터에 대한 참조 얻기
전제 조건 결론 설명
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 결과는 배열 값 e의 i번째 요소 값입니다.

i가 [0,N-1] 범위를 벗어나면:

e: array<T,N>
i: i32 또는 u32
T는 추상
i는 const 표현식
e[i] : T 결과는 배열 값 e의 i번째 요소 값입니다.

i가 [0,N-1] 범위를 벗어나면 셰이더 생성 오류입니다.

참고: 추상 배열 값 e를 const 표현식이 아닌 표현식으로 인덱싱하면, 인덱스를 적용하기 전에 배열이 구체화됩니다.

배열에 대한 메모리 뷰에서 배열 요소에 대한 참조 얻기
전제 조건 결론 설명
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은 S의 멤버 식별자 이름이며 유형은 T
e: S
e.M: T 결과는 구조체 값 e에서 이름이 M인 멤버의 값입니다.
구조체에 대한 메모리 뷰에서 구조체 멤버에 대한 참조 얻기
전제 조건 결론 설명
S는 구조체 유형
M은 S의 멤버 식별자 이름이며 유형은 T
r: ref<AS,S,AM> 또는
ptr<AS,S,AM>
r.M: ref<AS,T,AM> 구조체에 대한 메모리 뷰가 주어지면 결과는 식별자 이름이 M인 구조체 멤버에 대한 참조입니다.
결과 참조의 기원 변수는 r의 기원 변수와 같습니다.

8.6. 스위즐 뷰 표현식

스위즐 뷰 표현식은 swizzle_assignment 언어 확장에 의해 활성화됩니다.

스위즐 뷰는 다음 방식으로 형성됩니다:

이 규칙에 따라 스위즐 뷰의 인덱스 목록 부분은 셰이더 생성 시점에 완전히 결정됩니다.

이 절에서는 스위즐 인덱스 함수 SI를 다음과 같이 정의합니다:

다음 조건을 만족하면 스위즐 이름 Z가 K개의 인덱스 « Idx0, ..., IdxK−1 »를 나타낸다고 합니다:

참고: 예를 들어 스위즐 wzyx는 네 개의 인덱스 «3, 2, 1, 0»을 나타내고, 스위즐 rb는 두 개의 인덱스 «0, 2»를 나타냅니다. 스위즐 rgbz는 rgba와 xyzw 문자를 혼합하므로 어떤 인덱스 시퀀스도 나타내지 않습니다.

참조에서 스위즐 뷰 형성
전제 조건 결론 설명
swizzle_assignment이 지원됨

r: ref<AS,T,read_write>
T는 vecN<S>
스위즐 이름 Z는 K개의 인덱스 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>
스위즐 이름 Z는 K개의 인덱스 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>
스위즐 이름 Z는 KZ개의 인덱스 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 논리 부정입니다. e가 false이면 결과는 true이고 e가 true이면 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"입니다. e1과 e2가 모두 true이면 true를 산출하며, e1이 true인 경우에만 e2를 평가합니다.
e1: T
e2: T
T는 bool 또는 vecN<bool>
e1 | e2: T 논리 "or"입니다. T가 벡터이면 구성 요소별로 적용됩니다. e1과 e2를 모두 평가합니다.
e1: T
e2: T
T는 bool 또는 vecN<bool>
e1 & e2: T 논리 "and"입니다. T가 벡터이면 구성 요소별로 적용됩니다. e1과 e2를 모두 평가합니다.

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가 부호 있는 정수 스칼라 유형이면 e1과 e2를 한 번씩 평가하고 다음과 같이 평가됩니다:

참고: 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>
행렬 덧셈: 결과는 구성 요소별로 계산되며, 결과의 열 i는 e1[i] + e2[i]입니다.
e1 - e2: matCxR<T> 행렬 뺄셈: 결과는 구성 요소별로 계산되며, 결과의 열 i는 e1[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>
선형 대수 행렬-열 벡터 곱: 결과의 구성 요소 i는 dot(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
T는 S 또는 vecN<S>
T가 벡터이면 TB는 vecN<bool>,
그렇지 않으면 TB는 bool
e1 == e2: TB 동등 비교입니다. T가 벡터이면 구성 요소별로 적용됩니다.
e1: T
e2: T
S는 AbstractInt, AbstractFloat, bool, 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가 벡터이면 구성 요소별로 적용됩니다.
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
T는 S 또는 vecN<S>
T가 S이면 TS는 u32, 그렇지 않으면 TS는 vecN<u32>
e1 << e2: T 왼쪽 시프트(시프트되는 값은 구체적):

e1을 왼쪽으로 시프트하여 최하위 위치에 0 비트를 삽입하고 최상위 비트를 버립니다.

시프트할 비트 수는 e2의 값을 e1의 비트 너비로 나눈 나머지입니다.
e2가 e1의 비트 너비보다 크거나 같으면:

e1과 e2가 모두 셰이더 실행 시작 전에 알려진 경우, 결과는 오버플로해서는 안 됩니다:

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
T는 S 또는 vecN<S>
T가 S이면 TS는 u32, 그렇지 않으면 TS는 vecN<u32>
e1 >> e2: T 오른쪽 시프트(시프트되는 값은 구체적).

e1을 오른쪽으로 시프트하여 최하위 비트를 버립니다.

S가 부호 없는 유형이면 최상위 위치에 0 비트를 삽입합니다.

S가 부호 있는 유형이면:

  • e1이 음수이면 삽입되는 각 비트는 1이며 결과도 음수입니다.

  • 그렇지 않으면 삽입되는 각 비트는 0입니다.

시프트할 비트 수는 e2의 값을 e1의 비트 너비로 나눈 나머지입니다.

e2가 e1의 비트 너비보다 크거나 같으면:

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. 변수 식별자 표현식

변수 이름에서 참조 얻기
전제 조건 결론 설명
v는 주소 공간 AS에서 선언되고 저장 유형 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이 무효 메모리 참조이면 결과 포인터도 무효 메모리 참조입니다.

AS가 handle 주소 공간이면 셰이더 생성 오류입니다.

r이 벡터 구성 요소에 대한 참조이면 셰이더 생성 오류입니다.

8.15. 간접 참조 표현식

간접 참조 연산자는 포인터를 대응하는 참조로 변환합니다.

포인터에서 참조 얻기
전제 조건 결론 설명
p: ptr<AS,T,AM> *p: ref<AS,T,AM> 결과는 포인터 값 p와 동일한 메모리 뷰에 대응하는 참조 값입니다.

p가 무효 메모리 참조이면 결과 참조도 무효 메모리 참조입니다.

8.16. 값 선언을 위한 식별자 표현식

const, override 또는 let으로 선언된 식별자의 값 얻기
전제 조건 결론 설명
c는 유형 T의 const 선언으로 해석되는 범위 안의 식별자 c: T 결과는 초기화 표현식에 대해 계산된 값입니다. 표현식은 const 표현식이며 셰이더 생성 시점에 평가됩니다.
c는 유형 T의 override 선언으로 해석되는 범위 안의 식별자 c: T 파이프라인 생성에서 상수 ID에 대한 값을 지정한 경우 결과는 해당 값입니다. 이 값은 서로 다른 파이프라인 인스턴스에서 다를 수 있습니다.

그렇지 않으면 결과는 초기화 표현식에 대해 계산된 값입니다. 파이프라인 재정의 가능 상수는 모듈 범위에 나타나므로 셰이더 실행이 시작되기 전에 평가가 이루어집니다.

참고: API 호출에서 초기값이 지정되지 않았고 let 선언에 초기화 표현식도 없으면 파이프라인 생성이 실패합니다.

c는 유형 T의 let 선언으로 해석되는 범위 안의 식별자 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_statement는 continuing 문의 본문을 형성하고 끝에 선택적인 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는 쓰기 가능한 주소 공간,
접근 모드 AM은 write 또는 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. 다음과 같이 update 벡터를 계산합니다.
  //           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); }
여기서 식별자 c0와 p는 프로그램의 다른 모든 식별자와 다르도록 선택합니다.

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

유형 규칙 전제 조건: 각 if 및 else 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의 표현식은 const 표현식이어야 합니다.

같은 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 선택자에서 const 표현식을 사용할 수 있습니다.
    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 ( 초기화자 ; 조건 ; 갱신_부분 ) { 본문 }

조건 표현식이 존재하는 경우 for 문은 다음 형태의 루프로 디슈거링됩니다:

{
초기화자 ;
loop {
if !(조건) { break; }
본문
continuing { 갱신_부분 }
}
}
조건 표현식이 없는 경우 for 문은 다음 형태의 루프로 디슈거링됩니다:
{
초기화자 ;
loop {
본문
continuing { 갱신_부분 }
}
}

또한:

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, while 및 switch 문 안에서만 사용해야 합니다.

break 문은 루프의 continuing 문에서 빠져나가게 되는 위치에 배치해서는 안 됩니다. 대신 break-if 문을 사용하십시오.

예: continuing 절에서 잘못된 WGSL 루프 break
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 문에서 사용되는 선언을 지나 제어를 이동하게 되는 위치에 배치해서는 안 됩니다.

참고: continue는 continuing 문 안에 중첩된 다른 루프 내부에서 제어 흐름을 이동하는 데 사용하는 경우에만 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);

  // 값을 1로 설정하고 빨간색을 출력하지만 도우미 함수가
  // discard 문을 실행하지 않은 경우에만 그렇게 합니다.
  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. 규칙

제어 흐름에 영향을 미치는 일부 문은 특정 컨텍스트에서만 유효합니다. 예를 들어 continue는 loop, 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
B1 ∪ B2
loop {s1 continuing {s2}} s1: B1
s2: B2
B1 = {Return}
{Continue, Return} 중 어느 것도 B2에 없음
{Return}
s1: B1
s2: B2
B1 ≠ {Return}
{Continue, Return} 중 어느 것도 B2에 없음
Break가 (B1 ∪ B2)에 없음
(B1 ∪ B2)∖{Continue, Next}
s1: B1
s2: B2
B1 ≠ {Return}
{Continue, Return} 중 어느 것도 B2에 없음
Break가 (B1 ∪ B2)에 있음
(B1 ∪ B2 ∪ {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}
    }
  }            // 동작: {Next}, switch가 Break를 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는 유효하지 않습니다.
continue를 break로 바꾸어도 같은 이유로 동일한 예가 유효하지 않습니다.

10. 어설션

어설션은 불리언 조건이 충족되는지 확인하는 검사입니다.

global_assert :

const_assert ';'

WGSL은 한 종류의 어설션을 정의합니다: const 어설션.

const_assert :

'const_assert' expression

유형 규칙 전제 조건: 표현식은 bool 유형이어야 합니다.

10.1. 상수 어설션 문

const 어설션 문은 표현식이 false로 평가되면 셰이더 생성 오류를 발생시키는 어설션입니다. 표현식은 const 표현식이어야 합니다. 이 문은 셰이더의 정적 접근 조건을 충족할 수 있지만, 그 밖에는 컴파일된 셰이더에 영향을 주지 않습니다. const 어설션은 모듈 범위 또는 함수 범위 문으로 나타날 수 있습니다.

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; // 유효하지 않으며 표현식은 const 표현식이어야 합니다.
}

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 문법 규칙 인스턴스에서 첫 번째 토큰의 위치입니다. 호출 위치는 동적 컨텍스트입니다. 따라서 같은 텍스트 위치가 여러 호출 위치를 나타낼 수 있습니다.

참고: 쿼드의 모든 호출이 discard된 경우 프래그먼트 셰이더의 함수 호출이 반환되지 않을 수 있습니다. 이러한 경우 제어는 호출 함수로 다시 이동하지 않습니다.

11.3. const 함수

const 속성으로 선언된 함수는 셰이더 생성 시점에 평가할 수 있습니다. 이러한 함수를 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); // const 표현식은
                                 // override 표현식에서 사용할 수 있습니다.
                                 // 이 컨텍스트에서 firstLeadingBit(x)는
                                 // const 표현식이 아닙니다.

fn foo() {
  var a : array<i32, firstLeadingBit(257)>; // 모든 매개변수가 const 표현식이면
                                            // const 함수를 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)이 유형 T인 S의 멤버에 적용되고, S가 주소 공간 AS의 변수에 대한 저장 유형이 될 수 있으며, AS가 uniform이 아닌 경우, n은 다음을 만족해야 합니다:
어떤 양의 정수 k에 대해 n = k × RequiredAlignOf(T,AS).

정렬 및 크기 규칙은 상호 재귀적입니다. 그러나 위 제약 조건은 중첩된 유형의 필수 정렬에 의존하고, 유형은 제한된 중첩 깊이를 가지므로 잘 정의됩니다.

uniform 또는 storage 버퍼에 바인딩된 메모리의 시작 주소가 속성에 지정된 값보다 낮은 정렬을 가지면, 결과 정렬은 두 값 중 최소값이 됩니다. 구현은 변수의 기준 주소에 상대해서만 속성을 충족합니다.

§ 14.4 메모리 레이아웃을 참조하십시오.

매개변수 const 표현식이어야 하며, i32 또는 u32로 해석되어야 합니다.
양수여야 합니다.
2의 거듭제곱이어야 합니다.

12.2. binding

binding_attr :

'@' 'binding' '(' expression ',' ? ')'

binding 속성
설명 바인드 그룹에서 리소스의 바인딩 번호를 지정합니다. § 13.3.2 리소스 인터페이스를 참조하십시오.

리소스 변수에만 적용해야 합니다.

매개변수 const 표현식이어야 하며, i32 또는 u32로 해석되어야 합니다.
음수가 아니어야 합니다.

12.3. blend_src

blend_src_attr :

'@' 'blend_src' '(' expression ',' ? ')'

blend_src 속성
설명 dual_source_blending 기능이 활성화되었을 때 프래그먼트 출력의 일부를 지정합니다. § 13.3.1.3 입출력 위치를 참조하십시오.

location 속성이 있는 구조체 유형의 멤버에만 적용해야 합니다. 숫자 스칼라 또는 숫자 벡터 유형의 객체 선언에만 적용해야 합니다. 셰이더 스테이지 입력에 포함해서는 안 됩니다. 프래그먼트 셰이더 스테이지를 제외하고 셰이더 스테이지 출력에 포함해서는 안 됩니다.

매개변수 값이 0 또는 1인 i32 또는 u32로 해석되는 const 표현식이어야 합니다.

12.4. builtin

builtin_attr :

'@' 'builtin' '(' builtin_value_name ',' ? ')'

builtin 속성
설명 연결된 객체가 지정된 토큰으로 표시되는 내장 값임을 지정합니다. § 13.3.1.1 내장 입력 및 출력을 참조하십시오.

진입점 함수 매개변수, 진입점 반환 유형 또는 구조체의 멤버에만 적용해야 합니다.

매개변수 내장 값에 대한 내장 값 이름 토큰이어야 합니다.

12.5. const

const_attr :

'@' 'const'

const 속성
설명 함수가 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 리소스 인터페이스를 참조하십시오.

리소스 변수에만 적용해야 합니다.

매개변수 const 표현식이어야 하며, i32 또는 u32로 해석되어야 합니다.
음수가 아니어야 합니다.

12.8. id

id_attr :

'@' 'id' '(' expression ',' ? ')'

id 속성
설명 파이프라인 재정의 가능 상수의 대체 이름으로 숫자 식별자를 지정합니다.

스칼라 유형의 override 선언에만 적용해야 합니다.

매개변수 const 표현식이어야 하며, 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 입출력 위치를 참조하십시오.

진입점 함수 매개변수, 진입점 반환 유형 또는 구조체 유형의 멤버에만 적용해야 합니다. 숫자 스칼라 또는 숫자 벡터 유형의 객체 선언에만 적용해야 합니다. 컴퓨트 셰이더 스테이지 입력에 포함해서는 안 됩니다.

매개변수 const 표현식이어야 하며, 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 메모리 레이아웃을 참조하십시오.

구조체 유형의 멤버에만 적용해야 합니다. 멤버 유형은 생성 시 고정 풋프린트를 가져야 합니다.

매개변수 const 표현식이어야 하며, i32 또는 u32로 해석되어야 합니다.
양수여야 합니다.

12.14. subgroup_size

subgroup_size_attr :

'@' 'subgroup_size' '(' expression ',' ? ')'

subgroup_size 속성
설명 컴퓨트 셰이더 호출의 서브그룹 크기를 지정합니다.

컴퓨트 셰이더 진입점 함수에만 적용해야 합니다.

요구 사항 subgroup_size_control 확장이 활성화된 경우에만 사용해야 합니다.
매개변수 const 표현식 또는 override 표현식이어야 하며, i32 또는 u32로 해석되어야 합니다.

값이 2의 거듭제곱이 아니면:

진입점의 workgroup_size의 x 차원이 subgroup_size 값의 배수가 아니면 파이프라인 생성 오류가 발생합니다.

값이 subgroupMaxSize보다 크거나 subgroupMinSize보다 작으면 파이프라인 생성 오류가 발생합니다.

값이 subgroupMinSize와 subgroupMaxSize 사이에 있더라도 레지스터 압박 또는 특정 하드웨어 제한으로 인해 파이프라인 생성 시 분류되지 않은 오류가 발생할 수 있습니다.

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로 간주됩니다.

컴퓨트 셰이더 진입점 함수에만 적용해야 합니다. 다른 어떤 객체에도 적용해서는 안 됩니다.

매개변수 하나, 둘 또는 세 개의 매개변수를 받습니다.

각 매개변수는 const 표현식 또는 override 표현식이어야 합니다. 모든 매개변수는 i32 또는 u32 중 동일한 유형이어야 합니다.

지정된 매개변수 중 하나라도 양수가 아닌 값으로 평가되는 const 표현식이면 셰이더 생성 오류가 발생합니다.

지정된 매개변수 중 하나라도 양수가 아닌 값으로 평가되거나 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. 내장 입력 및 출력

내장 입력 값은 시스템에서 생성된 제어 정보에 대한 접근을 제공합니다. 진입점은 동일한 내장 값 이름을 가진 두 개의 내장 입력을 가져서는 안 됩니다.

이름이 X이고 유형이 TX인 스테이지 S의 내장 입력은 셰이더 스테이지 S의 진입점에 대한 형식 매개변수를 통해 다음 두 방법 중 하나로 접근합니다:

  1. 매개변수는 builtin(X) 속성을 가지며 유형은 TX입니다.

  2. 매개변수는 구조체 유형이고, 구조체 멤버 중 하나가 builtin(X) 속성을 가지며 유형은 TX입니다.

반대로 진입점의 매개변수 또는 매개변수 멤버에 builtin 속성이 있으면, 대응하는 builtin은 진입점의 셰이더 스테이지에 대한 입력이어야 합니다.

내장 출력 값은 셰이더가 파이프라인의 이후 처리 단계에 제어 정보를 전달하는 데 사용됩니다. 진입점은 동일한 내장 값 이름을 가진 두 개의 내장 출력을 가져서는 안 됩니다.

이름이 Y이고 유형이 TY인 스테이지 S의 내장 출력은 셰이더 스테이지 S의 진입점에 대한 반환 값을 통해 다음 두 방법 중 하나로 설정합니다:

  1. 진입점 반환 유형은 builtin(Y) 속성을 가지며 유형은 TY입니다.

  2. 진입점 반환 유형은 구조체 유형이고, 구조체 멤버 중 하나가 builtin(Y) 속성을 가지며 유형은 TY입니다.

반대로 진입점의 반환 유형 또는 반환 유형의 멤버에 builtin 속성이 있으면, 대응하는 builtin은 진입점의 셰이더 스테이지에 대한 출력이어야 합니다.

참고: position 내장 값은 버텍스 셰이더의 출력이자 프래그먼트 셰이더의 입력입니다.

내장 입력 값과 내장 출력 값을 통틀어 내장 값이라고 합니다.

다음 표는 사용 가능한 내장 값을 요약합니다. 각각은 내장 값에 대한 내장 값 이름 토큰입니다. 각각은 이후 절에서 자세히 설명합니다.

내장 입력 및 출력 값
이름 스테이지 방향 유형 확장
vertex_index 버텍스 입력 u32
instance_index 버텍스 입력 u32
clip_distances 버텍스 출력 array<f32, N> (N ≤ 8) 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 subgroups 및 subgroup_id
num_subgroups 컴퓨트 입력 u32 subgroups 및 subgroup_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의 깊이 속성입니다.

셰이더가 깊이 모드 약속을 위반하는 깊이 값을 반환하면 대신 불확정 깊이 값이 사용될 수 있습니다.

@fragment
fn main() -> @builtin(frag_depth, greater) f32 {
    return 1.0f;
}
13.3.1.1.3. front_facing
이름 front_facing
스테이지 프래그먼트
유형 bool
방향 입력
설명 현재 프래그먼트가 앞면을 향한 프리미티브에 있으면 True입니다. 그렇지 않으면 False입니다.
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 렌더링 파이프라인에 지정된 샘플 count입니다. 이 속성이 적용되었을 때 프래그먼트 셰이더의 효과가 sample_index 값에 따라 달라지는 경우, 프래그먼트 셰이더는 샘플마다 한 번 호출됩니다.

WebGPU § 10.3 GPURenderPipeline을 참조하십시오.

13.3.1.1.13. sample_mask
이름 sample_mask
스테이지 프래그먼트
유형 u32
방향 입력
설명 현재 프래그먼트의 샘플 커버리지 비트마스크입니다.

비트는 반개구간 [0, sampleCount)의 샘플 인덱스로 인덱싱되며, 여기서 sampleCount는 GPU 렌더링 파이프라인에 지정된 샘플 count입니다.

샘플이 렌더링되는 프리미티브에 포함되는 경우에 한해서만 비트가 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에 대해(셰이더 스테이지 입력 또는 출력에서 사용되는 것에 한정하지 않음), members를 location 속성이 있는 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 {
  // ...
}
예: 유효하지 않은 location 할당
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. 리소스 인터페이스

리소스는 셰이더 스테이지 외부의 데이터에 대한 접근을 제공하며, override 선언도 아니고, 즉시 데이터 변수도 아니며, 셰이더 스테이지 입력 또는 출력도 아닌 객체입니다. 리소스는 셰이더의 모든 호출이 공유합니다.

리소스에는 네 종류가 있습니다:

셰이더의 리소스 인터페이스는 셰이더 스테이지의 함수가 정적으로 접근하는 모듈 범위 리소스 변수의 집합입니다.

각 리소스 변수는 group 및 binding 속성을 모두 사용하여 선언되어야 합니다. 셰이더의 스테이지와 함께 이 값들은 셰이더 파이프라인에서 리소스의 바인딩 주소를 식별합니다. 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 {                          //             정렬(16) 크기(32)
  position : vec3f,                          // 오프셋(0)   정렬(16) 크기(12)
  // -- 암시적 멤버 정렬 패딩 -- // 오프셋(12)            크기(4)
  color : vec3f,                             // 오프셋(16)  정렬(16) 크기(12)
  // -- 암시적 구조체 크기 패딩 --      // 오프셋(28)            크기(4)
}

struct LightStorage {                        //             정렬(16)
  pointCount : u32,                          // 오프셋(0)   정렬(4)  크기(4)
  // -- 암시적 멤버 정렬 패딩 -- // 오프셋(4)             크기(12)
  point : array<PointLight>,                 // 오프셋(16)  정렬(16) 요소크기(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, write 및 read_write를 미리 선언합니다.

14.3. 주소 공간

메모리 위치는 주소 공간으로 분할됩니다. 각 주소 공간에는 변경 가능성, 가시성, 포함할 수 있는 값, 그리고 해당 공간의 변수를 사용하는 방법을 결정하는 고유한 특성이 있습니다. 자세한 내용은 § 7 변수 및 값 선언을 참조하십시오.

주어진 메모리 뷰의 접근 모드는 흔히 컨텍스트에 의해 결정됩니다:

storage 주소 공간은 read 및 read_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>, T는 bool, i32, u32, 또는 f32 8 8
vec2<f16> 4 4
vec3<T>, T는 bool, i32, u32, 또는 f32 16 12
vec3<f16> 8 6
vec4<T>, T는 bool, 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의 크기

참고: buffer 유형은 다른 어떤 유형에도 포함될 수 없으므로 정렬은 중요하지 않습니다.

참고: 많은 GPU는 잠재적인 데이터 경합을 도입하지 않고 단일 바이트 쓰기를 구현할 수 없습니다. bool 값이 4바이트 정렬로 4바이트를 차지하도록 지정함으로써 구현은 데이터 경합을 도입하지 않고 메모리에서 인접한 불리언 값을 지원할 수 있습니다.

14.4.2. 구조체 멤버 레이아웃

구조체의 내부 레이아웃은 멤버의 크기와 정렬에서 계산됩니다. 기본적으로 멤버는 멤버 정렬 요구 사항을 충족하면서 겹치지 않도록 순서대로 촘촘하게 배치됩니다.

이 기본 내부 레이아웃은 레이아웃 속성을 사용하여 재정의할 수 있으며, 해당 속성은:

구조체 유형 S의 i번째 멤버에는 각각 SizeOfMember(S, i) 및 AlignOfMember(S, i)로 나타내는 크기와 정렬이 있습니다. 멤버 크기와 정렬은 구조체 시작에서 각 멤버까지의 바이트 오프셋을 계산하는 데 사용되며, § 14.4.4 값의 내부 레이아웃에서 설명합니다.

S의 i번째 멤버에 속성 size(k)가 있으면 SizeOfMember(S, i)는 k입니다. 그렇지 않으면 멤버의 유형이 T일 때 SizeOf(T)입니다.
S의 i번째 멤버에 속성 align(k)가 있으면 AlignOfMember(S, i)는 k입니다. 그렇지 않으면 멤버의 유형이 T일 때 AlignOf(T)입니다.

구조체 멤버에 size 속성이 적용된 경우 값은 멤버 유형의 크기 이상이어야 합니다:

SizeOfMember(S, i) ≥ SizeOf(T)
여기서 T는 S의 i번째 멤버 유형입니다.

첫 번째 구조체 멤버는 항상 구조체 시작으로부터 바이트 오프셋이 0입니다:

OffsetOfMember(S, 1) = 0

이후의 각 멤버는 멤버 유형 정렬을 충족하고 이전 멤버와 겹치지 않는 가장 낮은 오프셋에 배치됩니다. 각 멤버 인덱스 i > 1에 대해:

OffsetOfMember(S, i) = roundUp(AlignOfMember(S, i ), OffsetOfMember(S, i-1) + SizeOfMember(S, i-1))
예: 암시적 멤버 크기와 정렬을 사용하는 구조체 레이아웃
struct A {                                     //             정렬(8)  크기(24)
    u: f32,                                    // 오프셋(0)   정렬(4)  크기(4)
    v: f32,                                    // 오프셋(4)   정렬(4)  크기(4)
    w: vec2<f32>,                              // 오프셋(8)   정렬(8)  크기(8)
    x: f32                                     // 오프셋(16)  정렬(4)  크기(4)
    // -- 암시적 구조체 크기 패딩 --      // 오프셋(20)            크기(4)
}

struct B {                                     //             정렬(16) 크기(160)
    a: vec2<f32>,                              // 오프셋(0)   정렬(8)  크기(8)
    // -- 암시적 멤버 정렬 패딩 -- // 오프셋(8)             크기(8)
    b: vec3<f32>,                              // 오프셋(16)  정렬(16) 크기(12)
    c: f32,                                    // 오프셋(28)  정렬(4)  크기(4)
    d: f32,                                    // 오프셋(32)  정렬(4)  크기(4)
    // -- 암시적 멤버 정렬 패딩 -- // 오프셋(36)            크기(4)
    e: A,                                      // 오프셋(40)  정렬(8)  크기(24)
    f: vec3<f32>,                              // 오프셋(64)  정렬(16) 크기(12)
    // -- 암시적 멤버 정렬 패딩 -- // 오프셋(76)            크기(4)
    g: array<A, 3>,    // 요소 스트라이드 24       오프셋(80)  정렬(8)  크기(72)
    h: i32                                     // 오프셋(152) 정렬(4)  크기(4)
    // -- 암시적 구조체 크기 패딩 --      // 오프셋(156)           크기(4)
}

@group(0) @binding(0)
var<storage,read_write> storage_buffer: B;
예: 명시적 멤버 크기와 정렬을 사용하는 구조체 레이아웃
struct A {                                     //             정렬(8)  크기(32)
    u: f32,                                    // 오프셋(0)   정렬(4)  크기(4)
    v: f32,                                    // 오프셋(4)   정렬(4)  크기(4)
    w: vec2<f32>,                              // 오프셋(8)   정렬(8)  크기(8)
    @size(16) x: f32                           // 오프셋(16)  정렬(4)  크기(16)
}

struct B {                                     //             정렬(16) 크기(208)
    a: vec2<f32>,                              // 오프셋(0)   정렬(8)  크기(8)
    // -- 암시적 멤버 정렬 패딩 -- // 오프셋(8)             크기(8)
    b: vec3<f32>,                              // 오프셋(16)  정렬(16) 크기(12)
    c: f32,                                    // 오프셋(28)  정렬(4)  크기(4)
    d: f32,                                    // 오프셋(32)  정렬(4)  크기(4)
    // -- 암시적 멤버 정렬 패딩 -- // 오프셋(36)            크기(12)
    @align(16) e: A,                           // 오프셋(48)  정렬(16) 크기(32)
    f: vec3<f32>,                              // 오프셋(80)  정렬(16) 크기(12)
    // -- 암시적 멤버 정렬 패딩 -- // 오프셋(92)            크기(4)
    g: array<A, 3>,    // 요소 스트라이드 32       오프셋(96)  정렬(8)  크기(96)
    h: i32                                     // 오프셋(192) 정렬(4)  크기(4)
    // -- 암시적 구조체 크기 패딩 --      // 오프셋(196)           크기(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 = 스트라이드 * 요소_수 = 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 = 스트라이드 * 요소_수 = 16 * 8
var bigger_stride: array<vec3<f32>, 8>;
예: 런타임 크기 배열 레이아웃 예제
// 다음과 같은 배열:
//   - 정렬은 4 = AlignOf(f32)
//   - 요소 스트라이드는 4 = roundUp(AlignOf(f32),SizeOf(f32)) = 4
// B가 그리기 또는 디스패치 명령에서 바인딩의 유효 버퍼 바인딩 크기이면
// 요소 수는 다음과 같습니다:
//   N_runtime = floor(B / 요소 스트라이드) = 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 / 요소 스트라이드) = floor(B / 16)
var<storage> directions: array<vec3<f32>>;

14.4.4. 값의 내부 레이아웃

이 절에서는 전체 값의 배치가 주어졌다고 가정할 때 호스트 공유 가능 값의 내부가 버퍼의 바이트 위치에 배치되는 방식을 설명합니다. 이러한 레이아웃은 값의 유형과 구조체 멤버의 align 및 size 속성에 따라 달라집니다. 이러한 규칙은 아래 설명과 같이 불투명하지 않은 유형에 적용되며, buffer 유형의 값에는 내부 구조가 없고 이 규칙의 제약을 받지 않습니다.

값이 배치되는 버퍼 바이트 오프셋은 유형 정렬 요구 사항을 충족해야 합니다: 유형 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 유형의 값 V는 IEEE-754 binary32 형식으로 표현됩니다. 부호 비트 1개, 지수 비트 8개, 가수 비트 23개를 가집니다. V가 호스트 공유 버퍼의 바이트 오프셋 k에 배치되면:

f16 유형의 값 V는 IEEE-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. 주소 공간 레이아웃 제약 조건

storage 및 uniform 주소 공간에는 이 절에서 설명하는 서로 다른 레이아웃 제약 조건이 있습니다.

uniform을 제외한 모든 주소 공간은 storage 주소 공간과 동일한 제약 조건을 가집니다.

변수가 직접 또는 간접적으로 참조하는 모든 구조체 및 배열 유형은 변수 주소 공간의 제약 조건을 따라야 합니다. 주소 공간 제약 조건을 위반하면 셰이더 생성 오류가 발생합니다.

이 절에서는 RequiredAlignOf(S, C)를 호스트 공유 가능 또는 고정 풋프린트 유형 S의 값이 주소 공간 C에서 사용될 때의 바이트 오프셋 정렬 요구 사항으로 정의합니다.

주소 공간 C에서 호스트 공유 가능 또는 고정 풋프린트 유형의 정렬 요구 사항
호스트 공유 가능 또는 고정 풋프린트 유형 S, S가 C에 나타날 수 있다고 가정 RequiredAlignOf(S, C),
uniform_buffer_standard_layout이 지원되거나 C가 uniform이 아님
RequiredAlignOf(S, C),
uniform_buffer_standard_layout이 지원되지 않고 C가 uniform임
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)
C가 uniform인 경우 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는 음이 아닌 정수이며 구조체 S의 i번째 멤버는 유형 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 주소 공간은 다음을 요구합니다:

참고: 다음 예제는 uniform 버퍼의 레이아웃 요구 사항을 충족하기 위해 구조체 멤버에서 align 및 size 속성을 사용하는 방법을 보여줍니다. 특히 이러한 기법을 사용하면 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> // 스트라이드 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> // 스트라이드 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. 메모리 모델 참조

각 모듈 범위 리소스 변수는 고유한 group 및 binding 쌍에 대한 메모리 모델 참조를 형성합니다. 다른 각 변수(즉, function, private, 및 workgroup 주소 공간의 변수)는 변수의 수명 동안 고유한 메모리 모델 참조를 형성합니다.

14.5.3. 범위 지정 연산

호출이 범위 지정 연산을 수행하면 하나 또는 두 개의 호출 집합에 영향을 줍니다. 이러한 집합은 메모리 범위와 실행 범위입니다. 메모리 범위는 연산의 영향을 받는 메모리 내용의 갱신을 볼 수 있는 호출 집합을 지정합니다. 동기화 내장 함수의 경우 이는 또한 함수보다 프로그램 순서상 앞에 있는 영향을 받는 모든 메모리 연산이 함수보다 프로그램 순서상 뒤에 있는 영향을 받는 연산에 보인다는 것을 의미합니다. 실행 범위는 연산에 참여할 수 있는 호출 집합을 지정합니다(§ 15.6 집단 연산 참조).

원자적 내장 함수는 메모리 범위가 다음과 같은 원자적 연산에 매핑됩니다:

동기화 내장 함수는 실행 범위와 메모리 범위가 Workgroup인 제어 배리어에 매핑됩니다.

암시적 및 명시적 도함수에는 암시적인 쿼드 실행 범위가 있습니다.

참고: 생성된 셰이더에서 Vulkan 메모리 모델이 활성화되지 않은 경우 QueueFamily 대신 Device 범위를 사용해야 합니다.

14.5.4. 메모리 의미론

모든 원자적 내장 함수는 Relaxed 메모리 의미론을 사용하므로 스토리지 클래스 의미론은 사용하지 않습니다.

참고: WGSL의 주소 공간은 SPIR-V의 스토리지 클래스와 같습니다.

workgroupBarrier는 AcquireRelease 메모리 의미론과 WorkgroupMemory 의미론을 사용합니다. storageBarrier는 AcquireRelease 메모리 의미론과 UniformMemory 의미론을 사용합니다. textureBarrier는 AcquireRelease 메모리 의미론과 ImageMemory 의미론을 사용합니다.

참고: workgroupBarrier와 storageBarrier를 결합하면 AcquireRelease 순서 의미론과 WorkgroupMemory 및 UniformMemory 메모리 의미론을 모두 사용합니다.

참고: 어떤 원자적 또는 동기화 내장 함수도 MakeAvailable 또는 MakeVisible 의미론을 사용하지 않습니다.

14.5.5. 프라이빗과 비프라이빗

storage 또는 workgroup 주소 공간의 모든 비원자적 읽기 접근은 non-private로 간주되며 Workgroup 범위의 NonPrivatePointer | MakePointerVisible 메모리 피연산자를 가진 읽기 연산에 대응합니다.

storage 또는 workgroup 주소 공간의 모든 비원자적 쓰기 접근은 non-private로 간주되며 Workgroup 범위의 NonPrivatePointer | MakePointerAvailable 메모리 피연산자를 가진 쓰기 연산에 대응합니다.

handle 주소 공간의 모든 비원자적 읽기 접근은 non-private로 간주되며 Workgroup 범위의 NonPrivateTexel | MakeTexelVisible 메모리 피연산자를 가진 읽기 연산에 대응합니다.

handle 주소 공간의 모든 비원자적 쓰기 접근은 non-private로 간주되며 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.info, 및 MayBeNonUniform을 제외하면 각 노드는 다음 명제 중 하나의 참/거짓 값을 나타내는 것으로 이해할 수 있습니다:

간선은 소스 노드에 대응하는 명제에서 대상 노드에 대응하는 명제로의 함의로 이해할 수 있습니다.

예를 들어 한 가지 균일성 요구 사항은 workgroupBarrier 내장 함수를 균일한 제어 흐름에서만 호출해야 한다는 것입니다. 이를 표현하기 위해 RequiredToBeUniform.error에서 workgroupBarrier 호출 위치에 대응하는 노드로 간선을 추가합니다. 이를 이해하는 한 가지 방법은 RequiredToBeUniform.error가 명제 True에 대응한다고 보는 것이며, 따라서 RequiredToBeUniform.error -> X는 X가 true라고 말하는 것과 같습니다.

반대로 어떤 것의 균일성을 보장할 수 없음을 표현하려면(예: 스레드 ID를 보유하는 변수) 해당 노드에서 MayBeNonUniform으로 간선을 추가합니다. 이를 이해하는 한 가지 방법은 MayBeNonUniform이 명제 False에 대응한다고 보는 것이며, 따라서 X -> MayBeNonUniform은 X가 false라고 말하는 것과 같습니다.

이 해석의 결과로 RequiredToBeUniform.error에서 도달 가능한 모든 노드는 프로그램이 유효하려면 균일해야 하는 것에 대응하고, MayBeNonUniform에 도달할 수 있는 모든 노드는 균일성을 보장할 수 없는 것에 대응합니다. 따라서 RequiredToBeUniform.error에서 MayBeNonUniform으로 가는 경로가 하나라도 있으면 균일성 위반이 있으며 균일성 실패가 트리거됩니다.

노드 RequiredToBeUniform.warning 및 RequiredToBeUniform.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에 p의 변수를 사용합니다.
  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
여기서 Next는 s1의 동작에 있습니다.

참고: s1은 흔히 세미콜론으로 끝납니다.

Vin(s2) Vout(s1)
if e s1 else s2
여기서 Next는 s1과 s2의 동작에 모두 있습니다.
Vin(next) Vout(s1), Vout(s2)
if e s1 else s2
여기서 Next는 s1의 동작에는 있지만 s2에는 없습니다.
Vin(next) Vout(s1)
if e s1 else s2
여기서 Next는 s2의 동작에는 있지만 s1에는 없습니다.
Vin(next) Vout(s2)
loop { s1 continuing { s2 } } Vin(s1) Vout(prev),
s1의 동작이 {Next,Continue}와 교차하면 Vout(s2)
loop { s1 continuing { s2 } } Vin(s2) Next가 s1의 동작에 있으면 Vout(s1),
s1 안에서 동작이 {Continue}이고 s2로 제어를 이동하는 모든 si에 대해 Vout(si)
loop { s1 continuing { s2 } } Vin(next) Break가 s1의 동작에 있으면 Vout(s2),
s1 안에서 동작이 {Break}이고 next로 제어를 이동하는 모든 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),
그리고 sj 안에서 동작이 {Break}이고
next로 제어를 이동하는 모든 문에 대해 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는 "x"의 Vout(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는 "x"의 Vin(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. 함수 범위 변수 균일성

이 예제는 함수 범위 변수의 값에 의존하는 유효한 배리어 함수 호출과 유효하지 않은 호출을 모두 보여줍니다. workgroupBarrier는 x의 값이 변경 가능한 모듈 범위 변수 a에서 파생되므로 유효하지 않습니다. storageBarrier는 x의 값이 변경 불가능한 모듈 범위 변수 b에서 파생되므로 유효합니다. 이 예제는 함수 범위 변수 수명에서 서로 다른 균일성 기간을 분리하는 값 분석의 능력을 강조합니다. 또한 첫 번째 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_y 및 workgroup_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_id 및 subgroup_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에서 반올림하여 T의 X'를 계산합니다:

X'에서 표현식의 최종 값 X''를 계산하거나 프로그램 오류를 감지합니다:

15.7.4. 부동 소수점 정확도

x를 무제한 정밀도로 계산했을 때 연산의 정확한 실수 값 또는 무한 결과라고 합니다. 부동 소수점 유형 T에 대한 연산의 올바르게 반올림된 결과는 다음과 같습니다:

즉, 결과는 위 또는 아래로 반올림될 수 있습니다: WGSL은 반올림 모드를 지정하지 않습니다.

참고: 부동 소수점 유형에는 양의 무한대와 음의 무한대가 포함되므로 올바르게 반올림된 결과는 유한하거나 무한할 수 있습니다.

참고: 무제한 정밀도로 계산한 연산 결과에는 double의 정밀도를 초과하는 정밀도가 필요할 수 있습니다. 이러한 경우의 예는 x - y에서 x=1.0 이고 y=1.17e-38인 경우입니다 (가장 작은 양의 정규 단정밀도 부동 소수점 수). 이 숫자들의 지수는 126만큼 차이가 납니다. IEEE-754 binary64(배정밀도) 형식은 가수에 52비트만 있으므로 뺄셈을 수행하면 y의 모든 유효 비트가 손실됩니다. 반올림 모드에 따라, 이 경우와 y가 작지만 0이 아닌 많은 다른 경우에서 WGSL 표현식 x - y는 x와 같은 값을 산출할 수 있습니다. [ECMASCRIPT]는 IEEE-754 roundTiesToEven 반올림 모드와 동등한 방식을 사용한다는 점에 유의하십시오.

마지막 자리 단위인 ULP는 부동 소수점 수 x에 대해 다음과 같이 정의됩니다 [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일 때는 둘이 다를 수 있습니다.

x와 low 또는 high 중 하나가 비정규이면 결과는 임의의 비정규 값일 수 있습니다. 이는 비정규 입력에 대한 min 및 max 함수의 가능한 결과에서 따릅니다.

cos(x) x가 구간 [-π, π]에 있을 때 절대 오차 최대 2-11 x가 구간 [-π, π]에 있을 때 절대 오차 최대 2-7
cosh(x) (exp(x) + exp(-x)) * 0.5에서 상속됨
cross(x, x) i ≠ j인 (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는 부동 소수점 연산을 사용하며, GPU의 determinant 구현은 오버플로와 오차에 대한 견고성보다 속도와 단순성을 우선합니다.

예를 들어 단순한 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) 올바르게 반올림됨

x와 y가 모두 비정규이면 결과는 두 입력 중 어느 것이든 될 수 있습니다.

min(x, y) 올바르게 반올림됨.

x와 y가 모두 비정규이면 결과는 두 입력 중 어느 것이든 될 수 있습니다.

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요소 벡터 a 및 b에 대한 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, modf 및 atomicCompareExchangeWeak가 반환하는 구조체 유형은 WGSL 모듈에서 작성할 수 없습니다.

참고: 해당 유형의 값 선언은 WGSL 텍스트의 그 문 위치에서 유효해야 합니다.

WGSL은 두 종류의 값 생성자를 제공합니다:

17.1.1. 0 값 내장 함수

각 구체적이고 구성 가능한 T에는 고유한 0 값이 있으며, WGSL에서 유형 뒤에 빈 괄호 쌍을 붙여 작성하는 대응하는 내장 함수가 있습니다: T (). 추상 숫자 유형에도 0 값이 있지만 이에 접근하는 내장 함수는 없습니다.

0 값은 다음과 같습니다:

참고: WGSL에는 원자적 유형, 런타임 크기 배열, 버퍼 또는 구성 가능하지 않은 다른 유형에 대한 0 값 내장 함수가 없습니다.

오버로드
@const @must_use fn T() -> T
매개변수화 T는 구체적 구성 가능한 유형입니다.
설명 유형 T의 0 값을 생성합니다.

참고: 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 값을 생성합니다.

T가 bool이면 이는 항등 연산입니다.
그렇지 않으면 불리언 강제 변환입니다. e가 0 값(부동 소수점 유형에서는 -0.0 포함)이면 결과는 false이고, 그렇지 않으면 true입니다.

17.1.2.3. f16
오버로드
@const @must_use fn f16(e : T) -> f16
매개변수화 T는 스칼라 유형입니다
설명 f16 값을 생성합니다.

T가 f16이면 이는 항등 연산입니다.
T가 숫자 스칼라(f16 제외)이면 e는 f16으로 변환됩니다(유효하지 않은 변환 포함).
T가 bool이면 e가 true일 때 결과는 1.0h이고, 그렇지 않으면 0.0h입니다.

17.1.2.4. f32
오버로드
@const @must_use fn f32(e : T) -> f32
매개변수화 T는 구체적 스칼라 유형입니다
설명 f32 값을 생성합니다.

T가 f32이면 이는 항등 연산입니다.
T가 숫자 스칼라(f32 제외)이면 e는 f32로 변환됩니다(유효하지 않은 변환 포함).
T가 bool이면 e가 true일 때 결과는 1.0f이고, 그렇지 않으면 0.0f입니다.

17.1.2.5. i32
오버로드
@const @must_use fn i32(e : T) -> i32
매개변수화 T는 스칼라 유형입니다
설명 i32 값을 생성합니다.

T가 i32이면 이는 항등 연산입니다.
T가 u32이면 이는 비트 재해석입니다(즉, 결과는 e와 동일한 비트 패턴을 가진 i32의 고유한 값입니다).
T가 부동 소수점 유형이면 e는 0 방향으로 반올림하여 변환되어 i32가 됩니다.
T가 bool이면 e가 true일 때 결과는 1i이고, 그렇지 않으면 0i입니다.
T가 AbstractInt이면 e를 i32로 표현할 수 있는 경우 항등 연산이고, 그렇지 않으면 셰이더 생성 오류가 발생합니다.

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>
매개변수화 T는 f16 또는 f32입니다
S는 AbstractFloat, f16 또는 f32입니다
설명 2x2 열 우선 행렬의 생성자입니다.

T가 S와 일치하지 않으면 변환이 발생합니다.

오버로드
@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>
매개변수화 T는 AbstractFloat, 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>
매개변수화 T는 AbstractFloat, 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>
매개변수화 T는 f16 또는 f32입니다
S는 AbstractFloat, f16 또는 f32입니다
설명 2x3 열 우선 행렬의 생성자입니다.

T가 S와 일치하지 않으면 변환이 발생합니다.

오버로드
@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>
매개변수화 T는 AbstractFloat, 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>
매개변수화 T는 AbstractFloat, 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>
매개변수화 T는 f16 또는 f32입니다
S는 AbstractFloat, f16 또는 f32입니다
설명 2x4 열 우선 행렬의 생성자입니다.

T가 S와 일치하지 않으면 변환이 발생합니다.

오버로드
@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>
매개변수화 T는 AbstractFloat, 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>
매개변수화 T는 AbstractFloat, 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>
매개변수화 T는 f16 또는 f32입니다
S는 AbstractFloat, f16 또는 f32입니다
설명 3x2 열 우선 행렬의 생성자입니다.

T가 S와 일치하지 않으면 변환이 발생합니다.

오버로드
@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>
매개변수화 T는 AbstractFloat, 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>
매개변수화 T는 AbstractFloat, 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>
매개변수화 T는 f16 또는 f32입니다
S는 AbstractFloat, f16 또는 f32입니다
설명 3x3 열 우선 행렬의 생성자입니다.

T가 S와 일치하지 않으면 변환이 발생합니다.

오버로드
@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>
매개변수화 T는 AbstractFloat, 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>
매개변수화 T는 AbstractFloat, 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>
매개변수화 T는 f16 또는 f32입니다
S는 AbstractFloat, f16 또는 f32입니다
설명 3x4 열 우선 행렬의 생성자입니다.

T가 S와 일치하지 않으면 변환이 발생합니다.

오버로드
@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>
매개변수화 T는 AbstractFloat, 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>
매개변수화 T는 AbstractFloat, 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>
매개변수화 T는 f16 또는 f32입니다
S는 AbstractFloat, f16 또는 f32입니다
설명 4x2 열 우선 행렬의 생성자입니다.

T가 S와 일치하지 않으면 변환이 발생합니다.

오버로드
@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>
매개변수화 T는 AbstractFloat, 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>
매개변수화 T는 AbstractFloat, 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>
매개변수화 T는 f16 또는 f32입니다
S는 AbstractFloat, f16 또는 f32입니다
설명 4x3 열 우선 행렬의 생성자입니다.

T가 S와 일치하지 않으면 변환이 발생합니다.

오버로드
@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>
매개변수화 T는 AbstractFloat, 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>
매개변수화 T는 AbstractFloat, 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>
매개변수화 T는 f16 또는 f32입니다
S는 AbstractFloat, f16 또는 f32입니다
설명 4x4 열 우선 행렬의 생성자입니다.

T가 S와 일치하지 않으면 변환이 발생합니다.

오버로드
@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>
매개변수화 T는 AbstractFloat, 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>
매개변수화 T는 AbstractFloat, 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 값을 생성합니다.

T가 u32이면 이는 항등 연산입니다.
T가 i32이면 이는 비트 재해석입니다(즉, 결과는 e와 동일한 비트 패턴을 가진 u32의 고유한 값입니다).
T가 부동 소수점 유형이면 e는 0 방향으로 반올림하여 변환되어 u32가 됩니다.
T가 bool이면 e가 true일 때 결과는 1u이고, 그렇지 않으면 0u입니다.
T가 AbstractInt이면 e를 u32로 표현할 수 있는 경우 항등 연산이고, 그렇지 않으면 셰이더 생성 오류가 발생합니다.

참고: 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.x 및 e.y를 구성 요소로 사용하는 2구성 요소 구성 요소별 벡터 생성입니다.

T가 S와 일치하지 않으면 변환이 사용되며 구성 요소는 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는 스칼라입니다
설명 e1 및 e2를 구성 요소로 사용하는 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구성 요소 구성 요소별 벡터 생성입니다.

T가 S와 일치하지 않으면 변환이 사용되며 구성 요소는 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구성 요소 구성 요소별 벡터 생성입니다.

T가 S와 일치하지 않으면 변환이 사용되며 구성 요소는 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입니다
T는 S가 아니며 i32, u32 또는 f32입니다
설명 비트를 T로 재해석합니다.
결과는 e의 비트를 T 값으로 재해석한 것입니다.
오버로드
@const @must_use fn bitcast<vecN<T>>(e : vecN<S>) -> vecN<T>
매개변수화 S는 i32, u32 또는 f32입니다
T는 S가 아니며 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>
매개변수화
설명 e를 u32로 표현할 수 있으면 항등 연산이고, 그렇지 않으면 셰이더 생성 오류가 발생합니다. 즉, 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는 스칼라입니다
설명 구성 요소별 선택입니다. 결과 구성 요소 i는 select(f[i], t[i], cond[i])로 평가됩니다.

17.4. 배열 내장 함수

17.4.1. arrayLength

오버로드
@must_use fn arrayLength(p: ptr<AS, array<E>, AM>) -> u32
매개변수화 E는 런타임 크기 배열의 요소 유형입니다.
AS는 storage, uniform 또는 workgroup 중 하나입니다.
접근 모드 AM은 read 또는 read_write이며 AS에 유효해야 합니다.

참고: p가 bufferView 또는 bufferArrayView 내장 함수의 결과에서 파생된 경우에만 AS가 uniform 또는 workgroup일 수 있습니다.

설명 런타임 크기 배열의 요소 수인 NRuntime을 반환합니다.

§ 13.3.4 버퍼 바인딩이 런타임 크기 배열 요소 수를 결정함을 참조하십시오.

p가 bufferView 또는 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인 구간 [-π, π]의 각도를 라디안으로 반환합니다.

결과가 선택하는 사분면은 y 및 x의 부호에 따라 달라집니다. 예를 들어 함수는 다음과 같이 구현할 수 있습니다:

  • 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가 벡터인 경우 구성 요소별로 적용됩니다.

low가 high보다 크면:

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입니다
설명 e1과 e2의 외적을 반환합니다.
정의역 가능한 구현으로 주어진 다음 선형 항에서 암시됩니다:
  • 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>입니다
설명 e1과 e2 사이의 거리(예: length(e1 - e2))를 반환합니다.

정의역은 뺄셈 e1−e2가 유효한 모든 벡터 (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입니다
설명 e1과 e2의 내적을 반환합니다.
정의역 e1[i] × e2[i] 항의 합에 대한 선형 항에서 암시됩니다.

17.5.21. dot4U8Packed

오버로드
@const @must_use fn dot4U8Packed(e1: u32,
                                 e2: u32) -> u32
설명 e1 및 e2는 4개의 8비트 부호 없는 정수 구성 요소를 가진 벡터로 해석됩니다. 이 두 벡터의 부호 없는 정수 내적을 반환합니다.

17.5.22. dot4I8Packed

오버로드
@const @must_use fn dot4I8Packed(e1: u32,
                                 e2: u32) -> i32
설명 e1 및 e2는 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가 스칼라 유형이면:

  • w는 T의 비트 너비입니다
  • o = min(offset, w)
  • c = min(count, w - o)
  • c가 0이면 결과는 0입니다.
  • 그렇지 않으면 결과의 비트 0..c - 1은 e의 비트 o..o + c - 1에서 복사됩니다. 결과의 다른 비트는 결과의 비트 c - 1과 같습니다.
T가 벡터인 경우 구성 요소별로 적용됩니다.

count + offset이 w보다 크면:

17.5.26. extractBits (부호 없음)

오버로드
@const @must_use fn extractBits(e: T,
                                offset: u32,
                                count: u32) -> T
매개변수화 T는 u32 또는 vecN<u32>입니다
설명 부호 확장 없이 정수에서 비트를 읽습니다.

T가 스칼라 유형이면:

  • w는 T의 비트 너비입니다
  • o = min(offset, w)
  • c = min(count, w - o)
  • c가 0이면 결과는 0입니다.
  • 그렇지 않으면 결과의 비트 0..c - 1은 e의 비트 o..o + c - 1에서 복사됩니다. 결과의 다른 비트는 0입니다.
T가 벡터인 경우 구성 요소별로 적용됩니다.

count + offset이 w보다 크면:

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가 스칼라 유형이면:

  • w는 T의 비트 너비입니다
  • o = min(offset, w)
  • c = min(count, w - o)
  • c가 0이면 결과는 e입니다.
  • 그렇지 않으면 결과의 비트 o..o + c - 1은 newbits의 비트 0..c - 1에서 복사됩니다. 결과의 다른 비트는 e에서 복사됩니다.
T가 벡터인 경우 구성 요소별로 적용됩니다.

count + offset이 w보다 크면:

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>입니다
I는 T가 벡터인 경우에만 벡터입니다
T는 I도 추상인 경우에만 추상일 수 있으며 그 반대도 마찬가지입니다

참고: 어느 한 매개변수가 구체적이면 다른 매개변수는 자동 변환을 거쳐 구체적 유형(해당하는 경우)이 되며 결과도 구체적 유형이 됩니다.

설명 다음을 제외하고 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라는 이름은 "load exponent"로 기억할 수 있습니다. 이 이름은 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>입니다
설명 e1이 e2보다 작으면 e2를 반환하고, 그렇지 않으면 e1을 반환합니다. 구성 요소별 로 T가 벡터인 경우 적용됩니다.

e1과 e2가 부동 소수점 값이면:

  • e1과 e2가 모두 비정규이면 결과는 둘 중 어느 값이어도 됩니다.

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>입니다
설명 e2가 e1보다 작으면 e2를 반환하고, 그렇지 않으면 e1을 반환합니다. 구성 요소별 로 T가 벡터인 경우 적용됩니다.

e1과 e2가 부동 소수점 값이면:

  • e1과 e2가 모두 비정규이면 결과는 둘 중 어느 값이어도 됩니다.

17.5.43. mix

오버로드
@const @must_use fn mix(e1: T,
                        e2: T,
                        e3: T) -> T
매개변수화 S는 AbstractFloat, f32 또는 f16입니다
T는 S 또는 vecN<S>입니다
설명 e1과 e2의 선형 혼합(예: 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>입니다
설명 e1과 e2의 구성 요소별 선형 혼합을 반환하며, 각 구성 요소에 스칼라 혼합 계수 e3를 사용합니다.
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와 같은 방향의 단위 벡터를 반환합니다.

정의역은 0 벡터를 제외한 모든 벡터입니다.

17.5.46. pow

오버로드
@const @must_use fn pow(e1: T,
                        e2: T) -> T
매개변수화 S는 AbstractFloat, f32 또는 f16입니다
T는 S 또는 vecN<S>입니다
설명 e1을 e2제곱한 값을 반환합니다. 구성 요소별 로 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비트 부동 소수점 값 e를 e가 IEEE-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에 있는 비트는 e의 위치 31 -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가 정수 k와 k + 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는 쌍곡 각도입니다. 순수 수학 함수 (ea − e−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일 때 함수는 x가 edge0보다 작으면 0이고, 이후 부드럽게 증가하여 x가 edge1에 도달하면 그 이후에는 1을 유지합니다.

  • edge0 > edge1일 때 함수는 x가 edge1보다 작으면 1이고, 이후 부드럽게 감소하여 x가 edge0에 도달하면 그 이후에는 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>입니다
설명 edge ≤ x이면 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는 쌍곡 각도입니다. 순수 수학 함수 (ea − e−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의 편미분을 반환합니다.

현재 호출과 동일한 쿼드에서 제공되며 쿼드 호출 ID가 i인 호출의 e 값을 ei라고 합니다.

결과는 다음과 같습니다.

  • 현재 호출의 쿼드 ID가 0 또는 1이면 e1 − e0입니다.

  • 그렇지 않으면 e3 − e2입니다.

비균일 제어 흐름에서 호출하면 불확정 값을 반환합니다.

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의 편미분을 반환합니다.

현재 호출과 동일한 쿼드에서 제공되며 쿼드 호출 ID가 i인 호출의 e 값을 ei라고 합니다.

결과는 다음과 같습니다.

  • 현재 호출의 쿼드 ID가 0 또는 2이면 e2 − e0입니다.

  • 그렇지 않으면 e3 − e1입니다.

비균일 제어 흐름에서 호출하면 불확정 값을 반환합니다.

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

텍스처 또는 텍스처의 밉 레벨 크기를 텍셀 단위로 반환합니다.

매개변수화 오버로드
ST는 i32, u32 또는 f32입니다
F는 텍셀 형식입니다
A는 접근 모드입니다

T는 texture_1d<ST> 또는 texture_storage_1d<F,A>입니다
@must_use fn textureDimensions(t: T) -> u32
ST는 i32, u32 또는 f32입니다

T는 texture_1d<ST>입니다

L은 i32 또는 u32입니다

@must_use fn textureDimensions(t: T,
                               level: L) -> u32
ST는 i32, u32 또는 f32입니다
F는 텍셀 형식입니다
A는 접근 모드입니다

T는 texture_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>
ST는 i32, u32 또는 f32입니다

T는 texture_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입니다

L은 i32 또는 u32입니다

@must_use fn textureDimensions(t: T,
                               level: L) -> vec2<u32>
ST는 i32, u32 또는 f32입니다
F는 텍셀 형식입니다
A는 접근 모드입니다

T는 texture_3d<ST> 또는 texture_storage_3d<F,A>입니다
@must_use fn textureDimensions(t: T) -> vec3<u32>
ST는 i32, u32 또는 f32입니다

T는 texture_3d<ST>입니다

L은 i32 또는 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구성 요소 벡터를 계산합니다:

네 텍셀은 WebGPU 샘플러 설명자에 설명된 샘플링 영역을 형성합니다.

매개변수화 오버로드
C는 i32 또는 u32입니다
ST는 i32, u32 또는 f32입니다
@must_use fn textureGather(component: C,
                           t: texture_2d<ST>,
                           s: sampler,
                           coords: vec2<f32>) -> vec4<ST>
C는 i32 또는 u32입니다
ST는 i32, u32 또는 f32입니다
@must_use fn textureGather(component: C,
                           t: texture_2d<ST>,
                           s: sampler,
                           coords: vec2<f32>,
                           offset: vec2<i32>) -> vec4<ST>
C는 i32 또는 u32입니다
A는 i32 또는 u32입니다
ST는 i32, u32 또는 f32입니다
@must_use fn textureGather(component: C,
                           t: texture_2d_array<ST>,
                           s: sampler,
                           coords: vec2<f32>,
                           array_index: A) -> vec4<ST>
C는 i32 또는 u32입니다
A는 i32 또는 u32입니다
ST는 i32, 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>
C는 i32 또는 u32입니다
ST는 i32, u32 또는 f32입니다
@must_use fn textureGather(component: C,
                           t: texture_cube<ST>,
                           s: sampler,
                           coords: vec3<f32>) -> vec4<ST>
C는 i32 또는 u32입니다
A는 i32 또는 u32입니다
ST는 i32, 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>
A는 i32 또는 u32입니다
@must_use fn textureGather(t: texture_depth_2d_array,
                           s: sampler,
                           coords: vec2<f32>,
                           array_index: A) -> vec4<f32>
A는 i32 또는 u32입니다
@must_use fn textureGather(t: texture_depth_2d_array,
                           s: sampler,
                           coords: vec2<f32>,
                           array_index: A,
                           offset: vec2<i32>) -> vec4<f32>
A는 i32 또는 u32입니다
@must_use fn textureGather(t: texture_depth_cube_array,
                           s: sampler,
                           coords: vec3<f32>,
                           array_index: A) -> vec4<f32>

매개변수:

component 깊이 텍스처가 아닌 경우에만 적용됩니다.
선택한 텍셀에서 읽을 채널의 인덱스입니다.
제공되는 경우 component 표현식은 반드시 const 표현식(예: 1)이어야 합니다.
값은 최소 0, 최대 3이어야 합니다. 이 범위를 벗어난 값은 셰이더 생성 오류를 발생시킵니다.
t 읽을 샘플링된 또는 깊이 텍스처입니다.
s 샘플러 유형입니다.
coords 텍스처 좌표입니다.
array_index 0 기반 텍스처 배열 인덱스입니다.
이 값은 [0, textureNumLayers(t) - 1] 범위로 제한됩니다.
offset 텍스처를 샘플링하기 전에 정규화되지 않은 텍스처 좌표에 적용되는 선택적 텍셀 오프셋입니다. 이 오프셋은 텍스처 래핑 모드를 적용하기 전에 적용됩니다.
offset 표현식은 반드시 const 표현식(예: 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

텍스처 개더 비교 연산은 깊이 텍스처의 네 텍셀에 대해 깊이 비교를 수행하고 결과를 다음과 같이 하나의 벡터로 수집합니다:

매개변수화 오버로드
@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>
A는 i32 또는 u32입니다
@must_use fn textureGatherCompare(t: texture_depth_2d_array,
                                  s: sampler_comparison,
                                  coords: vec2<f32>,
                                  array_index: A,
                                  depth_ref: f32) -> vec4<f32>
A는 i32 또는 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>
A는 i32 또는 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 표현식은 반드시 const 표현식(예: 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

샘플링이나 필터링 없이 텍스처에서 단일 텍셀을 읽습니다.

매개변수화 오버로드
C는 i32 또는 u32입니다
L은 i32 또는 u32입니다
ST는 i32, u32 또는 f32입니다
@must_use fn textureLoad(t: texture_1d<ST>,
                         coords: C,
                         level: L) -> vec4<ST>
C는 i32 또는 u32입니다
L은 i32 또는 u32입니다
ST는 i32, u32 또는 f32입니다
@must_use fn textureLoad(t: texture_2d<ST>,
                         coords: vec2<C>,
                         level: L) -> vec4<ST>
C는 i32 또는 u32입니다
A는 i32 또는 u32입니다
L은 i32 또는 u32입니다
ST는 i32, u32 또는 f32입니다
@must_use fn textureLoad(t: texture_2d_array<ST>,
                        coords: vec2<C>,
                        array_index: A,
                        level: L) -> vec4<ST>
C는 i32 또는 u32입니다
L은 i32 또는 u32입니다
ST는 i32, u32 또는 f32입니다
@must_use fn textureLoad(t: texture_3d<ST>,
                         coords: vec3<C>,
                         level: L) -> vec4<ST>
C는 i32 또는 u32입니다
S는 i32 또는 u32입니다
ST는 i32, u32 또는 f32입니다
@must_use fn textureLoad(t: texture_multisampled_2d<ST>,
                         coords: vec2<C>,
                         sample_index: S)-> vec4<ST>
C는 i32 또는 u32입니다
L은 i32 또는 u32입니다
@must_use fn textureLoad(t: texture_depth_2d,
                         coords: vec2<C>,
                         level: L) -> f32
C는 i32 또는 u32입니다
A는 i32 또는 u32입니다
L은 i32 또는 u32입니다
@must_use fn textureLoad(t: texture_depth_2d_array,
                         coords: vec2<C>,
                         array_index: A,
                         level: L) -> f32
C는 i32 또는 u32입니다
S는 i32 또는 u32입니다
@must_use fn textureLoad(t: texture_depth_multisampled_2d,
                         coords: vec2<C>,
                         sample_index: S)-> f32
C는 i32 또는 u32입니다
@must_use fn textureLoad(t: texture_external,
                         coords: vec2<C>) -> vec4<f32>
C는 i32 또는 u32입니다
AM은 read 또는 read_write입니다
CF는 스토리지 텍셀 형식 F에 따라 달라집니다. 텍셀 형식에서 채널 형식으로의 매핑은 텍셀 형식 표를 참조하십시오.
@must_use fn textureLoad(t : texture_storage_1d<F, AM>,
                         coords : C) -> vec4<CF>
C는 i32 또는 u32입니다
AM은 read 또는 read_write입니다
CF는 스토리지 텍셀 형식 F에 따라 달라집니다. 텍셀 형식에서 채널 형식으로의 매핑은 텍셀 형식 표를 참조하십시오.
@must_use fn textureLoad(t : texture_storage_2d<F, AM>,
                         coords : vec2<C>) -> vec4<CF>
C는 i32 또는 u32입니다
AM은 read 또는 read_write입니다
A는 i32 또는 u32입니다
CF는 스토리지 텍셀 형식 F에 따라 달라집니다. 텍셀 형식에서 채널 형식으로의 매핑은 텍셀 형식 표를 참조하십시오.
@must_use fn textureLoad(t : texture_storage_2d_array<F, AM>,
                         coords : vec2<C>,
                         array_index : A) -> vec4<CF>
C는 i32 또는 u32입니다
AM은 read 또는 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는 접근 모드입니다
ST는 i32, u32 또는 f32입니다

T는 texture_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

텍스처의 밉 레벨 수를 반환합니다.

매개변수화 오버로드
ST는 i32, u32 또는 f32입니다

T는 texture_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

멀티샘플링된 텍스처에서 텍셀당 샘플 수를 반환합니다.

매개변수화 오버로드
ST는 i32, u32 또는 f32입니다

T는 texture_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>
A는 i32 또는 u32입니다
@must_use fn textureSample(t: texture_2d_array<f32>,
                           s: sampler,
                           coords: vec2<f32>,
                           array_index: A) -> vec4<f32>
A는 i32 또는 u32입니다
@must_use fn textureSample(t: texture_2d_array<f32>,
                           s: sampler,
                           coords: vec2<f32>,
                           array_index: A,
                           offset: vec2<i32>) -> vec4<f32>
T는 texture_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>
A는 i32 또는 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
A는 i32 또는 u32입니다
@must_use fn textureSample(t: texture_depth_2d_array,
                           s: sampler,
                           coords: vec2<f32>,
                           array_index: A) -> f32
A는 i32 또는 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
A는 i32 또는 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 표현식은 반드시 const 표현식(예: 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>
A는 i32 또는 u32입니다
@must_use fn textureSampleBias(t: texture_2d_array<f32>,
                               s: sampler,
                               coords: vec2<f32>,
                               array_index: A,
                               bias: f32) -> vec4<f32>
A는 i32 또는 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>
T는 texture_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>
A는 i32 또는 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 표현식은 반드시 const 표현식(예: 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
A는 i32 또는 u32입니다
@must_use fn textureSampleCompare(t: texture_depth_2d_array,
                                  s: sampler_comparison,
                                  coords: vec2<f32>,
                                  array_index: A,
                                  depth_ref: f32) -> f32
A는 i32 또는 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
A는 i32 또는 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 표현식은 반드시 const 표현식(예: 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
A는 i32 또는 u32입니다
@must_use fn textureSampleCompareLevel(t: texture_depth_2d_array,
                                       s: sampler_comparison,
                                       coords: vec2<f32>,
                                       array_index: A,
                                       depth_ref: f32) -> f32
A는 i32 또는 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
A는 i32 또는 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 표현식은 반드시 const 표현식(예: 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>
A는 i32 또는 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>
A는 i32 또는 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>
T는 texture_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>
A는 i32 또는 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 표현식은 반드시 const 표현식(예: 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>
A는 i32 또는 u32입니다
@must_use fn textureSampleLevel(t: texture_2d_array<f32>,
                                s: sampler,
                                coords: vec2<f32>,
                                array_index: A,
                                level: f32) -> vec4<f32>
A는 i32 또는 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>
T는 texture_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>
A는 i32 또는 u32입니다
@must_use fn textureSampleLevel(t: texture_cube_array<f32>,
                                s: sampler,
                                coords: vec3<f32>,
                                array_index: A,
                                level: f32) -> vec4<f32>
L은 i32 또는 u32입니다
@must_use fn textureSampleLevel(t: texture_depth_2d,
                                s: sampler,
                                coords: vec2<f32>,
                                level: L) -> f32
L은 i32 또는 u32입니다
@must_use fn textureSampleLevel(t: texture_depth_2d,
                                s: sampler,
                                coords: vec2<f32>,
                                level: L,
                                offset: vec2<i32>) -> f32
A는 i32 또는 u32입니다
L은 i32 또는 u32입니다
@must_use fn textureSampleLevel(t: texture_depth_2d_array,
                                s: sampler,
                                coords: vec2<f32>,
                                array_index: A,
                                level: L) -> f32
A는 i32 또는 u32입니다
L은 i32 또는 u32입니다
@must_use fn textureSampleLevel(t: texture_depth_2d_array,
                                s: sampler,
                                coords: vec2<f32>,
                                array_index: A,
                                level: L,
                                offset: vec2<i32>) -> f32
L은 i32 또는 u32입니다
@must_use fn textureSampleLevel(t: texture_depth_cube,
                                s: sampler,
                                coords: vec3<f32>,
                                level: L) -> f32
A는 i32 또는 u32입니다
L은 i32 또는 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에는 텍스처의 전체 크기 버전이 포함됩니다. level이 f32인 함수의 경우 형식이 텍스처 형식 기능에 따라 필터링 가능하면 소수 값은 두 레벨 사이를 보간할 수 있습니다.
offset 텍스처를 샘플링하기 전에 정규화되지 않은 텍스처 좌표에 적용되는 선택적 텍셀 오프셋입니다. 이 오프셋은 텍스처 래핑 모드를 적용하기 전에 적용됩니다.
offset 표현식은 반드시 const 표현식(예: vec2<i32>(1, 2))이어야 합니다.
각 offset 구성 요소는 반드시 최소 -8이고 최대 7이어야 합니다. 이 범위를 벗어난 값은 셰이더 생성 오류를 발생시킵니다.

반환:

샘플링된 값입니다.

17.7.14. textureSampleBaseClampToEdge

텍스처 뷰의 기본 레벨에서 샘플링하며, 텍스처 좌표는 아래 설명과 같이 가장자리로 제한됩니다.

매개변수화 오버로드
T는 texture_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는 텍셀 형식입니다
C는 i32 또는 u32입니다
AM은 write 또는 read_write입니다
CF는 스토리지 텍셀 형식 F에 따라 달라집니다. 텍셀 형식에서 채널 형식으로의 매핑은 텍셀 형식 표를 참조하십시오.
fn textureStore(t: texture_storage_1d<F,AM>,
                coords: C,
                value: vec4<CF>)
F는 텍셀 형식입니다
C는 i32 또는 u32입니다
AM은 write 또는 read_write입니다
CF는 스토리지 텍셀 형식 F에 따라 달라집니다. 텍셀 형식에서 채널 형식으로의 매핑은 텍셀 형식 표를 참조하십시오.
fn textureStore(t: texture_storage_2d<F,AM>,
                coords: vec2<C>,
                value: vec4<CF>)
F는 텍셀 형식입니다
C는 i32 또는 u32입니다
AM은 write 또는 read_write입니다
A는 i32 또는 u32입니다
CF는 스토리지 텍셀 형식 F에 따라 달라집니다. 텍셀 형식에서 채널 형식으로의 매핑은 텍셀 형식 표를 참조하십시오.
fn textureStore(t: texture_storage_2d_array<F,AM>,
                coords: vec2<C>,
                array_index: A,
                value: vec4<CF>)
F는 텍셀 형식입니다
C는 i32 또는 u32입니다
AM은 write 또는 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. 함수 이름의 연산(예: max)을 값 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인 경우에 only if 값 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);
}

참고: 동등 비교는 일부 구현에서 허위로 실패할 수 있습니다. 즉, 결과 구조체의 exchanged 멤버는 old_value 멤버가 cmp와 같더라도 false일 수 있습니다.

17.8.6. 원자적 저장 최솟값 및 최댓값 함수

이 함수들은 모두 atomic_vec2u_min_max 언어 기능을 필요로 합니다.

이 함수들은 값을 반환하지 않습니다.

17.8.6.1. atomicStoreMin
fn atomicStoreMin(atomic_ptr: ptr<storage, atomic<vec2<u32>>, read_write>,
                  v: vec2<u32>)

atomic_ptr이 가리키는 원자적 객체에 대해 v 값을 사용해 64비트 부호 없는 정수 최솟값 연산을 원자적으로 수행합니다.

다음 단계를 원자적으로 수행합니다:

  1. atomic_ptr이 참조하는 메모리에서 원래 vec2u 값 old를 로드합니다.

  2. 64비트 부호 없는 정수 값을 계산합니다:

    • old64 = 232 × old[1] + old[0]

    • v64 = 232 × v[1] + v[0]

  3. old64와 v64의 최솟값으로 값 new64를 계산합니다.

  4. 다음과 같은 vec2<u32> 유형의 값 new를 계산합니다:

    • new[0]에는 new64의 최하위 32비트가 포함되고,

    • new[1]에는 new64의 최상위 32비트가 포함됩니다.

  5. new를 atomic_ptr이 참조하는 메모리에 저장합니다.

17.8.6.2. atomicStoreMax
fn atomicStoreMax(atomic_ptr: ptr<storage, atomic<vec2<u32>>, read_write>, v: vec2<u32>)

atomic_ptr이 가리키는 원자적 객체에 대해 v 값을 사용해 64비트 부호 없는 정수 최댓값 연산을 원자적으로 수행합니다.

다음 단계를 원자적으로 수행합니다:

  1. atomic_ptr이 참조하는 메모리에서 원래 vec2u 값 old를 로드합니다.

  2. 64비트 부호 없는 정수 값을 계산합니다:

    • old64 = 232 × old[1] + old[0]

    • v64 = 232 × v[1] + v[0]

  3. old64와 v64의 최댓값으로 값 new64를 계산합니다.

  4. 다음과 같은 vec2<u32> 유형의 값 new를 계산합니다:

    • new[0]에는 new64의 최하위 32비트가 포함되고,

    • new[1]에는 new64의 최상위 32비트가 포함됩니다.

  5. new를 atomic_ptr이 참조하는 메모리에 저장합니다.

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)이며, 여기서 v는 e의 8×i 비트부터 8×i + 7 비트까지를 2의 보수 부호 있는 정수로 해석한 값입니다.

17.10.2. unpack4x8unorm

오버로드
@const @must_use fn unpack4x8unorm(e: u32) -> vec4<f32>
설명 32비트 값을 네 개의 8비트 청크로 분해한 다음 각 청크를 부호 없는 정규화 부동 소수점 값으로 재해석합니다.
결과의 구성 요소 i는 v ÷ 255이며, 여기서 v는 e의 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)이며, 여기서 v는 e의 16×i 비트부터 16×i + 15 비트까지를 2의 보수 부호 있는 정수로 해석한 값입니다.

17.10.6. unpack2x16unorm

오버로드
@const @must_use fn unpack2x16unorm(e: u32) -> vec2<f32>
설명 32비트 값을 두 개의 16비트 청크로 분해한 다음 각 청크를 부호 없는 정규화 부동 소수점 값으로 재해석합니다.
결과의 구성 요소 i는 v ÷ 65535이며, 여기서 v는 e의 16×i 비트부터 16×i + 15 비트까지를 부호 없는 정수로 해석한 값입니다.

17.10.7. unpack2x16float

오버로드
@const @must_use fn unpack2x16float(e: u32) -> vec2<f32>
설명 32비트 값을 두 개의 16비트 청크로 분해한 다음 각 청크를 부동 소수점 값으로 재해석합니다.
결과의 구성 요소 i는 v의 f32 표현이며, 여기서 v는 e의 16×i 비트부터 16×i + 15 비트까지를 IEEE-754 binary16 값으로 해석한 것입니다. § 15.7.6 부동 소수점 변환을 참조하십시오.

17.11. 동기화 내장 함수

모든 동기화 함수는 Acquire/Release 메모리 순서를 사용하는 제어 배리어를 실행합니다. 즉, 모든 동기화 함수와 영향을 받는 메모리 및 원자적 연산은 동기화 함수에 대해 프로그램 순서로 정렬됩니다. 또한 동기화 함수보다 프로그램 순서상 앞선 영향을 받는 메모리 및 원자적 연산은 워크그룹의 어떤 멤버가 동기화 함수보다 프로그램 순서상 뒤에 있는 영향을 받는 메모리 또는 원자적 연산을 실행하기 전에 워크그룹의 다른 모든 스레드에서 볼 수 있어야 합니다.

모든 동기화 함수는 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
설명 서브그룹의 모든 활성 호출에서 e가 true이면 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
설명 서브그룹의 어떤 활성 호출에서든 e가 true이면 true를 반환합니다.

17.12.5. subgroupBallot

오버로드
@must_use fn subgroupBallot(pred : bool) -> vec4<u32>
설명 pred가 true인 서브그룹의 활성 호출 비트마스크를 반환합니다.

반환 값의 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는 구체적 숫자 스칼라 또는 구체적 숫자 벡터입니다
I는 u32 또는 i32입니다
설명 서브그룹에서 id와 일치하는 서브그룹 호출 ID를 가진 호출의 e 값을 활성 호출 전체에 반환합니다 서브그룹에서.

id는 반드시 [0, 128) 범위의 const 표현식이어야 합니다.

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는 구체적 숫자 스칼라 또는 구체적 숫자 벡터입니다
I는 u32 또는 i32입니다
설명 id와 일치하는 서브그룹 호출 ID를 가진 호출에서 e를 반환합니다.

id가 [0, 128) 범위를 벗어나면:

id가 활성 호출을 선택하지 않으면 불확정 값이 반환됩니다.

17.12.12.1. subgroupShuffleDown
오버로드
@must_use fn subgroupShuffleDown(e : T, delta : u32) -> T
전제 조건 T는 구체적 숫자 스칼라 또는 구체적 숫자 벡터입니다
설명 현재 호출에 대해 subgroup_invocation_id + delta와 일치하는 서브그룹 호출 ID를 가진 호출에서 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는 구체적 숫자 스칼라 또는 구체적 숫자 벡터입니다
설명 현재 호출에 대해 subgroup_invocation_id - delta와 일치하는 서브그룹 호출 ID를 가진 호출에서 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는 구체적 숫자 스칼라 또는 구체적 숫자 벡터입니다
설명 현재 호출에 대해 subgroup_invocation_id ^ mask와 일치하는 서브그룹 호출 ID를 가진 호출에서 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는 구체적 숫자 스칼라 또는 구체적 숫자 벡터입니다
I는 u32 또는 i32입니다
설명 쿼드에서 id와 일치하는 쿼드 호출 ID를 가진 호출의 e 값을 쿼드의 모든 활성 호출에 반환합니다.

id는 반드시 [0, 4) 범위의 const 표현식이어야 합니다.

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 언어 기능을 필요로 합니다.

이 함수들은 버퍼를 가리키는 포인터에서 동작합니다. bufferView와 bufferArrayView는 버퍼의 불투명 데이터를 다른 호스트 공유 가능 데이터 유형으로 재해석합니다. 결과 포인터는 다른 포인터와 마찬가지로 사용할 수 있습니다.

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>
전제 조건 AS는 storage, uniform 또는 workgroup 중 하나입니다.
AM은 AS에 유효한 접근 모드입니다.

T는 호스트 공유 가능 유형입니다.
T는 다음 두 유형이거나 그중 어느 하나를 포함하는 것이어서는 안 됩니다: 원자적 또는 버퍼 유형.
T는 반드시 AS에 대한 주소 공간 레이아웃 제약 조건을 만족해야 합니다.

I는 u32 또는 i32입니다.

설명 p의 시작부터 offset바이트 떨어진 메모리 뷰를 T 유형으로 재해석합니다. 즉, p와 연결된 메모리 위치가 [0, bufferLength(p)) 범위에 있으면 결과와 연결된 메모리 위치는 저장 유형 T와 함께 [offset, bufferLength(p)) 범위에 있습니다.

I가 i32이면:

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>
전제 조건 AS는 storage, uniform 또는 workgroup 중 하나입니다.
AM은 AS에 유효한 접근 모드입니다.

T는 호스트 공유 가능 유형입니다.
T는 다음 두 유형이거나 그중 어느 하나를 포함하는 것이어서는 안 됩니다: 원자적 또는 버퍼 유형.
T는 반드시 AS에 대한 주소 공간 레이아웃 제약 조건을 만족해야 합니다.

I는 u32 또는 i32입니다.

설명 p의 시작부터 offset바이트 떨어진 메모리 뷰를 T 유형으로 재해석합니다. 즉, p와 연결된 메모리 위치가 [0, bufferLength(p)) 범위에 있으면 결과와 연결된 메모리 위치는 저장 유형 T와 함께 [offset, bufferLength(p)) 범위에 있습니다.

I가 i32이면:

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>
전제 조건 AS는 storage, uniform 또는 workgroup 중 하나입니다.
AM은 AS에 유효한 접근 모드입니다.

T는 고정 풋프린트가 없는 호스트 공유 가능 유형입니다.
T는 원자적 유형이나 버퍼 유형이어서는 안 되며 이를 포함해서도 안 됩니다 원자적 또는 버퍼 유형.
T는 반드시 AS에 대한 주소 공간 레이아웃 제약 조건을 만족해야 합니다.

OI는 u32 또는 i32입니다.
SI는 u32 또는 i32입니다.

설명 p의 시작부터 offset바이트 떨어진 지점부터 size 바이트의 메모리 뷰를 T 유형으로 재해석합니다. 즉, p와 연결된 메모리 위치가 [0, bufferLength(p)) 범위에 있으면 결과와 연결된 메모리 위치는 저장 유형 T와 함께 [offset, offset + size) 범위에 있습니다.

OI가 i32이면:

SI가 i32이면:

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>
전제 조건 AS는 storage, uniform 또는 workgroup 중 하나입니다.
AM은 AS에 유효한 접근 모드입니다.

T는 고정 풋프린트가 없는 호스트 공유 가능 유형입니다.
T는 원자적 유형이나 버퍼 유형이어서는 안 되며 이를 포함해서도 안 됩니다 원자적 또는 버퍼 유형.
T는 반드시 AS에 대한 주소 공간 레이아웃 제약 조건을 만족해야 합니다.

OI는 u32 또는 i32입니다.
SI는 u32 또는 i32입니다.

설명 p의 시작부터 offset바이트 떨어진 지점부터 size 바이트의 메모리 뷰를 T 유형으로 재해석합니다. 즉, p와 연결된 메모리 위치가 [0, bufferLength(p)) 범위에 있으면 결과와 연결된 메모리 위치는 저장 유형 T와 함께 [offset, offset + size) 범위에 있습니다.

OI가 i32이면:

SI가 i32이면:

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
전제 조건 AS는 storage, uniform 또는 workgroup 중 하나입니다.
AM은 AS에 유효한 접근 모드입니다.
설명 프로시저 간 분석 중 발견된 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 미디어 유형

Internet Assigned Numbers Authority(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" 등)의 의미로 해석해야 합니다.

알고리즘이나 특정 단계로 표현된 적합성 요구 사항은 최종 결과가 동등하기만 하면 어떤 방식으로든 구현할 수 있습니다. 특히 이 명세에서 정의하는 알고리즘은 이해하기 쉽도록 작성되었으며 성능을 목적으로 하지 않습니다. 구현자는 최적화하는 것이 권장됩니다.

색인

이 명세에서 정의된 용어

참조에 의해 정의된 용어

참고 문헌

규범적 참고 문헌

[CSS-VALUES-4]
Tab Atkins Jr.; Elika Etemad. CSS 값 및 단위 모듈 레벨 4. 2024년 3월 12일. 작업 초안. URL: https://www.w3.org/TR/css-values-4/
[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. 유니코드 줄 바꿈 알고리즘. 2026년 9월 1일. 유니코드 표준 부록 #14. URL: https://www.unicode.org/reports/tr14/tr14-57.html
[UAX31]
Mark Davis; Robin Leroy. 유니코드 식별자 및 구문. 2026년 9월 1일. 유니코드 표준 부록 #31. URL: https://www.unicode.org/reports/tr31/tr31-45.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; et al. 월드 와이드 웹의 문자 모델: 문자열 일치. 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. 2×2 행렬식의 정확한 계산을 위한 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년 10월 23일. 후보 권고안 초안. URL: https://www.w3.org/TR/wasm-core-2/