1. 소개
WebGPU 셰이딩 언어(WGSL)는 [WebGPU]용 셰이더 언어이다. 즉, WebGPU API를 사용하는 애플리케이션은 WGSL을 사용하여 GPU에서 실행되는 셰이더라는 프로그램을 표현한다.
// 텍스처가 적용된 기하 도형을 점 광원으로 조명하는 프래그먼트 셰이더. // 스토리지 버퍼 바인딩의 광원. struct PointLight { position: vec3f, color : vec3f, } struct LightStorage { pointCount : u32, point : array< PointLight > , } @group ( 0 ) @binding ( 0 ) var < storage> lights : LightStorage ; // 텍스처 및 샘플러. @group ( 1 ) @binding ( 0 ) var baseColorSampler : sampler; @group ( 1 ) @binding ( 1 ) var baseColorTexture : texture_2d< f32> ; // 함수 인수는 버텍스 셰이더에서 가져온 값이다. @fragment fn fragmentMain ( @location ( 0 ) worldPos : vec3f, @location ( 1 ) normal : vec3f, @location ( 2 ) uv : vec2f) -> @location ( 0 ) vec4f{ // 텍스처에서 표면의 기본 색상을 샘플링한다. let baseColor = textureSample ( baseColorTexture , baseColorSampler , uv ); let N = normalize ( normal ); var surfaceColor = vec3f( 0 ); // 장면의 점 광원을 순회한다. for ( var i = 0u ; i < lights . pointCount ; i ++ ) { let worldToLight = lights . point [ i ]. position- worldPos ; let dist = length ( worldToLight ); let dir = normalize ( worldToLight ); // 이 광원이 표면 색상에 기여하는 정도를 결정한다. let radiance = lights . point [ i ]. color * ( 1 / pow ( dist , 2 )); let nDotL = max ( dot ( N , dir ), 0 ); // 광원의 기여도를 표면 색상에 누적한다. surfaceColor += baseColor . rgb * radiance * nDotL ; } // 누적된 표면 색상을 반환한다. return vec4( surfaceColor , baseColor . a ); }
1.1. 개요
WebGPU는 GPU 명령의 형태로 작업 단위를 GPU에 전달한다. WGSL은 두 종류의 GPU 명령을 다룬다.
두 종류의 파이프라인 모두 WGSL로 작성된 셰이더를 사용한다.
셰이더는 파이프라인에서 셰이더 스테이지를 실행하는 WGSL 프로그램의 일부이다. 셰이더는 다음으로 구성된다.
-
진입점에서 시작하여 호출되는 모든 함수의 전이 폐쇄. 이 집합에는 사용자 정의 함수와 내장 함수가 모두 포함된다. (더 엄밀한 정의는 “셰이더 스테이지의 함수”를 참조한다.)
-
이러한 모든 함수가 정적으로 접근하는 변수 및 상수의 집합.
-
이러한 모든 함수, 변수 및 상수를 정의하거나 분석하는 데 사용되는 유형의 집합.
참고: WGSL 프로그램에는 진입점이 필요하지 않다. 그러나
진입점은 GPUProgrammableStage를
생성하는 데 필요하므로 이러한 프로그램은 API에서 실행할 수 없다.
셰이더 스테이지를 실행할 때 구현은 다음을 수행한다.
-
모듈 범위에서 선언된 상수의 값을 계산한다.
-
리소스를 셰이더의 리소스 인터페이스에 있는 변수에 바인딩하여, 실행 중에 셰이더가 해당 리소스의 콘텐츠를 사용할 수 있게 한다.
-
다른 모듈 범위 변수에 메모리를 할당하고, 그 메모리를 지정된 초기 값으로 채운다.
-
진입점의 형식 매개변수가 존재하는 경우 셰이더 스테이지의 입력으로 채운다.
-
진입점의 반환 값이 존재하는 경우 셰이더 스테이지의 출력에 연결한다.
-
그런 다음 진입점을 호출한다.
WGSL 프로그램은 다음으로 구성된다.
-
모듈 수준의 동작 제어를 지정하는 지시문.
-
실행 동작을 지정하는 함수.
-
선언 또는 실행 가능한 동작의 단위인 문.
-
순수한 수학적 값의 텍스트 표현인 리터럴.
-
각각 특정 시점에 계산된 값의 이름을 제공하는 상수.
-
각각 값을 보유한 메모리의 이름을 제공하는 변수.
-
각각 값의 집합을 결합하여 결과 값을 생성하는 표현식.
-
각각 다음을 설명하는 유형.
-
값의 집합.
-
지원되는 표현식에 대한 제약 조건.
-
해당 표현식의 의미론.
-
-
다음과 같은 추가 정보를 지정하도록 객체를 수정하는 특성.
참고: 현재 WGSL 프로그램은 하나의 WGSL 모듈로 구성된다.
WGSL은 명령형 언어이다. 동작은 실행할 문의 시퀀스로 지정된다. 문은 다음을 수행할 수 있다.
-
변수의 콘텐츠를 수정한다.
-
구조적 프로그래밍 구문을 사용하여 실행 순서를 수정한다.
-
위 동작의 일부로 값을 계산하기 위해 표현식을 평가한다.
WGSL은 정적 유형 언어이다. 특정 표현식에서 계산되는 각 값은 프로그램 소스만 조사하여 결정되는 특정 유형에 속한다.
WGSL에는 불리언과 숫자 (정수 및 부동 소수점)를 설명하는 유형이 있다. 이러한 유형은 복합 유형 (벡터, 행렬, 배열 및 구조체)으로 집계할 수 있다. WGSL에는 고유한 연산을 제공하는 특수 유형(예: 원자적 유형)이 있다. WGSL은 메모리에 저장할 수 있는 유형을 메모리 뷰로 설명한다. WGSL은 일반적으로 사용되는 렌더링 유형을 텍스처 및 샘플러 형태로 제공한다. 이러한 유형에는 그래픽 렌더링용으로 일반적으로 제공되는 GPU 하드웨어의 기능을 노출하는 관련 내장 함수가 있다.
WGSL은 암시적 변환과 승격이 매우 제한적이다. 인수로 함수 호출에 전달되는 추상 유형 및 버퍼 포인터에서만 암시적 변환과 승격을 제공한다. 값을 하나의 구체적 숫자 또는 불리언 유형에서 다른 유형으로 변환하려면 명시적 변환, 값 생성자 또는 비트 재해석이 필요하다. 그러나 WGSL은 스칼라 유형을 벡터 유형으로 승격하는 제한적인 기능을 제공한다. 이는 복합 유형에도 적용된다.
셰이더 스테이지의 작업은 하나 이상의 호출로 분할되며, 각 호출은 약간 다른 조건에서 진입점을 실행한다. 셰이더 스테이지의 호출은 특정 변수에 대한 접근을 공유한다.
-
스테이지의 모든 호출은 셰이더 인터페이스의 리소스를 공유한다.
-
컴퓨트 셰이더에서 동일한 워크그룹의 호출은 주소 공간 중 워크그룹에 있는 변수를 공유한다. 서로 다른 워크그룹의 호출은 이러한 변수를 공유하지 않는다.
그러나 호출은 호출을 동료 호출과 구별하는 식별 값을 제공하는 내장 입력을 포함하여 서로 다른 셰이더 스테이지 입력 집합에 작용한다. 각 호출에는 비공개 및 함수 주소 공간의 변수 형태로 자체적인 독립 메모리 공간이 있다.
셰이더 스테이지 내의 호출은 동시에 실행되며, 흔히 병렬로 실행될 수 있다. 셰이더 작성자는 셰이더 스테이지 호출의 동적 동작이 다음을 충족하도록 해야 한다.
-
텍스처 샘플링 및 제어 배리어를 포함한 특정 기본 연산의 균일성 요구 사항을 충족한다.
-
데이터 경쟁을 방지하도록 공유 변수에 대한 잠재적으로 충돌하는 접근을 조정한다.
WGSL은 특정 기능에 대해 가능한 여러 동작을 허용하는 경우가 있다. 서로 다른 구현이 서로 다른 동작을 나타낼 수 있으므로 이는 이식성 위험 요소이다. WGSL의 설계는 이러한 사례를 최소화하는 것을 목표로 하지만, 실현 가능성과 광범위한 장치에서 높은 성능을 달성하려는 목표에 의해 제약된다.
동작 요구 사항은 구현이 WGSL 프로그램을 처리하거나 실행할 때 수행하는 작업이다. 이는 프로그래머와의 계약에서 구현이 지는 의무를 설명한다. 명세는 이러한 의무가 명백하지 않을 수 있는 경우 이를 명시적으로 기술한다.
1.2. 구문 표기법
다음 구문 표기법은 WGSL 구문 문법의 규칙을 설명한다.
-
규칙의 양쪽에 있는 기울임꼴 텍스트는 구문 규칙을 나타낸다.
-
규칙 오른쪽에서 작은따옴표(')로 시작하고 끝나는 굵은 고정폭 텍스트는 키워드와 토큰을 나타낸다.
-
일반 텍스트의 콜론(:)은 구문 규칙을 등록한다.
-
일반 텍스트의 세로 막대(|)는 대안을 나타낸다.
-
일반 텍스트의 물음표(?)는 앞의 키워드, 토큰, 규칙 또는 그룹이 0번이나 1번 나타남(선택 사항)을 의미한다.
-
일반 텍스트의 별표(*)는 앞의 키워드, 토큰, 규칙 또는 그룹이 0번 이상 나타남을 의미한다.
-
일반 텍스트의 더하기 기호(+)는 앞의 키워드, 토큰, 규칙 또는 그룹이 1번 이상 나타남을 의미한다.
-
일반 텍스트에서 서로 대응하는 여는 괄호(()와 닫는 괄호 ()) 쌍은 요소 그룹을 나타낸다.
1.3. 수학 용어 및 표기법
각도:
-
관례적으로 각도는 라디안으로 측정한다.
-
각도를 측정하기 위한 기준 반직선은 원점 (0,0)에서 (+∞,0)을 향하는 반직선이다.
-
θ를 비교 반직선과 기준 반직선 사이의 각도라고 하자. 그러면 비교 반직선이 시계 반대 방향으로 이동할수록 θ가 증가한다.
-
완전한 원 하나에는 2 π 라디안이 있다.
-
예:
-
각도 0은 원점에서 오른쪽의 (1,0)을 가리킨다.
-
각도 2π는 원점에서 오른쪽의 (1,0)을 가리킨다.
-
각도 π/4는 원점에서 점 (1,1)을 가리킨다.
-
각도 π/2는 원점에서 점 (0,1)을 가리킨다.
-
각도 π는 원점에서 점 (-1,0)을 가리킨다.
-
각도 (3/2)π는 원점에서 점 (0,-1)을 가리킨다.
-
쌍곡각은 전통적인 의미의 각도가 아니라 단위가 없는 넓이이다. 구체적으로는 다음과 같다.
-
x > 0인 쌍곡선 x2 - y2 = 1을 생각한다.
-
R을 원점에서 쌍곡선 위의 어떤 점 (x, y)으로 향하는 반직선이라고 하자.
-
a를 R, x축 및 쌍곡선 자체의 곡선으로 둘러싸인 넓이의 두 배라고 하자.
-
R이 x축 위에 있으면 a를 양수로, 아래에 있으면 음수로 간주한다.
그러면 넓이 a는 x가 a의 쌍곡코사인이고 y가 a의 쌍곡사인인 쌍곡각이다.
양의 무한대는 +∞로 표기하며 모든 실수보다 엄격하게 큰 고유한 값이다.
음의 무한대는 −∞로 표기하며 모든 실수보다 엄격하게 작은 고유한 값이다.
확장 실수 (아핀 확장 실수라고도 함)는 실수에 +∞와 −∞를 합친 집합이다. 컴퓨터는 부동 소수점 유형을 사용하여 두 무한대의 값을 포함한 확장 실수를 근사적으로 표현한다. § 15.7 부동 소수점 평가를 참조한다.
구간은 하한과 상한이 있는 연속적인 숫자 집합이다. 문맥에 따라 정수, 부동 소수점 수, 실수 또는 확장 실수의 집합이다.
-
닫힌 구간 [a,b]는 a ≤ x ≤ b인 숫자 x의 집합이다.
-
반열린 구간 [a,b)는 a ≤ x < b인 숫자 x의 집합이다.
-
반열린 구간 (a,b]는 a < x ≤ b인 숫자 x의 집합이다.
내림 표현식은 확장 실수 x에 대해 다음과 같이 정의된다.
-
⌊ +∞ ⌋ = +∞
-
⌊ −∞ ⌋ = −∞
-
실수 x에 대해 ⌊x⌋ = k이며, 여기서 k는 k ≤ x < k+1을 충족하는 유일한 정수이다.
올림 표현식은 확장 실수 x에 대해 다음과 같이 정의된다.
-
⌈ +∞ ⌉ = +∞
-
⌈ −∞ ⌉ = −∞
-
실수 x에 대해 ⌈x⌉ = k이며, 여기서 k는 k-1 < x ≤ k를 충족하는 유일한 정수이다.
truncate 함수는 확장 실수 x에 대해 다음과 같이 정의된다.
-
truncate(+∞) = +∞
-
truncate(−∞) = −∞
-
실수 x에 대해 절댓값이 x의 절댓값보다 작거나 같은 가장 가까운 정수를 계산한다.
-
x ≥ 0이면 truncate(x) = ⌊x⌋이고, x < 0이면 ⌈x⌉이다.
-
roundUp 함수는 양의 정수 k와 n에 대해 다음과 같이 정의된다.
-
roundUp(k, n) = ⌈n ÷ k⌉ × k
roundDown 함수는 양의 정수 k와 n에 대해 다음과 같이 정의된다.
-
roundDown(k, n) = ⌊n ÷ k⌋ × k
c열 r행 행렬 A의 전치는 A의 행을 AT의 열로 복사하여 형성한 r열 c행 행렬 AT이다.
-
transpose(A) = AT
-
transpose(A)i,j = Aj,i
열 벡터의 전치는 열 벡터를 1행 행렬로 해석하여 정의한다. 마찬가지로 행 벡터의 전치는 행 벡터를 1열 행렬로 해석하여 정의한다.
2. WGSL 모듈
WGSL 프로그램은 하나의 WGSL 모듈로 구성된다.
모듈은 선택적인 지시문의 시퀀스와 그 뒤에 오는 모듈 범위 선언 및 어설션으로 구성된다. 모듈은 다음으로 구성된다.
-
모듈 수준의 동작 제어를 지정하는 지시문.
-
실행 동작을 지정하는 함수.
-
선언 또는 실행 가능한 동작의 단위인 문.
-
순수한 수학적 값의 텍스트 표현인 리터럴.
-
각각 값을 보유한 메모리의 이름을 제공하는 변수.
-
각각 특정 시점에 계산된 값의 이름을 제공하는 상수.
-
각각 값의 집합을 결합하여 결과 값을 생성하는 표현식.
-
각각 다음을 설명하는 유형.
-
값의 집합.
-
지원되는 표현식에 대한 제약 조건.
-
해당 표현식의 의미론.
-
-
다음과 같은 추가 정보를 지정하도록 객체를 수정하는 특성.
global_directive * ( global_decl | global_assert | ';' ) *
2.1. 셰이더 수명 주기
WGSL 프로그램 및 그 안에 포함될 수 있는 셰이더의 수명 주기에는 네 가지 주요 이벤트가 있다. 처음 두 이벤트는 WGSL 프로그램의 실행을 준비하는 데 사용되는 WebGPU API 메서드에 대응한다. 마지막 두 이벤트는 셰이더 실행의 시작과 종료이다.
이벤트는 다음과 같다.
-
셰이더 모듈 생성
-
이는 WebGPU
createShaderModule()메서드가 호출될 때 발생한다. 이때 WGSL 프로그램의 소스 텍스트가 제공된다.
-
-
파이프라인 생성
-
이는 WebGPU
createComputePipeline()메서드 또는 WebGPUcreateRenderPipeline()메서드가 호출될 때 발생한다. 이 메서드는 다른 구성 정보와 함께 이전에 생성된 셰이더 모듈을 하나 이상 사용한다. -
파이프라인을 생성하는 동안에는
GPUProgrammableStage의 지정된 진입점에 대한 셰이더를 형성하는 코드만 고려한다. 즉, 진입점과 관련이 없는 코드는 컴파일 전에 사실상 제거된다. -
참고: 각 셰이더 스테이지는 별도로 컴파일되는 것으로 간주되므로 모듈의 서로 다른 부분을 포함할 수 있다.
-
-
셰이더 실행 시작
-
셰이더 실행 종료
이벤트의 순서는 다음 이유로 정해진다.
-
데이터 종속성: 셰이더 실행에는 파이프라인이 필요하고, 파이프라인에는 셰이더 모듈이 필요하다.
-
인과성: 셰이더는 실행을 마치기 전에 실행을 시작해야 한다.
2.2. 오류
WebGPU 구현은 다음 두 가지 이유로 셰이더를 처리하지 못할 수 있다.
-
셰이더가 WGSL 또는 WebGPU 명세의 요구 사항을 충족하지 않으면 프로그램 오류가 발생한다.
-
모든 WGSL 및 WebGPU 요구 사항이 충족되었더라도 분류되지 않은 오류가 발생할 수 있다. 가능한 원인은 다음과 같다.
-
셰이더가 너무 복잡하여 구현의 기능을 초과하지만, 규정된 제한으로 쉽게 표현할 수 없는 경우. 셰이더를 단순화하면 문제를 우회할 수 있다.
-
WebGPU 구현의 결함.
-
셰이더 수명 주기의 세 단계에서 처리 오류가 발생할 수 있다.
-
셰이더 생성 오류는 셰이더 모듈 생성 시점에 실현 가능하게 감지할 수 있는 오류이다. 감지는 WGSL 모듈 소스 텍스트와
createShaderModuleAPI 메서드에서 사용할 수 있는 기타 정보에만 의존한다. 프로그램이 수행해야 한다고 설명하는 이 명세의 문장은 일반적으로 해당 단언을 위반하면 셰이더 생성 오류를 발생시킨다. -
파이프라인 생성 오류는 파이프라인 생성 시점에 감지할 수 있는 오류이다. 감지는 WGSL 모듈 소스 텍스트와 특정 파이프라인 생성 API 메서드에서 사용할 수 있는 기타 정보에 의존한다. 이러한 오류는
GPUProgrammableStage용으로 컴파일되는 진입점의 셰이더에 존재하는 코드에 대해서만 트리거된다. -
동적 오류는 셰이더 실행 중에 발생하는 오류이다. 이러한 오류는 감지할 수도 있고 감지하지 못할 수도 있다.
참고: 예를 들어 데이터 경쟁은 감지하지 못할 수 있다.
각 요구 사항은 가능한 가장 이른 시점에 검사된다. 즉, 다음과 같다.
-
셰이더 생성 시점에 감지할 수 있는 요구 사항을 충족하지 못하면 셰이더 생성 오류가 발생한다.
-
파이프라인 생성 시점에는 감지할 수 있지만 더 이른 시점에는 감지할 수 없는 요구 사항을 충족하지 못하면 파이프라인 생성 오류가 발생한다.
문맥에서 명확하지 않은 경우 이 명세는 특정 요구 사항을 충족하지 못하면 셰이더 생성 오류, 파이프라인 생성 오류 또는 동적 오류 중 어느 것이 발생하는지를 나타낸다.
오류의 결과는 다음과 같다.
-
셰이더 생성 오류 또는 파이프라인 생성 오류가 있는 WGSL 모듈은 파이프라인에 통합되지 않으므로 실행되지 않는다.
-
동적 오류가 발생하는 경우:
-
-
WGSL 모듈의 변수에 바인딩된 리소스의 모든 부분 및
-
WGSL 모듈에서 선언된 기타 변수.
-
그 밖에는 프로그램이 이 명세의 나머지 부분에서 설명한 대로 동작하지 않을 수 있다. 참고: 이러한 영향은 비국소적일 수 있다.
-
2.3. 진단
구현은 셰이더 모듈 생성 또는 파이프라인 생성 중에 진단을 생성할 수 있다. 진단은 애플리케이션 작성자에게 도움을 주기 위해 구현이 생성하는 메시지이다.
트리거 규칙이라는 특정 조건이 충족되면 진단이 생성되거나 트리거된다. 소스 텍스트에서 조건이 충족되는 위치는 소스 텍스트 내의 점 또는 범위로 표현하며, 이를 트리거 위치라고 한다.
진단에는 다음 속성이 있다.
진단의 심각도는 다음 중 하나이며, 가장 높은 것부터 가장 낮은 것까지 나열되어 있다.
- 오류
-
진단이 오류이다. 이는 셰이더 생성 오류 또는 파이프라인 생성 오류에 해당한다.
- 경고
-
진단은 애플리케이션 개발자가 주의를 기울일 만하지만 오류는 아닌 이상 상태를 설명한다.
- 정보
-
진단은 애플리케이션 개발자가 주의를 기울일 만하지만 오류나 경고는 아닌 주목할 만한 조건을 설명한다.
- 꺼짐
-
진단이 비활성화된다. 애플리케이션에 전달되지 않는다.
트리거 규칙의 이름은 다음 중 하나이다.
-
diagnostic_name_token 하나 또는
-
마침표
'.'(U+002E)로 구분된 두 개의 diagnostic_name_token 토큰.
2.3.1. 진단 처리
트리거된 진단은 다음과 같이 처리된다.
-
각 진단 D에 대해 D의 트리거 위치를 포함하고 동일한 트리거 규칙을 가지면서 영향을 받는 범위가 가장 작은 진단 필터를 찾는다.
-
이러한 필터가 존재하면 D에 적용하여 D의 심각도를 업데이트한다.
-
그렇지 않으면 D는 변경되지 않는다.
-
-
심각도가 꺼짐인 진단을 폐기한다.
-
남아 있는 진단 중 하나 이상인 DI의 심각도가 정보이면 다음을 수행한다.
-
트리거 규칙이 동일한 다른 정보 진단을 폐기하여 원래 진단 DI만 남겨도 된다.
-
-
남아 있는 진단 중 하나 이상인 DW의 심각도가 경고이면 다음을 수행한다.
-
남아 있는 진단 중 하나 이상의 오류 심각도가 있으면 다음을 수행한다.
-
셰이더 모듈 생성 시점에 처리하는 경우 남아 있는 진단은 WebGPU
GPUCompilationInfo객체의messages멤버를 채운다. -
파이프라인 생성 중에 처리하는 경우 오류 진단은
GPUProgrammableStage를 검증할 때 WebGPU 검증 실패를 발생시킨다.
참고: 이 규칙은 구현이 오류를 감지하는 즉시 WGSL 모듈 처리를 중단할 수 있도록 허용한다. 또한 특정 종류의 경고에 대한 분석은 첫 번째 경고에서 중단할 수 있으며, 특정 종류의 정보 진단에 대한 분석은 첫 번째 발생에서 중단할 수 있다. WGSL은 서로 다른 종류의 분석을 수행하는 순서나 단일 분석 내의 순서를 지정하지 않는다. 따라서 동일한 WGSL 모듈에 대해 서로 다른 구현이 동일한 심각도를 가진 서로 다른 진단 인스턴스를 보고할 수 있다.
2.3.2. 필터링 가능한 트리거 규칙
대부분의 진단은 무조건 WebGPU 애플리케이션에 보고된다. 일부 종류의 진단은 부분적으로 해당 트리거 규칙의 이름을 지정하여 필터링할 수 있다. 다음 표에는 필터링할 수 있는 표준 트리거 규칙 집합이 나열되어 있다.
| 필터링 가능한 트리거 규칙 | 기본 심각도 | 트리거 위치 | 설명 |
|---|---|---|---|
| derivative_uniformity | 오류 | 도함수를 계산하는 내장 함수에 대한 호출 지점의 위치. 즉, 다음 중 하나에 대한 호출 위치이다. |
내장 함수 호출이 도함수를 계산하지만 균일성 분석으로는
호출이 균일한
제어 흐름에서 발생함을 증명할 수 없다.
§ 15.2 균일성을 참조한다. |
| subgroup_uniformity | 오류 | 서브그룹 또는 쿼드 내장 함수에 대한 호출 지점의 위치. |
서브그룹 또는 쿼드 내장 함수 호출이지만 균일성 분석으로는
호출이 균일한
제어 흐름에서 발생함을 증명할 수 없다.
또한 균일성 분석으로 다음 매개변수 값이 균일함을
증명할 수 없는 경우이다.
§ 15.2 균일성을 참조한다. |
단일 진단 이름 토큰으로 구성된 인식되지 않는 트리거 규칙을 사용하면 사용자 에이전트가 경고를 트리거해야 한다.
구현은 여기에 지정되지 않은 트리거 규칙을 지원할 수 있다. 단, 해당 규칙은 diagnostic_rule_name의 다중 토큰 형식을 사용하여 표기해야 한다. 다중 토큰 형식으로 표기된 인식되지 않는 트리거 규칙을 사용하면 그 자체로 진단을 트리거할 수도 있다.
이 명세의 향후 버전은 특정 규칙을 제거하거나 기본 심각도를 약화하면서
(즉, 현재 기본값을 심각도가 더 낮은 기본값으로 대체하면서도) 이전 버전과의
호환성을 충족하는 것으로 간주될 수 있다.
예를 들어 WGSL의 향후 버전은 derivative_uniformity의 기본 심각도를
error에서 warning 또는 info로 변경할 수 있다.
명세가 이와 같이 변경된 후에도 이전에 유효했던 프로그램은 계속 유효하다.
2.3.3. 진단 필터링
필터링 가능한 트리거 규칙을 가진 진단이 트리거되면 WGSL은 해당 진단을 폐기하거나 심각도를 수정하는 메커니즘을 제공한다.
진단 필터 DF에는 세 개의 매개변수가 있다.
진단 필터 DF(AR,NS,TR)를 진단 D에 적용하면 다음과 같은 효과가 있다.
범위 진단
필터는 영향 범위가 지정된 소스
텍스트 범위인 진단 필터이다.
범위 진단 필터는 다음 표에 지정된 대로 영향을 받는 소스 범위의 시작 부분에서
@diagnostic 특성으로 지정한다.
@diagnostic 특성은 그 밖의 위치에 나타나서는 안 된다.
| 배치 | 영향 범위 |
|---|---|
| 복합문의 시작. | 복합문. |
| 함수 선언의 시작. | 함수 선언. |
| if 문의 시작. | if 문: 모든 제어 조건 표현식을 포함한 if_clause와 연관된 모든 else_if_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)은 다음과 같은 경우 충돌한다.
-
(AR1 = AR2)이고
-
(TR1 = TR2)이며
-
(NS1 ≠ NS2)이다.
참고: 여러 전역 진단 필터가 충돌하지 않는 경우 이를 허용한다.
WGSL의 진단 필터는 영향 범위가 완벽하게 중첩되도록 설계되었다. DF1의 영향 범위와 DF2의 영향 범위가 겹치는 경우 DF1의 영향 범위가 DF2의 영향 범위에 완전히 포함되거나 그 반대이다.
소스 위치 L 및 트리거 규칙 TR에 대한 가장 가까운 둘러싸는 진단 필터가 존재하는 경우 다음을 충족하는 진단 필터 DF(AR,NS,TR)이다.
-
L이 영향 범위 AR에 속하고
-
L이 AR'에 속하는 다른 필터 DF'(AR',NS',TR)가 있다면 AR은 AR'에 포함된다.
영향 범위는 중첩되므로 가장 가까운 둘러싸는 진단은 다음과 같다.
2.4. 제한
WGSL 구현은 다음 제한을 충족하는 셰이더를 지원한다. WGSL 구현은 지정된 제한을 초과하는 셰이더를 지원할 수 있다.
참고: WGSL 구현이 지정된 제한을 초과하는 셰이더를 지원하지 않는다면 오류를 발생시켜야 한다.
| 제한 | 지원되는 최솟값 |
|---|---|
| 구조체 유형의 최대 멤버 수 | 1023 |
| 복합 유형의 최대 중첩 깊이 | 15 |
| 함수에서 중괄호로 둘러싸인 문의 최대 중첩 깊이 | 127 |
| 함수의 최대 매개변수 수 | 255 |
| switch 문에서 case 선택자 값의 최대 수. 각 case 문에 있는 case 값 수의 합으로, default 절을 포함한다. | 1023 |
| 단일 셰이더가 정적으로 접근하며 private 주소 공간에서 인스턴스화된 모든 변수의 최대 합산 바이트 크기 | 8192 |
| 단일 함수에서 선언되고 function 주소 공간에서 인스턴스화된 모든 변수의 최대 합산 바이트 크기 | 8192 |
|
단일 셰이더가
정적으로
접근하며
workgroup 주소 공간에서 인스턴스화된
모든 변수의
최대 합산 바이트 크기
이 제한의 목적상 override 값을 대입할 때 고정 풋프린트 배열은 생성 시 고정되는 풋프린트 배열로 취급한다. 이는 WebGPU의 maxComputeWorkgroupStorageSize 제한을 독립적인 WGSL 제한으로 매핑한다. | 16384 |
|
즉시 데이터
변수의 최대 바이트 크기.
이는 WebGPU의 maxImmediateSize 제한을 독립적인 WGSL 제한으로 매핑한다. | 64 |
| 배열 유형의 값 생성자 표현식에 있는 최대 요소 수 | 2047 |
3. 텍스트 구조
text/wgsl 미디어 유형은 콘텐츠를 WGSL 모듈로 식별하는 데 사용된다.
부록 A: text/wgsl 미디어 유형을 참조한다.
WGSL 모듈은 바이트 순서 표시(BOM) 없이 UTF-8 인코딩을 사용하는 유니코드 텍스트이다.
WGSL 모듈 텍스트는 다음을 형성하는 연속적인 비어 있지 않은 집합으로 그룹화된 유니코드 코드 포인트의 시퀀스로 구성된다.
프로그램 텍스트에는 null 코드 포인트(U+0000)가 포함되어서는 안 된다.
3.1. 구문 분석
WGSL 모듈을 구문 분석하려면 다음을 수행한다.
주석을 제거한다.
첫 번째 주석을 공백 코드 포인트(
U+0020)로 대체한다.주석이 남지 않을 때까지 반복한다.
§ 3.9 템플릿 목록의 알고리즘을 사용하여 템플릿 목록을 찾는다. 이 단계는
'<'(U+003C)와'>'(U+003E) 코드 포인트가 템플릿 목록 구분 기호로 사용되는 경우와 비교 연산자 등에 사용되는 경우를 구분한다.전체 텍스트를 구문 분석하여 translation_unit 문법 규칙과 일치하는지 확인한다. 구문 분석에서는 다음과 같이 사용자 지정된 LALR(1) 파서(하나의 선행 탐색 토큰)를 [DeRemer1969] 사용한다.
토큰화는 구문 분석과 교차하여 수행되며 문맥을 인식한다. 파서가 다음 토큰을 요청할 때:
공백 코드 포인트의 초기 시퀀스를 소비하고 무시한다.
다음 코드 포인트가 템플릿 목록의 시작이면 이를 소비하고 _template_args_start를 반환한다.
다음 코드 포인트가 템플릿 목록의 끝이면 이를 소비하고 _template_args_end를 반환한다.
그렇지 않으면:
토큰 후보는 아직 소비하지 않은 나머지 코드 포인트의 비어 있지 않은 접두사로 형성된 모든 WGSL 토큰이다.
반환되는 토큰은 현재 파서 상태에서 유효한 선행 탐색 토큰이기도 한 가장 긴 토큰 후보이다. [VanWyk2007]
다음과 같은 경우 셰이더 생성 오류가 발생한다.
-
전체 소스 텍스트를 유효한 토큰의 유한 시퀀스로 변환할 수 없는 경우 또는
-
translation_unit 문법 규칙이 전체 토큰 시퀀스와 일치하지 않는 경우.
대안은 템플릿 목록 탐색과 토큰화를 교차하여 수행하는 것이다. 이 접근 방식에서는 템플릿 목록이 나타날 수 있는 문법 규칙의 모든 위치에 합성 토큰(_disambiguate_template)을 배치한다. 스캐너가 _disambiguate_template 토큰을 일치시키려고 할 때:
-
스캐너는 남은 텍스트에서 템플릿 목록 탐색 알고리즘을 실행하여 템플릿 목록 구분 기호의 위치를 기록한다.
-
스캐너는 연관된 텍스트로 빈 문자열을 사용하여
_disambiguate_template토큰이 성공적으로 일치했음을 알린다.
향후 토큰 스캐닝 단계에서는 기록된 템플릿 목록 구분 기호의 위치를 사용하여 지시된 대로 _template_args_start 및 _template_args_end 토큰을 생성한다.
이 대안적 접근 방식은 비규범적이다. 규범적 문법에는 대안적 접근 방식을 사용하는 구현을 돕기 위한 _disambiguate_template 토큰이 포함된다. 표준 접근 방식을 사용하는 파서는 합성 토큰을 무시하거나, 이와 동등하게 항상 빈 문자열과 성공적으로 일치시킬 수 있다.
3.2. 공백 및 줄바꿈
공백은 유니코드 Pattern_White_Space 속성에 속하는 하나 이상의 코드 포인트를 임의로 조합한 것이다. 다음은 Pattern_White_Space에 속하는 코드 포인트 집합이다.
-
공백(
U+0020) -
수평 탭(
U+0009) -
줄 바꿈(
U+000A) -
수직 탭(
U+000B) -
폼 피드(
U+000C) -
캐리지 리턴(
U+000D) -
다음 줄(
U+0085) -
왼쪽에서 오른쪽 표시(
U+200E) -
오른쪽에서 왼쪽 표시(
U+200F) -
줄 구분 기호(
U+2028) -
단락 구분 기호(
U+2029)
줄바꿈은 줄의 끝을 나타내는 공백 코드 포인트의 연속적인 시퀀스이다. 이는 UAX14 제6.1절 맞춤 설정할 수 없는 줄바꿈 규칙의 LB4 및 LB5에 정의된 “필수 줄바꿈”을 나타내는 공백으로 정의된다. 즉, 줄바꿈은 다음 중 하나이다.
-
줄 바꿈(
U+000A) -
수직 탭(
U+000B) -
폼 피드(
U+000C) -
뒤에 줄 바꿈(
U+000A)이 오지 않는 캐리지 리턴(U+000D) -
뒤에 줄 바꿈(
U+000A)이 오는 캐리지 리턴(U+000D) -
다음 줄(
U+0085) -
줄 구분 기호(
U+2028) -
단락 구분 기호(
U+2029)
참고: 줄 번호로 소스 텍스트 위치를 보고하는 진단은 줄 수를 계산할 때 줄바꿈을 사용해야 한다.
3.3. 주석
주석은 토큰을 구분할 수 있다는 점을 제외하면 WGSL 프로그램의 유효성이나 의미에 영향을 주지 않는 텍스트 범위이다. 셰이더 작성자는 주석을 사용하여 프로그램을 문서화할 수 있다.
줄 끝
주석은 두 코드 포인트 //(U+002F 다음에 U+002F)와
그 뒤에 오는 코드 포인트로 구성된 주석의 한 종류이며,
다음은 포함하지 않고 그 직전까지 이어진다.
-
다음 줄바꿈 또는
-
프로그램의 끝.
블록 주석은 다음으로 구성되는 주석의 한 종류이다.
-
두 코드 포인트
/*(U+002F다음에U+002A) -
그런 다음 다음 항목의 임의 시퀀스:
-
블록 주석 또는
-
*/(U+002A다음에U+002F)이나/*(U+002F다음에U+002A)를 포함하지 않는 텍스트
-
-
그런 다음 두 코드 포인트
*/(U+002A다음에U+002F)
참고: 블록 주석은 중첩할 수 있다. 블록 주석에는 서로 대응하는 시작 및 종료 텍스트 시퀀스가 필요하고 임의 중첩을 허용하므로 정규 표현식으로 블록 주석을 인식할 수 없다. 이는 정규 언어의 펌핑 보조정리에서 비롯된 결과이다.
const f = 1.5 ; // 이것은 줄 끝 주석이다. const g = 2.5 ; /* 이것은 여러 줄에 걸쳐 있는 블록 주석이다. /* 블록 주석은 중첩할 수 있다. */ 그러나 모든 블록 주석은 종료되어야 한다. */
3.4. 토큰
토큰은 다음 중 하나를 형성하는 연속적인 코드 포인트 시퀀스이다.
3.5. 리터럴
리터럴은 다음 중 하나이다.
-
불리언 리터럴:
true또는false. -
숫자 리터럴: 정수 리터럴 또는 부동 소수점 리터럴이며, 숫자를 표현하는 데 사용된다.
3.5.1. 불리언 리터럴
'true'
| 'false'
3.5.2. 숫자 리터럴
숫자 리터럴의 형식은 패턴 일치를 통해 정의된다.
정수 리터럴은 다음과 같다.
-
다음 중 하나로 지정된 정수:
-
0 -
첫 번째 숫자가
0이 아닌 10진수 숫자의 시퀀스. -
0x또는0X뒤에 오는 16진수 숫자의 시퀀스.
-
-
그런 다음 선택적인
i또는u접미사.
참고: 다른 언어에서 선행 0이 8진수를 의미하는 표기법과 혼동하지 않도록 0이 아닌 정수 리터럴 앞에 0을 붙이는 것(예: 012)은 금지된다.
/0[iu]?/
| /[1-9][0-9]*[iu]?/
/0[xX][0-9a-fA-F]+[iu]?/
부동 소수점 리터럴은 10진수 부동 소수점 리터럴 또는 16진수 부동 소수점 리터럴이다.
부동 소수점 리터럴에는 분수를 나타내는 가수와 선택적인 지수라는 두 가지 논리적 부분이 있다. 대략적으로 리터럴의 값은 가수에 밑을 주어진 지수만큼 거듭제곱한 값을 곱한 것이다. 가수 숫자가 0이 아니거나 그 왼쪽과 오른쪽에 모두 0이 아닌 가수 숫자가 있으면 유효하다. 유효 숫자는 왼쪽에서 오른쪽으로 센다. N번째 유효 숫자의 왼쪽에는 N-1개의 유효 숫자가 있다.
10진수 부동 소수점 리터럴은 다음과 같다.
-
숫자의 시퀀스로 지정되며 그 사이 어딘가에 선택적인 소수점(
.)이 있는 가수. 가수는 밑이 10인 표기법으로 분수를 나타낸다. -
그런 다음 다음으로 구성된 선택적인 지수 접미사:
-
e또는E. -
그런 다음 선택적인 선행 부호(
+또는-)가 있는 10진수로 지정된 지수. -
그런 다음 선택적인
f또는h접미사.
-
-
소수점, 지수,
f또는h접미사 중 하나 이상이 반드시 있어야 한다. 아무것도 없으면 해당 토큰은 대신 정수 리터럴이다.
/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 ;
-
significand에서 effective_significand를 계산한다.
-
significand의 유효 숫자가 20개 이하이면 effective_significand는 significand이다.
-
그렇지 않으면:
-
truncated_significand를 significand와 동일하게 하되 20번째 유효 숫자 오른쪽의 각 숫자를 0으로 대체한다.
-
truncated_significand_next를 significand와 동일하게 하되 다음과 같이 한다.
-
20번째 유효 숫자를 1만큼 증가시키고 각 숫자가 0에서 9 범위에 계속 있도록 필요에 따라 올림을 왼쪽으로 전파하며,
-
20번째 유효 숫자 오른쪽의 각 숫자를 0으로 대체한다.
-
-
effective_significand를 truncated_significand 또는 truncated_significand_next로 설정한다. 이는 구현이 선택한다.
-
-
-
리터럴의 수학적 값은 effective_significand를 10진 분수로 나타낸 수학적 값에 10의 지수 제곱을 곱한 값이다. 지수를 지정하지 않으면 지수가 0이라고 가정한다.
참고: 10진 가수는 20개의 10진수 숫자 이후에서 잘리며, 분수에서 약 log(10)/log(2)×20 ≈ 66.4개의 유효 비트를 보존한다.
16진수 부동 소수점 리터럴은 다음과 같다.
-
0x또는0X접두사 -
그런 다음 16진수 숫자의 시퀀스로 지정되며 그 사이 어딘가에 선택적인 16진 소수점 (
.)이 있는 가수. 가수는 밑이 16인 표기법으로 분수를 나타낸다. -
그런 다음 다음으로 구성된 선택적인 지수 접미사:
-
p또는P -
그런 다음 선택적인 선행 부호(
+또는-)가 있는 10진수로 지정된 지수. -
그런 다음 선택적인
f또는h접미사.
-
-
16진 소수점 또는 지수 중 하나 이상이 반드시 있어야 한다. 둘 다 없으면 해당 토큰은 대신 정수 리터럴이다.
/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]?/
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 ;
-
significand에서 effective_significand를 계산한다.
-
significand의 유효 숫자가 16개 이하이면 effective_significand는 significand이다.
-
그렇지 않으면:
-
truncated_significand를 significand와 동일하게 하되 16번째 유효 숫자 오른쪽의 각 숫자를 0으로 대체한다.
-
truncated_significand_next를 significand와 동일하게 하되 다음과 같이 한다.
-
16번째 유효 숫자를 1만큼 증가시키고 각 숫자가 0에서
f범위에 계속 있도록 필요에 따라 올림을 왼쪽으로 전파하며, -
16번째 유효 숫자 오른쪽의 각 숫자를 0으로 대체한다.
-
-
effective_significand를 truncated_significand 또는 truncated_significand_next로 설정한다. 이는 구현이 선택한다.
-
-
-
리터럴의 수학적 값은 effective_significand를 16진 분수로 나타낸 수학적 값에 2의 지수 제곱을 곱한 값이다. 지수를 지정하지 않으면 지수가 0이라고 가정한다.
참고: 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 |
다음과 같은 경우 셰이더 생성 오류가 발생한다.
-
i또는u접미사가 있는 정수 리터럴을 대상 유형으로 표현할 수 없는 경우. -
f또는h접미사가 있는 16진수 부동 소수점 리터럴이 오버플로되거나 대상 유형으로 정확하게 표현될 수 없는 경우. -
f또는h접미사가 있는 10진수 부동 소수점 리터럴이 대상 유형에서 오버플로되는 경우. -
f16 확장이 활성화되지 않은 상태에서
h접미사가 있는 부동 소수점 리터럴을 사용하는 경우.
참고: 16진 부동 소수점 값 0x1.00000001p0을 정확하게 표현하려면 33개의 가수 비트가 필요하지만, f32에는 명시적 가수 비트가 23개뿐이다.
참고: f 접미사를 사용하여
16진 부동 소수점 리터럴을 해당 유형으로 강제하려면 리터럴에서 이진 지수도
사용해야 한다. 예를 들어 0x1p0f로 작성한다. 이와 달리 0x1f는
16진수 정수 리터럴이다.
3.6. 키워드
키워드는 미리 정의된 언어 개념을 참조하는 토큰이다. WGSL 키워드 목록은 § 16.1 키워드 요약을 참조한다.
3.7. 식별자
식별자는 이름으로 사용되는 토큰의 한 종류이다. § 5 선언 및 범위를 참조한다.
WGSL은 사용 사례를 구분하기 위해 두 개의 문법 비단말 기호를 사용한다.
-
ident는 선언된 객체의 이름을 지정하는 데 사용된다.
-
member_ident는 구조체 유형의 멤버 이름을 지정하는 데 사용된다.
식별자의 형식은 유니코드 버전 14.0.0의 유니코드 표준 부록 #31을 기반으로 하며 다음과 같이 보충된다.
식별자는 UAX31 문법을 기준으로 설명한 다음 프로파일을 사용한다.
<Identifier> := <Start> <Continue>* (<Medial> <Continue>+)* <Start> := XID_Start + U+005F <Continue> := <Start> + XID_Continue <Medial> :=
이는 다음과 같이 ASCII가 아닌 코드 포인트를 가진 식별자도
유효하다는 뜻이다. Δέλτα, réflexion, Кызыл, 𐰓𐰏𐰇,
朝焼け, سلام, 검정, שָׁלוֹם, गुलाबी,
փիրուզ.
단, 다음은 예외이다.
/([_\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 내장 입력 및 출력을 참조한다.
내장 값의 이름은 다음과 같다.
3.8.3. 진단 규칙 이름
진단 이름 토큰은 진단 트리거 규칙의 이름에 사용되는 토큰이다.
§ 2.3 진단을 참조한다.
미리 정의된 진단 규칙 이름은 다음과 같다.
3.8.4. 진단 심각도 제어 이름
유효한 진단 필터 심각도 제어 이름은 § 2.3 진단에 나열되어 있지만 식별자와 형식이 같다.
진단 필터 심각도 제어 이름은 다음과 같다.
3.8.5. 확장 이름
유효한 활성화 확장 이름은 § 4.1.1 확장 활성화에 나열되어 있지만 일반적으로 식별자와 형식이 같다.
활성화 확장 이름은 다음과 같다.
유효한 언어 확장 이름은 § 4.1.2 언어 확장에 나열되어 있지만 일반적으로 식별자와 형식이 같다.
언어 확장 이름은 다음과 같다.
3.8.6. 보간 유형 이름
보간 유형 이름 토큰은 interpolate_type_name을 위한 보간 유형의 이름에 사용되는 토큰이다.
§ 13.3.1.4 보간을 참조한다.
보간 유형 이름은 다음과 같다.
3.8.7. 보간 샘플링 이름
보간 샘플링 이름 토큰은 보간 샘플링의 이름에 사용되는 토큰이다.
§ 13.3.1.4 보간을 참조한다.
보간 샘플링 이름은 다음과 같다.
3.8.8. 스위즐 이름
스위즐 이름은 벡터 접근 표현식과 스위즐 뷰 표현식에 사용된다.
/[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. 템플릿 목록
템플릿 매개변수화는 일반 개념을 수정하는 매개변수를 지정하는 방법입니다. 템플릿 매개변수화를 작성하려면 일반 개념을 작성한 다음 템플릿 목록을 작성합니다.
주석과 공백을 무시할 때, 템플릿 목록은 다음과 같습니다.
-
처음의
'<'(U+003C) 코드 포인트, 그다음 -
하나 이상의 템플릿 매개변수로 이루어진 쉼표로 구분된 목록, 그다음
-
선택적인 후행 쉼표, 그다음
-
끝을 나타내는
'>'(U+003E) 코드 포인트.
템플릿 매개변수의 형식은 아래의 템플릿 목록 탐색 알고리즘에 의해 암묵적으로 정의됩니다. 일반적으로 이름, 식 또는 타입입니다.
참고: 예를 들어 vec3<f32>라는 구문은
vec3가 수정되는 일반 개념이고,
<f32>가 하나의 매개변수인 f32 타입을 포함하는 템플릿
목록인 템플릿 매개변수화입니다.
이 둘을 합친 vec3<f32>는 특정 벡터 타입을
나타냅니다.
참고: 예를 들어
var<storage,read_write>라는 구문은 일반적인 var 개념을 템플릿
매개변수 storage 및 read_write로 수정합니다.
array<vec4<f32>>라는 구문에는 두 개의
템플릿 매개변수화가 있습니다.
-
vec4<f32>는 일반적인vec4개념을 템플릿 매개변수f32로 수정합니다. -
array<vec4<f32>>는 일반적인array개념을 템플릿 매개변수vec4<f32>로 수정합니다.
템플릿 목록을 구분하는 '<'(U+003C) 및 '>'(U+003E) 코드 포인트는
다음을 표기할 때도 사용됩니다.
-
relational_expression의 비교 연산자.
-
shift_expression의 시프트 연산자.
-
시프트 연산 후 대입을 수행하는 compound_assignment_operator.
구문적 모호성은 템플릿 목록을 우선하는 방식으로 해결됩니다.
-
이후 단계의 토큰화 과정에서 템플릿 목록의 첫
'<'(U+003C)는 _template_args_start 토큰으로 매핑되고, 템플릿 목록의 끝'>'(U+003E)는 _template_args_end 토큰으로 매핑됩니다.
템플릿 목록 탐색 알고리즘은 아래와 같습니다. 이 알고리즘은 다음과 같은 가정과 속성을 사용합니다.
-
템플릿 매개변수는 식이므로
'<'(U+003C) 또는'='(U+003D) 코드 포인트로 시작하지 않습니다. -
식에는
';'(U+003B),'{'(U+007B) 또는':'(U+003A) 코드 포인트가 포함되지 않습니다. -
식에는 대입이 포함되지 않습니다.
-
'='(U+003D) 코드 포인트는 비교 연산의 일부일 때만 나타납니다. 즉, 다음 중 하나에만 나타납니다.'<=','>=','=='또는'!='. 그 외의 경우'='(U+003D) 코드 포인트는 대입의 일부로 나타납니다. -
템플릿 목록 구분자는 괄호 '(...)'와 배열 인덱싱 '[...]'으로 형성된 중첩 식을 따릅니다. 템플릿 목록의 시작과 끝은 동일한 중첩 수준에 나타나야 합니다.
알고리즘: 템플릿 목록 탐색입력: 프로그램 소스 텍스트.
레코드 타입:
UnclosedCandidate를 다음을 포함하는 레코드 타입이라고 합니다.
position, 소스 텍스트 내의 위치
depth, 정수이며 position에서 식의 중첩 깊이
TemplateList를 다음을 포함하는 레코드 타입이라고 합니다.
start_position, 이 템플릿 목록을 시작하는
'<'(U+003C) 코드 포인트의 소스 위치.end_position, 이 템플릿 목록을 끝내는
'>'(U+003E) 코드 포인트의 소스 위치.출력: DiscoveredTemplateLists, TemplateList 레코드의 목록.
절차:
DiscoveredTemplateLists를 빈 목록으로 초기화합니다.
Pending 변수를 UnclosedCandidate 레코드의 빈 스택으로 초기화합니다.
CurrentPosition 정수 변수를 0으로 초기화합니다. 이 변수는 현재 검사 중인 코드 포인트의 위치를 소스 텍스트 시작 이후의 코드 포인트 수로 인코딩합니다.
이 변수는 알고리즘을 실행하는 동안 텍스트에서 앞으로 진행합니다. 텍스트 끝에 도달하면 알고리즘을 즉시 종료하고 DiscoveredTemplateLists를 반환합니다.
NestingDepth 정수 변수를 0으로 초기화합니다.
다음 단계를 반복합니다.
ident_pattern_token이 CurrentPosition의 텍스트와 일치하면 다음을 수행합니다.
CurrentPosition을 ident_pattern_token 다음으로 이동합니다.
공백과 주석이 있으면 CurrentPosition을 그 다음으로 이동합니다.
CurrentPosition에
'<'(U+003C)가 나타나면 다음을 수행합니다.
참고: 이 코드 포인트는 템플릿 목록의 시작 후보입니다. 입력의 뒤쪽에 나타나는 끝
'>'(U+003E)와 대응시킬 수 있도록 충분한 상태를 저장합니다.UnclosedCandidate(position=CurrentPosition,depth=NestingDepth)를 Pending 스택에 푸시합니다.
CurrentPosition을 다음 코드 포인트로 이동합니다.
CurrentPosition에
'<'(U+003C)가 나타나면 다음을 수행합니다.
참고: 가정 1에 따라 템플릿 매개변수는
'<'(U+003C)로 시작하지 않으므로 이전 코드 포인트는 템플릿 목록의 시작일 수 없습니다. 따라서 현재 코드 포인트와 이전 코드 포인트는'<<'연산자여야 합니다.Pending 스택에서 맨 위 항목을 팝합니다.
CurrentPosition을 이 코드 포인트 다음으로 이동하고 루프의 다음 반복을 시작합니다.
CurrentPosition에
'='(U+003D)가 나타나면 다음을 수행합니다.
참고: 가정 1에 따라 템플릿 매개변수는
'='(U+003C)로 시작하지 않으므로 이전 코드 포인트는 템플릿 목록의 시작일 수 없습니다. 현재 코드 포인트와 이전 코드 포인트가'<='비교 연산자를 형성한다고 가정합니다. 이후 단계에서'='(U+003D) 코드 포인트를 대입으로 오인하지 않도록 이 코드 포인트를 건너뜁니다.Pending 스택에서 맨 위 항목을 팝합니다.
CurrentPosition을 이 코드 포인트 다음으로 이동하고 루프의 다음 반복을 시작합니다.
루프의 다음 반복을 시작합니다.
CurrentPosition에
'>'(U+003E)가 나타나면 다음을 수행합니다.
참고: 이 코드 포인트는 템플릿 목록의 끝 후보입니다.
Pending이 비어 있지 않으면 맨 위 항목을 T라고 하고, T.depth가 NestingDepth와 같으면 다음을 수행합니다.
참고: 이 코드 포인트는 시작 위치가 T에 기록된 현재 템플릿 목록을 끝냅니다.
TemplateList(start_position=T.position, end_position=CurrentPosition)를 DiscoveredTemplateLists에 추가합니다.
Pending 스택에서 T를 팝합니다.
CurrentPosition을 이 코드 포인트 다음으로 이동하고 루프의 다음 반복을 시작합니다.
그렇지 않으면 이 코드 포인트는 템플릿 목록을 끝내지 않습니다.
CurrentPosition을 이 코드 포인트 다음으로 이동합니다.
CurrentPosition에
'='(U+003D)가 나타나면 다음을 수행합니다.
참고: 현재 코드 포인트와 이전 코드 포인트가
'>='비교 연산자를 형성한다고 가정합니다. 이후 단계에서'='(U+003D) 코드 포인트를 대입으로 오인하지 않도록 이 코드 포인트를 건너뜁니다.CurrentPosition을 이 코드 포인트 다음으로 이동합니다.
루프의 다음 반복을 시작합니다.
CurrentPosition에
'('(U+0028) 또는'['(U+005B)가 나타나면 다음을 수행합니다.
참고: 중첩된 식에 진입합니다.
NestingDepth에 1을 더합니다.
CurrentPosition을 이 코드 포인트 다음으로 이동하고 루프의 다음 반복을 시작합니다.
CurrentPosition에
')'(U+0029) 또는']'(U+005D)가 나타나면 다음을 수행합니다.
참고: 중첩된 식에서 나갑니다.
Pending 스택이 비거나 맨 위 항목의 depth가 NestingDepth보다 작아질 때까지 항목을 팝합니다.
NestingDepth를 0과 NestingDepth − 1 중 더 큰 값으로 설정합니다.
CurrentPosition을 이 코드 포인트 다음으로 이동하고 루프의 다음 반복을 시작합니다.
CurrentPosition에
'!'(U+0021)가 나타나면 다음을 수행합니다.
CurrentPosition을 이 코드 포인트 다음으로 이동합니다.
CurrentPosition에
'='(U+003D)가 나타나면 다음을 수행합니다.
참고: 현재 코드 포인트와 이전 코드 포인트가
'!='비교 연산자를 형성한다고 가정합니다. 이후 단계에서'='(U+003D) 코드 포인트를 대입으로 오인하지 않도록 이 코드 포인트를 건너뜁니다.CurrentPosition을 이 코드 포인트 다음으로 이동합니다.
루프의 다음 반복을 시작합니다.
CurrentPosition에
'='(U+003D)가 나타나면 다음을 수행합니다.
CurrentPosition을 이 코드 포인트 다음으로 이동합니다.
CurrentPosition에
'='(U+003D)가 나타나면 다음을 수행합니다.
참고: 현재 코드 포인트와 이전 코드 포인트가
'=='비교 연산자를 형성한다고 가정합니다. 이후 단계에서'='(U+003D) 코드 포인트를 대입으로 오인하지 않도록 이 코드 포인트를 건너뜁니다.CurrentPosition을 이 코드 포인트 다음으로 이동하고 루프의 다음 반복을 시작합니다.
참고: 이 코드 포인트는 식의 일부로 나타날 수 없으므로 템플릿 목록에도 나타날 수 없는 대입의 일부라고 가정합니다. 닫히지 않은 대기 중인 후보를 모두 비웁니다.
NestingDepth를 0으로 설정합니다.
Pending 스택에서 모든 항목을 제거합니다.
CurrentPosition을 이 코드 포인트 다음으로 이동하고 루프의 다음 반복을 시작합니다.
CurrentPosition에
';'(U+003B),'{'(U+007B) 또는':'(U+003A)가 나타나면 다음을 수행합니다.
참고: 이들은 식의 중간에 나타날 수 없으므로 템플릿 목록에도 나타날 수 없습니다. 닫히지 않은 대기 중인 후보를 모두 비웁니다.
NestingDepth를 0으로 설정합니다.
Pending 스택에서 모든 항목을 제거합니다.
CurrentPosition을 이 코드 포인트 다음으로 이동하고 루프의 다음 반복을 시작합니다.
'&&'또는'||'가 CurrentPosition의 텍스트와 일치하면 다음을 수행합니다.
참고: 이들은 비교보다 우선순위가 낮은 연산자입니다. 현재 식 수준에서 닫히지 않은 대기 중인 모든 후보를 거부합니다.
참고: 이 규칙을 적용하면 프로그램 조각
a<b || c>d에서는 템플릿 목록이 발견되지 않습니다. 대신 두 비교의 단락 평가 논리합으로 인식됩니다.Pending 스택이 비거나 맨 위 항목의 depth가 NestingDepth보다 작아질 때까지 항목을 팝합니다.
CurrentPosition을 두 코드 포인트 다음으로 이동하고 루프의 다음 반복을 시작합니다.
CurrentPosition을 현재 코드 포인트 다음으로 이동합니다.
-
UnclosedCandidate에 다음 필드를 추가하도록 수정합니다.
-
parameters, 템플릿 매개변수 소스 범위의 목록.
-
parameter_start_position, 소스 위치.
-
-
TemplateList에 다음 필드를 추가하도록 수정합니다.
-
parameters, 템플릿 매개변수 소스 범위의 목록.
-
-
새 UnclosedCandidate를 Pending 스택에 푸시할 때 다음을 수행합니다.
-
해당 parameters 필드를 빈 목록으로 설정합니다.
-
parameter_start_position을 CurrentPosition에서 한 코드 포인트 뒤로 설정합니다.
-
-
TemplateList인 TL을 DiscoveredTemplateLists에 추가할 때 다음을 수행합니다.
-
원래 알고리즘과 같이 T를 Pending 스택의 맨 위 항목이라고 합니다.
-
T.parameter_start_position에서 시작하여 CurrentPosition−1에서 끝나는 소스 범위를 T.parameters에 푸시합니다.
-
원래 알고리즘과 같이 TL을 준비합니다.
-
TL.parameters를 T.parameters로 설정합니다.
-
-
현재 코드 포인트 다음으로 이동하기 직전인 루프 끝에 다음 검사를 삽입합니다.
-
CurrentPosition에 '
,'(U+002C)가 나타나고 Pending이 비어 있지 않으면 다음을 수행합니다.-
T를 Pending 스택의 맨 위 항목이라고 합니다.
-
T.parameter_start_position에서 시작하여 CurrentPosition−1에서 끝나는 소스 범위를 T.parameters에 푸시합니다.
-
T.parameter_start_position을 CurrentPosition+1로 설정합니다.
-
-
참고: 일부 숫자 리터럴은 문자로 끝나므로 알고리즘은
리터럴을 명시적으로 건너뜁니다. 예를 들면 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+003C) 코드 포인트(B 다음)를 검사한 후에는 '='
(U+003D) 코드 포인트를 대입의 일부로 가정하지 않도록 특별히 인식해야 합니다.
참고:
A<(B!=C)>라는 구문을 검사할 때 템플릿 목록은 하나이며, 첫 번째 '<'(U+003C)
코드 포인트에서 시작하고 마지막 '>'(U+003E) 코드 포인트에서 끝나며 템플릿 인수로
B!=C를 갖습니다.
'!'(U+0021) 코드 포인트('B' 다음)를 검사한 후에는 '='
(U+003D) 코드 포인트를 대입의 일부로 가정하지 않도록 특별히 인식해야 합니다.
참고:
A<(B==C)>라는 구문을 검사할 때 템플릿 목록은 하나이며, 첫 번째 '<'(U+003C)
코드 포인트에서 시작하고 마지막 '>'(U+003E) 코드 포인트에서 끝나며 템플릿 인수로
B==C를 갖습니다.
첫 번째 '='(U+003D) 코드 포인트('B' 다음)를 검사한 후에는 두 번째
'='(U+003D) 코드 포인트를 특별히 인식하여 둘 중 어느 것도
대입의 일부로 가정하지 않도록 해야 합니다.
템플릿 목록 탐색이 완료되면, 구문 분석은 반드시 각 템플릿 목록을 template_list 문법 규칙에 일치시키려고 시도합니다.
_template_args_start template_arg_comma_list _template_args_end
template_arg_expression ( ',' template_arg_expression ) * ',' ?
4. 지시문
지시문은 WebGPU 구현이 WGSL 프로그램을 처리하는 방식을 수정하는 토큰 시퀀스입니다.
지시문은 선택 사항입니다. 지시문이 있는 경우 모든 지시문은 모든 선언 또는 const 단언보다 앞에 나타나야 합니다.
4.1. 확장
WGSL은 시간이 지남에 따라 발전할 것으로 예상됩니다.
확장은 WGSL 명세에 대한 일관된 수정 집합을 명명하여 묶은 것으로, 다음 항목을 조합하여 구성됩니다.
-
다음을 포함하여 새로운 구문을 통해 새 개념과 동작 추가:
-
선언, 문, 특성 및 내장 함수.
-
-
현재 명세 또는 이전에 게시된 확장의 제한 제거.
-
허용되는 동작의 집합을 줄이는 구문.
-
프로그램의 일부에서 사용할 수 있는 기능을 제한하는 구문.
-
확장이 기존 명세 및 선택적으로 다른 확장과 상호 작용하는 방법에 대한 설명.
가정적으로 확장은 다음을 수행할 수 있습니다.
-
비트 폭이 다른 정수와 같은 숫자 스칼라 타입 추가.
-
부동 소수점 반올림 모드를 제한하는 구문 추가.
-
셰이더가 원자 타입을 사용하지 않음을 알리는 구문 추가.
-
새로운 종류의 문 추가.
-
새 내장 함수 추가.
-
셰이더 호출의 실행 방식을 제한하는 구문 추가.
-
새 셰이더 단계 추가.
확장에는 활성화 확장과 언어 확장이라는 두 종류가 있습니다.
4.1.1. 활성화 확장
활성화 확장은 다음 조건을 모두 충족할 때만 기능을 사용할 수 있는 확장입니다.
-
구현이 이를 지원하고,
-
셰이더가 활성화 지시문을 통해 이를 명시적으로 요청하며,
-
해당 WebGPU
GPUFeatureName이GPUDevice를 생성할 때 요청한 필수 기능 중 하나였어야 합니다.
활성화 확장은 보편적으로 지원되지 않는 하드웨어 기능을 노출하기 위한 것입니다.
활성화 지시문은 하나 이상의 활성화 확장에 대한 지원을 켜는 지시문입니다. 구현이 나열된 활성화 확장을 모두 지원하지 않으면 셰이더 생성 오류가 발생합니다.
'enable' enable_extension_list ';'
다른 지시문과 마찬가지로 활성화 지시문이 있으면 모든 선언 및 const 단언보다 앞에 나타나야 합니다. 확장 이름은 식별자가 아닙니다. 확장 이름은 선언으로 해석되지 않습니다.
유효한 활성화 확장은 다음 표에 나열되어 있습니다.
| WGSL 활성화 확장 | WebGPU GPUFeatureName
| 설명 |
|---|---|---|
f16
| "shader-f16" | WGSL 모듈에서 f16 타입을 유효하게 사용할 수 있습니다. 그렇지 않으면 f16을 직접 또는 간접적으로 사용할 때 셰이더 생성 오류가 발생합니다. |
clip_distances
| "clip-distances" | WGSL 모듈에서 내장 변수 clip_distances를 유효하게 사용할 수 있습니다. 그렇지 않으면 clip_distances를 사용할 때 셰이더 생성 오류가 발생합니다. |
dual_source_blending
| "dual-source-blending" | WGSL 모듈에서 특성 blend_src를 유효하게 사용할 수 있습니다. 그렇지 않으면 blend_src를 사용할 때 셰이더 생성 오류가 발생합니다. |
subgroups
| "subgroups" | WGSL 모듈에서 하위 그룹 내장 값, 하위 그룹 내장 함수 및 쿼드 내장 함수를 유효하게 사용할 수 있습니다. 그렇지 않으면 이를 사용할 때 셰이더 생성 오류가 발생합니다. |
primitive_index
| "primitive-index"
| WGSL 모듈에서 내장 변수 primitive_index를 유효하게 사용할 수 있습니다. 그렇지 않으면 primitive_index를 사용할 때 셰이더 생성 오류가 발생합니다. |
subgroup_size_control
| "subgroup-size-control"
| WGSL 모듈에서 특성 subgroup_size를 유효하게 사용할 수 있습니다.
그렇지 않으면 subgroup_size를 사용할 때 셰이더 생성 오류가 발생합니다.
subgroup_size_control이 활성화되면 subgroups가
자동으로 활성화됩니다.
|
// 임의 정밀도 부동 소수점 타입을 위한 가상의 확장을 활성화합니다. enable arbitrary_precision_float ; enable arbitrary_precision_float ; // 중복 활성화 지시문도 허용됩니다. // 반올림 모드를 제어하는 가상의 확장을 활성화합니다. enable rounding_mode ; // arbitrary_precision_float가 다음의 사용을 활성화한다고 가정합니다. // - 타입 f<E,M> // - 함수 반환, 형식 매개변수 및 let 선언의 타입으로 사용 // - AbstractFloat로부터 생성하는 값 생성자로 사용 // - 나눗셈 연산자 /의 피연산자 // @rounding_mode 특성이 rounding_mode 활성화 지시문에 의해 활성화된다고 가정합니다. @rounding_mode ( round_to_even ) fn halve_it ( x : f < 8 , 7 > ) -> f < 8 , 7 > { let two = f < 8 , 7 > ( 2 ); return x / 2 ; // 최근접 짝수 방향 반올림 모드를 사용합니다. }
4.1.2. 언어 확장
언어 확장은 구현에서 지원하면 자동으로 사용할 수 있는 확장입니다. 프로그램에서 이를 명시적으로 요청할 필요는 없습니다.
언어 확장은 어떤 WebGPU 구현에서도 합리적으로 지원할 수 있는 기능을 구체화합니다. 기능이 보편적으로 지원되지 않는다면, 이는 일부 WebGPU 구현에서 아직 해당 기능을 구현하지 않았기 때문입니다.
참고: 예를 들어 do-while 루프는 언어 확장이 될 수 있습니다.
WebGPU GPU
객체의 wgslLanguageFeatures
멤버는 구현에서 지원하는
언어 확장
집합을 나열합니다.
requires 지시문은 프로그램이 하나 이상의 언어 확장을 사용함을 문서화하는 지시문입니다. 이 지시문은 구현에서 노출하는 기능을 변경하지 않습니다. 구현이 필수 확장 중 하나를 지원하지 않으면 셰이더 생성 오류가 발생합니다.
WGSL 모듈은 requires 지시문을 사용하여 이식성이 없을 가능성과, 이식성을 위해 의도한 최소 기준을 알릴 수 있습니다.
참고: WebGPU 구현 외부의 도구는 프로그램에서 사용한 모든 언어 확장이 프로그램의 requires 지시문에 포함되는지 확인할 수 있습니다.
'requires' 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 |
루트 식이 포인터이고 참조를 산출하는 복합 값
분해 식을 지원합니다.
예를 들어 마찬가지로 |
| 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 |
스위즐 뷰
타입을 지원합니다.
이를 통해 스위즐 대입이 가능해집니다. 하나의 대입문으로 전체 벡터를 업데이트하지 않고도 벡터의 여러 성분을 업데이트할 수 있습니다. 예를 들어 변수 pointer_composite_access도
지원되면 포인터에서도 작동합니다. |
참고: 장기적으로 WGSL은 해당 시점에 일반적으로 지원되는 언어 확장의 모든 기능을 구체화하는 언어 확장을 정의할 것입니다. requires 지시문에서 이들은 그러한 공통 기능을 모두 나열하는 축약형으로 사용됩니다. 이들은 점진적으로 증가하는 기능 집합을 나타내며 일종의 언어 버전으로 볼 수 있습니다.
4.2. 전역 진단 필터
전역 진단
필터는 영향 범위가 WGSL 모듈
전체인 진단 필터입니다.
이는 지시문이므로 모든
모듈 범위
선언보다 앞에 나타납니다.
특성 형식과 동일하게 표기하지만 선행 @(U+0040) 코드 포인트가 없고
끝에 세미콜론이 붙습니다.
'diagnostic' diagnostic_control ';'
5. 선언과 범위
선언은 식별자를 다음 종류의 객체 중 하나와 연결합니다.
즉, 선언은 객체에 대한 이름을 도입합니다.
선언이 프로그램 소스에는 나타나지만 다른 선언의 텍스트 외부에 있으면 해당 선언은 모듈 범위에 있습니다.
함수 선언은 모듈 범위에 나타납니다. 함수 선언에는 형식 매개변수가 있으면 그 선언이 포함되며, 함수의 본문 안에 변수 및 값 선언을 포함할 수 있습니다. 따라서 이러한 포함된 선언은 모듈 범위에 있지 않습니다.
참고: 다른 선언을 포함하는 유일한 종류의 선언은 함수 선언입니다.
특정 객체는 WebGPU 구현에서 제공되며 WGSL 모듈 소스가 시작되기 전에 선언된 것처럼 취급됩니다. 이러한 객체를 미리 선언된 객체라고 합니다. 예를 들어 WGSL은 다음을 미리 선언합니다.
-
array,ptr및texture_2d와 같은 내장 타입 생성자, 그리고 -
read_write, workgroup 및 rgba8unorm과 같은 열거자.
선언의 범위는 선언된 식별자가 연결된 객체를 잠재적으로 나타내는 프로그램 소스 위치의 집합입니다. 이러한 소스 위치에서 식별자가 해당 선언의 범위 내에 있다고 합니다.
선언이 나타나는 위치에 따라 범위가 결정됩니다.
-
미리 선언된 객체와 모듈 범위에서 선언된 객체는 프로그램 소스 전체에서 범위 내에 있습니다.
-
사용자 선언 함수의 각 형식 매개변수는 해당 함수 본문 전체에서 범위 내에 있습니다. § 11.1 사용자 정의 함수 선언을 참조하십시오.
-
그 외의 경우 범위는 선언의 끝 바로 다음에서 시작하는 텍스트 구간입니다. 자세한 내용은 § 7 변수 및 값 선언을 참조하십시오.
동일한 WGSL 소스 프로그램의 두 선언은 다음 조건을 동시에 충족해서는 안 됩니다.
-
동일한 식별자 이름을 도입하고,
-
동일한 범위 끝을 가짐.
참고: 미리 선언된 객체에는 WGSL 소스의 선언이 없습니다. 따라서 모듈 범위나 함수 내부에서 사용자가 지정한 선언은 미리 선언된 객체와 동일한 이름을 가질 수 있습니다.
식별자는 문법적 문맥에 따라 다음과 같이 구분하여 사용됩니다.
-
ident 문법 요소와 일치하는 토큰은 다음과 같이 사용됩니다.
-
선언에서 선언되는 객체의 이름으로 사용되거나,
-
다른 곳에 선언된 객체를 나타내는 이름으로 사용됩니다. 이것이 일반적인 경우입니다.
-
-
member_ident 문법 요소와 일치하는 토큰은 다음과 같이 사용됩니다.
-
구조체 값의 멤버 또는 구조체 멤버에 대한 참조를 나타내는 이름으로 사용됩니다. § 8.5.4 구조체 접근 식을 참조하십시오.
ident 토큰이 다른 곳에서 선언된 객체를 나타내는 이름으로 나타날 때, 해당 토큰은 어떤 선언의 범위 내에 있어야 합니다. 식별자 토큰이 나타내는 객체는 다음과 같이 결정됩니다.
-
토큰이 하나 이상의 비모듈 범위 선언의 범위 내에 있으면 해당 토큰은 그 선언 중 가장 가까운 선언과 연결된 객체를 나타냅니다.
참고: 가장 가까운 선언은 식별자 토큰보다 앞에 나타납니다.
-
그렇지 않고 해당 이름을 가진 모듈 범위 선언이 있으면 토큰은 그 선언된 객체를 나타냅니다.
참고: 모듈 범위 선언은 식별자 토큰의 앞 또는 뒤에 나타날 수 있습니다.
-
그렇지 않고 해당 이름을 가진 미리 선언된 객체가 있으면 토큰은 그 객체를 나타냅니다.
위 알고리즘을 사용하여 식별자를 선언에 매핑할 때 식별자가 해당 선언으로 해석된다고 합니다. 마찬가지로 식별자가 선언된 객체로 해석된다고도 합니다.
모듈 범위 선언이 재귀적이면 셰이더 생성 오류입니다. 즉, 선언 사이에 순환이 존재할 수 없습니다.
다음과 같은 방향 그래프를 고려합니다.
각 노드는 선언 D에 대응합니다.
D의 정의가 T로 해석되는 식별자를 언급하면 선언 D에서 선언 T로 향하는 간선이 있습니다.
이 그래프에는 순환이 없어야 합니다.
참고: 함수 본문은 함수 선언의 일부이므로 함수는 직접적으로든 간접적으로든 재귀적이어서는 안 됩니다.
참고: 비모듈 범위 식별자 선언은 텍스트에서 해당 선언의 사용보다 앞에 있어야 합니다.
// 유효함: 사용자 정의 변수는 내장 함수와 같은 이름을 가질 수 있습니다. 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에서 다음과 같이 서로 다른 값에 대응합니다.
-
32비트 부호 있는 정수 값
1i, -
32비트 부호 없는 정수 값
1u, -
32비트 부동 소수점 값
1.0f, -
f16 확장이 활성화된 경우 16비트 부동 소수점 값
1.0h, -
AbstractInt 값 1, 그리고
-
AbstractFloat 값 1.0
WGSL은 이들의 기계 표현과 연산이 다르므로 서로 다른 값으로 취급합니다.
일부 타입은 불투명합니다. 이는 그 값에 WGSL 프로그램 내에서 직접 검사하거나 분해하거나 조작할 수 없는 구현 정의 표현이 있음을 의미합니다.
타입은 미리 선언되거나 WGSL 소스에서 선언을 통해 생성됩니다.
일부 타입은 템플릿
매개변수화로 표현됩니다.
타입 생성자는
템플릿
목록으로 매개변수화될 때 타입을 나타내는 미리
선언된 객체입니다.
예를 들어 타입 atomic<u32>은 타입 생성자 atomic과
템플릿 목록 <u32>을 결합합니다.
타입의 개념과 해당 타입을 나타내는 WGSL의 구문을 구분합니다. 많은 경우 이 명세에서 타입을 표기하는 방법은 WGSL 구문과 같습니다. 예:
-
32비트 부호 없는 정숫값의 집합은 이 명세와 WGSL 모듈에서 모두
u32로 표기됩니다. -
구조체 타입 또는 구조체를 포함하는 타입은 표기가 다릅니다.
일부 WGSL 타입은 소스 프로그램을 분석하고 프로그램의 런타임 동작을 결정하는 데만 사용됩니다. 이 명세에서는 이러한 타입을 설명하지만 WGSL 소스 텍스트에는 나타나지 않습니다.
참고: 참조 타입은 WGSL 모듈에 작성되지 않습니다. § 6.5.3 참조 및 포인터 타입을 참조하십시오.
참고: 스위즐 뷰 타입은 WGSL 모듈에 작성되지 않습니다. § 6.5.4 스위즐 뷰 타입을 참조하십시오.
6.1. 타입 검사
WGSL 값은 식을 평가하여 계산됩니다.
식은 이름이
"expression"으로 끝나는 WGSL 문법 규칙 중 하나로 구문 분석되는 소스 텍스트 구간입니다.
식 E에는 외부 식 E 안에 완전히 포함된 식인
하위 식이 포함될 수 있습니다.
최상위
식은 그 자체가 하위 식이 아닌 식입니다.
§ 8.19 식 문법 요약을 참조하십시오.
식 평가로 생성되는 특정 값은 다음 항목에 따라 달라집니다.
-
정적 문맥: 식을 둘러싼 소스 텍스트, 그리고
-
동적 문맥: 식을 평가하는 호출의 상태와 해당 호출이 실행 중인 실행 문맥.
특정 식을 평가하여 나올 수 있는 값은 항상 특정 WGSL 타입에 속하며, 이를 식의 정적 타입이라고 합니다. WGSL 규칙은 식의 정적 타입이 해당 식의 정적 문맥에만 의존하도록 설계되었습니다.
타입 단언은 일부 WGSL 소스 식을 WGSL 타입에 매핑한 것입니다. 표기법
e : T
은 T가 WGSL 식 e의 정적 타입임을 의미하는 타입 단언입니다.
참고: 타입 단언은 프로그램 텍스트에 관한 사실을 진술한 것입니다. 런타임 검사가 아닙니다.
문은 흔히 식을 사용하며 해당 식의 정적 타입에 요구 사항을 부과할 수 있습니다. 예:
성공적으로 구문 분석된 WGSL 모듈의 타입 검사는 각 식을 정적 타입에 매핑하고 각 문의 타입 요구 사항이 충족되는지 검증하는 과정입니다. 타입 검사에 실패하면 셰이더 생성 오류의 특수한 경우인 타입 오류가 발생합니다.
타입 검사는 구문 구절에 타입 규칙을 재귀적으로 적용하여 수행할 수 있습니다. 여기서 구문 구절은 식 또는 문입니다. 타입 규칙은 구문 구절의 정적 문맥이 해당 구절에 포함된 식의 정적 타입을 결정하는 방법을 설명합니다. 타입 규칙은 두 부분으로 구성됩니다.
-
결론.
-
다음으로 구성되는 전제 조건:
타입 규칙의 전제 조건과 결론에는 타입 매개변수가 있을 수 있습니다. 타입 규칙의 결론이나 전제 조건에 타입 매개변수가 포함되어 있으면 해당 규칙이 매개변수화되었다고 합니다. 포함되어 있지 않으면 규칙이 완전히 구체화되었다고 합니다. 매개변수화된 규칙의 각 타입 매개변수를 타입으로 치환하고, 규칙에서 특정 매개변수가 나타나는 모든 곳에 동일한 타입을 사용하여 완전히 구체화된 타입 규칙을 만들 수 있습니다. 규칙의 타입 매개변수에 타입을 할당하는 것을 치환이라고 합니다.
예를 들어 다음은 논리 부정
(!e 형식의 식)에 대한 타입 규칙입니다.
| 전제 조건 | 결론 |
|---|---|
| e: T T는 bool 또는 vecN<bool> | !e: T
|
이 규칙은 타입 매개변수 T를 포함하므로 매개변수화된 규칙입니다.
T는 네 타입
bool, vec2<bool>,
vec3<bool> 또는 vec4<bool> 중 하나를 나타낼 수 있습니다.
T를 vec3<bool>에 매핑하는 치환을 적용하면
다음과 같이 완전히 구체화된 타입 규칙이 생성됩니다.
| 전제 조건 | 결론 |
|---|---|
e: vec3<bool> | !e: vec3<bool>
|
매개변수화된 규칙의 다른 조건을 충족하는 치환을 적용하여 만들 수 있는 완전히 구체화된 각 규칙을 해당 매개변수화된 규칙의 오버로드라고 합니다. 예를 들어 불리언 부정 규칙에는 타입 매개변수 T에 타입을 할당할 수 있는 방법이 네 가지이므로 네 개의 오버로드가 있습니다.
참고: 즉, 매개변수화된 타입 규칙은 완전히 구체화된 타입 규칙 모음의 패턴을 제공하며, 각 규칙은 매개변수화된 규칙에 서로 다른 치환을 적용하여 생성됩니다.
다음 조건을 충족하면 타입 규칙이 구문 구절에 적용됩니다.
-
규칙의 결론이 구문 구절의 유효한 구문 분석과 일치하고,
-
규칙의 전제 조건이 충족됨.
식에 적용되는 완전히 구체화된 타입 규칙을 생성하는 치환이 존재하면 매개변수화된 타입 규칙이 해당 식에 적용됩니다.
1u+2u라는 식을 살펴봅니다.
이 식에는 1u와 2u라는 두 개의 리터럴 하위 식이
있으며 둘 다 u32 타입입니다.
최상위 식은 덧셈입니다.
§ 8.8 산술식의 규칙을 참조하면 다음과 같은 이유로 덧셈 타입 규칙이
해당 식에 적용됩니다.
-
1u+2u는 e1이1u를 나타내고 e2가2u를 나타내는 e1+e2 형식의 구문 분석과 일치하고, -
e1은 u32 타입이고,
-
e2는 u32 타입이며,
-
타입 규칙의 타입 매개변수 T를 u32로 치환할 수 있으며, 그 결과 전체 식에 적용되는 완전히 구체화된 규칙이 생성되기 때문입니다.
구문 구절을 분석할 때 다음 세 가지 경우가 발생할 수 있습니다.
-
식에 적용되는 타입 규칙이 없습니다. 이 경우 타입 오류가 발생합니다.
-
정확히 하나의 완전히 구체화된 타입 규칙이 식에 적용됩니다. 이 경우 규칙의 결론이 단언되어 식의 정적 타입을 결정합니다.
-
둘 이상의 타입 규칙이 적용됩니다. 즉, 둘 이상의 오버로드에 대한 전제 조건이 충족됩니다. 이 경우 § 6.1.3 오버로드 결정에 설명된 동률 해결 절차를 사용합니다.
위의 예를 계속하면 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가 타입 규칙 전제 조건으로 사용되는 경우 다음 조건 중 하나를 충족하면 해당 전제 조건이 충족됩니다.
-
e가 이미 T 타입이거나,
-
e가 S 타입이고 아래에 정의된 것처럼 S 타입을 T 타입으로 자동 변환할 수 있음.
이 규칙은 아래 표에 정의된 타입 쌍에 대한 ConversionRank 함수로 성문화됩니다. ConversionRank 함수는 한 타입(Src)의 값을 다른 타입(Dest)으로 자동 변환하는 것에 대한 선호도와 실행 가능성을 나타냅니다. 순위가 낮을수록 더 선호됩니다.
실행 가능한 자동 변환은 값을 Src 타입에서 Dest 타입으로 변환하며, ConversionRank(Src,Dest)가 유한할 때 허용됩니다. 이러한 변환은 § 15.7 부동 소수점 평가에 설명된 제한을 전제로 값을 보존합니다.
참고: 자동 변환은 두 종류의 상황에서만 발생합니다. 첫째, 상수 식을 GPU에서 사용할 수 있는 해당 타입의 숫자 값으로 변환할 때입니다. 둘째, 메모리 참조에서 로드가 발생하여 해당 메모리에 저장된 값을 산출할 때입니다.
참고: 순위가 무한대인 변환은 실행할 수 없습니다. 즉, 허용되지 않습니다.
참고: 변환을 수행하지 않으면 변환 순위는 0입니다.
| 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는 모두 상수 식이고 Dest는 Src에 있는 인수에 대응하는 형식 매개변수의 타입입니다. | N2 < N1이면 1, 그렇지 않으면 무한대 | 고정 크기 버퍼 포인터 인수를 더 작은 크기의 포인터 매개변수로 변환합니다.1 |
| ptr<AS, buffer<N>, AM> 여기서 Src는 함수 호출 인수의 타입입니다. | ptr<AS, buffer, AM> 여기서 Dest는 Src에 있는 인수에 대응하는 형식 매개변수의 타입입니다. | 1 | 고정 크기 버퍼 포인터 인수를 런타임 크기 버퍼 포인터 매개변수로 변환합니다.1 |
| S | T 위의 경우가 적용되지 않음 | 무한대 | 다른 타입 사이에는 자동 변환이 없습니다. |
-
이러한 변환에는 unrestricted_pointer_parameters 및 buffer_view 언어 기능이 필요합니다.
다음 조건을 충족하면 타입 T는 타입 S의
구체화입니다.
-
T가 구체 타입이고, -
T가 참조 타입이 아니며, -
T가 스위즐 뷰 타입이 아니고, -
ConversionRank(
S,T)가 유한하며, -
위의 기준을 충족하는 다른 모든 타입
T2에 대해 ConversionRank(S,T2) > ConversionRank(S,T)임.
T 타입 값 e의 값 구체화는 T를
T의 구체화로 매핑하는 실행 가능한 변환을 e에 적용하여 얻은 값입니다.
참고: f32로의 변환은 항상 f16으로의 변환보다 선호되므로, 모듈에서 f16 확장이 활성화된 경우에만 자동 변환으로 f16 값이 생성될 수 있습니다.
6.1.3. 오버로드 결정
둘 이상의 타입 규칙이 구문 구절에 적용될 때 어느 규칙을 적용할지 결정하는 동률 해결 절차가 사용됩니다. 이 절차를 오버로드 결정이라고 하며, 타입 검사가 이미 하위 식의 정적 타입을 성공적으로 찾았다고 가정합니다.
구문 구절 P와 P에 적용되는 모든 타입 규칙을 살펴봅니다. 오버로드 결정 알고리즘에서는 이러한 타입 규칙을 오버로드 후보라고 합니다. 각 후보에는 다음이 적용됩니다.
P의 오버로드 결정은 가장 선호되는 단일 오버로드 후보를 찾는 것을 목표로 다음과 같이 진행됩니다.
-
각 후보 C에 대해 구문 구절에 있는 하위 식의 변환 순위를 열거합니다. 후보의 전제 조건이 충족되었으므로 P의 i번째 하위 식에는 다음이 적용됩니다.
-
하위 식의 정적 타입이 계산되었습니다.
-
식의 정적 타입에서 전제 조건의 해당 타입 단언이 요구하는 타입으로의 실행 가능한 자동 변환이 있습니다. C.R(i)를 해당 변환의 ConversionRank라고 합니다.
-
-
실행 가능한 자동 변환 후 후보의 하위 식 중 하나가 추상 타입으로 해석되지만 다른 하위 식은 상수 식이 아닌 모든 후보를 제거합니다.
참고: 따라서 구절의 하위 식 중 하나라도 상수 식이 아니면 구절의 모든 하위 식은 구체 타입이어야 합니다.
-
후보 순위 지정: 두 오버로드 후보 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를 적용하는 데 필요한 해당 변환보다 엄격히 더 선호되는 변환이 하나 이상 있습니다.
-
-
-
다른 모든 후보보다 선호되는 단일 후보 C가 있으면 오버로드 결정이 성공하여 후보 타입 규칙 C를 산출합니다. 그렇지 않으면 오버로드 결정이 실패합니다.
6.2. 일반 타입
일반 타입은 불리언 값, 숫자, 벡터, 행렬 또는 이러한 값의 집합체를 기계에서 표현하기 위한 타입입니다.
일반 타입은 스칼라 타입, 원자 타입 또는 복합 타입입니다.
참고: WGSL의 일반 타입은 C++의 Plain-Old-Data 타입과 유사하지만 원자 타입과 추상 숫자 타입도 포함합니다.
6.2.1. 추상 숫자 타입
이러한 타입은 WGSL 소스에 표기할 수 없습니다. 타입 검사에서만 사용됩니다.
특정 식은 셰이더 생성 시점에 평가되며, GPU에서 직접 구현하는 것보다 더 큰 숫자 범위와 정밀도를 사용할 수 있습니다.
WGSL은 이러한 평가를 위해 두 가지 추상 숫자 타입을 정의합니다.
-
AbstractInt 타입은 부호 비트가 최상위 비트 위치에 있는 64비트 2의 보수 형식으로 표현할 수 있는 정수의 집합입니다.
-
AbstractFloat 타입은 IEEE-754 binary64(배정밀도) 형식으로 표현할 수 있는 유한 부동 소수점 수의 집합입니다.
이러한 타입 중 하나에 속하는 식을 평가할 때 오버플로가 발생하거나 무한대 또는 NaN 값이 생성되어서는 안 됩니다.
타입이 추상 숫자 타입이거나 추상 숫자 타입을 포함하면 해당 타입은 추상 타입입니다. 추상 타입이 아니면 구체 타입입니다.
접미사가 없는 숫자 리터럴은 추상 숫자 타입의 값을 나타냅니다.
-
i또는u접미사가 없는 정수 리터럴은 AbstractInt 값을 나타냅니다. -
f또는h접미사가 없는 부동 소수점 리터럴은 AbstractFloat 값을 나타냅니다.
예: 식 log2(32)는 다음과 같이 분석됩니다.
-
log2(32)는 피연산자로 AbstractInt 값 32를 사용하는log2내장 함수의 함수 호출로 구문 분석됩니다. -
정수 스칼라 형식 매개변수를 갖는
log2오버로드는 없습니다. -
대신 세 가지 가능한 오버로드와 실행 가능한 자동 변환을 고려하여 오버로드 결정이 적용됩니다.
-
AbstractInt에서 AbstractFloat로. (변환 순위 4)
-
AbstractInt에서 f32로. (변환 순위 5)
-
AbstractInt에서 f16으로. (변환 순위 6)
-
-
결과 계산은 AbstractFloat로 수행됩니다 (예:
log2(32.0)).
예: 식 1 + 2.5는 다음과 같이 분석됩니다.
-
1 + 2.5는 AbstractInt 값 1과 AbstractFloat 값 2.5를 하위 식으로 갖는 덧셈 연산으로 구문 분석됩니다. -
e가 정수 타입이고 f가 부동 소수점 타입인 e+f의 오버로드는 없습니다.
-
하지만 실행 가능한 자동 변환을 사용하면 다음과 같은 세 가지 잠재적 오버로드가 있습니다.
-
1은 AbstractFloat 값1.0으로 변환되고 (순위 4),2.5는 AbstractFloat로 유지됩니다(순위 0).
-
-
첫 번째 오버로드가 선호되는 후보이며 타입 검사가 성공합니다.
-
결과 계산은 AbstractFloat
1.0 + 2.5로 수행됩니다.
예: let x = 1 + 2.5;
-
이 예제는 위의 예제와 유사하지만
x가 추상 숫자 타입으로 해석될 수 없다는 점이 다릅니다. -
선언의 효과는
let x : f32 = 1.0f + 2.5f;라고 작성한 것과 같습니다.
예: 1u + 2.5는 셰이더 생성 오류를 발생시킵니다.
-
1u항은 u32 타입의 식입니다. -
2.5항은 AbstractFloat 타입의 식입니다. -
유효한 오버로드 후보가 없습니다.
예: -1 * i32(-2147483648)은 셰이더 생성 오류를
발생시키지 않습니다.
-
-1항은 AbstractInt 타입의 식입니다. -
i32(-2147483648)항은 i32 타입의 식입니다. -
이 두 타입에 대한 곱셈 연산자 오버로드는 없으며 i32 항을 AbstractInt로 상향 변환할 수 없습니다.
-
실행 가능한 유일한 자동 변환은 AbstractInt를 i32로 변환하는 것이므로 다음이 적용됩니다.
// 명시적으로 타입이 지정된 부호 없는 정수 리터럴입니다. var u32_1 = 1u ; // 변수는 u32를 저장합니다 // 명시적으로 타입이 지정된 부호 있는 정수 리터럴입니다. var i32_1 = 1i ; // 변수는 i32를 저장합니다 // 명시적으로 타입이 지정된 부동 소수점 리터럴입니다. var f32_1 = 1f ; // 변수는 f32를 저장합니다 // 명시적으로 타입이 지정된 부호 없는 정수 리터럴은 부정할 수 없습니다. var u32_neg = - 1u ; // 유효하지 않음: 단항 빼기는 u32를 지원하지 않습니다 // 구체 타입이 필요하지만 문이나 식의 어떤 부분도 특정 구체 타입을 // 강제하지 않으면 정수 리터럴은 i32 값으로 해석됩니다. // let 선언의 초기화 값은 생성 가능 타입 또는 포인터여야 합니다. // AbstractInt에서 생성 가능 타입으로의 가장 선호되는 자동 변환은 // 변환 순위 2인 AbstractInt에서 i32로의 변환입니다. 따라서 '1'은 i32로 추론됩니다. let some_i32 = 1 ; // let some_i32: i32 = 1i;와 같음 // 선언 타입에서 추론됩니다. var i32_from_type : i32= 1 ; // 변수는 i32를 저장합니다. AbstractInt에서 i32, 변환 순위 2 var u32_from_type : u32= 1 ; // 변수는 u32를 저장합니다. AbstractInt에서 u32, 변환 순위 3 // 접미사가 없는 정수 리터럴은 필요한 경우 부동 소수점으로 변환될 수 있습니다. // 변환 순위 5로 AbstractInt를 f32로 자동 변환합니다. var f32_promotion : f32= 1 ; // 변수는 f32를 저장합니다 // 유효하지 않음: 부동 소수점에서 정수로 실행 가능한 변환이 없습니다 var i32_demotion : i32= 1.0 ; // 유효하지 않음 // 식에서 추론됩니다. var u32_from_expr = 1 + u32_1 ; // 변수는 u32를 저장합니다 var i32_from_expr = 1 + i32_1 ; // 변수는 i32를 저장합니다 // 값을 표현할 수 있어야 합니다. let u32_too_large : u32= 1234567890123456890 ; // 유효하지 않음, 오버플로 let i32_too_large : i32= 1234567890123456890 ; // 유효하지 않음, 오버플로 let u32_large : u32= 2147483649 ; // 유효함 let i32_large : i32= 2147483649 ; // 유효하지 않음, 오버플로 let f32_out_of_range1 = 0x1p500 ; // 유효하지 않음, 범위를 벗어남 let f32_hex_lost_bits = 0x1.0000000001p0 ; // 유효하지 않음, f32로 정확히 표현할 수 없음 // 최솟값 정수: AbstractInt에 단항 부정을 적용한 다음 i32로 추론합니다. // AbstractInt에서 생성 가능 타입으로의 가장 선호되는 변환(가장 낮은 // 변환 순위)은 AbstractInt에서 i32로의 변환입니다. let i32_min = - 2147483648 ; // i32 타입을 가집니다 // 유효하지 않음. 위와 같이 AbstractInt에서 i32로의 변환을 선택하지만 값이 // 범위를 벗어나 셰이더 생성 오류가 발생합니다. let i32_too_large_2 = 2147483648 ; // 유효하지 않음. // 하위 식은 AbstractInt 및 AbstractFloat로 해석될 수 있습니다. // 다음 예제는 모두 유효하며 변수의 값은 6u입니다. var u32_expr1 = ( 1 + ( 1 + ( 1 + ( 1 + 1 )))) + 1u ; var u32_expr2 = 1u + ( 1 + ( 1 + ( 1 + ( 1 + 1 )))); var u32_expr3 = ( 1 + ( 1 + ( 1 + ( 1u + 1 )))) + 1 ; var u32_expr4 = 1 + ( 1 + ( 1 + ( 1 + ( 1u + 1 )))); // 내장 함수 매개변수를 기반으로 추론합니다. // 가장 선호되는 후보는 clamp(i32,i32,i32)->i32입니다 let i32_clamp = clamp ( 1 , - 5 , 5 ); // 가장 선호되는 후보는 clamp(u32,u32,u32)입니다. // 리터럴은 AbstractInt에서 u32로의 자동 변환을 사용합니다. let u32_clamp = clamp ( 5 , 0 , u32_from_expr ); // 가장 선호되는 후보는 clamp(f32,f32,f32)->f32입니다 // 리터럴은 AbstractInt에서 f32로의 자동 변환을 사용합니다. let f32_clamp = clamp ( 0 , f32_1 , 1 ); // 다음 예제는 모두 초깃값이 10f인 f32로 승격됩니다. let f32_promotion1 = 1.0 + 2 + 3 + 4 ; let f32_promotion2 = 2 + 1.0 + 3 + 4 ; let f32_promotion3 = 1f + (( 2 + 3 ) + 4 ); let f32_promotion4 = (( 2 + ( 3 + 1f )) + 4 ); // 타입 규칙 위반. // 유효하지 않음: 초기화 값은 f32로만 해석될 수 있습니다. // AbstractFloat에서 u32로 실행 가능한 자동 변환이 없습니다. let mismatch : u32= 1.0 ; // 유효하지 않음. 부호가 혼합된 매개변수를 허용하는 clamp 오버로드는 없습니다. let ambiguous_clamp = clamp ( 1u , 0 , 1i ); // 추론은 문 수준에서 완료됩니다. // let 선언의 초기화 값은 생성 가능 타입 또는 포인터여야 합니다. // AbstractInt에서 생성 가능 타입으로의 가장 선호되는 자동 변환은 // 변환 순위 2인 AbstractInt에서 i32로의 변환입니다. 따라서 '1'은 i32로 추론됩니다. let some_i32 = 1 ; // let some_i32: i32 = 1i;와 같음 let some_f32 : f32= some_i32 ; // 타입 오류: i32를 f32에 대입할 수 없습니다 // 또 다른 오버플로 사례 let overflow_u32 = ( 1 - 2 ) + 1u ; // 유효하지 않음, -1은 u32 범위를 벗어납니다 // 이상적인 값은 32비트 범위를 벗어나지만 다시 범위 안으로 돌아옵니다 let out_and_in_again = ( 0x1ffffffff / 8 ); // 유사하지만 유효하지 않습니다 let out_of_range = ( 0x1ffffffff / 8u ); // 계산을 32비트에서 수행해야 하므로 // 0x1ffffffff가 범위를 벗어납니다.
6.2.2. 불리언 타입
bool 타입은
true와 false 값을 포함합니다.
| 전제 조건 | 결론 | 설명 |
|---|---|---|
true: bool
| 참 값. | |
false: bool
| 거짓 값. |
6.2.3. 정수 타입
u32 타입은 32비트 부호 없는 정수의 집합입니다.
i32 타입은 32비트 부호 있는 정수의 집합입니다. 부호 비트가 최상위 비트 위치에 있는 2의 보수 표현을 사용합니다.
오버플로가 발생하는 구체 정수 타입에 대한 식은 2비트 폭을 법으로 한 결과를 생성합니다.
| 타입 | 최솟값 | 최댓값 |
|---|---|---|
| i32 | i32(-2147483648) | 2147483647i |
| i32(-0x80000000) | 0x7fffffffi | |
| u32 | 0u | 4294967295u |
| 0x0u | 0xffffffffu |
참고: AbstractInt도 정수 타입입니다.
6.2.4. 부동 소수점 타입
f32 타입은 IEEE-754 binary32(단정밀도) 형식의 32비트 부동 소수점 값 집합입니다. 자세한 내용은 § 15.7 부동 소수점 평가를 참조하십시오.
f16 타입은
IEEE-754 binary16(반정밀도) 형식의
16비트 부동 소수점 값 집합입니다. 프로그램에 f16
확장을 활성화하는 enable f16; 지시문이
포함되지 않은 상태에서 f16 타입을 사용하면 셰이더 생성 오류입니다.
자세한 내용은 § 15.7 부동 소수점 평가를 참조하십시오.
다음 표는 부동 소수점 타입의 특정 극값을 나열합니다. 각 값에는 그에 대응하는 음숫값이 있습니다.
| 타입 | 가장 작은 양의 비정규 값 | 가장 작은 양의 정규 값 | 가장 큰 양의 유한 값 | 가장 큰 유한한 2의 거듭제곱 |
|---|---|---|---|---|
| f32 | 1.40129846432481707092e-45f | 1.17549435082228750797e-38f | 3.40282346638528859812e+38f | 0x1p+127f |
| 0x1p-149f | 0x1p-126f | 0x1.fffffep+127f | ||
| f16 | 5.9604644775390625e-8h | 0.00006103515625h | 65504.0h | 0x1p+15h |
| 0x1p-24h | 0x1p-14h | 0x1.ffcp+15h |
참고: AbstractFloat도 부동 소수점 타입입니다.
6.2.5. 스칼라 타입
스칼라 타입은 bool, AbstractInt, AbstractFloat, i32, u32, f32, 그리고 f16이다.
숫자 스칼라 타입은 AbstractInt, AbstractFloat, i32, u32, f32, 그리고 f16이다.
정수 스칼라 타입은 AbstractInt, i32, 그리고 u32이다.
스칼라 변환은 한 스칼라 타입의 값을 다른 스칼라 타입의 값으로 매핑한다. 일반적으로 결과 값은 대상 타입의 한계 내에서 원래 값에 가깝다. 스칼라 변환은 다음 중 하나로 발생한다.
-
값 생성자를 명시적으로 호출하는 경우, 또는
-
추상 숫자 타입의 상수 식을 실현 가능한 자동 변환을 통해 다른 타입으로 변환하는 경우.
6.2.6. 벡터 타입
벡터는 2개, 3개 또는 4개의 스칼라 성분을 묶은 시퀀스이다.
| 타입 | 설명 |
|---|---|
| vecN<T> | 타입 T의 성분 N개로 구성된 벡터. N은 {2, 3, 4} 중 하나여야 하고, T는 스칼라 타입 중 하나여야 한다. T를 벡터의 성분 타입이라고 한다. |
벡터의 성분 타입이 숫자 스칼라이면 해당 벡터를 숫자 벡터라고 한다.
벡터의 주요 사용 사례는 다음과 같다.
-
방향과 크기를 함께 표현한다.
-
공간의 위치를 표현한다.
-
특정 색 공간의 색상을 표현한다. 예를 들어 성분은 빨강, 초록 및 파랑의 강도가 될 수 있고, 네 번째 성분은 알파(불투명도) 값이 될 수 있다.
벡터와 행렬에 대한 많은 연산은 성분별로 동작한다. 즉, 각 스칼라 성분을 독립적으로 연산하여 결과를 구성한다.
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]
| 미리 선언된 별칭 | 원래 타입 | 제한 사항 |
|---|---|---|
| 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 산술 식을 참조한다.
| 미리 선언된 별칭 | 원래 타입 | 제한 사항 |
|---|---|---|
| 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 중 하나여야 한다. |
식은 원자 타입으로 평가되어서는 안 된다.
원자 타입은 workgroup 주소 공간의 변수 또는
read_write 접근 모드를 사용하는
스토리지 버퍼 변수에
의해서만 인스턴스화될 수 있다.
이 타입에 대한 연산의 메모리 범위는 타입이 인스턴스화된
주소 공간에 따라 결정된다.
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이 오버라이드 선언에 의존하는 경우, 요소 수 값은 파이프라인 생성 시점에 완전히 결정되며, 그렇지 않으면 셰이더 모듈 생성 시점에 완전히 결정된다.
참고: 타입 동등성을 충족하려면 상수 식이 아닌 모든 오버라이드 식은 식별자여야 한다. 오버라이드 가능한 상수로 크기가 결정되는 작업 그룹 변수를 참조한다.
런타임 크기 배열의 요소 수는 해당 스토리지 버퍼 변수와 연결된 버퍼 바인딩의 크기에 따라 결정된다. § 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' ident struct_body_decl
'{' struct_member ( ',' struct_member ) * ',' ? '}'
구조체 멤버에는 다음 특성을 적용할 수 있다.
builtin, location, blend_src, interpolate, 그리고 invariant 특성은 IO 특성이다. 구조체 S의 멤버에 있는 IO 특성은 S가 진입점의 형식 매개변수 또는 반환 타입으로 사용될 때만 효과가 있다. § 13.3.1 단계 간 입력 및 출력 인터페이스를 참조한다.
align 및 size 특성은 레이아웃 특성이며, 구조체 타입이 유니폼 버퍼 또는 스토리지 버퍼를 정의하는 데 사용되는 경우 필요할 수 있다. § 14.4 메모리 레이아웃을 참조한다.
// 런타임 배열 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)로 표기하며, 그 값은 다음과 같다.
-
벡터 타입은 1
-
행렬 타입은 2
-
요소 타입이 E인 배열 타입은 1 + NestDepth(E)
-
T가 멤버 타입 M1,...,MN을 가진 구조체 타입이면 1 + max(NestDepth(M1),..., NestDepth(MN))
6.2.12. 생성 가능한 타입
많은 종류의 값은 생성하고, 불러오고, 저장하고, 함수에 전달하고, 함수에서 반환할 수 있다. 이러한 값을 생성 가능하다고 한다.
타입이 다음 중 하나이면 생성 가능하다.
참고: 모든 생성 가능한 타입은 생성 시 고정된 풋프린트를 가진다.
참고: 원자 타입과 런타임 크기 배열 타입은 생성 가능하지 않다. 원자 타입과 런타임 크기 배열을 포함하는 복합 타입도 생성 가능하지 않다.
6.2.13. 고정 풋프린트 타입
변수의 메모리 풋프린트는 변수의 내용을 저장하는 데 사용되는 메모리 위치의 수이다. 변수의 메모리 풋프린트는 저장소 타입에 따라 달라지며 셰이더 수명 주기의 어느 시점에 확정된다. 대부분의 변수는 매우 이른 셰이더 생성 시점에 크기가 결정된다. 일부 변수는 더 늦은 파이프라인 생성 시점에, 다른 변수는 셰이더 실행 시작 시점에야 크기가 결정될 수 있다.
타입을 구체화한 결과의 크기가 셰이더 생성 시점에 완전히 결정되면, 그 타입은 생성 시 고정된 풋프린트를 가진다.
타입의 크기가 파이프라인 생성 시점에 완전히 결정되면, 그 타입은 고정 풋프린트를 가진다.
참고: 모든 구체 생성 시 고정된 풋프린트 타입과 고정 풋프린트 타입은 저장 가능하다.
참고: 파이프라인 생성은 셰이더 생성에 의존하므로 생성 시 고정된 풋프린트를 가진 타입은 고정 풋프린트도 가진다.
생성 시 고정된 풋프린트를 가진 타입은 다음과 같다.
-
스칼라 타입
-
벡터 타입
-
행렬 타입
-
원자 타입
-
다음 조건을 만족하는 고정 크기 배열 타입:
-
모든 멤버가 생성 시 고정된 풋프린트를 가진 구조체 타입.
-
다음 조건을 만족하는 고정 크기 버퍼 타입:
-
크기가 상수 식이다.
-
참고: 생성 가능한 타입은 생성 시 고정된 풋프린트를 가진다.
고정 풋프린트를 가진 타입은 다음 중 하나이다.
-
생성 시 고정된 풋프린트를 가진 타입
-
크기에 추가 제약이 없는 고정 크기 버퍼 타입
참고: 상수 식이 아닌 오버라이드 식을 요소 수로 사용하는 고정 크기 배열의 유일하게 유효한 용도는 workgroup 주소 공간의 메모리 뷰이다. 여기에는 작업 그룹 변수의 저장소 타입도 포함된다.
참고: 고정 풋프린트 타입은 직접 또는 간접적으로 원자 타입을 포함할 수 있지만, 생성 가능한 타입은 포함할 수 없다.
참고: 고정 풋프린트 타입에는 런타임 크기 배열, 런타임 크기 버퍼, 런타임 크기 배열을 포함하는 모든 구조체가 제외된다.
6.3. 버퍼 타입
이 타입에는 buffer_view 언어 기능이 필요하다.
버퍼 값은 그 내용을 다른 호스트 공유 가능 타입으로 해석할 수 있는 메모리를 나타낸다. 그 밖의 측면에서 버퍼 값은 불투명하다. 버퍼 값은 변수의 데이터에 여러 타입으로 접근해야 하거나 셰이더 작성자가 하나의 변수를 여러 논리적 변수로 세분화하려는 경우 유용하다.
버퍼 타입은 생성 가능하지 않으며, buffer_view 내장 함수를 통해 데이터를 불투명하지 않은 호스트 공유 가능 타입으로 해석한 후에만 접근할 수 있다.
| 타입 | 설명 |
|---|---|
| buffer<N> | N바이트의 저장 공간을 가진 고정 크기 버퍼. N은 오버라이드 식이어야 한다. |
| buffer | 런타임 크기 버퍼. |
고정 크기 버퍼는 storage, uniform 및 workgroup 주소 공간의 변수에 의해서만 인스턴스화될 수 있다. storage 및 uniform 주소 공간에서는 크기가 상수 식이어야 한다. 런타임 크기 버퍼는 storage 주소 공간의 변수에 의해서만 인스턴스화될 수 있다.
N이 0보다 크지 않은 경우:
-
그렇지 않으면 파이프라인 생성 오류이다.
f16 확장이 활성화되어 있고 N이 2로 나누어떨어지지 않는 경우:
-
그렇지 않으면 파이프라인 생성 오류이다.
f16 확장이 활성화되어 있지 않고 N이 4로 나누어떨어지지 않는 경우:
-
그렇지 않으면 파이프라인 생성 오류이다.
두 버퍼 타입은 다음 조건 중 하나가 성립하는 경우에만 동일하다.
-
둘 다 런타임 크기이다.
-
둘 다 생성 시 고정된 풋프린트를 가진 고정 크기이고 크기의 값이 같다. 한쪽이 부호 있는 값이고 다른 쪽이 부호 없는 값이어도 마찬가지이다. (크기는 항상 양수이므로 이 경우 부호 있는 값과 부호 없는 값을 비교할 수 있다.)
-
둘 다 고정 크기이며, 크기가 동일한 파이프라인 오버라이드 가능 상수 선언으로 해석되는 식별자로 지정되어 있다.
6.4. 열거형 타입
열거형 타입은 이름 있는 값의 제한된 집합이다. 열거형은 유효한 텍셀 형식 집합과 같이 특정 개념의 가능성 집합을 구별하는 데 사용된다.
열거자는 열거형에 있는 이름 있는 값 중 하나이다. 각 열거자는 다른 모든 열거자 및 다른 모든 종류의 값과 구별된다.
WGSL 소스에는 새로운 열거자나 새로운 열거형 타입을 선언하는 메커니즘이 없다.
참고: 열거자는 템플릿 매개변수로 사용된다.
6.4.1. 미리 선언된 열거자
다음 표에는 WGSL의 열거형 타입, 미리 선언된 열거자, 그리고 해당 열거형 타입에 필요한 언어 확장이 나열되어 있다. 열거형 타입은 존재하지만 WGSL 소스에서 표기할 수 없다.
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 소스 텍스트에서는 다음과 같다.
-
참조 타입이 나타나서는 안 된다.
-
포인터 타입은 나타날 수 있다.
-
포인터 타입은 다음 매개변수를 사용하여 표기한다.
-
저장소 타입, 그리고
-
§ 14.3 주소 공간에 지정된 대로 경우에 따라 접근 모드.
-
프로그램 소스에 포인터 타입이 나타나면, 프로그램의 어느 위치에서 해당 포인터 타입의 주소 공간, 저장소 타입 및 접근 모드를 사용하여 해당 타입의 변수를 선언하거나 함수 호출에서 해당 타입을 반환하는 것도 유효해야 한다.
참고: 이 제한은 런타임에 절대로 사용할 수 없는 특정 타입 별칭 및 함수 형식 매개변수의 선언을 금지한다. 이 제한이 없다면 포인터 타입의 별칭을 선언할 수 있지만 해당 타입의 포인터 값을 생성할 수는 없는 상황이 유효해진다. 마찬가지로 포인터 형식 매개변수가 있는 함수를 선언할 수 있지만 해당 함수를 호출할 수는 없는 상황도 유효해진다.
-
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는 타입 vecN<S>인 벡터를 가리키며 read_write 접근 모드를 가진 포인터이다.
-
IndexList = « Idx0, ..., IdxK−1 »이며, 다음 조건을 만족하는 인덱스의 시퀀스이다.
-
각 Idxi는 [0,N−1] 범위에 있다.
-
vecK<S>는 유효한 벡터 타입이다. 즉, K는 {2,3,4} 중 하나이다.
-
알고리즘: SwizzleViewRead
포인터 p를 통해 읽은 벡터의 성분을 선택하고 선택적으로 치환하여 구성한 벡터를 산출한다.
참고: 스위즐 뷰를 통한 읽기는 일부 벡터 성분이 결과에 나타나지 않더라도 메모리에서 전체 벡터를 읽는다.
입력: 타입 swizzle<AS,S,N,K>의 스위즐 뷰 (p, IndexList)
출력: (p, IndexList)를 읽은 결과인 타입 vecK<S>의 벡터 값 v.
절차:
관례에 따라 IndexList = « Idx0, ..., IdxK−1 »이다.
p가 참조하는 메모리에서 벡터 u를 읽는다. u의 타입은 vecN<S>이다.
다음 조건을 만족하는 타입 vecK<S>의 값 v를 구성한다.
v의 성분 i는 u의 성분 Idxi 값과 같다. 인덱싱 구문을 사용하면 다음과 같다. v[i] = u[Idxi]
알고리즘: SwizzleViewWrite
update 벡터의 성분을 포인터 p가 참조하는 메모리 내 벡터의 지정된 성분에 쓴다.
참고: 스위즐 뷰를 통한 쓰기는 이 과정에서 성분 값이 변경되지 않더라도 메모리의 전체 벡터를 쓴다.스위즐 뷰 쓰기와 균일성 분석 및 메모리 모델의 상호 작용에 관한 설명은 아래를 참조한다.
입력:
타입 swizzle<AS,S,N,K>의 스위즐 뷰 (p, IndexList)
타입 vecN<S>의 벡터 old_contents
old_contents는 과거의 특정 시점에 p가 참조하는 메모리에 저장되어 있던 벡터를 나타내기 위한 것이다.
타입 vecK<S>의 벡터 update
IndexList의 모든 인덱스는 서로 달라야 한다. 이 요구 사항에 따라 K ≤ N이다.
변수:
타입 vecN<S>의 new
절차:
관례에 따라 IndexList = « Idx0, ..., IdxK−1 »이다.
변수 new를 old_contents로 초기화한다.
0..K-1의 각 i에 대해:
new의 성분 Idxi를 update의 성분 i 값으로 설정한다. 인덱싱 구문을 사용하면 다음과 같다. new[Idxi] = update[i].
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)의 집합으로 식별되는
스위즐 뷰
타입이다.
스위즐 뷰 타입은 WGSL 소스에 작성되지 않으며, 대신 WGSL 모듈을 분석하는 데 사용된다. |
스위즐 뷰는 다음 방법으로 구성한다.
-
read_write 접근 모드를 가지고 저장소 타입이 벡터인 참조 또는 포인터 값에 여러 글자로 된 스위즐 이름을 적용한다. 또는
-
스위즐 뷰에 여러 글자로 된 스위즐 이름을 적용한다.
이 규칙에 따라 스위즐 뷰의 IndexList 부분은 셰이더 생성 시점에 완전히 결정된다.
자세한 내용은 § 8.6 스위즐 뷰 식을 참조한다.
fn swizzle_read_and_write () { var v : vec4u; // 다음과 동일하다: v.y = 1; v.z = 2; // 그러나 벡터를 메모리에서 정확히 한 번 읽고 메모리에 정확히 한 번 쓴다. v . yz = vec2u( 1 , 2 ); // 다음과 동일하다: let u = vec3(v.a, v.g, v.b); // 식 v.agb는 타입 swizzle<function,u32,4,3>의 스위즐 뷰이다. // let 선언의 유효 값 타입은 구체적이고 생성 가능한 타입 또는 포인터 타입이어야 한다. // 따라서 스위즐 뷰 로드 규칙을 호출하여 스위즐 뷰를 vec3u로 자동 변환한다. let u = v . agb ; // 스위즐은 연쇄할 수 있다. // 다음과 동일하다: v.zy = vec2(99,100); v . yz . yx = vec2( 99 , 100 ); // 스위즐 뷰에 한 글자를 적용하면 기반 벡터의 스칼라 성분에 대한 // 참조가 산출된다. // 다음과 동일하다: v.z = 99; v . yz . y = 99 ; // 스위즐 뷰를 인덱싱하면 벡터 성분 중 하나에 대한 참조가 산출된다. // 한 글자 벡터 접근을 구성하는 것처럼 동작하지만, 인덱스는 스위즐 이름에서 // 사용할 글자를 선택한다. v . zy [ 1 ] = 50 ; // v.y = 50;과 동일하다. }
// 이 예제에서는 swizzle_assignment 외에 pointer_composite_access도 // 지원한다고 가정한다. requires pointer_composite_access ; fn swizzle_read_and_write_via_pointer ( p : ptr< function, vec4u> ) { // 다음과 동일하다: (*p).y = 1; (*p).z = 2; p . yz = vec2u( 1 , 2 ); // 다음과 동일하다: let u = vec3((*p).a, (*p).g, (*p).b); let u = p . agb ; // 스위즐은 연쇄할 수 있다. // 다음과 동일하다: p.zy = vec2(99,100); p . yz . yx = vec2( 99 , 100 ); // 포인터에서 스위즐 뷰를 구성할 수 있다. // 스위즐 뷰에 한 글자를 적용하면 기반 벡터의 스칼라 성분에 대한 // 참조가 산출된다. // 다음과 동일하다: (*p).z = 99; p . yz . y = 99 ; // 스위즐 뷰를 인덱싱하면 벡터 성분 중 하나에 대한 참조가 산출된다. // 한 글자 벡터 접근을 구성하는 것처럼 동작하지만, 인덱스는 스위즐 이름에서 // 사용할 글자를 선택한다. p . zy [ 1 ] = 50 ; // (*p).y = 50;과 동일하다. }
fn invalid_swizzle_cases () { var v : vec2u; // 유효하지 않음: 성분이 반복되는 스위즐에는 할당할 수 없다 v . xx = vec2u( 1 , 2 ); // 유효하지 않음: 'z'는 대상 벡터의 범위를 벗어난다. v . xz = vec2u( 1 , 2 ); let u = v . xz ; // 유효하지 않음: xyzw와 rgba 글자 체계를 혼합해서는 안 된다 v . xr = vec2u( 1 , 2 ); // 스위즐 뷰의 주소를 가져올 수 없다. // 여기서 v.xy는 스위즐 뷰 (&v,`01`)이다 // & 연산자는 스위즐 뷰에 적용되지 않으므로 타입 검사가 실패한다. let p = & v . xy ; }
균일성 분석의 목적상 스위즐 뷰 쓰기는 갱신되는 성분의 값 균일성에만 영향을 줄 수 있다. 이것이 전체 스위즐 뷰와 부분 스위즐 뷰를 구분하는 이유이다.
그러나 기반 벡터의 모든 성분을 쓴다는 사실은 메모리 모델에서 중요하다. 동일한 메모리 내 벡터의 서로 다른 성분을 동시에 갱신하는 서로 다른 두 호출은 데이터 경합을 일으킨다.
var < workgroup> w : vec4u; @compute @workgroup_size ( 2 ) fn this_races ( @builtin ( local_invocation_index) gid : u32) { if ( gid == 0 ) { w . xy = vec2u( 0 , 1 ); // 전체 벡터를 쓰므로 다른 호출과 경합한다. } else { w . zw = vec2u( 2 , 3 ); // 전체 벡터를 쓰므로 다른 호출과 경합한다. } }
6.5.5. 유효하거나 유효하지 않은 메모리 참조
참조를 구성하는 자세한 방법은 § 6.5.9 참조 및 포인터 값 구성에 설명되어 있다. 일반적으로 유효한 참조는 다음 방법으로 구성한다.
-
변수의 이름을 지정한다. 또는
일반적으로 유효하지 않은 메모리 참조는 다음 방법으로 구성된다.
-
유효하지 않은 포인터에 간접 참조 연산자를 적용한다. 또는
유효하지 않은 포인터는 다음 방법으로 구성된다.
-
유효하지 않은 메모리 참조에 주소 가져오기 연산자(단항
&)를 적용한다. 또는 -
결과 포인터의 메모리 뷰에 버퍼 포인터 인수의 메모리 뷰 범위를 벗어난 메모리 위치가 포함될 때 bufferView 또는 bufferArrayView 내장 함수를 호출한다.
유효한 포인터는 유효한 참조에 대응하는 포인터이다.
유효한 스위즐 뷰는 포인터 값이 유효한 스위즐 뷰이다. 유효하지 않은 스위즐 뷰는 포인터 값이 유효하지 않은 스위즐 뷰이다.
6.5.6. 기원 변수
포인터 값의 기원 변수는 대응하는 참조 값의 기원 변수로 정의된다.
스위즐 뷰의 기원 변수는 해당 스위즐 뷰 포인터의 기원 변수로 정의된다.
참고: 기원 변수는 동적 개념이다. 함수 형식 매개변수의 기원 변수는 해당 함수의 호출 지점에 따라 달라진다. 서로 다른 호출 지점은 서로 다른 기원 변수 내부를 가리키는 포인터를 제공할 수 있다.
유효한 참조는 항상 어떤 변수의 메모리 위치 일부 또는 전부에 대한 비어 있지 않은 메모리 뷰에 대응한다.
유효한 스위즐 뷰는 항상 어떤 변수 내부에 있는 벡터의 메모리 위치에 대응한다.
다음 예제에서 참조 the_particle.position[i]는 i가 0 또는
1인 경우에만 유효하다.
i가 2이면 해당 참조는 유효하지 않은
메모리 참조가 되지만, 그 밖의 측면에서는
the_particle.color_index의 메모리 위치에 대응한다.
6.5.7. 범위를 벗어난 접근
유효하지 않은 메모리 참조 또는 유효하지 않은 스위즐 뷰에 접근하는 연산은 범위를 벗어난 접근이다.
범위를 벗어난 접근은 프로그램 결함이다. 작성된 그대로 수행되면 일반적으로 다음 중 하나가 발생하기 때문이다.
따라서 구현은 작성된 그대로 접근을 수행하지 않는다. 범위를 벗어난 접근을 실행하면 동적 오류가 발생한다.
참고: 저장소 타입을 잘못 해석하는 예는
이전 절의 예제에서 볼 수 있다.
i가 2이면 식 the_particle.velocity[i]의 타입은
ref<storage,f32,read_write>이다. 이는
f32를
저장소 타입으로 사용하는 메모리 뷰라는 의미이다.
그러나 해당 메모리 위치는 color_index 멤버에 할당되므로 실제로 저장된 값의
타입은 i32이다.
가능한 결과에는 다음이 포함되지만 이에 한정되지는 않는다.
- 트랩
-
셰이더 호출이 즉시 종료되고 셰이더 단계 출력이 0 값으로 설정된다.
- 유효하지 않은 로드
-
유효하지 않은 참조로부터 수행되는 로드는 다음 중 하나를 반환할 수 있다.
- 유효하지 않은 저장
-
유효하지 않은 참조에 대한 저장은 다음 중 하나를 수행할 수 있다.
유효하지 않은 로드 또는 저장이 공유 주소 공간의 변수 내부에 있는 다른 위치에 접근하도록 리디렉션되면 데이터 경합이 발생할 수 있다. 예를 들어 동시에 실행되는 여러 호출의 접근이 배열의 첫 번째 요소로 리디렉션될 수 있다. 하나 이상의 접근이 쓰기이고 다른 방식으로 동기화되지 않았다면 그 결과는 데이터 경합이며, 따라서 동적 오류이다.
범위를 벗어난 접근은 균일성 분석의 가정을 무효화한다. 예를 들어 호출이 범위를 벗어난 접근으로 인해 일찍 종료되면 더 이상 집합 연산에 참여할 수 없다. 특히 workgroupBarrier 호출은 셰이더를 멈추게 할 수 있고 도함수는 유효하지 않은 결과를 산출할 수 있다.
6.5.8. 참조 및 포인터의 사용 사례
참조와 포인터는 사용 방식에 따라 구별된다.
-
변수의 타입은 참조 타입이다.
-
주소 가져오기 연산(단항
&)은 참조 값을 대응하는 포인터 값으로 변환한다. -
간접 참조 연산(단항
*)은 포인터 값을 대응하는 참조 값으로 변환한다. -
let 선언은 포인터 타입일 수 있지만 참조 타입일 수는 없다.
-
형식 매개변수는 포인터 타입일 수 있지만 참조 타입일 수는 없다.
-
read_write 접근 모드를 가지고 저장소 타입이 벡터인 참조 또는 포인터 값에 여러 글자로 된 스위즐 이름을 적용하여 스위즐 뷰를 구성할 수 있다.
-
스위즐 할당 문은 스위즐 뷰를 통해 메모리 내 벡터의 두 개 이상의 성분을 갱신한다.
-
스위즐 뷰는 위와 같이 포인터나 참조 또는 다른 스위즐 뷰에서 생성된다. § 8.6 스위즐 뷰 식을 참조한다.
-
-
로드 규칙: 함수 내부에서는 타입 규칙을 충족하기 위해 참조를 자동으로 역참조하여 읽는다.
-
함수에서 저장소 타입이 T인 참조 식 r이 문이나 식에 사용되고 다음 조건을 만족하는 경우:
-
r의 접근 모드는 read 또는 read_write이다. 그리고
-
잠재적으로 일치할 수 있는 유일한 타입 규칙이 r에 타입 T의 값을 요구한다.
-
-
그러면 해당 타입 규칙 요구 사항을 충족한 것으로 간주한다. 그리고
-
해당 컨텍스트에서 r을 평가한 결과는 평가 시점에 r이 참조하는 메모리 위치에 저장된 타입 T의 값이다. 즉, 결과 값을 생성하기 위해 읽기 접근을 수행한다.
-
-
이와 유사하게 스위즐 뷰 로드 규칙이 있다. 함수 내부에서는 타입 규칙을 충족하기 위해 스위즐 뷰 읽기를 수행한다.
참조를 이러한 방식으로 정의하면 변수를 단순하고 관용적으로 사용할 수 있다.
@compute @workgroup_size ( 1 ) fn main () { // 'i'의 참조 타입은 ref<function,i32,read_write>이다 // 'i'의 메모리 위치에는 i32 값 0이 저장된다. var i : i32= 0 ; // 'i + 1'은 'i' 하위 식의 타입이 i32인 타입 규칙에만 일치할 수 있다. // 따라서 식 'i + 1'의 타입은 i32이고, 평가할 때 'i' 하위 식은 평가 시점에 // 'i'의 메모리 위치에 저장된 i32 값으로 평가된다. let one : i32= i + 1 ; // 'i'가 참조하는 위치의 값을 갱신하여 값 2를 보관하게 한다. i = one + 1 ; // 'i'가 참조하는 위치의 값을 갱신하여 값 5를 보관하게 한다. // 우변 평가는 할당이 적용되기 전에 발생한다. i = i + 3 ; }
var < private> age : i32; fn get_age () -> i32{ // 반환 문의 식은 함수에 선언된 반환 타입과 일치해야 하므로 // 해당 식의 타입은 'i32'여야 한다. // 'age' 식의 타입은 ref<private,i32,read_write>이다. // 참조의 저장소 타입이 식에 필요한 타입과 일치하고 다른 타입 규칙이 // 적용되지 않으므로 로드 규칙을 적용한다. // 이 컨텍스트에서 'age'를 평가한 결과는 반환 문이 실행되는 시점에 // 'age'가 참조하는 메모리 위치에서 로드된 i32 값이다. return age ; } fn caller () { age = 21 ; // copy_age 상수는 i32 값 21을 얻는다. let copy_age : i32= get_age (); }
포인터를 이러한 방식으로 정의하면 다음 두 가지 주요 사용 사례가 가능해진다.
-
포인터 타입의 let 선언을 사용하여 변수 내용의 일부에 짧은 이름을 지정한다.
-
함수의 형식 매개변수를 사용하여 호출 함수에서 접근할 수 있는 변수의 메모리를 참조한다.
struct Particle { position: vec3< f32> , velocity : vec3< f32> } struct System { active_index : i32, timestep : f32, particles : array< Particle , 100 > } @group ( 0 ) @binding ( 0 ) var < storage, read_write> system : System ; @compute @workgroup_size ( 1 ) fn main () { // storage 메모리의 특정 Particle에 대한 포인터를 구성한다. let active_particle = & system . particles [ system . active_index ]; let delta_position : vec3< f32> = ( * active_particle ). velocity * system . timestep ; let current_position : vec3< f32> = ( * active_particle ). position; ( * active_particle ). position= delta_position + current_position ; }
fn add_one ( x : ptr< function, i32> ) { /* 'x'의 위치를 갱신하여 그다음으로 큰 정숫값을 포함하게 한다 (또는 가장 작은 음의 i32 값으로 순환하게 한다). 좌변에서 단항 '*'는 포인터를 할당할 수 있는 참조로 변환한다. 기본적으로 read_write 접근 모드를 가진다. /* 우변에서는: - 단항 '*'가 포인터를 read_write 접근 모드의 참조로 변환한다. - 일치하는 유일한 타입 규칙은 덧셈(+)에 대한 규칙이며 '*x'의 타입이 '*x'의 저장소 타입인 i32일 것을 요구한다. 따라서 로드 규칙이 적용되고 '*x'는 평가 시점에 '*x'의 메모리에 저장된 값, 즉 i32 값 0으로 평가된다. - 0에 1을 더하여 우변의 최종 값 1을 생성한다. */ '*x'의 메모리에 1을 저장한다. */ * x = * x + 1 ; } @compute @workgroup_size ( 1 ) fn main () { var i : i32= 0 ; // 'i'의 내용을 수정하여 1을 포함하게 한다. // 단항 '&'를 사용하여 'i'의 포인터 값을 얻는다. // 이는 호출된 함수가 'i'의 메모리에 접근할 수 있으며 해당 메모리를 수정할 수 있다는 // 명확한 신호이다. add_one ( & i ); let one : i32= i ; // 'one'의 값은 1이다. }
6.5.9. 참조 및 포인터 값 구성
참조 값은 다음 방법 중 하나로 구성된다.
-
포인터에 간접 참조 연산(단항
*)을 사용한다. -
복합 값에 대한 메모리 뷰 또는 스위즐 뷰에 명명된 성분 식을 사용한다.
-
벡터 저장소 타입의 메모리 뷰 또는 스위즐 뷰에 한 글자 벡터 접근 구문을 추가하면 벡터의 명명된 성분에 대한 참조가 생성된다. § 8.5.1.3 벡터 메모리 뷰 또는 스위즐 뷰의 성분 참조를 참조한다.
-
구조체 저장소 타입의 메모리 뷰에 멤버 접근 구문을 추가하면 구조체의 명명된 멤버에 대한 참조가 생성된다. § 8.5.4 구조체 접근 식을 참조한다.
-
-
복합 값에 대한 메모리 뷰 또는 스위즐 뷰에 인덱싱 식을 사용한다.
-
벡터 저장소 타입의 메모리 뷰에 배열 인덱스 접근 구문을 추가하면 벡터의 인덱싱된 성분에 대한 참조가 생성된다. § 8.5.1.3 벡터 메모리 뷰 또는 스위즐 뷰의 성분 참조를 참조한다.
-
스위즐 뷰에 배열 인덱스 접근 구문을 추가하면 벡터의 한 성분에 대한 참조가 생성된다. 이 경우에는 간접적으로 인덱싱한다. 주어진 인덱스는 스위즐 뷰의 IndexList에서 성분의 인덱스로 사용할 멤버를 선택한다. § 8.5.1.3 벡터 메모리 뷰 또는 스위즐 뷰의 성분 참조를 참조한다.
-
행렬 저장소 타입의 메모리 뷰에 배열 인덱스 접근 구문을 추가하면 행렬의 인덱싱된 열 벡터에 대한 참조가 생성된다. § 8.5.2 행렬 접근 식을 참조한다.
-
배열 저장소 타입의 메모리 뷰에 배열 인덱스 접근 구문을 추가하면 배열의 인덱싱된 요소에 대한 참조가 생성된다. § 8.5.3 배열 접근 식을 참조한다.
-
모든 경우에 결과의 접근 모드는 원래 참조의 접근 모드와 같다.
struct S { age : i32, weight : f32} var < private> person : S ; // 다른 위치에서 'person'은 변수의 기반 메모리에 대한 참조를 나타내며 // 타입은 ref<private,S,read_write>이다. fn f () { var uv : vec2< f32> ; // 이 함수 본문의 나머지 부분에서 'uv'는 변수의 기반 메모리에 대한 // 참조를 나타내며 타입은 ref<function,vec2<f32>,read_write>이다. // 할당의 좌변을 평가한다: // 'uv.x'를 평가하여 참조를 산출한다: // 1. 먼저 'uv'를 평가하여 'uv' 변수의 메모리에 대한 참조를 산출한다. // 결과의 타입은 ref<function,vec2<f32>,read_write>이다. // 2. 그런 다음 '.x' 벡터 접근 구문을 적용하여 이전 단계의 참조 값이 // 가리키는 벡터의 첫 번째 성분 메모리에 대한 참조를 산출한다. // 결과의 타입은 ref<function,f32,read_write>이다. // 할당의 우변을 평가하면 f32 값 1.0이 산출된다. // uv.x가 참조하는 storage 메모리 위치에 f32 값 1.0을 저장한다. uv . x = 1.0 ; // 할당의 좌변을 평가한다: // 'uv[1]'을 평가하여 참조를 산출한다: // 1. 먼저 'uv'를 평가하여 'uv' 변수의 메모리에 대한 참조를 산출한다. // 결과의 타입은 ref<function,vec2<f32>,read_write>이다. // 2. 그런 다음 '[1]' 배열 인덱스 구문을 적용하여 이전 단계에서 참조한 // 벡터의 두 번째 성분 메모리에 대한 참조를 산출한다. // 결과의 타입은 ref<function,f32,read_write>이다. // 할당의 우변을 평가하면 f32 값 2.0이 산출된다. // uv[1]이 참조하는 storage 메모리 위치에 f32 값 2.0을 저장한다. uv [ 1 ] = 2.0 ; var m : mat3x2< f32> ; // 'm[2]'를 평가할 때: // 1. 먼저 'm'을 평가하여 'm' 변수의 메모리에 대한 참조를 산출한다. // 결과의 타입은 ref<function,mat3x2<f32>,read_write>이다. // 2. 그런 다음 '[2]' 배열 인덱스 구문을 적용하여 이전 단계의 참조 값이 // 가리키는 세 번째 열 벡터의 메모리에 대한 참조를 산출한다. // 따라서 'm[2]' 식의 타입은 ref<function,vec2<f32>,read_write>이다. // 'let' 선언은 타입 vec2<f32>에 대한 것이므로 선언 문은 초기화 값의 타입이 // vec2<f32>일 것을 요구한다. // 다른 타입 규칙을 적용할 수 없으므로 로드 규칙이 적용되며, 초기화 값의 평가는 // 선언이 실행되는 시점에 'm[2]'가 참조하는 메모리 위치에서 로드된 // vec2<f32> 값을 산출한다. let p_m_col2 : vec2< f32> = m [ 2 ]; var A : array< i32, 5 > ; // 'A[4]'를 평가할 때 // 1. 먼저 'A'를 평가하여 'A' 변수의 메모리에 대한 참조를 산출한다. // 결과의 타입은 ref<function,array<i32,5>,read_write>이다. // 2. 그런 다음 '[4]' 배열 인덱스 구문을 적용하여 이전 단계의 참조 값이 // 참조하는 배열의 다섯 번째 요소 메모리에 대한 참조를 산출한다. // 결과 값의 타입은 ref<function,i32,read_write>이다. // let 선언은 우변의 타입이 i32일 것을 요구한다. // 다른 타입 규칙을 적용할 수 없으므로 로드 규칙이 적용되며, 초기화 값의 평가는 // 선언이 실행되는 시점에 'A[4]'가 참조하는 메모리 위치에서 로드된 // i32 값을 산출한다. let A_4_value : i32= A [ 4 ]; // 'person.weight'를 평가할 때 // 1. 먼저 'person'을 평가하여 모듈 범위에 선언된 'person' 변수의 // 메모리에 대한 참조를 산출한다. // 결과의 타입은 ref<private,S,read_write>이다. // 2. 그런 다음 '.weight' 멤버 접근 구문을 적용하여 이전 단계의 참조 값이 // 참조하는 메모리의 두 번째 멤버에 대한 참조를 산출한다. // 결과의 타입은 ref<private,f32,read_write>이다. // let 선언은 우변의 타입이 f32일 것을 요구한다. // 다른 타입 규칙을 적용할 수 없으므로 로드 규칙이 적용되며, 초기화 값의 평가는 // 선언이 실행되는 시점에 'person.weight'가 참조하는 메모리 위치에서 로드된 // f32 값을 산출한다. let person_weight : f32= person . weight ; // 또는 동일한 구문을 사용하여 포인터에서도 참조를 구성할 수 있다. let uv_ptr = & uv ; // 이 함수 본문의 나머지 부분에서 'uv_ptr'은 'uv'의 기반 메모리에 대한 // 포인터를 나타내며 타입은 ptr<function,vec2<f32>,read_write>이다. // 할당의 좌변을 평가한다: // '*uv_ptr'을 평가하여 참조를 산출한다: // 1. 먼저 'uv_ptr'을 평가하여 'uv' 변수의 메모리에 대한 포인터를 산출한다. // 결과의 타입은 ptr<function,vec2<f32>,read_write>이다. // 2. 그런 다음 간접 참조 식 연산자를 적용하여 'uv'의 메모리에 대한 // 참조를 산출한다. // 할당의 우변을 평가하면 vec2<f32> 값 (1.0, 2.0)이 산출된다. // uv가 참조하는 storage 메모리 위치에 값 (1.0, 2.0)을 저장한다. * uv_ptr = vec2f( 1.0 , 2.0 ); // 할당의 좌변을 평가한다: // 'uv_ptr.x'를 평가하여 참조를 산출한다: // 1. 먼저 'uv_ptr'을 평가하여 'uv' 변수의 메모리에 대한 포인터를 산출한다. // 결과의 타입은 ptr<function,vec2<f32>,read_write>이다. // 2. 그런 다음 '.x' 벡터 접근 구문을 적용하여 이전 단계의 참조 값이 // 가리키는 벡터의 첫 번째 성분 메모리에 대한 참조를 산출한다. // 결과의 타입은 ref<function,f32,read_write>이다. // 할당의 우변을 평가하면 f32 값 1.0이 산출된다. // uv.x가 참조하는 storage 메모리 위치에 f32 값 1.0을 저장한다. uv_ptr . x = 1.0 ; // 할당의 좌변을 평가한다: // 'uv_ptr[1]'을 평가하여 참조를 산출한다: // 1. 먼저 'uv_ptr'을 평가하여 'uv' 변수의 메모리에 대한 포인터를 산출한다. // 결과의 타입은 ptr<function,vec2<f32>,read_write>이다. // 2. 그런 다음 '[1]' 배열 인덱스 구문을 적용하여 이전 단계에서 참조한 // 벡터의 두 번째 성분 메모리에 대한 참조를 산출한다. // 결과의 타입은 ref<function,f32,read_write>이다. // 할당의 우변을 평가하면 f32 값 2.0이 산출된다. // uv[1]이 참조하는 storage 메모리 위치에 f32 값 2.0을 저장한다. uv_ptr [ 1 ] = 2.0 ; let m_ptr = & m ; // 'm_ptr[2]'를 평가할 때: // 1. 먼저 'm_ptr'을 평가하여 'm' 변수의 메모리에 대한 포인터를 산출한다. // 결과의 타입은 ptr<function,mat3x2<f32>,read_write>이다. // 2. 그런 다음 '[2]' 배열 인덱스 구문을 적용하여 이전 단계의 참조 값이 // 가리키는 세 번째 열 벡터의 메모리에 대한 참조를 산출한다. // 따라서 'm[2]' 식의 타입은 ref<function,vec2<f32>,read_write>이다. // 'let' 선언은 타입 vec2<f32>에 대한 것이므로 선언 문은 초기화 값의 타입이 // vec2<f32>일 것을 요구한다. // 다른 타입 규칙을 적용할 수 없으므로 로드 규칙이 적용되며, 초기화 값의 평가는 // 선언이 실행되는 시점에 'm[2]'가 참조하는 메모리 위치에서 로드된 // vec2<f32> 값을 산출한다. let p_m_col2 : vec2< f32> = m_ptr [ 2 ]; let A_ptr = & A ; // 'A[4]'를 평가할 때 // 1. 먼저 'A'를 평가하여 'A' 변수의 메모리에 대한 포인터를 산출한다. // 결과의 타입은 ptr<function,array<i32,5>,read_write>이다. // 2. 그런 다음 '[4]' 배열 인덱스 구문을 적용하여 이전 단계의 참조 값이 // 참조하는 배열의 다섯 번째 요소 메모리에 대한 참조를 산출한다. // 결과 값의 타입은 ref<function,i32,read_write>이다. // let 선언은 우변의 타입이 i32일 것을 요구한다. // 다른 타입 규칙을 적용할 수 없으므로 로드 규칙이 적용되며, 초기화 값의 평가는 // 선언이 실행되는 시점에 'A[4]'가 참조하는 메모리 위치에서 로드된 // i32 값을 산출한다. let A_4_value : i32= A_ptr [ 4 ]; let person_ptr = & person ; // 'person.weight'를 평가할 때 // 1. 먼저 'person_ptr'을 평가하여 모듈 범위에 선언된 'person' 변수의 // 메모리에 대한 포인터를 산출한다. // 결과의 타입은 ptr<private,S,read_write>이다. // 2. 그런 다음 '.weight' 멤버 접근 구문을 적용하여 이전 단계의 참조 값이 // 참조하는 메모리의 두 번째 멤버에 대한 참조를 산출한다. // 결과의 타입은 ref<private,f32,read_write>이다. // let 선언은 우변의 타입이 f32일 것을 요구한다. // 다른 타입 규칙을 적용할 수 없으므로 로드 규칙이 적용되며, 초기화 값의 평가는 // 선언이 실행되는 시점에 'person.weight'가 참조하는 메모리 위치에서 로드된 // f32 값을 산출한다. let person_weight : f32= person_ptr . weight ; }
포인터 값은 다음 방법 중 하나로 구성된다.
-
참조에 주소 가져오기 연산자(단항
&)를 사용한다. -
함수 형식 매개변수가 포인터 타입이면, 런타임에 함수를 호출할 때 형식 매개변수의 사용은 호출 함수의 호출 지점에서 대응하는 피연산자에 제공된 포인터 값을 나타낸다.
-
bufferView 또는 bufferArrayView 내장 함수 호출의 결과이다.
모든 경우에 결과의 접근 모드는 원래 포인터의 접근 모드와 같다.
// 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의 참조와 포인터는 다른 언어보다 더 많은 제한을 받는다. 특히 다음과 같다.
-
WGSL에서는 변수 또는 형식 매개변수로 참조를 다른 참조나 변수의 별칭으로 직접 선언할 수 없다.
-
WGSL에서 포인터와 참조는 저장 가능하지 않다. 즉, WGSL 변수 선언의 내용에는 포인터나 참조가 포함될 수 없다.
-
WGSL에서 함수는 포인터나 참조를 반환해서는 안 된다.
-
WGSL에는 정숫값과 포인터 값을 서로 변환하는 방법이 없다.
-
WGSL에는 포인터 값의 타입을 다른 포인터 타입으로 강제로 변경하는 방법이 없다.
-
복합 성분 참조 식은 다르다. 이 식은 복합 값에 대한 참조를 받아 복합 값 내부의 성분이나 요소 중 하나에 대한 참조를 산출한다. 구현 추상화의 더 낮은 수준에서는 동일한 머신 주소를 가질 수 있지만, WGSL에서는 서로 다른 참조로 간주된다.
-
-
WGSL에는 참조 값의 타입을 다른 참조 타입으로 강제로 변경하는 방법이 없다.
-
WGSL에는 포인터나 참조의 접근 모드를 변경하는 방법이 없다.
-
이와 비교하여 C++는 const가 아닌 포인터를 const 포인터로 자동 변환하며, const 값을 const가 아닌 값으로 변환하는
const_cast를 제공한다.
-
-
WGSL에는 "힙"에서 새 메모리를 할당하는 방법이 없다.
-
WGSL에는 변수를 명시적으로 파괴하는 방법이 없다. WGSL 변수의 메모리는 해당 변수가 범위를 벗어날 때만 접근할 수 없게 된다.
참고: 위 규칙에 따라 "댕글링" 포인터, 즉 "활성" 기원 변수의 메모리를 참조하지 않는 포인터를 구성할 수 없다. 메모리 뷰는 유효하지 않은 메모리 참조일 수 있지만, 기원 변수나 버퍼와 연결되지 않은 메모리 위치에 절대로 접근하지 않는다.
6.6. 텍스처 및 샘플러 타입
텍셀은 텍스처에서 독립적으로 접근할 수 있는 가장 작은 요소로 사용되는 스칼라 또는 벡터이다. 텍셀이라는 단어는 텍스처 요소의 줄임말이다.
텍스처는 렌더링에 유용한 특수 연산을 지원하는 텍셀의 모음이다. WGSL에서는 텍스처 내장 함수를 통해 이러한 연산을 호출한다. 전체 목록은 § 17.7 텍스처 내장 함수를 참조한다.
WGSL 텍스처는 WebGPU GPUTexture에
대응한다.
텍스처에는 다음 특성이 있다.
- 텍셀 형식
-
각 텍셀의 데이터 표현이다. § 6.6.1 텍셀 형식을 참조한다.
- 차원 수
-
격자 좌표의 차원 수와 좌표가 해석되는 방식이다. 차원 수는 1, 2 또는 3이다. 대부분의 텍스처는 데카르트 좌표를 사용한다. 큐브 텍스처는 여섯 개의 정사각형 면을 가지며, 원점에서 원점을 중심으로 하는 큐브를 향하는 방향 벡터로 해석되는 3차원 좌표를 사용하여 샘플링된다.
GPUTextureViewDimension을 참조한다. - 크기
-
각 차원을 따라 이어지는 격자 좌표의 범위이다. 이는 밉 레벨의 함수이다.
- 밉 레벨 수
-
밉 레벨 수는 샘플링 텍스처와 깊이 텍스처에서는 1 이상이며, 스토리지 텍스처에서는 1이다.
밉 레벨 0에는 전체 크기 버전의 텍스처가 포함된다. 이후의 각 밉 레벨에는 이전 밉 레벨 크기의 절반인 이전 밉 레벨의 필터링된 버전이 포함된다. 이때 반올림이 적용될 수 있다.
텍스처를 샘플링할 때는 명시적으로 지정하거나 암시적으로 계산한 세부 수준을 사용하여 텍셀 데이터를 읽을 밉 레벨을 선택한다. 그런 다음 필터링을 통해 이들을 결합하여 샘플링된 값을 생성한다. - 배열형
-
텍스처가 배열형인지 여부이다.
-
배열형이 아닌 텍스처는 텍셀 격자이다.
-
배열형 텍스처는 동종 텍셀 격자의 배열이다.
-
- 배열 크기
-
텍스처가 배열형인 경우 동종 격자의 수이다.
- 샘플 수
-
텍스처가 다중 샘플링되는 경우 샘플의 수이다.
텍스처의 각 텍셀에는 다음을 포함하는 정수 튜플인 고유한 논리적 텍셀 주소가 연결된다.
텍스처의 물리적 구성은 일반적으로 렌더링 연산에 맞게 최적화된다. 이를 위해 데이터 레이아웃, 데이터 타입 및 셰이더 언어로 직접 표현할 수 없는 내부 연산을 비롯한 많은 세부 사항이 프로그래머에게 숨겨진다.
따라서 셰이더는 텍스처 변수 내의 텍셀 메모리에 직접 접근할 수 없다. 대신 불투명 핸들을 통해 접근한다.
-
셰이더 내부에서는 다음과 같다.
-
WebGPU 파이프라인을 구성할 때 텍스처 변수의 저장소 타입과 바인딩은 대응하는 바인드 그룹 레이아웃 항목과 호환되어야 한다.
이와 같이 텍스처 타입에서 지원되는 연산 집합은 해당 텍스처 타입의 형식 매개변수를 가진 텍스처 내장 함수의 가용성에 따라 결정된다.
참고: 텍스처 변수가 저장하는 핸들은 셰이더에서 변경할 수 없다. 즉, 접근을 제공하는 기반 텍스처가 변경 가능하더라도 이 변수는 읽기 전용이다. 예를 들면 쓰기 전용 스토리지 텍스처가 있다.
텍스처 타입은 다음 절에서 정의되는 타입 집합이다.
샘플러는 샘플링 텍스처 또는 깊이 텍스처에서 텍셀에 접근하는 방식을 제어하는 불투명 핸들이다.
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 스토리지 텍스처 타입에서 정의하는
스토리지 텍스처 타입을
매개변수화하는 데 사용된다.
텍셀 형식에 네 개의 채널이 모두 포함되지 않은 경우 다음이 적용된다.
-
-
텍셀 형식에 초록색 채널이 없으면 셰이더 값의 두 번째 성분은 0이다.
-
텍셀 형식에 파란색 채널이 없으면 셰이더 값의 세 번째 성분은 0이다.
-
텍셀 형식에 알파 채널이 없으면 셰이더 값의 네 번째 성분은 1이다.
-
-
텍셀을 쓸 때 역채널 전달 함수가 성분별로 적용되며, 존재하지 않는 채널에 대한 셰이더 값 성분은 무시된다.
아래 표의 마지막 열은 채널 형식 표에 있는 형식별 채널 전달 함수를 사용한다.
| 텍셀 형식 | 채널 형식 | 메모리 순서의 채널 | 대응하는 셰이더 값 | 필요한 언어 확장 |
|---|---|---|---|---|
| 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
| 예 |
-
T는 샘플링 타입이다.
-
이미지의 매개변수화된 타입은 샘플링 변환 후의 타입이다. 예를 들어 8비트 unorm 성분의 텍셀을 가진 이미지가 있을 수 있지만, 이를 샘플링하면 32비트 부동 소수점 결과 또는 f32 벡터를 얻는다.
6.6.3. 다중 샘플링 텍스처 타입
다중 샘플링 텍스처는 1 이상의 샘플 수를 가진다. 이름과 달리 샘플러와 함께 사용할 수 없다. 샘플 인덱스를 무시하면 각 논리적 텍셀 주소에 여러 텍셀에 해당하는 데이터를 실질적으로 저장한다.
텍셀 형식은 텍스처 변수에 바인딩된
GPUTexture의
format
특성이다.
WebGPU는 텍스처, 바인드 그룹 레이아웃의 sampleType
및 텍스처 변수의 샘플링 타입 사이의 호환성을 검증한다.
texture_multisampled_2d는 샘플링 타입으로 매개변수화되며,
이 타입은 f32, i32 또는 u32여야
한다.
| 타입 | 차원 수 | 배열형 |
|---|---|---|
| texture_multisampled_2d<T> | 2D
| 아니요 |
| texture_depth_multisampled_2d | 2D
| 아니요 |
-
T는 샘플링 타입이다.
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
| 아니요 |
-
Format은 스토리지 텍스처의 텍셀 형식 중 하나에 대한 열거자여야 한다.
-
Format과 Access의 조합이 유효하지 않다는 이유로 셰이더 생성 오류가 발생하지는 않는다. Format과 Access의 조합은 파이프라인 생성 중 셰이더 바인딩 검증 단계에서 검사된다. 유효하지 않은 조합은 파이프라인 생성 오류를 일으킨다.
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의 멤버에 이어진다.
참고: 별칭이 지정되는 타입이 값 생성자 내장 함수를 지원하면, 타입 별칭이 범위 내에 있고 해당 함수를 호출하는 것이 다른 측면에서도 유효한 경우 원래 타입 지정자 이름 대신 별칭 이름을 통해 해당 함수를 호출할 수 있다.
'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 타입 식을 참조한다.
참고: 식도 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 ;
각 선언에는 명시적으로 지정한 타입 또는 초기화 값이 있어야 한다. 타입과 초기화 값을 모두 지정할 수도 있다. 각 선언은 연결된 데이터 값의 타입을 결정하며, 이를 선언의 유효 값 타입이라고 한다. 선언의 유효 값 타입은 다음과 같다.
-
타입을 명시적으로 지정한 경우 선언된 타입.
-
그렇지 않고 초기화 식의 타입이
T인 경우:-
const선언에서는 유효 값 타입이T자체이다. -
override,let또는var선언에서는 유효 값 타입이T의 구체화이다.
-
각 종류의 값 또는 변수 선언은 초기화 식이 있는 경우 그 형식과 유효 값 타입에 추가 제약을 적용할 수 있다.
| 선언 | 가변성 | 범위 | 유효 값 타입1 | 초기화 값 지원 | 초기화 식2 | 리소스 인터페이스의 일부 |
|---|---|---|---|---|---|---|
| const | 불변 | 모듈 또는 함수 | 생성 가능(구체 또는 추상) | 필수 | 상수 식 | 아니요 |
| override | 불변 | 모듈 | 구체 스칼라 | 선택 사항3 | 상수 식 또는 오버라이드 식 | 아니요4 |
| let | 불변 | 함수 | 구체 생성 가능 타입 또는 포인터 타입. 또한 texture_and_sampler_let 기능이 지원되면 텍스처 또는 샘플러 타입. | 필수 | 상수 식, 오버라이드 식 또는 런타임 식 | 아니요 |
|
var<storage, read> var<storage> | 불변 | 모듈 | 구체 호스트 공유 가능 | 허용되지 않음 | 예. 스토리지 버퍼 | |
| var<storage, read_write>5,6 | 가변 | 모듈 | 구체 호스트 공유 가능 | 허용되지 않음 | 예. 스토리지 버퍼 | |
| var<uniform> | 불변 | 모듈 | 구체 생성 가능 호스트 공유 가능 타입 또는 고정 크기 버퍼 | 허용되지 않음 | 예. 유니폼 버퍼 | |
| var<immediate> | 불변 | 모듈 | 배열 및 배열 멤버를 포함하는 구조체를 제외한 구체 생성 가능 호스트 공유 가능 타입 | 허용되지 않음 | 예. 즉시 데이터 | |
| var5 | 불변7 | 모듈 | 텍스처 | 허용되지 않음 | 예. 텍스처 리소스 | |
| var | 불변 | 모듈 | 샘플러 | 허용되지 않음 | 예. 샘플러 리소스 | |
| var<workgroup>6,8 | 가변 | 모듈 | 고정 풋프린트를 가진 구체 일반 타입 또는 고정 크기 버퍼9 | 허용되지 않음10 | 아니요 | |
| var<private> | 가변 | 모듈 | 구체 생성 가능 | 선택 사항10 | 상수 식 또는 오버라이드 식 | 아니요 |
| var<function> var | 가변 | 함수 | 구체 생성 가능 | 선택 사항10 | 상수 식, 오버라이드 식 또는 런타임 식 | 아니요 |
-
식의 타입을 유효 값 타입으로 실현 가능하게 변환할 수 있어야 한다.
-
초기화 값을 지정하지 않으면 파이프라인 생성 시점에 값을 제공해야 한다.
-
오버라이드 선언은 셰이더 인터페이스의 일부지만 바인딩된 리소스는 아니다.
-
read 이외의 접근 모드를 가진 스토리지 버퍼 및 스토리지 텍스처에는 버텍스 셰이더 단계에서 정적으로 접근할 수 없다. WebGPU
createBindGroupLayout()을 참조한다. -
원자 타입은 가변 스토리지 버퍼 또는 작업 그룹 변수에만 나타날 수 있다.
-
write 또는 read_write 접근 모드를 가진 스토리지 텍스처의 데이터는 변경할 수 있지만, textureStore 내장 함수를 통해서만 수정할 수 있다. 변수 자체는 수정할 수 없다.
-
workgroup 주소 공간의 변수에는 컴퓨트 셰이더 단계에서만 정적으로 접근할 수 있다.
-
초기화 값이 없으면 변수를 기본 초기화한다.
7.1. 변수와 값 비교
변수 선언은 WGSL 모듈에서 유일한 가변 데이터이다. 값 선언은 항상 불변이다. 변수에는 연결된 메모리 위치가 있으므로 참조 및 포인터 값의 기초가 될 수 있지만, 값 선언은 포인터나 참조 값의 기초가 될 수 없다.
변수를 사용하려면 변수에 연결된 메모리 위치를 읽거나 쓰기 위한 추가 연산이 필요하므로, 일반적으로 값 선언을 사용하는 것보다 비용이 더 많이 든다.
일반적으로 작성자는 가장 선호되는 선택지가 먼저 나열된 다음 순서로 선언을 사용하는 것이 좋다.
일반적으로 이렇게 하면 셰이더의 전체 성능이 가장 좋아진다.
7.2. 값 선언
식별자가 값 선언으로 해석되면 해당 식별자는 그 값을 나타낸다.
WGSL은 여러 종류의 값 선언을 제공한다. 각 선언 종류의 값은 셰이더 수명 주기의 서로 다른 시점에 확정된다. 값 선언의 종류와 해당 값이 확정되는 시점은 다음과 같다.
참고: 형식 매개변수는 § 11 함수에 설명되어 있다.
7.2.1. const 선언
const 선언은 셰이더 생성 시점에 확정되는 데이터 값의 이름을 지정한다. 각 const 선언에는 초기화 값이 필요하다. const 선언은 모듈 또는 함수 범위에서 선언할 수 있다. 초기화 식은 상수 식이어야 한다. const 선언의 타입은 구체 또는 추상 생성 가능 타입이어야 한다. const 선언은 유효 값 타입이 추상일 수 있는 유일한 선언이다.
참고: 추상 숫자 타입은 WGSL에서 표기할 수 없으므로 타입 추론을 통해서만 사용할 수 있다.
const a = 4 ; // 값이 4인 AbstractInt. const b : i32= 4 ; // 값이 4인 i32. const c : u32= 4 ; // 값이 4인 u32. const d : f32= 4 ; // 값이 4인 f32. const e = vec3( a , a , a ); // 값이 (4, 4, 4)인 AbstractInt의 vec3. const f = 2.0 ; // 값이 2인 AbstractFloat. const g = mat2x2( a , f , a , f ); // 다음 값을 가진 AbstractFloat의 mat2x2: // ((4.0, 2.0), (4.0, 2.0)). // AbstractInt a는 AbstractFloat로 변환된다. // AbstractFloat는 AbstractInt로 변환될 수 없다. const h = array( a , f , a , f ); // 네 개의 성분으로 구성된 AbstractFloat 배열: // (4.0, 2.0, 4.0, 2.0).
7.2.2. override 선언
오버라이드 선언은 파이프라인 오버라이드 가능 상숫값의 이름을 지정한다. 오버라이드 선언은 모듈 범위에서만 선언되어야 한다. 파이프라인 오버라이드 가능 상수의 값은 파이프라인 생성 시점에 확정된다. 값이 지정되면 WebGPU 파이프라인 생성 메서드에서 제공한 값을 사용하고, 그렇지 않으면 구체화된 초기화 식의 값을 사용한다. 오버라이드 선언의 유효 값 타입은 구체 스칼라 타입이어야 한다.
초기화 식은 선택 사항이다. 초기화 식이 있으면 오버라이드 식이어야 하며, 파이프라인 오버라이드 가능 상수의 기본값을 나타낸다. 초기화 값을 지정하지 않았고 파이프라인 생성 시점에도 값을 제공하지 않으면 파이프라인 생성 오류이다.
선언에 id 특성이 적용되면 리터럴 피연산자를 파이프라인 상수 ID라고 하며, 이 값은 0 이상 65535 이하의 고유한 정수여야 한다. 즉, 두 오버라이드 선언이 동일한 파이프라인 상수 ID를 사용해서는 안 된다.
애플리케이션은 파이프라인 생성 시점에 오버라이드 선언의 값을 직접 지정할 수 있다. 파이프라인 생성 API는 오버라이드 가능한 상수에서 해당 상수 타입의 값으로 이어지는 매핑을 받는다. 상수는 파이프라인 오버라이드 가능 상수 식별자 문자열로 식별된다. 이 문자열은 파이프라인 상수 ID가 지정된 경우 파이프라인 상수 ID의 10진수 표현이고, 그렇지 않으면 선언된 상수의 이름이다.
@id ( 0 ) override has_point_light : bool= true ; // 알고리즘 제어 @id ( 1200 ) override specular_param : f32= 2.3 ; // 숫자 제어 @id ( 1300 ) override gain : f32; // 반드시 오버라이드해야 함 override width : f32= 0.0 ; // API 수준에서 "width"라는 // 이름을 사용하여 지정한다. override depth : f32; // API 수준에서 "depth"라는 // 이름을 사용하여 지정한다. // 반드시 오버라이드해야 한다. override height = 2 * depth ; // 기본값은 API 수준에서 // 설정되지 않은 경우 다른 // 오버라이드 가능한 상수에 // 따라 달라진다.
7.2.3. let 선언
let 선언은 런타임에 해당 문이 실행될 때마다 확정되는 값의 이름을 지정한다. let 선언은 함수 범위에서만 선언되어야 하며, 따라서 동적 컨텍스트이다. let 선언에는 초기화 식이 있어야 한다. 값은 초기화 값의 구체화된 값이다. let 선언의 유효 값 타입은 구체 생성 가능 타입 또는 포인터 타입 중 하나여야 한다. texture_and_sampler_let 기능이 지원되면 유효 값 타입이 텍스처 또는 샘플러 타입일 수도 있다.
참고: 버퍼 타입은 생성 가능하지 않으므로 버퍼의 포인터만 let 선언이 될 수 있다.
// '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>이다.
변수의 저장소 타입은 항상 구체 타입이다.
변수 선언은 다음을 수행한다.
-
변수의 이름을 지정한다.
-
변수의 주소 공간, 저장소 타입 및 접근 모드를 결정한다. 이들은 함께 변수의 참조 타입을 구성한다.
-
저장소 타입은 변수 선언의 유효 값 타입이다.
-
-
실행 환경이 변수의 수명 동안 지정된 주소 공간에 주어진 접근 모드를 지원하는 저장소 타입 값의 메모리를 할당하도록 보장한다.
-
변수가 private 또는 function 주소 공간에 있으면 선택적으로 초기화 식을 가질 수 있다. 초기화 식이 있으면 변수의 저장소 타입으로 평가되어야 한다. private 변수의 초기화 식이 있으면 상수 식 또는 오버라이드 식이어야 한다. function 또는 private 이외의 주소 공간에 있는 변수에는 초기화 값이 있어서는 안 된다.
식별자가 변수 선언으로 해석되면, 해당 식별자는 변수 메모리의 참조 메모리 뷰를 나타내는 식이며 타입은 변수의 참조 타입이다. § 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 구성으로 제한된다.
텍스처 리소스는 유효 값 타입이 텍스처 타입인 변수이다. 모듈 범위에서 선언된다. 텍스처의 기반 텍셀 격자에 접근하는 데 사용되는 불투명 핸들을 보유한다. 핸들 자체는 handle 주소 공간에 있으며 항상 읽기 전용이다. 많은 경우 기반 텍셀은 읽기 전용이며 이때 텍스처 변수가 불변이라고 한다. 쓰기 전용 스토리지 텍스처와 읽기-쓰기 스토리지 텍스처에서는 기반 텍셀을 변경할 수 있으며, 관례적으로 텍스처 변수가 가변이라고 한다.
샘플러 리소스는 유효 값 타입이 샘플러 타입인 변수이다. 모듈 범위에서 선언되며 handle 주소 공간에 존재하고 불변이다.
§ 13.3.2 리소스 인터페이스에 설명된 것처럼 유니폼 버퍼, 스토리지 버퍼, 텍스처 및 샘플러는 셰이더의 리소스 인터페이스를 구성한다.
변수의 수명은 셰이더 실행 중 메모리 위치가 변수와 연결되는 기간이다. 모듈 범위 변수의 수명은 셰이더 단계 실행 전체이다. 각 호출에는 private 및 function 주소 공간의 독립적인 변수 버전이 있다. 함수 범위 변수는 동적 컨텍스트이다. 함수 범위 변수의 수명은 해당 범위에 따라 결정된다.
-
제어 흐름이 변수 선언에 진입할 때 시작된다.
-
이름이 동적 컨텍스트의 어떤 부분에서도 더 이상 범위 내에 있지 않을 때 끝난다. 즉, 수명에는 이름이 범위 내에 있는 동안 호출된 모든 함수가 포함된다.
두 리소스 변수의 메모리 위치가 겹칠 수 있지만, 두 변수 중 하나라도 가변이면 동적 오류이다. 수명이 겹치는 다른 변수의 메모리 위치는 서로 겹치지 않는다. 변수의 수명이 끝나면 해당 메모리를 다른 변수에 사용할 수 있다.
참고: WGSL은 변수의 내용을 해당 변수의 수명 동안에만 관찰할 수 있도록 보장한다.
private, function 또는 workgroup 주소 공간의 변수가 생성되면 초깃값을 가진다. 초기화 값을 지정하지 않으면 초깃값은 기본 초깃값이다. 초깃값은 다음과 같이 계산된다.
-
function 주소 공간의 변수:
-
private 주소 공간의 변수:
-
그렇지 않으면 구체화된 초기화 식을 평가한 결과. 초기화 식은 오버라이드 식이어야 하므로 해당 값은 늦어도 파이프라인 생성 시점에 확정된다.
-
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 코드 조각을 살펴보자.
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_decl '=' expression
| 'let' optionally_typed_ident '=' expression
| 'const' optionally_typed_ident '=' expression
'var' _disambiguate_template template_list ? optionally_typed_ident
ident ( ':' type_specifier ) ?
attribute * variable_decl ( '=' expression ) ?
'const' optionally_typed_ident '=' expression
| attribute * 'override' optionally_typed_ident ( '=' expression ) ?
8. 식
식은 값이 계산되는 방식을 지정한다.
다양한 종류의 값 식은 평가되는 시점과 표현할 수 있는 범위 사이의 절충을 제공한다. 평가가 빠를수록 연산에 더 많은 제약이 있지만, 그 값을 사용할 수 있는 위치는 더 많아진다. 이러한 절충으로 인해 각 값 선언 종류마다 서로 다른 유연성이 생긴다. 상수 식과 오버라이드 식은 GPU에서 실행되기 전에 평가되므로 최종 GPU 코드에는 식을 계산한 결과만 필요하다. 또한 상수 식은 셰이더 생성 시점에 평가되므로 오버라이드 식보다 더 많은 상황에서 사용할 수 있다. 예를 들어 함수 범위 변수의 배열 크기를 정하는 데 사용할 수 있다. 런타임 식은 상수 식도 오버라이드 식도 아닌 식이다. 런타임 식은 셰이더 실행 중 GPU에서 계산된다. 런타임 식을 사용할 수 있는 문법 요소는 더 적지만, 다른 런타임 값과 같이 더 폭넓은 종류의 식으로부터 계산할 수 있다.
8.1. 조기 평가 식
WGSL은 런타임 전에 평가할 수 있는 두 종류의 식을 정의한다.
8.1.1. const 식
셰이더 생성 시점에 평가할 수 있는 식을 상수 식이라고 한다. 식의 모든 식별자가 다음 중 하나로 해석되면 그 식은 상수 식이다.
const 식의 타입은 생성 시 고정된 풋프린트를 갖는 타입으로
해석되어야 한다.
참고: 추상 타입은 상수 식의 추론된 타입이 될 수 있다.
상수 식 E는 다음 중 하나에 해당하는 경우에만 평가된다.
-
E가 최상위 식인 경우,
-
E가 식 OuterE의 부분식이고, OuterE가 평가되며, OuterE의 평가에 E의 평가가 필요한 경우,
-
E가 식 OuterE의 부분식이고, OuterE가 셰이더 생성 오류를 발생시키기 위해 E의 평가를 요구하는 경우 (예: 정수 나눗셈).
참고: 이 평가 규칙은 단락 평가 연산자
&&와 ||가 정적 타입을 결정하기 위해 평가해야 하는
부분식이 없는 한 오른쪽 부분식의 평가를 차단한다는
것을 뜻한다.
상수 식은 WebGPU API 메서드를 구현하는 CPU에서 평가될 수 있다. 따라서 AbstractFloat 값에 대한 연산의 정확도 요구 사항은 WebAssembly [WASM-CORE-2] 및 ECMAScript [ECMASCRIPT]와 같은 일반적인 WebGPU 런타임 환경에서 요구되는 것보다 더 엄격하지 않다. 구체 부동 소수점 타입(예: f32)에 대한 정확도 요구 사항은 § 15.7.4.1 구체 부동 소수점 식의 정확도에 명시되어 있다.
예: (42)는 다음과 같이 분석된다.
-
항
42는 AbstractInt 값 42이다. -
이 항을 괄호로 둘러싸면 타입이 AbstractInt이고 값이 42인 새 식
(42)가 생성된다.
예: -5는 다음과 같이 분석된다.
-
항
5는 AbstractInt 값 5이다. -
이 항 앞에 '
-'를 붙이면 타입이 AbstractInt이고 값이 -5인 새 식-5가 생성된다.
예: -2147483648은 다음과 같이 분석된다.
-
항
2147483648은 AbstractInt 값 2147483648이다. 이 값은 32비트 부호 있는 정수에 들어맞지 않는다. -
이 항 앞에 '
-'를 붙이면 타입이 AbstractInt이고 값이 -2147483648인 새 식-2147483648이 생성된다.
예: const minint = -2147483648;은 다음과 같이 분석된다.
-
위와 같이
-2147483648은 AbstractInt 값 -2147483648로 평가된다. -
그 결과
minint는 AbstractInt 값 -2147483648로 선언된다.
예: let minint = -2147483648;은 다음과 같이 분석된다.
-
위와 같이
-2147483648은 AbstractInt 값 -2147483648로 평가된다. -
let 선언에는 명시적 타입이 없으므로 오버로드 해석이 사용된다. 적용 가능한 오버로드 후보는 AbstractInt에서 i32, u32 또는 f32로의 실행 가능한 자동 변환을 사용한다. 가장 낮은 순위의 변환은 i32로의 변환이므로, AbstractInt 값 -2147483648은 i32 값 -2147483648로 변환된다.
-
그 결과
minint는 i32 값 -2147483648로 선언된다.
예: false && (10i < i32(5 * 1000 * 1000 * 1000))은 다음과 같이 분석된다.
-
전체 식은 상수 식이다.
-
하지만
&&연산자의 단락 평가 규칙이 적용된다. 왼쪽은false로 평가되므로 오른쪽은 평가되지 않는다. -
i32(5 * 1000 * 1000 * 1000)을 평가했다면 AbstractInt 값 5000000000이 i32 타입을 오버플로하므로 셰이더 생성 오류가 발생했을 것이다.
예: false && array<u32, 1 + 2>(0, 1, 2)[0] == 0
-
전체 식은 상수 식이다.
-
타입 검사에는
e1 : bool && e2 : bool이 필요하다.-
false는 bool 값이다. -
타입 검사는 오른쪽에서 계속 진행되며, 결국 배열 요소 개수 식의
1 + 2를 평가한다.
-
-
1 + 2는 i32 값3으로 평가된다.-
배열의 타입은
array<u32, 3i>이다.
-
-
배열 접근 식과 동등 연산자는 모두 평가되지 않는다.
8.1.2. override 식
파이프라인 생성 시점에 평가할 수 있는 식을 오버라이드 식이라고 한다. 식의 모든 식별자가 다음 중 하나로 해석되면 그 식은 오버라이드 식이다.
참고: 모든 상수 식은 오버라이드 식이기도 하다.
상수 식이 아닌 오버라이드 식은 파이프라인 생성 중에만, 그리고 API가 제공한 값을 오버라이드 선언에 대입한 후에만 검증되거나 평가된다. 오버라이드 선언의 값이 API를 통해 대입되면, 이니셜라이저 식이 있더라도 평가되지 않는다. 그렇지 않으면 오버라이드 식 E는 다음 조건을 모두 만족하는 경우에만 평가된다.
-
E가
GPUProgrammableStage에 지정된 진입점의 셰이더 일부를 구성하고, -
다음 중 하나가 참인 경우:
참고: 모든 오버라이드 식을 오버라이드 선언의 이니셜라이저로 사용할 수 있는 것은 아니다. 이러한 이니셜라이저는 구체 스칼라 타입으로 해석되어야 하기 때문이다.
예: override x = 42;는 다음과 같이 분석된다.
-
항
42는 AbstractInt 값 42이다. -
42는 실행 가능한 자동 변환을 통해 i32로 변환된다.
예: let y = x + 1;은 다음과 같이 분석된다.
예: vec3(x,x,x)는 다음과 같이 분석된다.
-
vec3(x,x,x)의 유일한 식별자가 오버라이드 선언으로 해석되므로 이 식은 오버라이드 식이다.
override a : i32= 0 ; override b = a / 0 ; // c 오버라이드를 시도하는지와 관계없이 // 셰이더 생성 오류
override a : i32= 0 ; override b = 1 / a ; // b는 frag1 셰이더의 일부이다. frag1을 파이프라인으로 컴파일할 때 // 다음과 같은 경우가 발생할 수 있다. // * b가 오버라이드되면 오류가 발생하지 않는다. // * a가 0이 아닌 값으로 오버라이드되면 오류가 발생하지 않는다. // * a가 0이고 b가 오버라이드되지 않으면 파이프라인 생성 오류가 발생한다. @fragment fn frag1 () { _ = b ; } // b는 frag2 셰이더의 일부가 아니다. frag2를 파이프라인으로 컴파일할 때는 // b가 오버라이드되지 않고 a의 값이 0이어도 오류가 발생하지 않는다. @fragment fn frag2 () { }
8.2. 미정 값
제한적인 경우에 런타임 식은 그 부분식에 지원되지 않는 값을 사용하여 평가될 수 있다.
그러한 경우 평가 결과는 식의 정적 타입에 속하는 미정 값이다. 즉, 구현이 임의로 선택한 정적 타입의 값이다.
식이 평가되는 각각의 고유한 동적 컨텍스트마다 별개의 값이 생성될 수 있다. 예를 들어 루프의 각 반복에서 평가가 한 번씩 일어나면 반복마다 서로 다른 값이 계산될 수 있다.
참고: 타입이 부동 소수점 타입이고 구현이 NaN 값을 지원한다면 런타임에 생성되는 미정 값은 NaN 값일 수 있다.
fn fun () { var extracted_values : array< i32, 2 > ; const v = vec2< i32> ( 0 , 1 ); for ( var i : i32= 0 ; i < 2 ; i ++ ) { // 벡터를 인덱싱하는 데 사용된 런타임 식이 벡터의 // 인덱싱 범위를 벗어나면 벡터 컴포넌트 타입의 // 미정 값이 생성된다. let extract = v [ i + 5 ]; // 이제 'extract'는 i32 타입의 임의의 값이다. // 나중을 위해 저장한다. extracted_values [ i ] = extract ; if extract == extract { // 항상 실행된다 } if extract < 2 { // 실행될 수도 있고 실행되지 않을 수도 있다. // 원래 벡터 컴포넌트가 0과 1이더라도 // 추출된 값은 이 두 값 중 어느 것도 아닐 수 있다. } } if extracted_values [ 0 ] == extracted_values [ 1 ] { // 실행될 수도 있고 실행되지 않을 수도 있다. } } fn float_fun ( runtime_index : u32) { const v = vec2< f32> ( 0 , 1 ); // 부동 소수점 값의 벡터 // 앞의 예와 마찬가지로 'float_extract'는 미정 값이다. // 부동 소수점 타입이므로 NaN일 수 있다. let float_extract : f32= v [ runtime_index + 5 ]; if float_extract == float_extract { // 다음 이유로 실행되지 *않을 수도* 있다. // - 'float_extract'가 NaN일 수 있고, // - NaN은 다른 어떤 부동 소수점 숫자와도 같지 않으며, // 다른 NaN과도 같지 않다. } }
8.3. 리터럴 값 식
| 전제 조건 | 결론 | 설명 |
|---|---|---|
true: bool
| true 불리언 값.
| |
false: bool
| false 불리언 값.
| |
| e는 접미사가 없는 정수 리터럴 | e: AbstractInt | 추상 정수 리터럴 값. |
| e는 접미사가 없는 부동 소수점 리터럴 | e: AbstractFloat | 추상 부동 소수점 리터럴 값. |
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)를 쓰고 그 뒤에 컴포넌트의 이름을 쓴다. - 인덱싱 식
-
베이스에 대한 식 뒤에
'['(U+005B), 인덱스에 대한 식,']'(U+005D)을 차례로 쓴다.
참고: 스위즐 뷰는 인덱싱 식을 직접 지원하지 않는다. 스위즐 뷰 뒤에 인덱싱 식 절이 나타나면 먼저 스위즐 뷰 로드 규칙을 적용하여 벡터 값을 생성한 다음, 그 벡터 값에 인덱싱 식을 적용한다.
구문상 이 두 형식은 component_or_swizzle_specifier 문법 규칙을 사용하여 구현된다.
-
베이스가 행렬 또는 행렬에 대한 메모리 뷰이면 N은 행렬 타입의 열 개수이다.
-
베이스가 고정 크기 배열 또는 고정 크기 배열에 대한 메모리 뷰이면 N은 고정 크기 배열 타입의 요소 개수이다.
인덱스 값이 범위 내 인덱스가 아니면 범위를 벗어난 인덱스이다. 범위를 벗어난 인덱스는 대개 프로그래밍 결함이며 흔히 오류를 일으킨다. 자세한 내용은 아래를 참조한다.
또한 벡터 타입은 다른 벡터의 컴포넌트로부터 새 벡터 값을 생성하는 스위즐 구문을 지원한다.
8.5.1. 벡터 접근 식
벡터의 컴포넌트에는 다음 방법 중 하나로 접근할 수 있다.
-
배열 첨자 사용(예:
v[2]), 또는 -
스위즐 이름 사용. 스위즐 이름은 편의 이름의 시퀀스로 작성되는 컨텍스트 종속 이름이며, 각 편의 이름은 원본 벡터의 컴포넌트에 대응한다.
-
색상 편의 이름 집합: 벡터 컴포넌트 0, 1, 2, 3에 각각 대응하는
r,g,b,a. -
차원 편의 이름 집합: 벡터 컴포넌트 0, 1, 2, 3에 각각 대응하는
x,y,z,w.
-
편의 이름에는 . 표기법을 사용하여 접근한다(예: 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: Te .r: T
|
e의 첫 번째 컴포넌트를 선택한다.
이는 단일 문자 스위즐이다. |
| e: vecN<T> |
e.y: Te .g: T
|
e의 두 번째 컴포넌트를 선택한다.
이는 단일 문자 스위즐이다. |
| e: vecN<T> N은 3 또는 4 |
e.z: Te .b: T
|
e의 세 번째 컴포넌트를 선택한다.
이는 단일 문자 스위즐이다. |
| e: vec4<T> |
e.w: Te .a: T
|
e의 네 번째 컴포넌트를 선택한다.
이는 단일 문자 스위즐이다. |
| e: vecN<T> i: i32 또는 u32 T는 구체 | e[i]: T |
벡터의 i번째 컴포넌트를 선택한다. 첫 번째 컴포넌트의 인덱스는 i=0이다. i가 범위 [0,N-1] 밖에 있는 경우:
|
| e: vecN<T> i: i32 또는 u32 T는 추상 i는 상수 식 | e[i]: T |
벡터의 i번째 컴포넌트를 선택한다. 첫 번째 컴포넌트의 인덱스는 i=0이다. i가 범위 [0,N-1] 밖에 있으면 셰이더 생성 오류이다. |
8.5.1.2. 벡터 다중 컴포넌트 선택
이 절의 식은 내부 식에 다중 문자 스위즐을 적용한다.
-
내부 식이 벡터이면 결과는 벡터이다. 아래 표를 참조한다.
-
내부 식이 벡터 저장소 타입을 갖는 포인터 또는 참조이면:
-
swizzle_assignment 언어 확장이 지원되지 않으면 결과는 벡터이다. 아래 표를 참조한다.
-
swizzle_assignment 언어 확장이 지원되면 대신 § 8.6 스위즐 뷰 식을 참조한다.
-
참고: swizzle_assignment 언어 확장이 지원되지 않으면 다중 문자 스위즐은 할당의 왼쪽에 나타날 수 없다. 할당의 왼쪽은 참조 타입이어야 하지만, 확장이 없으면 다중 문자 스위즐 식은 항상 벡터 타입의 값을 생성하기 때문이다.
| 전제 조건 | 결론 | 설명 |
|---|---|---|
|
e: vecN<T> I는 문자 x, y, z 또는 wJ는 문자 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 또는 aJ는 문자 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 또는 wJ는 문자 x, y, z 또는 wK는 문자 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 또는 aJ는 문자 r, g, b 또는 aK는 문자 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 또는 wJ는 문자 x, y, z 또는 wK는 문자 x, y, z 또는 wL는 문자 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 또는 aJ는 문자 r, g, b 또는 aK는 문자 r, g, b 또는 aL는 문자 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>> |
pr.IJ: vec2<T> |
평가 시점에 pr가 참조하는 메모리 위치에 저장된 벡터를 e라고 할 때,
e.IJ를 계산한다.
문자 |
|
swizzle_assignment가 지원되지 않음
pr: ref<AS,vecN<T,AM>> 또는
ptr<AS,vecN<T,AM>> |
pr.IJ: vec2<T> |
평가 시점에 pr가 참조하는 메모리 위치에 저장된 벡터를 e라고 할 때,
e.IJ를 계산한다.
문자 |
|
swizzle_assignment가 지원되지 않음
pr: ref<AS,vecN<T,AM>> 또는
ptr<AS,vecN<T,AM>> |
pr.IJK: vec3<T> |
평가 시점에 pr가 참조하는 메모리 위치에 저장된 벡터를 e라고 할 때,
e.IJK를 계산한다.
문자 |
|
swizzle_assignment가 지원되지 않음
pr: ref<AS,vecN<T,AM>> 또는
ptr<AS,vecN<T,AM>> |
pr.IJK: vec3<T> |
평가 시점에 pr가 참조하는 메모리 위치에 저장된 벡터를 e라고 할 때,
e.IJK를 계산한다.
문자 |
|
swizzle_assignment가 지원되지 않음
pr: ref<AS,vecN<T,AM>> 또는
ptr<AS,vecN<T,AM>> |
pr.IJKL:
vec4<T> |
평가 시점에 pr가 참조하는 메모리 위치에 저장된 벡터를 e라고 할 때,
e.IJKL을 계산한다.
문자 |
|
swizzle_assignment가 지원되지 않음
pr: ref<AS,vecN<T,AM>> 또는
ptr<AS,vecN<T,AM>> |
pr.IJKL:
vec4<T> |
평가 시점에 pr가 참조하는 메모리 위치에 저장된 벡터를 e라고 할 때,
e.IJKL을 계산한다.
문자 |
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는 상수 식 | e[i]: vecR<T> |
결과는 e의 i번째 열 벡터이다.
i가 범위 [0,C-1] 밖에 있으면 셰이더 생성 오류이다. |
| 전제 조건 | 결론 | 설명 |
|---|---|---|
|
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는 상수 식 | e[i] : T |
결과는 배열 값 e의 i번째 요소 값이다.
i가 범위 [0,N-1] 밖에 있으면 셰이더 생성 오류이다. |
| 전제 조건 | 결론 | 설명 |
|---|---|---|
|
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은 타입이 T인 S 멤버의 식별자 이름 e: S | e.M: T | 결과는 구조체 값 e에서 이름이 M인 멤버의 값이다. |
| 전제 조건 | 결론 | 설명 |
|---|---|---|
|
S는 구조체 타입 M은 타입이 T인 S 멤버의 식별자 이름 r: ref<AS,S,AM> 또는 ptr<AS,S,AM> | r.M: ref<AS,T,AM> | 구조체에 대한 메모리 뷰가 주어지면 결과는 식별자 이름이
M인 구조체 멤버에 대한 참조이다. 결과 참조의 기원 변수는 r의 기원 변수와 같다. |
8.6. 스위즐 뷰 식
스위즐 뷰 식은 swizzle_assignment 언어 확장으로 활성화된다.
스위즐 뷰는 다음과 같이 구성된다.
이러한 규칙에 따라 스위즐 뷰의 인덱스 목록 부분은 셰이더 생성 시점에 완전히 결정된다.
이 절에서는 스위즐 인덱스 함수 SI를 다음과 같이 정의한다.
-
SI(
x) = 0 -
SI(
y) = 1 -
SI(
z) = 2 -
SI(
w) = 3 -
SI(
r) = 0 -
SI(
g) = 1 -
SI(
b) = 2 -
SI(
a) = 3
다음 조건을 만족하면 스위즐 이름 Z는 K개의 인덱스 « Idx0, ..., IdxK−1 »를 나타낸다고 한다.
-
다음 중 하나가 참이다.
-
Z의 각 문자는
x,y,z또는w이다. 또는 -
Z의 각 문자는
r,g,b또는a이다.
-
-
각 Idxi는 SI(L)과 같다. 여기서 L은 Z의 i번째 문자이다.
참고: 예를 들어 스위즐 wzyx는
네 인덱스 «3, 2, 1, 0»을 나타내고, 스위즐 rb는 두 인덱스 «0, 2»를 나타낸다.
스위즐 rgbz는 rgba 문자와 xyzw 문자를 혼합하므로
어떤 인덱스 시퀀스도 나타내지 않는다.
| 전제 조건 | 결론 | 설명 |
|---|---|---|
|
swizzle_assignment가 지원됨
r: ref<AS,T,read_write> | r.Z : swizzle<AS,S,N,K> |
결과는 스위즐
뷰(&r, I)이다.
I의 각 인덱스는 N보다 작아야 한다. r이 유효하지 않은 메모리 참조이면 결과는 유효하지 않은 스위즐 뷰이다. |
| 전제 조건 | 결론 | 설명 |
|---|---|---|
|
swizzle_assignment가 지원됨 pointer_composite_access가 지원됨 p: ptr<AS,T,read_write> | 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을 다음 시퀀스라고 하자. 식의 결과는 스위즐 뷰(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)의 집합이다.
|
| e1 : T e2 : T S는 AbstractInt, AbstractFloat, i32, u32, f32 또는 f16 T는 S 또는 vecN<S> | e1 / e2 : T
|
나눗셈. T가 벡터이면 컴포넌트별로 적용된다.
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가 부호 있는 정수 스칼라 타입이면 e1과 e2를 한 번씩 평가하고 다음과 같이 평가된다.
참고: 0이 아닐 때 결과는 e1과 같은 부호를 갖는다. 참고: 일관된 동작을 보장해야 하므로 구현은 부호 없는 나머지를 계산할 때보다 더 많은 연산을 수행해야 할 수 있다. T가 부호 없는 정수 스칼라 타입이면 다음과 같이 평가된다.
T가 부동 소수점 타입이면 결과는 다음과 같다. T가 부동 소수점 타입이면 스칼라 정의역은 다음을 제외한 확장 실수의 모든 순서쌍 (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의 비트 너비로 나눈 나머지이다.
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가 부호 있는 타입인 경우:
시프트할 비트 수는 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. 값 선언의 식별자 식
| 전제 조건 | 결론 | 설명 |
|---|---|---|
| c는 타입이 T인 const 선언으로 해석되는 범위 내 식별자 | c: T | 결과는 이니셜라이저 식에 대해 계산된 값이다. 이 식은 상수 식이며 셰이더 생성 시점에 평가된다. |
| c는 타입이 T인 오버라이드 선언으로 해석되는 범위 내 식별자 | c: T |
파이프라인 생성에서 상수 ID의 값을 지정했다면
결과는 그 값이다.
이 값은 파이프라인 인스턴스마다 다를 수 있다.
그렇지 않으면 결과는 이니셜라이저 식에 대해 계산된 값이다. 파이프라인 오버라이드 가능 상수는 모듈 범위에 나타나므로 셰이더가 실행을 시작하기 전에 평가된다. 참고: API 호출에 초깃값이 지정되지 않았고
|
| 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 | tg _template_args_start e1, ..., eN _template_args_end : AllTypes |
각 타입 생성기에는 요구하고
허용하는 템플릿 매개변수에 대한
고유한 요구 사항이 있으며, 템플릿 매개변수가 결과 타입을 결정하는 방식을 정의한다.
e1부터 eN까지의 식은 타입 생성기의 템플릿 매개변수이다. 예를 들어 타입 식 미리 선언된 타입 생성기의 목록은 § 6.10 미리 선언된 타입 및 타입 생성기 요약을 참조한다. 참고: 여기의 두 변형은 eN 뒤에 후행 쉼표가 있는지 여부만 다르다. |
| tg _template_args_start e1, ..., eN, _template_args_end : AllTypes |
8.19. 식 문법 요약
식별자가 call_phrase의 첫 번째 토큰이면 다음 중 하나이다.
선언 및 범위 규칙은 이러한 이름이 항상 서로 다르도록 보장한다.
expression ( ',' expression ) * ',' ?
'[' expression ']' component_or_swizzle_specifier ?
| multiplicative_expression multiplicative_operator unary_expression
| additive_expression additive_operator multiplicative_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
binary_and_expression '&' unary_expression
| short_circuit_or_expression '||'
relational_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개 이상의 문의 시퀀스입니다. 선언이 이러한 문 중 하나인 경우, 그 식별자는 다음 문의 시작부터 복합문의 끝까지 범위 안에 있습니다.
continuing_compound_statement는 continuing 문의 본문을 구성하고 끝에 선택적 break-if 문을 허용하는 특수한 형태의 복합문입니다.
9.2. 할당문
할당은 식을 평가하고, 선택적으로 결과를 메모리에 저장합니다(따라서 변수의 내용을 갱신합니다).
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의 각 인덱스가 [0,N-1]에 속하도록 보장합니다. 다음 단계를 수행합니다.
참고: 스위즐 뷰가 유효하지 않은 스위즐 뷰인 경우 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 중 하나인 경우 복합 할당입니다.
각 문의 타입 요구 사항, 의미론 및 동작은 다음 표와 같이 복합 할당을 확장한 것처럼 정의되지만, 다음 사항은 예외입니다.
-
식 e1이 참조 식인 경우:
-
e1의 참조 타입은 read_write 접근 모드를 반드시 가져야 합니다.
-
다음 단계를 수행합니다.
-
&e1을 평가하여 포인터 p를 산출합니다.
-
p가 참조하는 메모리를 읽어 값 old_contents를 산출합니다.
아래에 제시된 확장에서 old_contents를 e1의 값으로 사용합니다.
-
e2를 평가합니다.
-
old_contents와 e2에 지정된 이항 연산을 수행하여 update를 계산합니다.
-
예를 들어 복합 할당이
v += w이면 지정된 연산은 덧셈입니다.
-
-
포인터 p를 통해 update를 메모리에 씁니다.
-
-
-
식 e1이 스위즐 뷰 식인 경우:
-
관례상 스위즐 뷰 e1은 (p, IndexList)로 쓸 수 있습니다.
-
참고: p의 타입은 read_write 접근 모드를 가집니다.
-
-
스위즐 할당과 동일한 제약 조건이 적용됩니다.
-
IndexList의 인덱스는 반드시 모두 서로 달라야 합니다.
-
참고: 스위즐 뷰 식 규칙은 IndexList의 각 인덱스가 [0,N-1]에 속하도록 보장합니다.
-
-
다음 단계를 수행합니다.
-
p를 평가합니다.
-
SwizzleViewRead(p, IndexList)를 수행하여 vecK<S> 타입의 벡터 viewed_contents를 산출합니다.
이 값은 아래에 제시된 확장에서 이항 연산자의 왼쪽 피연산자로 사용되는 e1의 값입니다. 이항 식의 왼쪽에서 오른쪽으로의 평가를 보장하려면, 이 단계는 e2를 평가하기 전에 수행되어야 합니다.
-
e2를 평가합니다.
-
p가 참조하는 메모리를 읽어 vecN<S> 타입의 벡터 old_contents를 산출합니다.
-
viewed_contents와 e2에 지정된 이항 연산을 수행하여 update를 계산합니다.
-
예를 들어 스위즐 할당이
v.xy += w이면 지정된 연산은 덧셈입니다.
-
-
SwizzleViewWrite(p, IndexList, old_contents, update)를 수행합니다.
-
-
| 문 | 확장 |
|---|---|
| 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가 들어 있습니다. }
var < private> v : array< vec4u, 1 > ; fn update_and_index () -> u32{ v [ 0 ] += vec4u( 2 , 4 , 8 , 10 ); return 0 ; } fn update_and_rhs () -> vec2u{ v [ 0 ]. x = 900 ; v [ 0 ]. z = 100 ; return vec2u( 55 , 66 ); } fn eval_order_compound_swizzle_assignment () { v [ 0 ] = vec4u( 0 , 0 , 0 , 0 ); // 1. 포인터 p를 평가합니다. 이 과정에서 // 좌변의 인덱스를 평가하고, // 부수 효과로 v[0] = vec4u(2,4,8,10)을 설정하며 // 인덱스로 0을 산출합니다. // 2. 스위즐 이름은 .yx이므로 IndexList는 목록 1,0입니다. // SwizzleViewRead(p,IndexList)를 수행하여 // view_contents = vec2u(4,2)를 산출합니다. // 3. 우변을 평가하여 // v[0].x = 900 // v[0].z = 100 // 을 설정하고 vec2u(55,66)을 산출합니다. // 4. 다음과 같이 갱신 벡터를 계산합니다. // view_contents + vec2u(55,66) // = vec2u(4,2) + vec2u(55,66) // = vec2u(59,68) // 5. 그런 다음 스위즐 할당은 v[0].x와 v[0].y만 갱신하고, // v[0].z와 v[0].w를 보존합니다. v [ update_and_index ()]. yx += update_and_rhs (); // 이제 v[0]은 vec4u(68,59,100,10)과 같습니다. }
e1+=e2;
는 다음과 같이 다시 작성할 수 있습니다.
여기서 식별자{ let p = &(e1); *p = *p + (e2); }
p는 프로그램의 다른 모든 식별자와 다르게 선택합니다.
ev다음과 같이 다시 작성할 수 있습니다.[c] +=e2;
여기서 식별자{ let p = &(ev); let c0 =c; (*p)[c0] = (*p)[c0] + (e2); }
c0와 p는 프로그램의 다른 모든 식별자와 다르게 선택합니다.
9.3. 증가문과 감소문
증가문은 변수의 내용에 1을 더합니다. 감소문은 변수의 내용에서 1을 뺍니다.
식은 구체 정수 스칼라 저장소 타입과 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)과 동일 |
9.4. 제어 흐름
제어 흐름 문은 프로그램이 비순차적 순서로 실행되게 할 수 있습니다.
9.4.1. If 문
if 문은 조건 식의 평가에 따라 최대 하나의 복합문을 조건부로 실행합니다.
if 문에는 if 절이 있고, 그 뒤에 0개 이상의 else if 절과
선택적 else 절이 이어집니다.
'else' 'if' expression compound_statement
'else' compound_statement
타입 규칙 전제
조건:
각 if와 else if 절의 식은 bool 타입이어야 합니다.
if 문은 다음과 같이 실행됩니다.
-
if절에 연결된 조건을 평가합니다. 결과가true이면 제어가 첫 번째 복합문(조건 식 바로 뒤)으로 이동합니다. -
그렇지 않으면 텍스트 순서상 다음
else if절의 조건(존재하는 경우)을 평가하고, 결과가true이면 제어가 연결된 복합문으로 이동합니다.-
조건 중 하나가
true로 평가될 때까지 모든else if절에 대해 이 동작을 반복합니다.
-
-
어떤 조건도
true로 평가되지 않으면 제어가else절에 연결된 복합문(존재하는 경우)으로 이동합니다.
9.4.2. Switch 문
switch 문은 선택자 식의 평가에 따라 case 절 집합 중 하나 또는 default 절로 제어를 이동합니다.
attribute * 'switch' expression switch_body
attribute * '{' switch_clause + '}'
'case' case_selectors ':' ? compound_statement
'default' ':' ? compound_statement
case_selector ( ',' case_selector ) * ',' ?
'default'
case 절은
'case' 토큰 뒤에 쉼표로
구분된
case 선택자 목록과
복합문 형태의 본문이 이어지는
것입니다.
독립 default
절은 'default' 토큰 뒤에 복합문 형태의 본문이 이어지는 것입니다.
default 절은 다음 중 하나입니다.
각 switch 문에는 정확히 하나의 default 절이 반드시 있어야 합니다.
'default'
토큰은 하나의
case_selector
목록에 두 번 이상 나타나서는
안 됩니다.
타입 규칙 전제 조건: 하나의 switch 문에서 선택자 식과 모든 case 선택자 식은 동일한 구체 정수 스칼라 타입이어야 합니다.
case_selectors의 식은 상수 식이어야 합니다.
동일한 switch 문에 있는 서로 다른 두 case 선택자 식은 같은 값을 가져서는 안 됩니다.
선택자 값이 case_selector 목록에 있는 식의 값과 같으면 제어가 해당 case 절의 본문으로 이동합니다. 선택자 값이 어느 case 선택자 값과도 같지 않으면 제어가 default 절의 본문으로 이동합니다.
제어가 절 본문의 끝에 도달하면 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 ; } }
const c = 2 ; var a : i32; let x : i32= generateValue (); switch x { case 0 : { a = 1 ; } case 1 , c { // case 선택자에 상수 식을 사용할 수 있습니다. a = 3 ; } case 3 , default { // default 키워드를 다른 절과 함께 사용할 수 있습니다. a = 4 ; } }
9.4.3. Loop 문
loop 문은 루프 본문을 반복 실행합니다. 루프 본문은 복합문으로 지정됩니다. 루프 본문의 각 실행을 반복이라고 합니다.
이 반복은 break 또는 return 문으로 중단할 수 있습니다.
선택적으로 루프 본문의 마지막 문은 continuing 문일 수 있습니다.
loop가 무한한 수의 반복을 실행하게 되는 경우 동적 오류가 발생합니다. 이로 인해 루프가 조기에 종료되거나, 다른 비지역적 효과가 발생하거나, 심지어 기기 손실이 발생할 수도 있습니다.
루프 본문의 문 중 하나가 선언인 경우, 복합문 내부 선언의 일반적인 범위 및 수명 규칙을 따릅니다. 즉, 루프 본문은 문의 시퀀스이며 그중 하나가 선언이면 해당 선언의 범위는 시퀀스에서 다음 문의 시작부터 루프 본문의 끝까지 이어집니다. 선언은 도달할 때마다 실행되므로 각각의 새로운 반복은 변수 또는 값의 새 인스턴스를 생성하고 다시 초기화합니다.
참고: loop 문은 특수한 구문이므로
일반적으로는 for 또는 while 문을 사용하는 것이 좋습니다.
loop 문은 다른 셰이더 언어와의 가장 큰 차이점 중 하나입니다.
이 설계는 컴파일된 코드에서 흔히 볼 수 있는 루프 관용구를 직접 표현합니다. 특히 루프 갱신문을 루프 본문의 끝에 배치하면 루프 본문에 정의된 값을 자연스럽게 사용할 수 있습니다.
-
<1> 초기화는 루프 앞에 나열됩니다.
var a : i32= 2 ; let step : i32= 1 ; for ( var i : i32= 0 ; i < 4 ; i += step ) { if ( i % 2 == 0 ) { continue ; } a *= 2 ; }
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 ; }
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 ; } }
-
<2> continue 구문은
loop의 끝에 배치됩니다.
9.4.4. For 문
attribute * 'for' '(' for_header ')' compound_statement
for_init ? ';' expression ? ';' for_update ?
for 문은 loop 문을 포함하는
복합문을 위한 구문 설탕입니다.
일반적으로 for 문은 다음 형식을 취합니다.
for (initializer;condition;update_part) {body}
조건 식이 있는 경우 for 문은 다음 형태의 루프로 역당화됩니다.
{조건 식이 없는 경우
initializer ;
loop {
if !(condition) { break; }
body
continuing { update_part }
}
}
for 문은 다음 형태의 루프로 역당화됩니다.
{
initializer ;
loop {
body
continuing { update_part }
}
}
추가로:
-
initializer가 비어 있지 않으면 첫 번째 반복 전에 추가 범위 안에서 실행됩니다. 초기화 구문에 있는 선언의 범위는 루프 본문의 끝까지 이어집니다. -
타입 규칙 전제 조건: 조건이 비어 있지 않으면 bool 타입의 식이어야 합니다.
-
조건이 있으면 for 루프 본문을 실행하기 직전에 평가됩니다. 조건이 false이면 § 9.4.6 Break 문이 실행되어 루프 실행이 끝납니다. 이 검사는 각 루프 반복의 시작에서 수행됩니다.
-
-
update_part가 비어 있지 않으면 루프 구문의 끝에서 continuing 문이 됩니다. -
역당화는
update_part의 모든 식별자가 역당화 전과 동일한 선언으로 계속 해석되도록 필요에 따라body에 선언된 식별자의 이름을 바꿀 것입니다.
for 루프의 initializer는 루프를 실행하기 전에 한 번 실행됩니다.
선언이 초기화 구문에
나타나는 경우 그 식별자는 body의
끝까지
범위 안에 있습니다.
body의 선언과 달리 이 선언은 각 반복에서 다시 초기화되지 않습니다.
condition, body, update_part는 이 순서로 실행되어
하나의 루프 반복을 형성합니다.
body는 특수한 형태의 복합문입니다.
body에 있는 선언의 식별자는 다음 문의 시작부터 body의 끝까지
범위 안에 있습니다.
선언은 도달할 때마다 실행되므로 각각의 새로운 반복은 변수 또는 상수의 새 인스턴스를 생성하고
다시 초기화합니다.
var a : i32= 2 ; for ( var i : i32= 0 ; i < 4 ; i ++ ) { if a == 0 { continue ; } a = a + 2 ; }
다음으로 변환됩니다.
var a : i32= 2 ; { // 루프 변수 i를 위한 새 범위를 도입합니다. var i : i32= 0 ; loop { if ! ( i < 4 ) { break ; } if a == 0 { continue ; } a = a + 2 ; continuing { i ++ ; } } }
var a : i32= 2 ; for ( var i : i32= 0 ; ; i ++ ) { if a == 0 { continue ; } if i == 4 { break ; } a = a + 2 ; }
다음으로 변환됩니다.
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 문
attribute * 'while' expression compound_statement
while 문은 조건으로 매개변수화된 루프의 한 종류입니다. 각 루프 반복의 시작에서 불리언 조건을 평가합니다. 조건이 false이면 while 루프의 실행이 끝납니다. 그렇지 않으면 반복의 나머지 부분을 실행합니다.
타입 규칙 전제 조건: 조건은 bool 타입이어야 합니다.
while 루프는 loop 또는 for 문을 위한 구문 설탕으로 볼 수 있습니다. 다음 문 형식은 동등합니다.
-
whilecondition{body_statements} -
loop { if !condition{break;}body_statements} -
for (;condition;) {body_statements}
while 루프가 무한한 수의 반복을 실행하게 되는 경우 동적 오류가 발생합니다. 이로 인해 루프가 조기에 종료되거나, 다른 비지역적 효과가 발생하거나, 심지어 기기 손실이 발생할 수도 있습니다.
9.4.6. Break 문
'break'
break 문은 가장 가까이 둘러싸는 루프 또는 switch 문의 본문 바로 뒤로 제어를 이동하여 루프 또는 switch 문의 실행을 끝냅니다.
break 문은 loop,
for, while 및 switch 문 안에서만
반드시 사용해야
합니다.
break 문은 루프의 continuing 문에서 빠져나가게 되는
위치에 배치해서는 안
됩니다.
대신 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 ; if i >= 4 { break ; } // 유효하지 않습니다. 대신 break-if를 사용하십시오. } }
9.4.7. Break-If 문
'break' 'if' expression ';'
break-if 문은 불리언 조건을 평가합니다. 조건이 true이면 제어가 가장 가까이 둘러싸는 loop 문의 본문 바로 뒤로 이동하여 해당 루프의 실행을 끝냅니다.
타입 규칙 전제 조건: 조건은 bool 타입이어야 합니다.
참고: break-if 문은 continuing 문 본문의 마지막 문으로만 나타날 수 있습니다.
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'
continue 문은 가장 가까이 둘러싸는 loop 안에서 다음과 같이 제어를 이동합니다.
-
해당 루프 본문 끝에 continuing 문이 있으면 그 문으로 전방 이동합니다.
-
그렇지 않으면 루프 본문의 첫 번째 문으로 후방 이동하여 다음 반복을 시작합니다.
continue 문은 loop, for 또는 while 문 안에서만
반드시 사용해야
합니다.
continue 문은 제어를 둘러싸는 continuing 문으로
이동하게 되는 위치에 배치해서는 안 됩니다.
(continuing 문으로 분기할 때는 전방 분기입니다.)
continue 문은 대상 continuing 문에서 사용하는 선언을 지나 제어를
이동하게 되는 위치에 배치해서는 안 됩니다.
참고: continue는
continuing 문 안에 중첩된 다른 루프 내부에서 제어 흐름을 이동하는 데 사용되는 경우에만
continuing 문 안에서 사용할 수 있습니다. 즉, continue는 현재 실행 중인
continuing 문의 시작으로 제어를 이동하는 데 사용할 수 없습니다.
var i : i32= 0 ; loop { if i >= 4 { break ; } if i % 2 == 0 { continue ; } // <3> let step : i32= 2 ; continuing { i = i + step ; } }
-
<3>
continue는continuing구문에서 사용하는step의 선언을 우회하므로 유효하지 않습니다.
9.4.9. Continuing 문
'continuing' continuing_compound_statement
continuing 문은 루프 반복의 끝에서 실행할 복합문을 지정합니다. 이 구문은 선택 사항입니다.
복합문은 어느 복합문 중첩 수준에서도 return을 포함해서는 안 됩니다.
9.4.10. Return 문
'return' expression ?
return 문은 현재 함수의 실행을 끝냅니다. 함수가 진입점이면 현재 셰이더 호출이 종료됩니다. 그렇지 않으면 현재 함수 호출의 호출 지점 평가 뒤에 오는 다음 식 또는 문부터 평가가 계속됩니다.
함수에 반환 타입이 없으면 return 문은 선택 사항입니다. 이러한 함수에 return 문이 제공된 경우 값을 제공해서는 안 됩니다. 그렇지 않으면 식이 반드시 있어야 하며, 이를 반환 값이라고 합니다. 이 경우 이 함수 호출의 호출 지점은 반환 값으로 평가됩니다. 반환 값의 타입은 함수의 반환 타입과 반드시 일치해야 합니다.
9.4.11. Discard 문
discard 문은 호출을
보조 호출로 변환하고 프래그먼트 출력을
버립니다.
discard 문은 프래그먼트 셰이더
스테이지에서만
반드시 사용해야
합니다.
더 정확히 말하면 discard 문을 실행하면 다음을 수행할
것입니다.
-
현재 호출을 보조 호출로 변환하고,
-
현재 프래그먼트 출력이 GPURenderPipeline의 이후 단계에서 처리되지 않도록 합니다.
discard 문보다 먼저 실행된 문만 관찰 가능한 효과를 가질
것입니다.
참고: discard 문은
프래그먼트
스테이지의 함수라면 어느 함수에서든
실행할 수 있으며 효과는 동일합니다.
프래그먼트 출력이 버려집니다.
@group ( 0 ) @binding ( 0 ) var < storage, read_write> will_emit_color : u32; fn discard_if_shallow ( pos : vec4< f32> ) { if pos . z < 0.001 { // 이것이 실행되면 보조 호출은 공유 메모리에 쓰지 않으므로 // will_emit_color 변수는 절대로 1로 설정되지 // 않습니다. discard ; } will_emit_color = 1 ; } @fragment fn main ( @builtin ( position) coord_in : vec4< f32> ) -> @location ( 0 ) vec4< f32> { discard_if_shallow ( coord_in ); // 보조 함수가 discard 문을 실행하지 않은 경우에만 // 값을 1로 설정하고 빨간색을 출력합니다. will_emit_color = 1 ; return vec4< f32> ( 1.0 , 0.0 , 0.0 , 1.0 ); }
9.5. 함수 호출문
함수 호출문은 함수 호출을 실행합니다.
호출된 함수에 must_use 특성이 있으면 셰이더 생성 오류가 발생합니다.
참고: 함수가 값을 반환하고 함수에 must_use 특성이 없으면 해당 값은 무시됩니다.
9.6. 문 문법 요약
statement 규칙은 함수 본문 내부의 대부분 위치에서 사용할 수 있는 문과 일치합니다.
또한 일부 문은 매우 특정한 문맥에서만 사용할 수 있습니다.
9.7. 문 동작 분석
9.7.1. 규칙
제어 흐름에 영향을 주는 일부 문은 특정 문맥에서만 유효합니다. 예를 들어 continue는 loop, for 또는 while 외부에서는 유효하지 않습니다. 또한 균일성 분석(§ 15.2 균일성 참조)은 제어 흐름이 여러 가지 방식으로 문을 빠져나갈 수 있는 때를 알아야 합니다.
두 목표 모두 문의 실행 동작을 요약하는 체계를 통해 달성됩니다. 동작 분석은 각 문을 해당 문의 평가가 완료된 후 실행이 진행될 수 있는 방식의 집합에 매핑합니다. 값과 식의 타입 분석과 마찬가지로 동작 분석은 상향식으로 진행됩니다. 먼저 특정 기본 문의 동작을 결정하고, 결합 규칙을 적용하여 상위 수준 구문의 동작을 결정합니다.
동작은 집합이며, 그 원소는 다음 중 하나일 수 있습니다.
-
Return
-
Break
-
Continue
-
Next
각 항목은 키워드를 통하거나 다음 문으로 자연스럽게 진행하는 방식("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 루프에 초기화문 또는 갱신문이 없을 때
발생합니다.
이 분석에서는 다음과 같이 처리합니다.
-
for루프를 역당화합니다(§ 9.4.4 For 문 참조). -
while루프를 역당화합니다(§ 9.4.5 While 문 참조). -
loop {s}를loop {s continuing {}}로 취급합니다. -
else분기가 없는if문은 빈 else 분기를 가진 것처럼, 즉else {}로 끝나는 것처럼 취급합니다. 이에 따라 해당 동작에 Next가 추가됩니다. -
else if분기가 있는if문은 단순한if/else문이 중첩된 것처럼 취급합니다. -
default로 시작하는 switch_clause는case _:로 시작하는 switch_clause와 똑같이 동작합니다.
각 내장 함수의 동작은 {Next}입니다. 또한 위 표에 나열되지 않은 각 연산자 적용은 동일한 피연산자를 사용하고 함수의 동작이 {Next}인 함수 호출과 동일한 동작을 가집니다.
함수의 동작은 위에 제시된 규칙을 충족해야 합니다.
참고: 위 규칙은 루프의 동작이 {Next}, {Return} 또는 {Next,Return}임을 뜻합니다.
참고: 식은 항상 {Next}이거나 이전에 분석한 함수에서 오류가 발생하므로 식의 동작을 분석할 필요가 없습니다.
9.7.2. 참고 사항
이 절은 정보 제공 목적이며 비규범적입니다.
동작 분석으로 인해 프로그램은 다음과 같은 방식으로 거부될 수 있습니다 (위의 요구 사항을 다시 기술함).
-
함수의 본문(일반적인 문으로 취급)의 동작이 {Next, Return}에 포함되지 않습니다.
-
반환 타입이 있는 함수 본문의 동작이 {Return}이 아닙니다.
-
continuing 블록의 동작에 Continue 또는 Return이 포함됩니다.
-
명백한 일부 무한 루프는 동작 집합이 비어 있으므로 유효하지 않습니다.
함수 호출의 동작은 함수의 코드에 따라 달라질 수 있으므로 호출 그래프를 상향식으로 분석하면 이 분석을 선형 시간에 실행할 수 있습니다.
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} }
fn if_example () { var a : i32= 0 ; loop { if a == 5 { break ; // 동작: {Break} } // 전체 if 복합문의 동작: {Break, Next}, // if에 암시적인 빈 else가 있기 때문입니다. a = a + 1 ; // 이전 문의 동작에 "Next"가 있으므로 유효합니다. } }
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} } }
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}
fn switch_example () { var a : i32= 0 ; switch a { default : { break ; // 동작: {Break} } } // switch가 Break를 Next로 바꾸므로 동작은 {Next}입니다. a = 5 ; // 이전 문의 동작에 Next가 있으므로 유효합니다. }
fn invalid_infinite_loop () { loop { discard ; // 동작 { Next }. } // 전체 루프의 동작이 { }이므로 유효하지 않습니다. }
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"로 바꾸기 때문입니다. }
fn redundant_continue_with_continuing () { var a : i32; loop { if a == 5 { break ; } continue ; // 유효합니다. 다음 문으로 분기하므로 중복입니다. continuing { a = a + 1 ; } } }
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"가 추가됩니다.
fn missing_return () -> i32{ var a : i32= 0 ; if a == 42 { return a ; // 동작: {Return} } // 동작: {Next, Return} } // 오류: 반환 타입이 있는 함수의 본문에서는 // Next가 유효하지 않습니다.
fn continue_out_of_loop () { var a : i32= 0 ; if a > 0 { continue ; // 동작: {Continue} } // 동작: {Next, Continue} } // 오류: 함수 본문에서는 Continue가 유효하지 않습니다.
continue를 break로 바꾸어도 동일한 이유로 유효하지 않습니다.
10. 단언
단언은 불리언 조건이 충족되는지 확인하는 검사입니다.
WGSL은 한 종류의 단언, 즉 상수 단언을 정의합니다.
'const_assert' expression
타입 규칙 전제 조건: 식은 bool 타입이어야 합니다.
10.1. 상수 단언문
상수 단언문은 식이 false로 평가되면
셰이더 생성 오류를
발생시키는
단언입니다.
식은 상수 식이어야 합니다.
이 문은 셰이더의 정적 접근
조건을 충족할 수 있지만
그 외에는 컴파일된 셰이더에 영향을 주지 않습니다.
상수 단언은 모듈 범위 또는 함수 범위 문으로 나타날 수 있습니다.
const x = 1 ; const y = 2 ; const_assert x < y ; // 모듈 범위에서 유효합니다. const_assert ( y != 0 ); // 괄호는 선택 사항입니다. fn foo () { const z = x + y - 2 ; const_assert z > 0 ; // 함수 안에서 유효합니다. let a = 3 ; const_assert a != 0 ; // 유효하지 않습니다. 식은 상수 식이어야 합니다. }
11. 함수
함수는 호출될 때 계산 작업을 수행합니다.
함수는 다음 방법 중 하나로 호출됩니다.
-
함수 호출 식을 평가하여 호출합니다. § 8.11 함수 호출 식을 참조하십시오.
-
함수 호출문을 실행하여 호출합니다. § 9.5 함수 호출문을 참조하십시오.
-
진입점 함수는 파이프라인의 셰이더 스테이지 작업을 수행하기 위해 WebGPU 구현에 의해 호출됩니다. § 13 진입점을 참조하십시오.
WGSL의 함수는 사용된 위치보다 소스에서 뒤에 정의되는 경우를 포함하여 어떤 순서로든 정의할 수 있습니다. 따라서 함수 프로토타입이나 전방 선언은 필요하지 않으며 이를 작성하는 방법도 없습니다.
함수에는 두 종류가 있습니다.
-
내장 함수는 WGSL 구현에서 제공하며 WGSL 모듈에서 항상 사용할 수 있습니다. § 17 내장 함수를 참조하십시오.
-
사용자 정의 함수는 WGSL 모듈에서 선언됩니다.
11.1. 사용자 정의 함수 선언
함수 선언은 다음을 지정하여 사용자 정의 함수를 생성합니다.
-
선택적인 특성 집합.
-
함수의 이름.
-
형식 매개변수 목록: 쉼표로 구분되고 괄호로 둘러싸인 0개 이상의 형식 매개변수 선언의 순서 있는 시퀀스.
-
함수가 진입점이면 매개변수에 특성을 적용하여 해당 매개변수를 셰이더 스테이지 입력으로 지정할 수 있습니다.
-
-
선택적인 반환 타입.
-
함수가 진입점이면 반환 타입에 특성을 적용하여 셰이더 스테이지 출력을 지정할 수 있습니다.
-
-
함수 본문. 함수가 호출될 때 실행되는 문 집합입니다.
함수 선언은 모듈 범위에서만 반드시 나타나야 합니다. 함수 이름은 프로그램 전체에서 범위 안에 있습니다.
참고: 각 사용자 정의 함수에는 하나의 오버로드만 있습니다.
형식 매개변수 선언은 함수를 호출할 때 반드시 제공해야 하는 값의 식별자 이름과 타입을 지정합니다. 진입점 함수의 형식 매개변수에는 특성을 적용할 수 있습니다. § 11.2 함수 호출을 참조하십시오. 식별자의 범위는 함수 본문입니다. 주어진 함수의 두 형식 매개변수는 같은 이름을 가져서는 안 됩니다.
참고: 일부 내장 함수는 매개변수에 추상 숫자 타입을 허용할 수 있습니다. 그러나 이 기능은 현재 사용자 선언 함수에서 지원되지 않습니다.
WGSL은 함수 선언에 적용할 수 있는 다음 특성을 정의합니다.
'fn' ident '(' param_list ? ')' ( '->' attribute * template_elaborated_ident ) ?
// 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. 함수 호출
함수 호출은 함수를 호출하는 문 또는 식입니다.
함수 호출을 포함하는 함수는 호출 함수 또는 호출자입니다. 호출되는 함수는 피호출 함수 또는 피호출자입니다.
함수 호출은 다음을 수행합니다.
-
피호출 함수의 이름을 지정하고,
-
괄호로 둘러싸이고 쉼표로 구분된 인수 값 식 목록을 제공합니다.
함수 호출은 피호출 함수에 있는 형식 매개변수와 동일한 수의 인수 값을 반드시 제공해야 합니다. 각 인수 값은 위치상 대응하는 형식 매개변수와 동일한 타입으로 반드시 평가되어야 합니다.
요약하면 함수를 호출할 때 다음이 수행됩니다.
피호출 함수는 다음과 같이 반환합니다.
구체적으로 함수 호출이 실행될 때 다음 단계가 발생합니다.
-
함수 호출의 인수 값을 평가합니다. 상대적인 평가 순서는 왼쪽에서 오른쪽입니다.
-
피호출 함수가 사용자 정의 함수이면 피호출 함수의 각 함수 범위 변수에 메모리를 할당합니다.
-
초기화는 § 7.3 var 선언에 설명된 대로 수행됩니다.
-
-
피호출 함수의 형식 매개변수 값은 함수 호출의 인수 값을 위치별로 대응시켜 결정합니다. 예를 들어 피호출 함수의 첫 번째 형식 매개변수에는 호출 지점에 있는 첫 번째 인수의 값이 지정됩니다.
-
제어가 피호출 함수로 이동합니다. 피호출 함수가 사용자 정의 함수이면 본문의 첫 번째 문부터 실행을 진행합니다.
-
피호출 함수는 반환할 때까지 실행됩니다.
-
제어가 호출 함수로 다시 이동하고 피호출 함수 실행의 일시 중단 상태가 해제됩니다. 피호출 함수가 값을 반환하면 해당 값이 함수 호출 식의 값으로 제공됩니다.
함수 호출의 위치를 호출 지점이라고 하며, 구체적으로는 파싱된 call_phrase 문법 규칙 인스턴스의 첫 번째 토큰 위치입니다. 호출 지점은 동적 문맥입니다. 따라서 동일한 텍스트 위치가 여러 호출 지점을 나타낼 수 있습니다.
참고: 쿼드의 모든 호출이 폐기되면 프래그먼트 셰이더의 함수 호출이 반환하지 않을 수 있습니다. 이 경우 제어는 호출 함수로 다시 이동하지 않습니다.
11.3. const 함수
const 특성으로 선언된 함수는 셰이더 생성 시점에 평가할 수 있습니다. 이러한 함수를 const 함수라고 합니다. 이러한 함수의 호출은 상수 식의 일부가 될 수 있습니다.
함수에 상수 식이 아닌 식이나 const 선언이 아닌 선언이 포함되어 있으면 셰이더 생성 오류입니다.
참고: const 특성은 사용자 선언 함수에 적용할 수 없습니다.
const first_one = firstLeadingBit ( 1234 + 4567 ); // 12로 평가됩니다. // firstLeadingBit는 AbstractInt에서 // 연산할 수 없으므로 first_one의 // 타입은 i32입니다. @id ( 1 ) override x : i32; override y = firstLeadingBit ( x ); // 상수 식은 오버라이드 식에서 // 사용할 수 있습니다. // 이 문맥에서 firstLeadingBit(x)는 // 상수 식이 아닙니다. fn foo () { var a : array< i32, firstLeadingBit ( 257 ) > ; // 모든 매개변수가 상수 식이면 // const 함수를 상수 식에서 // 사용할 수 있습니다. }
11.4. 함수에 대한 제한
-
-
생성 가능 타입
-
포인터 타입
-
텍스처 타입
-
샘플러 타입
-
-
각 함수 호출 인수는 대응하는 함수 매개변수의 타입으로 반드시 평가되어야 합니다.
참고: 어떤 종류의 선언 사이에서도 순환이 허용되지 않으므로 재귀가 허용되지 않습니다.
fn bar ( p : ptr< function, f32> ) { } fn baz ( p : ptr< private, i32> ) { } fn bar2 ( p : ptr< function, f32> ) { let a = &*&* ( p ); bar ( p ); // 유효함 bar ( a ); // 유효함 } fn baz2 ( p : ptr< storage, f32> ) { } struct S { x : i32} @group ( 0 ) @binding ( 0 ) var < storage> ro_storage : f32; @group ( 0 ) @binding ( 1 ) var < storage, read_write> rw_storage : f32; var usable_priv : i32; var unusable_priv : array< i32, 4 > ; fn foo () { var usable_func : f32; var unusable_func : S ; var i32_func : i32; let a_priv = & usable_priv ; let b_priv = a_priv ; let c_priv = &*& usable_priv ; let d_priv = & ( unusable_priv . x ); let e_priv = d_priv ; let a_func = & usable_func ; let b_func = & unusable_func ; let c_func = & ( * b_func )[ 0 ]; let d_func = c_func ; let e_func = &* a_func ; baz ( & usable_priv ); // 유효함, 변수의 주소 가져오기입니다. baz ( a_priv ); // 유효함, 실질적으로 변수의 주소 가져오기입니다. baz ( b_priv ); // 유효함, 실질적으로 변수의 주소 가져오기입니다. baz ( c_priv ); // 유효함, 실질적으로 변수의 주소 가져오기입니다. baz ( d_priv ); // 유효함, 메모리 뷰가 변경되었습니다. baz ( e_priv ); // 유효함, 메모리 뷰가 변경되었습니다. baz ( & i32_func ); // 유효하지 않음, 주소 공간이 일치하지 않습니다. bar ( & usable_func ); // 유효함, 변수의 주소 가져오기입니다. bar ( c_func ); // 유효함, 메모리 뷰가 변경되었습니다. bar ( d_func ); // 유효함, 메모리 뷰가 변경되었습니다. bar ( e_func ); // 유효함, 실질적으로 변수의 주소 가져오기입니다. baz2 ( & ro_storage ); // 유효함, 변수의 주소 가져오기입니다. baz2 ( & rw_storage ); // 유효하지 않음, 접근 모드가 일치하지 않습니다. }
11.4.1. 별칭 분석
11.4.1.1. 루트 식별자
함수를 실행하는 동안 메모리 뷰 또는 스위즐 뷰를 사용하여 메모리 위치에 접근할 수 있습니다. 함수 내에서 각 메모리 뷰에는 특정한 루트 식별자가 있습니다. 이 식별자는 해당 함수에서 그 메모리에 처음으로 접근을 제공하는 변수 또는 형식 매개변수의 이름입니다. 마찬가지로 스위즐 뷰의 루트 식별자는 스위즐 뷰 포인터의 루트 식별자입니다.
참조 또는 포인터 타입의 지역적으로 파생된 식은 특정 루트 식별자의 새 이름을 도입할 수 있지만 각 식에는 정적으로 결정할 수 있는 루트 식별자가 있습니다.
포인터 또는 참조 타입의 식 E가 주어졌을 때, 루트 식별자는 다음과 같이 찾은 기원 변수 또는 포인터 타입의 형식 매개변수입니다.
-
E가 변수로 해석되는 식별자이면 루트 식별자는 해당 변수입니다.
-
E가 포인터 타입의 형식 매개변수로 해석되는 식별자이면 루트 식별자는 해당 형식 매개변수입니다.
-
E가
(E2),&E2,*E2 또는 E2[Ei]형식이면 루트 식별자는 E2의 루트 식별자입니다. -
E가 E2.swiz 형식의 벡터 접근 식이고 swiz가 스위즐 이름이면 루트 식별자는 E2의 루트 식별자입니다.
-
E가 E2.member_name 형식의 구조체 접근 식이면 루트 식별자는 E2의 루트 식별자입니다.
-
E가 bufferView 또는 bufferArrayView 내장 호출이면 루트 식별자는 포인터 인수의 루트 식별자입니다.
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와의 인터페이스 지정 등 다양한 목적으로 사용됩니다.
일반적으로 언어의 관점에서 특성은 타입 및 의미 검사를 수행할 때 무시할 수 있습니다. 또한 특성 이름은 문맥 의존적 이름이며, 일부 특성 매개변수도 문맥 의존적 이름입니다.
'@' ident_pattern_token
argument_expression_list ?
| id_attr
특성의 설명에서 명시적으로 허용하지 않는 한, 객체 또는 타입 하나에 동일한 특성을 두 번 이상 지정해서는 안 됩니다.
12.1. align
'@' 'align' '(' expression ',' ?
')'
| 설명 |
메모리에서 구조체 멤버의 배치를 제한합니다.
이 특성은 이를 포함하는 구조체 타입의 값이 메모리에 나타나는 방식에 영향을 줍니다. 즉, 구조체 자체와 그 구성 멤버들이 나타날 수 있는 바이트 주소를 제한합니다. align(n)이 타입 T인 S의 멤버에
적용되고,
S가 주소 공간 AS에 있는 변수의 저장소 타입이 될 수 있으며,
AS가 uniform이 아니라면,
n은 반드시 다음을 충족해야 합니다.
어떤 양의 정수 k에 대해 n = k × RequiredAlignOf(T,AS)입니다. 정렬과 크기에 관한 규칙은 상호 재귀적입니다. 그러나 위 제약 조건은 중첩된 타입의 필수 정렬에 의존하고, 타입의 중첩 깊이에는 상한이 있으므로 명확하게 정의됩니다. 유니폼 또는 스토리지 버퍼에 바인딩된 메모리의 시작 주소가 특성에 지정된 값보다 낮은 정렬을 가지면, 결과 정렬은 두 값 중 작은 값이 됩니다. 구현은 변수의 기준 주소에 대해서만 이 특성을 충족합니다. § 14.4 메모리 레이아웃을 참조하십시오. |
| 매개변수 | 반드시 상수 식이어야 하며, 그 식은
해석될 때 i32 또는 u32가 되어야 합니다. 반드시 양수여야 합니다. 반드시 2의 거듭제곱이어야 합니다. |
12.2. binding
'@' 'binding' '(' expression ',' ?
')'
| 설명 | 바인드 그룹에서 리소스의 바인딩 번호를 지정합니다. § 13.3.2 리소스 인터페이스를 참조하십시오. |
| 매개변수 | 반드시 상수 식이어야 하며, 그 식은
해석될 때 i32 또는 u32가 되어야 합니다. 반드시 음수가 아니어야 합니다. |
12.3. blend_src
'@' 'blend_src' '(' expression ',' ?
')'
| 설명 |
dual_source_blending 기능이
활성화되었을 때 프래그먼트 출력의 일부를
지정합니다.
§ 13.3.1.3 입출력 위치를 참조하십시오.
반드시 location 특성이 있는 구조체 타입의 멤버에만 적용해야 합니다. 반드시 숫자 스칼라 또는 숫자 벡터 타입인 객체의 선언에만 적용해야 합니다. 셰이더 스테이지 입력에 포함해서는 안 됩니다. 프래그먼트 셰이더 스테이지를 제외하고 셰이더 스테이지 출력에 포함해서는 안 됩니다. |
| 매개변수 | 반드시 상수 식이어야 하며, 그 식은
해석될 때 값이
0 또는 1인 i32
또는 u32가 되어야 합니다.
|
12.4. builtin
'@' 'builtin' '(' builtin_value_name ',' ? ')'
| 설명 | 지정된 토큰이 나타내는 대로 연결된 객체가 내장 값임을 지정합니다. § 13.3.1.1 내장 입력과 출력을 참조하십시오. |
| 매개변수 | 반드시 내장 값을 위한 내장 값 이름 토큰이어야 합니다. |
12.5. const
'@' 'const'
| 설명 |
함수를 상수 함수로 사용할
수 있음을 지정합니다.
이 특성을 사용자 정의 함수에 적용해서는 안 됩니다.
반드시 함수 선언에만 적용해야 합니다. 참고: 이 특성은 어떤 내장 함수를 상수 식에서 사용할 수 있는지 설명하는 표기 규약으로 사용됩니다. |
| 매개변수 | 없음 |
12.6. diagnostic
'@' 'diagnostic' diagnostic_control
'(' severity_control_name ',' diagnostic_rule_name ',' ? ')'
| 설명 |
범위
진단 필터를 지정합니다. § 2.3 진단을 참조하십시오.
하나의 구문 형식에 둘 이상의 diagnostic 특성을 지정할 수 있지만, 서로 다른 트리거 규칙을 지정해야 합니다. |
| 매개변수 |
첫 번째 매개변수는 severity_control_name입니다.
두 번째 매개변수는 트리거 규칙을 지정하는 diagnostic_rule_name 토큰입니다. |
12.7. group
'@' 'group' '(' expression ',' ?
')'
| 설명 | 리소스의 바인딩 그룹을 지정합니다. § 13.3.2 리소스 인터페이스를 참조하십시오. |
| 매개변수 | 반드시 상수 식이어야 하며, 그 식은
해석될 때 i32 또는 u32가 되어야 합니다. 반드시 음수가 아니어야 합니다. |
12.8. id
'@' 'id' '(' expression ',' ?
')'
| 설명 | 파이프라인 오버라이드 가능 상수의 대체 이름으로 사용할 숫자 식별자를 지정합니다. |
| 매개변수 | 반드시 상수 식이어야 하며, 그 식은
해석될 때 i32 또는 u32가 되어야 합니다. 반드시 음수가 아니어야 합니다. |
12.9. interpolate
'@' 'interpolate' '(' interpolate_type_name ',' ? ')'
| '@' 'interpolate' '(' interpolate_type_name ',' interpolate_sampling_name ',' ? ')'
| 설명 | 사용자 정의 IO를 어떻게 보간해야 하는지 지정합니다. § 13.3.1.4 보간을 참조하십시오. |
| 매개변수 |
첫 번째 매개변수는 보간 타입을 위한
보간 타입 이름 토큰이어야 합니다.
두 번째 매개변수가 존재한다면 보간 샘플링을 위한 보간 샘플링 이름 토큰이어야 합니다. |
12.10. invariant
'@' 'invariant'
| 설명 |
버텍스 셰이더의 position 내장 출력값에
적용하면 결과 계산은 서로 다른 프로그램 및 동일한 진입점의 서로 다른 호출 전반에서 불변입니다.
즉, 서로 다른 진입점의 두 position 출력에서 데이터 흐름과 제어 흐름이 일치하면
결과 값이 동일함이 보장됩니다.
position 내장 입력값에는 아무런 영향이 없습니다.
참고: 이 특성은 HLSL의
|
| 매개변수 | 없음 |
12.11. location
'@' 'location' '(' expression ',' ?
')'
| 설명 |
진입점의 사용자 정의 IO 일부를 지정합니다.
§ 13.3.1.3 입출력 위치를 참조하십시오.
반드시 진입점 함수 매개변수, 진입점 반환 타입 또는 구조체 타입의 멤버에만 적용해야 합니다. 반드시 숫자 스칼라 또는 숫자 벡터 타입인 객체의 선언에만 적용해야 합니다. 컴퓨트 셰이더 스테이지 입력에 포함해서는 안 됩니다. |
| 매개변수 | 반드시 상수 식이어야 하며, 그 식은
해석될 때 i32 또는 u32가 되어야 합니다. 반드시 음수가 아니어야 합니다. |
12.12. must_use
'@' 'must_use'
| 설명 |
이 함수에 대한 호출을 식으로 사용해야 함을 지정합니다.
즉, 이 함수에 대한 호출이 함수 호출문의 전부여서는 안 됩니다.
반드시 반환 타입이 있는 함수의 선언에만 적용해야 합니다. 참고: 많은 함수는 값을 반환하며
부수 효과가 없습니다.
그러한 함수에 대한 호출을 함수 호출문에서 유일한 요소로 사용하는 것은 흔히 프로그래밍 결함입니다.
이러한 속성을 가진 내장 함수는 참고: |
| 매개변수 | 없음 |
12.13. size
'@' 'size' '(' expression ',' ?
')'
| 설명 |
구조체 멤버를 위해 예약되는 바이트 수를 지정합니다.
§ 14.4 메모리 레이아웃을 참조하십시오. 반드시 구조체 타입의 멤버에만 적용해야 합니다. 멤버 타입은 생성 시 고정된 풋프린트를 가져야 합니다. |
| 매개변수 | 반드시 상수 식이어야 하며, 그 식은
해석될 때 i32 또는 u32가 되어야 합니다. 반드시 양수여야 합니다. |
12.14. subgroup_size
'@' 'subgroup_size' '(' expression ',' ? ')'
| 설명 | 컴퓨트 셰이더 호출의 서브그룹 크기를 지정합니다. |
| 요구 사항 | 반드시 subgroup_size_control 확장이 활성화된 경우에만 사용해야 합니다. |
| 매개변수 |
상수 식 또는
오버라이드
식이어야 하며, 그 식은
해석될 때 i32 또는 u32가 되어야 합니다. 값이 2의 거듭제곱이 아니라면 다음과 같습니다.
진입점 값이 값이 |
12.15. workgroup_size
'@' 'workgroup_size' '(' expression ',' ? ')'
| '@' 'workgroup_size' '(' expression ',' expression ',' ?
')'
| '@' 'workgroup_size' '(' expression ',' expression ','
expression ',' ?
')'
| 설명 |
컴퓨트 셰이더의 워크그룹
그리드에 대한 x, y, z 차원을 지정합니다.
첫 번째 매개변수는 x 차원을 지정합니다. 두 번째 매개변수가 제공되면 y 차원을 지정하며, 그렇지 않으면 1로 간주됩니다. 세 번째 매개변수가 제공되면 z 차원을 지정하며, 그렇지 않으면 1로 간주됩니다. |
| 매개변수 |
하나, 둘 또는 세 개의 매개변수를 받습니다.
각 매개변수는 상수 식 또는 오버라이드 식이어야 합니다. 모든 매개변수는 i32 또는 u32 중 하나인 동일한 타입이어야 합니다. 지정된 매개변수 중 하나라도 양수가 아닌 값으로 평가되는 상수 식이면 셰이더 생성 오류가 발생합니다. 지정된 매개변수 중 하나라도 양수가 아닌 값으로 평가되거나 WebGPU API가 지정한 상한을 초과하는 경우, 또는 매개변수 값의 곱이 WebGPU API가 지정한 상한을 초과하는 경우 파이프라인 생성 오류가 발생합니다(WebGPU § 3.6.2 제한 참조). |
12.16. 셰이더 스테이지 특성
아래의 셰이더 스테이지 특성은 함수를 특정 셰이더 스테이지의 진입점으로 지정합니다. 이러한 특성은 함수 선언에만 적용해야 하며, 지정된 함수에는 최대 하나만 존재할 수 있습니다. 매개변수는 받지 않습니다.
12.16.1. vertex
'@' 'vertex'
vertex 특성은 함수를 렌더
파이프라인의 버텍스 셰이더
스테이지를 위한 진입점으로 선언합니다.
12.16.2. fragment
'@' 'fragment'
fragment 특성은 함수를 렌더
파이프라인의 프래그먼트 셰이더
스테이지를 위한 진입점으로 선언합니다.
12.16.3. compute
'@' 'compute'
compute 특성은 함수를 컴퓨트 파이프라인의 컴퓨트 셰이더
스테이지를 위한 진입점으로 선언합니다.
13. 진입점
진입점은 특정 셰이더 스테이지를 위한 작업을 수행하는 사용자 정의 함수입니다.
13.1. 셰이더 스테이지
WebGPU는 그리기 또는 디스패치 명령의 형태로 GPU에 작업을 지시합니다. 이러한 명령은 셰이더 스테이지 입력, 출력 및 연결된 리소스의 집합이라는 문맥에서 파이프라인을 실행합니다.
파이프라인은 GPU에서 수행할 작업을 일련의 스테이지로 설명하며, 이 중 일부는 프로그래밍할 수 있습니다. WebGPU에서는 그리기 또는 디스패치 명령의 실행을 예약하기 전에 파이프라인이 생성됩니다. 파이프라인에는 GPUComputePipeline과 GPURenderPipeline의 두 종류가 있습니다.
디스패치 명령은 GPUComputePipeline을 사용하여 제어 가능한 수준의 병렬 처리로 논리적 점 그리드 전체에서 컴퓨트 셰이더 스테이지를 실행하면서 버퍼 및 이미지 리소스를 읽고 필요에 따라 갱신합니다.
그리기 명령은 GPURenderPipeline을 사용하여 다른 고정 기능 스테이지들 사이에서 프로그래밍 가능한 두 스테이지가 포함된 다단계 처리를 실행합니다.
-
버텍스 셰이더 스테이지는 단일 버텍스의 입력 특성을 해당 버텍스의 출력 특성으로 매핑합니다.
-
고정 기능 스테이지는 버텍스를 그래픽 프리미티브(예: 삼각형)로 매핑하며, 그런 다음 이를 래스터화하여 래스터화 프래그먼트를 생성합니다. 각 래스터화 프래그먼트는 그려지는 프리미티브와 프레임버퍼의 특정 픽셀 사이의 겹침을 나타냅니다.
-
프래그먼트 셰이더 스테이지는 각 프래그먼트를 처리하며, 프래그먼트 출력을 생성할 수 있습니다.
-
일반적으로 각 래스터화 프래그먼트마다 하나의 프래그먼트 셰이더 호출이 생성됩니다. 래스터화 프래그먼트가 여러 샘플을 포함하면 둘 이상의 프래그먼트 호출이 생성될 수 있습니다. WebGPU § 23.2.10 샘플별 셰이딩을 참조하십시오.
-
래스터화 프래그먼트가 프리미티브의 경계에 가까우면 추가적인 보조 호출도 생성될 수 있습니다. § 15.4 프래그먼트 셰이더와 보조 호출을 참조하십시오.
-
-
고정 기능 스테이지는 프래그먼트 출력을 소비하며, 색상 어태치먼트와 깊이 및 스텐실 버퍼 같은 외부 상태를 갱신할 수 있습니다.
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은 진입점 선언에 적용할 수 있는 다음과 같은 특성을 정의합니다.
@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는 다음과 같은 경우 셰이더에서 정적으로 접근됩니다.
-
D로 해석되는 식별자가 셰이더 스테이지의 함수 중 하나의 선언에 나타납니다.
이제 셰이더의 인터페이스를 다음 항목으로 구성된 것으로 정확하게 정의할 수 있습니다.
-
진입점의 반환 값. 이는 셰이더 스테이지 출력을 나타냅니다.
13.3.1. 스테이지 간 입력 및 출력 인터페이스
셰이더 스테이지 입력은 파이프라인의 상류에서 셰이더 스테이지로 제공되는 데이터입니다. 각 데이터는 내장 입력값 또는 사용자 정의 입력입니다.
셰이더 스테이지 출력은 셰이더가 파이프라인 하류의 추가 처리를 위해 제공하는 데이터입니다. 각 데이터는 내장 출력값 또는 사용자 정의 출력입니다.
IO 특성은 객체를 셰이더 스테이지 입력 또는 셰이더 스테이지 출력으로 확립하거나, 입력 또는 출력의 속성을 추가로 설명하는 데 사용됩니다. IO 특성은 다음과 같습니다.
13.3.1.1. 내장 입력과 출력
내장 입력값은 시스템에서 생성된 제어 정보에 대한 접근을 제공합니다. 진입점에는 동일한 내장 값 이름을 가진 두 개의 내장 입력이 있어서는 안 됩니다.
스테이지 S에 대한 이름 X, 타입 TX인 내장 입력에는 다음 두 방법 중 하나로 셰이더 스테이지 S의 진입점에 대한 형식 매개변수를 통해 접근합니다.
-
매개변수에
builtin(X)특성이 있고 타입이 TX입니다. -
매개변수가 구조체 타입이며, 구조체 멤버 중 하나에
builtin(X)특성이 있고 타입이 TX입니다.
반대로 진입점의 매개변수 또는 매개변수의 멤버에 builtin 특성이 있으면, 이에 대응하는 내장 값은 진입점의 셰이더 스테이지에 대한 입력이어야 합니다.
내장 출력값은 셰이더가 파이프라인의 후속 처리 단계에 제어 정보를 전달하는 데 사용됩니다. 진입점에는 동일한 내장 값 이름을 가진 두 개의 내장 출력이 있어서는 안 됩니다.
스테이지 S에 대한 이름 Y, 타입 TY인 내장 출력은 다음 두 방법 중 하나로 셰이더 스테이지 S의 진입점에 대한 반환 값을 통해 설정됩니다.
-
진입점 반환 타입에
builtin(Y)특성이 있고 타입이 TY입니다. -
진입점 반환 타입이 구조체 타입이며, 구조체 멤버 중 하나에
builtin(Y)특성이 있고 타입이 TY입니다.
반대로 진입점의 반환 타입 또는 반환 타입의 멤버에 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의 depth 속성입니다. 셰이더가 깊이 모드 약속을 위반하는 깊이 값을 반환하면 그 대신 불확정 깊이 값이 사용될 수 있습니다.
|
13.3.1.1.3. front_facing
| 이름 | front_facing |
| 스테이지 | 프래그먼트 |
| 타입 | bool |
| 방향 | 입력 |
| 설명 | 현재 프래그먼트가 앞면을 향한 프리미티브 위에 있으면 참입니다. 그렇지 않으면 거짓입니다. |
13.3.1.1.4. global_invocation_id
| 이름 | global_invocation_id |
| 스테이지 | 컴퓨트 |
| 타입 | vec3<u32> |
| 방향 | 입력 |
| 설명 | 현재 호출의 전역 호출 ID, 즉 컴퓨트 셰이더 그리드 내 위치입니다. global_invocation_id의 값은 workgroup_id * workgroup_size + local_invocation_id와 같습니다. |
13.3.1.1.5. global_invocation_index
| 이름 | global_invocation_index |
| 스테이지 | 컴퓨트 |
| 타입 | u32; |
| 방향 | 입력 |
| 설명 |
현재 호출의 전역 호출 인덱스, 즉
컴퓨트 셰이더
그리드 내 선형 위치입니다.
global_invocation_index의 값은
다음과 같습니다.
global_invocation_id.x +
참고: 디스패치된 워크그룹 수로 인해 이 값이 u32 타입의 범위를 초과하게
되면 디스패치가 실패합니다.
|
13.3.1.1.6. instance_index
| 이름 | instance_index |
| 스테이지 | 버텍스 |
| 타입 | u32 |
| 방향 | 입력 |
| 설명 |
현재 API 수준 그리기 명령 내 현재 버텍스의 인스턴스 인덱스입니다.
직접 제공되었든 간접적으로 제공되었든 첫 번째 인스턴스의 인덱스는 그리기의
|
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라고 합니다. 개략적으로 다음과 같습니다. fp.xy = rp.destination.position 더 자세히 설명하면 다음과 같습니다.
WebGPU § 3.3 좌표계 및 WebGPU § 23.2.5 래스터화를 참조하십시오. |
13.3.1.1.11. primitive_index
| 이름 | primitive_index |
| 스테이지 | 프래그먼트 |
| 타입 | u32 |
| 방향 | 입력 |
| 설명 | 현재 그리기 작업을 시작한 후 현재 인스턴스에서 처리된 프리미티브 수를 바탕으로 한 프리미티브별 인덱스입니다. 0에서 시작하며 점, 선 또는 삼각형 프리미티브가 처리될 때마다 1씩 증가합니다. 그려지는 각 인스턴스 사이에서 0으로 재설정됩니다. 프리미티브 재시작 값으로 스트립 프리미티브를 다시 시작해도 프리미티브 인덱스에는 영향을 주지 않습니다. 인덱스는 프리미티브의 모든 프래그먼트에서 균일합니다. |
13.3.1.1.12. sample_index
| 이름 | sample_index |
| 스테이지 | 프래그먼트 |
| 타입 | u32 |
| 방향 | 입력 |
| 설명 |
현재 프래그먼트 래스터화 지점의 샘플 인덱스입니다.
값은 최소 0이고 최대 sampleCount-1입니다.
여기서 sampleCount는 GPU 렌더 파이프라인에 지정된 샘플
개수입니다.
이 특성이 적용된 경우 프래그먼트 셰이더의 효과가 sample_index 값에 따라 달라지면
프래그먼트 셰이더가 샘플당 한 번씩 호출됩니다.
WebGPU § 10.3 GPURenderPipeline을 참조하십시오. |
13.3.1.1.13. sample_mask
| 이름 | sample_mask |
| 스테이지 | 프래그먼트 |
| 타입 | u32 |
| 방향 | 입력 |
| 설명 |
현재 프래그먼트의 샘플 커버리지 비트마스크입니다.
비트는 반개구간 [0, 샘플이 렌더링 중인 프리미티브에 포함된 경우에만 비트가 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 수준 그리기 명령 내 현재 버텍스의 인덱스입니다.
인덱싱되지 않은 그리기의 경우, 직접 제공되었든 간접적으로 제공되었든 첫 번째 버텍스의
인덱스는 그리기의 인덱싱된 그리기의 경우 인덱스는 해당 버텍스의 인덱스 버퍼 항목에,
직접 제공되었든 간접적으로 제공되었든 그리기의 |
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 타입의 범위를 초과하게
되면 디스패치가 실패합니다.
|
13.3.1.1.17. subgroup_invocation_id
| 이름 | subgroup_invocation_id |
| 스테이지 | 컴퓨트 또는 프래그먼트 |
| 타입 | u32 |
| 방향 | 입력 |
| 설명 |
현재 호출의 서브그룹 호출 ID입니다.
ID는 [0, subgroup_size - 1] 범위에 있습니다. 컴퓨트 셰이더에서 ID는 0부터 시작하며 조밀합니다. 즉, 컴퓨트 셰이더가 실행을 시작할 때 각 서브그룹 내에서는 다음과 같습니다.
참고: 프래그먼트 셰이더의 서브그룹 호출 인덱싱은 조밀하지 않을 수 있습니다. 구현은 번호가 더 작은 일부 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. 사용자 정의 입력과 출력
사용자 정의 데이터는 파이프라인 시작 부분에 입력으로 전달하거나, 파이프라인의 스테이지 사이에 전달하거나, 파이프라인 끝에서 출력할 수 있습니다.
각 사용자 정의 입력 데이터와 사용자 정의 출력 데이터는 반드시 다음을 충족해야 합니다.
-
IO 위치가 할당되어야 합니다. § 13.3.1.3 입출력 위치를 참조하십시오.
컴퓨트 셰이더에는 사용자 정의 입력이나 출력이 있어서는 안 됩니다.
13.3.1.3. 입출력 위치
각 입출력 위치에는 최대 16바이트 크기의 값을 저장할 수 있습니다. 타입의 바이트 크기는 § 14.4.1 정렬 및 크기의 SizeOf 열을 사용하여 정의됩니다. 예를 들어 부동 소수점 값의 4컴포넌트 벡터는 단일 위치를 차지합니다.
IO 위치는 location 특성을 통해 지정됩니다.
각 사용자 정의 입력과 출력에는 명시적으로 지정된 IO 위치가 있어야 합니다. 진입점 IO의 각 구조체 멤버는 내장 값(§ 13.3.1.1 내장 입력과 출력 참조)이거나 위치가 할당되어야 합니다.
참고: 위치 번호는 입력과 출력 사이에서 서로 구분됩니다. 진입점의 셰이더 스테이지 입력에 대한 위치 번호는 해당 진입점의 셰이더 스테이지 출력에 대한 위치 번호와 충돌하지 않습니다.
참고: 진입점의 출력 내 위치 중복을 방지하기 위한 추가 규칙은 필요하지 않습니다. 출력이 구조체이면 위의 첫 번째 규칙이 중복을 방지합니다. 그렇지 않으면 출력은 스칼라 또는 벡터이며 하나의 위치만 할당할 수 있습니다.
참고: 진입점에 사용할 수 있는 위치의 수는 WebGPU API에서 정의합니다.
사용자 정의 IO는 동일한 구조체에서 내장 값과 함께 사용할 수 있습니다. 예를 들면 다음과 같습니다.
// 내장 입력과 사용자 정의 입력을 혼합합니다. struct MyInputs { @location ( 0 ) x : vec4< f32> , @builtin ( front_facing) y : bool, @location ( 1 ) @interpolate ( flat) z : u32} struct MyOutputs { @builtin ( frag_depth) x : f32, @location ( 0 ) y : vec4< f32> } @fragment fn fragShader ( in1 : MyInputs ) -> MyOutputs { // ... }
struct A { @location ( 0 ) x : f32, // 유효하지 않음: x와 y는 위치를 공유할 수 없습니다. @location ( 0 ) y : f32} struct B { @location ( 0 ) x : f32} struct C { // 유효하지 않음: 사용자 정의 IO가 있는 구조체는 중첩할 수 없습니다. b : B } struct D { x : vec4< f32> } @fragment // 유효하지 않음: location은 구조체 타입에 적용할 수 없습니다. fn fragShader1 ( @location ( 0 ) in1 : D ) { // ... } @fragment // 유효하지 않음: in1과 in2는 위치를 공유할 수 없습니다. fn fragShader2 ( @location ( 0 ) in1 : f32, @location ( 0 ) in2 : f32) { // ... } @fragment // 유효하지 않음: location은 구조체에 적용할 수 없습니다. fn fragShader3 ( @location ( 0 ) in1 : vec4< f32> ) -> @location ( 0 ) D { // ... }
13.3.1.4. 보간
작성자는 interpolate 특성을 사용하여 사용자 정의 IO 데이터가 보간되는 방식을 제어할 수 있습니다. WGSL은 보간 타입과 보간 샘플링이라는 두 가지 보간 측면을 제어할 수 있도록 합니다.
보간 타입은 다음 보간 타입 이름 토큰 중 하나여야 합니다.
- perspective
-
값이 원근 보정 방식으로 보간됩니다.
- linear
-
값이 원근 보정 없이 선형 방식으로 보간됩니다.
- flat
-
값이 보간되지 않습니다.
보간 샘플링은 다음 보간 샘플링 이름 토큰 중 하나여야 합니다.
- center
-
픽셀 중심에서 보간이 수행됩니다.
- centroid
-
현재 프리미티브 내에서 프래그먼트가 포함하는 모든 샘플의 내부에 있는 지점에서 보간이 수행됩니다. 이 값은 프리미티브의 모든 샘플에서 동일합니다.
- sample
-
샘플별로 보간이 수행됩니다. 이 특성이 적용되면 프래그먼트 셰이더가 샘플당 한 번씩 호출됩니다.
- first
-
프리미티브의 첫 번째 버텍스가 값을 제공합니다.
- either
-
프리미티브의 첫 번째 또는 마지막 버텍스가 값을 제공합니다. 값이 첫 번째 버텍스에서 오는지 마지막 버텍스에서 오는지는 구현에 따라 다릅니다.
스칼라 또는 벡터 부동 소수점 타입의 사용자 정의 IO에는 다음이 적용됩니다.
-
보간 특성을 지정하지 않으면
@interpolate(perspective, center)로 간주합니다. -
보간 타입과 함께 보간 특성을 지정한 경우:
스칼라 또는 벡터 정수 타입의 사용자 정의 버텍스 출력과 프래그먼트 입력에는
항상 보간 타입 flat을 지정해야 합니다.
스테이지 간 인터페이스 유효성 검사는 렌더 파이프라인 내에서 각 사용자 정의 프래그먼트 입력의 보간 속성이 동일한 location 할당을 가진 버텍스 출력의 보간 속성과 일치하는지 검사합니다. 일치하지 않으면 파이프라인 생성 오류가 발생합니다.
13.3.2. 리소스 인터페이스
리소스는 셰이더 스테이지 외부의 데이터에 대한 접근을 제공하며, 오버라이드 선언도 아니고, 즉시 데이터 변수도 아니며, 셰이더 스테이지 입력 또는 출력도 아닌 객체입니다. 리소스는 셰이더의 모든 호출에서 공유됩니다.
리소스에는 다음 네 종류가 있습니다.
셰이더의 리소스 인터페이스는 셰이더 스테이지의 함수에서 정적으로 접근되는 모듈 범위 리소스 변수 집합입니다.
각 리소스 변수는 group 및 binding 특성을 모두 사용하여 선언해야 합니다. 이 특성들은 셰이더의 스테이지와 함께 셰이더 파이프라인에서 리소스의 바인딩 주소를 식별합니다. WebGPU § 8.3 GPUPipelineLayout을 참조하십시오.
즉시 데이터 변수는 group 또는 binding 특성을 사용하지 않습니다.
셰이더의 서로 다른 두 리소스 변수는 group 값과 binding 값을 한 쌍으로 간주했을 때 동일한 값을 가져서는 안 됩니다.
13.3.3. 리소스 레이아웃 호환성
WebGPU에서는 셰이더의 리소스 인터페이스가 해당 셰이더를 사용하는 파이프라인의 레이아웃과 일치해야 합니다.
리소스 인터페이스의 WGSL 변수가 호환되지 않는 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의
크기를 통해 결정됩니다.
T를 스토리지 버퍼 변수의 저장소 타입이라고 합니다. 여기서 T는 런타임 크기 배열 타입이거나 런타임 크기 배열 타입을 포함합니다.
bufferBinding을 버퍼 바인딩으로 가져오기(
resource)라고 합니다.EBS를 스토리지 버퍼 변수에 대응하는 파이프라인 바인딩 주소에 바인딩된 bufferBinding의 유효 버퍼 바인딩 크기라고 합니다.
그러면 NRuntime, 즉 런타임 크기 배열의 요소 수는 SizeOf(T) ≤ EBS를 충족하는 가장 큰 정수입니다.
더 자세히 설명하면 타입이 RAT인 런타임 크기 배열의 NRuntime은 다음과 같습니다.
truncate((EBBS − array_offset) ÷ array_stride). 여기서:
EBBS는 변수와 연결된 유효 버퍼 바인딩 크기이며,
array_offset은 변수의 저장소 타입 내 런타임 크기 배열의 바이트 오프셋입니다.
저장소 타입이 런타임 크기 배열 타입 자체인 RAT이면 0입니다.
그렇지 않으면 저장소 타입은 구조체이고 마지막 멤버가 런타임 크기 배열입니다. 이 경우 array_offset은 구조체 내 해당 멤버의 바이트 오프셋입니다.
array_stride은 배열 타입의 스트라이드, 즉 StrideOf(RAT)입니다.
셰이더는 arrayLength 내장 함수를 통해 NRuntime을 계산할 수 있습니다.
NRuntime은 대응하는 버퍼 바인딩의 크기에 의해 결정되며, 각 그리기 또는 디스패치 명령마다 달라질 수 있습니다.
WebGPU 유효성 검사 규칙은 1 ≤ NRuntime임을 보장합니다.
-
weights변수는 스토리지 버퍼입니다. -
저장소 타입은 런타임 크기 배열 타입
array<f32>입니다. -
배열 오프셋은 0입니다.
-
배열 스트라이드는 StrideOf(array<f32>), 즉 4입니다.
다음 표는 대응하는 유효 버퍼 바인딩 크기를 기준으로 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 ) |
-
lights변수는 스토리지 버퍼입니다. -
저장소 타입은
LightStorage입니다. -
LightStorage의point멤버는 타입이array<PointLight>인 런타임 크기 배열입니다.
struct PointLight { // align(16) size(32) position: vec3f, // offset(0) align(16) size(12) // -- 암시적 멤버 정렬 패딩 -- // offset(12) size(4) color : vec3f, // offset(16) align(16) size(12) // -- 암시적 구조체 크기 패딩 -- // offset(28) size(4) } struct LightStorage { // align(16) pointCount : u32, // offset(0) align(4) size(4) // -- 암시적 멤버 정렬 패딩 -- // offset(4) size(12) point : array< PointLight > , // offset(16) align(16) elementsize(32) } @group ( 0 ) @binding ( 1 ) var < storage> lights : LightStorage ;
다음 표는 lights 변수의 point 멤버에 대한 NRuntime 예를 보여 줍니다.
| 유효 버퍼 바인딩 크기 | lights 변수의 point 멤버에 대한 NRuntime
| 계산 |
|---|---|---|
| 1024 | 31 | truncate( ( 1024 - 16 ) ÷ 32) ) |
| 1025 | 31 | truncate( ( 1025 - 16 ) ÷ 32) ) |
| 1039 | 31 | truncate( ( 1039 - 16 ) ÷ 32) ) |
| 1040 | 32 | truncate( ( 1040 - 16 ) ÷ 32) ) |
14. 메모리
WGSL에서 저장 가능 타입의 값은 나중에 가져올 수 있도록 메모리에 저장할 수 있습니다. 이 절에서는 메모리의 구조와 메모리에 접근하는 연산의 의미를 설명합니다. 메모리에 배치할 수 있는 값의 타입과 메모리 접근을 수행하는 데 사용되는 타입에 대해서는 § 6.5 메모리 뷰를 참조하십시오.
14.1. 메모리 위치
메모리는 서로 구분되는 메모리 위치 집합으로 구성됩니다. 각 메모리 위치의 크기는 8비트입니다. 메모리에 영향을 주는 연산은 하나 이상의 메모리 위치 집합과 상호 작용합니다. 복합 값에 대한 메모리 연산은 패딩 메모리 위치에 접근하지 않습니다. 따라서 연산이 접근하는 메모리 위치 집합은 연속적이지 않을 수 있습니다.
두 메모리 위치 집합의 교집합이 비어 있지 않으면 두 집합은 중첩됩니다.
14.2. 메모리 접근 모드
메모리 접근은 메모리 위치에 작용하는 연산입니다.
-
읽기 접근은 메모리 위치의 내용을 관찰합니다.
-
쓰기 접근은 메모리 위치의 내용을 설정합니다.
하나의 연산은 읽거나, 쓰거나, 읽기와 쓰기를 모두 수행할 수 있습니다.
특정 메모리 위치는 메모리의 접근 모드로 표현되는 특정 종류의 접근만 지원할 수 있습니다.
| 접근 모드 | 지원되는 접근 |
|---|---|
| read | 읽기 접근은 지원하지만 쓰기는 지원하지 않습니다. |
| write | 쓰기 접근은 지원하지만 읽기는 지원하지 않습니다. |
| read_write | 읽기와 쓰기 접근을 모두 지원합니다. |
WGSL은 read, 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는 호스트 공유 가능 또는 고정 풋프린트 배열이나 런타임 크기 배열입니다.
-
AlignOfMember(S, i)는 S의 i번째 멤버의 정렬입니다.
-
SizeOf(T)는 T의 바이트 크기입니다.
-
SizeOfMember(S, i)는 S의 i번째 멤버의 크기입니다.
-
OffsetOfMember(S, i)는 S의 시작 지점에서 i번째 멤버까지의 오프셋입니다.
-
StrideOf(A)는 A의 요소 스트라이드이며, 한 배열 요소의 시작 지점에서 다음 요소의 시작 지점까지의 바이트 수로 정의됩니다. 이는 배열 요소 타입의 크기를 해당 요소 타입의 정렬까지 올림한 값과 같습니다.
StrideOf(array<E, N>) = roundUp(AlignOf(E), SizeOf(E))
StrideOf(array<E>) = roundUp(AlignOf(E), SizeOf(E)) -
AccessibleBytes(T)는 타입 T의 인스턴스에서 데이터를 포함하는 바이트 오프셋의 집합입니다.
-
T가 스칼라 또는 벡터이면 AccessibleBytes(T)는
0 <= k <SizeOf(T)를 충족하는 정수k의 집합입니다. -
T가 C개의 열과 R개의 행을 가진 행렬이면 AccessibleBytes(T)는 다음과 같이 계산한 집합입니다.
-
0..C-1에 속하는 각i에 대해:-
AccessibleBytes(vecR)에 속하는 각
k에 대해:-
집합에
k + i * Stride가 포함됩니다.
-
-
-
T가 구조체 S이면 AccessibleBytes(T)는 다음과 같이 계산한 집합입니다.
-
바이트 오프셋
Offset= OffsetOfMember(S,i)에 있는 각 멤버M_i에 대해:-
AccessibleBytes(
M_i)에 속하는 각k에 대해:-
집합에
k + Offset이 포함됩니다.
-
-
-
-
-
AccessibleSlots(T)는 구간
[4*i, 4*i+4)와 AccessibleBytes(T)의 교집합이 비어 있지 않은 정수i의 집합입니다.
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의
크기
|
참고: 버퍼 타입은 다른 타입에 포함될 수 없으므로 정렬은 중요하지 않습니다.
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 { // align(8) size(24) u : f32, // offset(0) align(4) size(4) v : f32, // offset(4) align(4) size(4) w : vec2< f32> , // offset(8) align(8) size(8) x : f32// offset(16) align(4) size(4) // -- 암시적 구조체 크기 패딩 -- // offset(20) size(4) } struct B { // align(16) size(160) a : vec2< f32> , // offset(0) align(8) size(8) // -- 암시적 멤버 정렬 패딩 -- // offset(8) size(8) b : vec3< f32> , // offset(16) align(16) size(12) c : f32, // offset(28) align(4) size(4) d : f32, // offset(32) align(4) size(4) // -- 암시적 멤버 정렬 패딩 -- // offset(36) size(4) e : A , // offset(40) align(8) size(24) f : vec3< f32> , // offset(64) align(16) size(12) // -- 암시적 멤버 정렬 패딩 -- // offset(76) size(4) g : array< A , 3 > , // element stride 24 offset(80) align(8) size(72) h : i32// offset(152) align(4) size(4) // -- 암시적 구조체 크기 패딩 -- // offset(156) size(4) } @group ( 0 ) @binding ( 0 ) var < storage, read_write> storage_buffer : B ;
struct A { // align(8) size(32) u : f32, // offset(0) align(4) size(4) v : f32, // offset(4) align(4) size(4) w : vec2< f32> , // offset(8) align(8) size(8) @size ( 16 ) x : f32// offset(16) align(4) size(16) } struct B { // align(16) size(208) a : vec2< f32> , // offset(0) align(8) size(8) // -- 암시적 멤버 정렬 패딩 -- // offset(8) size(8) b : vec3< f32> , // offset(16) align(16) size(12) c : f32, // offset(28) align(4) size(4) d : f32, // offset(32) align(4) size(4) // -- 암시적 멤버 정렬 패딩 -- // offset(36) size(12) @align ( 16 ) e : A , // offset(48) align(16) size(32) f : vec3< f32> , // offset(80) align(16) size(12) // -- 암시적 멤버 정렬 패딩 -- // offset(92) size(4) g : array< A , 3 > , // element stride 32 offset(96) align(8) size(96) h : i32// offset(192) align(4) size(4) // -- 암시적 구조체 크기 패딩 -- // offset(196) size(12) } @group ( 0 ) @binding ( 0 ) var < uniform> uniform_buffer : B ;
14.4.3. 배열 레이아웃 예
// 다음과 같은 배열: // - 정렬은 4 = AlignOf(f32) // - 요소 스트라이드는 4 = roundUp(AlignOf(f32),SizeOf(f32)) = roundUp(4,4) // - 크기는 32 = stride * number_of_elements = 4 * 8 var small_stride : array< f32, 8 > ; // 다음과 같은 배열: // - 정렬은 16 = AlignOf(vec3<f32>) = 16 // - 요소 스트라이드는 16 = roundUp(AlignOf(vec3<f32>), SizeOf(vec3<f32>)) // = roundUp(16,12) // - 크기는 128 = stride * number_of_elements = 16 * 8 var bigger_stride : array< vec3< f32> , 8 > ;
// 다음과 같은 배열: // - 정렬은 4 = AlignOf(f32) // - 요소 스트라이드는 4 = roundUp(AlignOf(f32),SizeOf(f32)) = 4 // B가 그리기 또는 디스패치 명령의 바인딩에 대한 // 유효 버퍼 바인딩 크기라면 요소 수는 다음과 같습니다: // N_runtime = floor(B / element stride) = floor(B / 4) @group ( 0 ) @binding ( 0 ) var < storage> weights : array< f32> ; // 다음과 같은 배열: // - 정렬은 16 = AlignOf(vec3<f32>) = 16 // - 요소 스트라이드는 16 = roundUp(AlignOf(vec3<f32>), SizeOf(vec3<f32>)) // = roundUp(16,12) // B가 그리기 또는 디스패치 명령의 바인딩에 대한 // 유효 버퍼 바인딩 크기라면 요소 수는 다음과 같습니다: // N_runtime = floor(B / element stride) = floor(B / 16) var < storage> directions : array< vec3< f32>> ;
14.4.4. 값의 내부 레이아웃
이 절에서는 전체 값의 배치가 주어졌다고 가정할 때 호스트 공유 가능 값의 내부가 버퍼의 바이트 위치에 배치되는 방식을 설명합니다. 이러한 레이아웃은 값의 타입과 구조체 멤버에 적용된 align 및 size 특성에 따라 달라집니다. 아래에서 설명하는 것처럼 이 규칙은 불투명하지 않은 타입에 적용됩니다. 버퍼 타입의 값에는 내부 구조가 없으며 이 규칙의 제약을 받지 않습니다.
값이 배치되는 버퍼 바이트 오프셋은 타입 정렬 요구 사항을 충족해야 합니다. 타입 T의 값이 버퍼 오프셋 k에 배치되면, 어떤 음이 아닌 정수 c에 대해 k = c × AlignOf(T)입니다.
데이터는 주소 공간과 관계없이 동일하게 나타납니다.
참고: bool 타입은 호스트 공유 가능 타입이 아닙니다. WGSL은 bool 값의 크기와 정렬이 4바이트라고 지정하지만 bool 값의 내부 레이아웃은 지정하지 않습니다.
타입이 u32 또는 i32인 값 V가 호스트 공유 버퍼의 바이트 오프셋 k에 배치되면:
-
바이트 k에는 V의 비트 0부터 7까지가 포함됩니다.
-
바이트 k+1에는 V의 비트 8부터 15까지가 포함됩니다.
-
바이트 k+2에는 V의 비트 16부터 23까지가 포함됩니다.
-
바이트 k+3에는 V의 비트 24부터 31까지가 포함됩니다.
참고: i32는 2의 보수 표현을 사용하므로 부호 비트는 비트 위치 31에 있습니다.
64비트 정수 레이아웃: WebGPU API의 일부 기능은 부호 없는 64비트 정수 값을 버퍼에 씁니다. 그러한 값 V가 호스트 공유 버퍼의 바이트 오프셋 k에 나타나면:
-
바이트 k에는 V의 비트 0부터 7까지가 포함됩니다.
-
바이트 k+1에는 V의 비트 8부터 15까지가 포함됩니다.
-
바이트 k+2에는 V의 비트 16부터 23까지가 포함됩니다.
-
바이트 k+3에는 V의 비트 24부터 31까지가 포함됩니다.
-
바이트 k+4에는 V의 비트 32부터 39까지가 포함됩니다.
-
바이트 k+5에는 V의 비트 40부터 47까지가 포함됩니다.
-
바이트 k+6에는 V의 비트 48부터 55까지가 포함됩니다.
-
바이트 k+7에는 V의 비트 56부터 63까지가 포함됩니다.
참고: WGSL에는 구체적 64비트 정수 타입이 없습니다.
타입이 f32인 값 V는 IEEE-754 binary32 형식으로 표현됩니다. 부호 비트 1개, 지수 비트 8개 및 가수 비트 23개를 가집니다. V가 호스트 공유 버퍼의 바이트 오프셋 k에 배치되면:
-
바이트 k에는 가수의 비트 0부터 7까지가 포함됩니다.
-
바이트 k+1에는 가수의 비트 8부터 15까지가 포함됩니다.
-
바이트 k+2의 비트 0부터 6까지에는 가수의 비트 16부터 22까지가 포함됩니다.
-
바이트 k+2의 비트 7에는 지수의 비트 0이 포함됩니다.
-
바이트 k+3의 비트 0부터 6까지에는 지수의 비트 1부터 7까지가 포함됩니다.
-
바이트 k+3의 비트 7에는 부호 비트가 포함됩니다.
타입이 f16인 값 V는 IEEE-754 binary16 형식으로 표현됩니다. 부호 비트 1개, 지수 비트 5개 및 가수 비트 10개를 가집니다. V가 호스트 공유 버퍼의 바이트 오프셋 k에 배치되면:
-
바이트 k에는 가수의 비트 0부터 7까지가 포함됩니다.
-
바이트 k+1의 비트 0부터 1까지에는 가수의 비트 8부터 9까지가 포함됩니다.
-
바이트 k+1의 비트 2부터 6까지에는 지수의 비트 0부터 4까지가 포함됩니다.
-
바이트 k+1의 비트 7에는 부호 비트가 포함됩니다.
참고: 위 규칙에 따라 호스트 공유 버퍼의 숫자 값은 리틀 엔디언 형식으로 저장됩니다.
원자 타입
atomic<T>인 값
V가 호스트 공유 버퍼에 배치되면 기반 타입 T 값과 동일한 내부 레이아웃을 가집니다.
벡터 타입 vecN<T>인 값 V가 호스트 공유 버퍼의 바이트 오프셋 k에 배치되면:
-
V.x는 바이트 오프셋 k에 배치됩니다.
-
V.y는 바이트 오프셋 k + SizeOf(T)에 배치됩니다.
-
N ≥ 3이면 V.z는 바이트 오프셋 k + 2 × SizeOf(T)에 배치됩니다.
-
N ≥ 4이면 V.w는 바이트 오프셋 k + 3 × SizeOf(T)에 배치됩니다.
행렬 타입 matCxR<T>인 값 V가 호스트 공유 버퍼의 바이트 오프셋 k에 배치되면:
-
V의 열 벡터 i는 바이트 오프셋 k + i × AlignOf(vecR<T>)에 배치됩니다.
배열 타입 A의 값이 호스트 공유 메모리 버퍼의 바이트 오프셋 k에 배치되면:
-
배열의 요소 i는 바이트 오프셋 k + i × StrideOf(A)에 배치됩니다.
구조체 타입 S의 값이 호스트 공유 메모리 버퍼의 바이트 오프셋 k에 배치되면:
-
구조체 값의 i'번째 멤버는 바이트 오프셋 k + OffsetOfMember(S,i)에 배치됩니다. § 14.4.2 구조체 멤버 레이아웃을 참조하십시오.
14.4.5. 주소 공간 레이아웃 제약 조건
storage 및 uniform 주소 공간에는 이 절에서 설명하는 서로 다른 레이아웃 제약 조건이 있습니다.
uniform을 제외한 모든 주소 공간에는 storage 주소 공간과 동일한 제약 조건이 적용됩니다.
변수가 직접 또는 간접적으로 참조하는 모든 구조체 및 배열 타입은 변수 주소 공간의 제약 조건을 준수해야 합니다. 주소 공간 제약 조건을 위반하면 셰이더 생성 오류가 발생합니다.
이 절에서는 RequiredAlignOf(S, C)를 호스트 공유 가능 또는 고정 풋프린트 타입 S의 값이 주소 공간 C에서 사용될 때 요구되는 바이트 오프셋 정렬로 정의합니다.
| S가 C에 나타날 수 있다고 가정할 때, 호스트 공유 가능 또는 고정 풋프린트 타입 S | 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 주소 공간은 다음을 요구합니다.
-
배열 요소는 16바이트 경계에 정렬됩니다. 즉, 어떤 양의 정수 k에 대해 StrideOf(array<T,N>) = 16 × k’ 입니다.
-
구조체 멤버 자체의 타입이 구조체
S이면 해당 멤버의 시작 지점과 그 이후 멤버의 시작 지점 사이의 바이트 수는 최소한 roundUp(16, SizeOf(S))여야 합니다.
참고: 다음 예제는 유니폼 버퍼의 레이아웃 요구 사항을 충족하도록 구조체 멤버에 align 및 size 특성을 사용하는 방법을 보여 줍니다. 특히 이러한 기법을 사용하여 std140 레이아웃의 GLSL 버퍼를 WGSL로 기계적으로 변환할 수 있습니다.
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 ;
struct small_stride { a : array< f32, 8 > // stride 4 } // 유효하지 않음: 스트라이드는 16의 배수여야 합니다. @group ( 0 ) @binding ( 0 ) var < uniform> invalid : small_stride ; struct wrapped_f32 { @size ( 16 ) elem : f32} struct big_stride { a : array< wrapped_f32 , 8 > // stride 16 } @group ( 0 ) @binding ( 1 ) var < uniform> valid : big_stride ; // 유효함
14.5. 메모리 모델
일반적으로 WGSL은 Vulkan 메모리 모델을 따릅니다. 이 절의 나머지 부분에서는 WGSL 프로그램이 Vulkan 메모리 모델에 매핑되는 방식을 설명합니다.
참고: Vulkan 메모리 모델은 형식 Alloy 모델의 텍스트 버전입니다.
14.5.1. 메모리 연산
WGSL에서 읽기 접근은 Vulkan 메모리 모델의 메모리 읽기 연산과 동일합니다. WGSL에서 쓰기 접근은 Vulkan 메모리 모델의 메모리 쓰기 연산과 동일합니다.
호출이 다음 중 하나를 실행하면 읽기 접근이 발생합니다.
-
로드 규칙의 평가
-
스위즐 뷰 로드 규칙의 평가
-
다음을 제외한 모든 텍스처 내장 함수:
-
atomicStore를 제외한 모든 원자 내장 함수
-
workgroupUniformLoad 내장 함수
호출이 다음 중 하나를 실행하면 쓰기 접근이 발생합니다.
-
textureStore 내장 함수
-
atomicLoad를 제외한 모든 원자 내장 함수
-
atomicCompareExchangeWeak는 반환된 결과의
exchanged멤버가true인 경우에만 쓰기를 수행합니다.
-
원자적 읽기-수정-쓰기 내장 함수는 읽기 접근이면서 쓰기 접근인 단일 메모리 연산을 수행합니다.
그 밖의 상황에서는 읽기와 쓰기 접근이 발생하지 않습니다. 읽기와 쓰기 접근을 통틀어 Vulkan 메모리 모델에서 메모리 연산이라고 합니다.
메모리 뷰를 통한 메모리 연산은 일반적으로 해당 메모리 뷰와 연결된 위치 집합에 정확히 접근합니다. 예외적으로 벡터 컴포넌트에 대한 쓰기 접근은 해당 벡터와 연결된 모든 메모리 위치에 접근할 수 있습니다.
-
예를 들어 여러 멤버를 포함하는 구조체에서 u32에 접근하는 메모리 읽기는 해당 u32 멤버와 연결된 메모리 위치만 읽습니다.
-
예를 들어 3요소 벡터의 두 번째 컴포넌트에 대한 메모리 쓰기는 두 번째 컴포넌트의 위치에 쓰며, 벡터의 세 요소를 모두 읽고 쓸 수도 있습니다.
스위즐 뷰를 통한 메모리 연산은 기반 벡터와 연결된 모든 메모리 위치에 접근합니다. 자세한 내용은 스위즐 뷰 읽기 및 스위즐 뷰 쓰기를 참조하십시오.
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. Private와 Non-private
storage 또는
workgroup 주소 공간의 모든 비원자적 읽기 접근은 비프라이빗으로 간주되며,
Workgroup 범위를 가진 NonPrivatePointer | MakePointerVisible 메모리
피연산자를 사용하는 읽기 연산에 대응합니다.
storage 또는
workgroup 주소 공간의 모든 비원자적 쓰기 접근은 비프라이빗으로 간주되며,
Workgroup 범위를 가진 NonPrivatePointer | MakePointerAvailable 메모리
피연산자를 사용하는 쓰기 연산에 대응합니다.
handle 주소 공간의
모든 비원자적 읽기 접근은 비프라이빗으로 간주되며,
Workgroup 범위를 가진 NonPrivateTexel | MakeTexelVisible 메모리
피연산자를 사용하는 읽기 연산에 대응합니다.
handle 주소 공간의
모든 비원자적 쓰기 접근은 비프라이빗으로 간주되며,
Workgroup 범위를 가진 NonPrivateTexel | MakeTexelAvailable 메모리
피연산자를 사용하는 쓰기 연산에 대응합니다.
15. 실행
§ 1.1 개요에서는 셰이더가 호출되고 호출로 분할되는 방식을 설명합니다. 이 절에서는 호출이 개별적으로 그리고 집합적으로 실행되는 방식에 관한 추가 제약 조건을 설명합니다.
15.1. 호출 내 프로그램 순서
WGSL 모듈의 각 문은 실행 중 0회 이상 실행될 수 있습니다. 주어진 호출에서 특정 문의 각 실행은 고유한 동적 문 인스턴스를 나타냅니다.
문에 식이 포함된 경우 해당 문의 의미 체계는 다음을 결정합니다.
-
문 실행의 일부로 식을 평가하는지 여부.
-
문에 있는 독립적인 식 사이의 상대적인 평가 순서.
식의 중첩은 평가를 완료하기 위해 충족해야 하는 데이터 의존성을 정의합니다.
즉, 중첩된 식은 이를 포함하는 식을 평가하기 전에 평가해야 합니다.
WGSL에서 식의 피연산자는 왼쪽에서 오른쪽 순서로 평가됩니다.
예를 들어 foo() + bar()에서는 bar()보다 foo()를 먼저
평가해야 합니다.
§ 8 식을 참조하십시오.
WGSL 모듈의 문은 제어 흐름 순서로 실행됩니다. § 9 문 및 § 11.2 함수 호출을 참조하십시오.
15.2. 균일성
집합 연산 (예: 장벽, 미분 또는 암시적으로 계산된 미분에 의존하는 텍스처 연산)은 GPU에서 동시에 실행되는 여러 호출 간의 조정을 요구합니다. 모든 호출이 연산을 동시에, 즉 균일 제어 흐름에서 실행할 때 연산이 정확하고 이식 가능하게 실행됩니다.
반대로 호출의 엄격한 부분집합이 연산을 실행할 때, 즉 비균일 제어 흐름에서는 부정확하거나 이식 불가능한 동작이 발생합니다. 비공식적으로 말하면 비균일 제어 의존성으로 인해 일부 호출은 집합 연산에 도달하지만 다른 호출은 도달하지 않거나 같은 시간에 도달하지 않습니다. 비균일 제어 의존성은 비균일 값에 따라 동작이 달라지는 제어 흐름문에서 발생합니다.
예를 들어 서로 다른 호출이 if, break-if, while 또는 for의 조건에 대해 서로 다른 값을 계산하거나, switch의 선택자 또는 단락 평가 이항 연산자 (&&또는||)의 좌측 피연산자에 대해 서로 다른 값을 계산할 때 비균일 제어 의존성이 발생합니다.
이러한 비균일 값은 정적으로 균일하다고 입증되지 않은 특정 소스로 거슬러 올라가는 경우가 많습니다. 이러한 소스에는 다음이 포함되지만 이에 한정되지는 않습니다.
정확하고 이식 가능한 동작을 보장하기 위해 WGSL 구현은 정적 균일성 분석을 수행하여 각 집합 연산이 균일 제어 흐름에서 실행됨을 입증하려고 합니다. 이후 하위 절에서 분석을 설명합니다.
균일성 분석이 특정 집합 연산이 균일 제어 흐름에서 실행됨을 입증할 수 없으면 균일성 실패가 트리거됩니다.
-
미분을 계산하는 내장 함수에서 균일성 실패가 트리거되면 derivative_uniformity 진단이 트리거됩니다.
-
서브그룹 또는 쿼드 내장 함수에서 균일성 실패가 트리거되면 subgroup_uniformity 진단이 트리거됩니다.
-
진단의 트리거 위치는 해당 내장 함수의 호출 지점 위치이거나, subgroupShuffleUp, subgroupShuffleDown 또는 subgroupShuffleXor의 경우 균일해야 하는 매개변수의 위치입니다.
-
15.2.1. 용어 및 개념
다음 정의는 단지 참고 정보이며, 다음 하위 절의 분석이 무엇을 계산하는지 직관적으로 설명하려는 것입니다. 실제로 이러한 개념과 프로그램이 유효한 경우 또는 균일성 규칙을 위반하는 경우를 정의하는 것은 분석입니다.
주어진 호출 그룹에 대해:
-
주어진 범위의 모든 호출이 프로그램의 특정 지점에서 록스텝으로 실행되는 것처럼 실행된다면 해당 지점에는 주어진 균일성 범위에 대한 균일 제어 흐름이 있다고 합니다.
-
워크그룹 균일성 범위: 컴퓨트 셰이더 스테이지의 균일성 범위는 동일한 워크그룹의 모든 호출입니다.
-
그리기 균일성 범위: 다른 셰이더 스테이지의 균일성 범위는 동일한 그리기 명령에서 해당 진입점에 대한 모든 호출입니다.
-
서브그룹 균일성 범위: subgroup_uniformity 기능이 지원되면 서브그룹 및 쿼드 내장 함수의 균일성 범위는 대신 동일한 서브그룹의 모든 호출입니다.
-
-
식이 균일 제어 흐름에서 실행되고 모든 호출이 동일한 값을 계산하면 해당 식을 균일 값이라고 합니다.
-
호출이 지역 변수가 유효한 모든 지점에서 동일한 값을 보유하면 해당 변수를 균일 변수라고 합니다.
15.2.2. 균일성 분석 개요
나머지 하위 절에서는 집합 연산이 균일 제어 흐름에서만 실행되는지 검증하는 정적 분석을 지정합니다. subgroup_uniformity 기능이 지원되면 여러 균일성 범위가 존재합니다. 이 분석은 각 범위에 대해 한 번씩 수행됩니다.
참고: 분석은 범위마다 한 번씩 실행되는 것으로 설명되지만 구현은 각 범위를 포함하는 단일 분석을 수행할 수 있습니다. 워크그룹 및 그리기 균일성 범위는 서로 다른 셰이더 스테이지에서 작동하고 셰이더 스테이지에서 가장 큰 균일성 범위를 나타내므로 실질적으로 동등합니다.
분석에서는 동적 오류가 발생하지 않는다고 가정합니다. 동적 오류가 있는 셰이더 스테이지는 균일성 분석 결과와 관계없이 이미 이식 가능하지 않습니다.
각 함수는 다음 두 가지를 보장하기 위해 분석됩니다.
-
다른 함수를 호출할 때 균일성 요구 사항이 충족되는지, 그리고
-
해당 함수가 호출될 때마다 균일성 요구 사항이 충족되는지.
이 작업의 일부로 분석은 함수에 관한 메타데이터를 계산하여 해당 함수의 호출자를 차례로 분석하는 데 활용합니다. 즉, 먼저 호출 그래프를 구축한 다음 리프부터 위쪽으로, 다시 말해 표준 라이브러리 외부의 함수를 호출하지 않는 함수부터 진입점 방향으로 함수를 분석해야 합니다. 이 방식에서는 함수를 분석할 때마다 모든 피호출자의 메타데이터가 이미 계산되어 있습니다. 언어에서 재귀가 금지되므로 순환에 갇힐 위험은 없습니다.
참고: 같은 내용을 다른 방식으로 표현하면, “(직접 또는 간접적인) 피호출자이다”라는 부분 순서에 따라 정렬된 함수의 위상 정렬을 수행하고 그 순서대로 분석합니다.
또한 각 함수 호출에 대해 분석은 해당 호출이 균일 제어 흐름에 있음을 입증할 수 없을 때 트리거되는 트리거 규칙 집합이 있다면 이를 계산하고 전파합니다. 이를 호출의 잠재적 트리거 집합이라고 합니다. 이 집합의 요소는 다음 가능성에서 선택됩니다.
-
미분 계산에 의존하는 함수의 경우 derivative_uniformity,
-
§ 17.12 서브그룹 내장 함수 또는 § 17.13 쿼드 연산의 함수인 경우 subgroup_uniformity, 또는
-
필터링할 수 없는 균일성 요구 사항의 경우 이름 없는 트리거 규칙.
-
이는 동기화 함수에 의존하는 컴퓨트 셰이더 함수에 사용됩니다.
-
15.2.3. 함수의 균일성 요구 사항 분석
각 함수는 두 단계로 분석됩니다.
첫 번째 단계에서는 다음 하위 절의 규칙에 따라 함수의 구문을 순회하면서 방향 그래프를 구축합니다. 두 번째 단계에서는 해당 그래프를 탐색하여 이 함수를 호출하는 데 관한 제약 조건을 계산하고 잠재적으로 균일성 실패를 트리거합니다.
-
프로그램의 특정 지점은 균일 제어 흐름에서 실행되어야 합니다.
-
식은 균일 값이어야 합니다.
-
변수는 균일 변수여야 합니다.
-
포인터를 통해 로드할 수 있는 메모리에 저장된 값은 균일 값이어야 합니다.
에지는 소스 노드에 대응하는 문에서 대상 노드에 대응하는 문으로의 함의로 이해할 수 있습니다.
예를 들어 균일성 요구 사항 중 하나는 workgroupBarrier 내장 함수를 균일 제어 흐름
내에서만 호출해야 한다는 것입니다.
이를 표현하기 위해 RequiredToBeUniform.error에서
workgroupBarrier 호출
지점에 대응하는 노드로 에지를 추가합니다.
이를 이해하는 한 가지 방법은 RequiredToBeUniform.error가 명제 참에 대응하므로
RequiredToBeUniform.error -> X는 X가 참이라고
말하는 것과 같다는 것입니다.
반대로 어떤 항목의 균일성을 보장할 수 없음을 표현하기 위해(예: 스레드 ID를 보유한 변수) 해당 노드에서 MayBeNonUniform으로 에지를 추가합니다. 이를 이해하는 한 가지 방법은 MayBeNonUniform이 명제 거짓에 대응하므로 X -> MayBeNonUniform은 X가 거짓이라고 말하는 것과 같다는 것입니다.
이 해석에 따르면 RequiredToBeUniform.error에서 도달 가능한 모든 노드는 프로그램이 유효하기 위해 균일해야 하는 항목에 대응하고, MayBeNonUniform에 도달할 수 있는 모든 노드는 균일성을 보장할 수 없는 항목에 대응합니다. 따라서 RequiredToBeUniform.error에서 MayBeNonUniform으로 가는 경로가 하나라도 있으면 균일성 위반이 발생하여 균일성 실패가 트리거됩니다.
RequiredToBeUniform.warning 및 RequiredToBeUniform.info 노드도 비슷한 방식으로 사용되지만 경고 또는 정보 진단을 트리거해야 하는 시점을 결정하는 데 도움을 줍니다.
-
RequiredToBeUniform.warning에서 MayBeNonUniform으로 가는 경로가 있으면 경고 진단이 트리거됩니다.
-
RequiredToBeUniform.info에서 MayBeNonUniform으로 가는 경로가 있으면 정보 진단이 트리거됩니다.
§ 2.3 진단에 설명된 대로 더 높은 심각도의 진단도 생성된 경우에는 더 낮은 심각도의 진단이 폐기될 수 있습니다.
각 함수에 대해 두 개의 태그를 계산합니다.
-
함수의 호출 지점에 대한 제어 흐름 균일성 요구 사항을 설명하는 호출 지점 태그, 그리고
-
균일성에 대한 함수의 영향을 설명하는 함수 태그.
함수의 각 형식 매개변수에 대해 하나 또는 두 개의 태그를 계산합니다.
-
매개변수 태그는 매개변수 값의 균일성 요구 사항을 설명합니다.
-
매개변수 반환 태그는 매개변수의 균일성이 함수의 반환 값의 균일성에 미치는 영향을 설명합니다.
-
매개변수 타입이 function 주소 공간을 가리키는 포인터인 경우의 포인터 매개변수 태그. 이 태그는 함수 호출을 실행하는 동안 매개변수가 가리키는 메모리의 값이 비균일해질 수 있는지를 설명합니다.
| 호출 지점 태그 | 설명 |
|---|---|
| CallSiteRequiredToBeUniform.S, 여기서 S는 오류, 경고 또는 정보 중 하나의 심각도입니다. |
함수는 균일
제어 흐름에서만 호출해야 합니다.
그렇지 않으면 심각도가 S인 진단이 트리거됩니다.
잠재적 트리거 집합과 연결됩니다. |
| CallSiteNoRestriction | 함수는 비균일 제어 흐름에서 호출할 수 있습니다. |
| 함수 태그 | 설명 |
|---|---|
| ReturnValueMayBeNonUniform | 함수의 반환 값이 비균일할 수 있습니다. |
| NoRestriction | 함수는 비균일성을 도입하지 않습니다. |
| 매개변수 태그 | 설명 |
|---|---|
| ParameterRequiredToBeUniform.S, 여기서 S는 오류, 경고 또는 정보 중 하나의 심각도입니다. |
매개변수는 균일 값이어야 합니다.
매개변수 타입이 포인터이면 반드시 그 내용까지 균일할 필요는 없지만 메모리 뷰는 균일해야 합니다.
그렇지 않으면 심각도가 S인 진단이 트리거됩니다.
잠재적 트리거 집합과 연결됩니다. |
| ParameterContentsRequiredToBeUniform.S, 여기서 S는 오류, 경고 또는 정보 중 하나의 심각도입니다. |
포인터 매개변수가 가리키는 메모리에 저장된 값은 균일 값이어야 합니다.
그렇지 않으면 심각도가 S인 진단이 트리거됩니다.
잠재적 트리거 집합과 연결됩니다. |
| ParameterNoRestriction | 매개변수 값에는 균일성 요구 사항이 없습니다. |
| 매개변수 반환 태그 | 설명 |
|---|---|
| ParameterReturnContentsRequiredToBeUniform | 반환 값이 균일 값이 되려면 매개변수가 균일 값이어야 합니다. 매개변수가 포인터이면 포인터가 가리키는 메모리에 저장된 값도 균일해야 합니다. |
| ParameterReturnNoRestriction | 매개변수 값에는 균일성 요구 사항이 없습니다. |
| 포인터 매개변수 태그 | 설명 |
|---|---|
| PointerParameterMayBeNonUniform | 함수 호출 후 포인터 매개변수가 가리키는 메모리에 저장된 값이 비균일할 수 있습니다. |
| PointerParameterNoRestriction | 포인터 매개변수가 가리키는 메모리에 저장된 값의 균일성은 함수 호출의 영향을 받지 않습니다. |
다음 알고리즘은 주어진 함수에 대해 이러한 태그를 계산하는 방법을 설명합니다.
-
다음 노드를 생성합니다.
-
RequiredToBeUniform.error, RequiredToBeUniform.warning 및 RequiredToBeUniform.info. 이들을 통틀어 RequiredToBeUniform.S 노드라고 합니다.
-
각 노드는 처음에는 비어 있는 잠재적 트리거 집합과 연결됩니다.
-
-
MayBeNonUniform
-
함수가 실행되기 시작할 때의 제어 흐름 균일성 요구 사항을 나타내는 CF_start.
-
param_i. 여기서 i의 범위는 함수의 형식 매개변수 전체입니다.
-
함수에 반환 타입이 있으면 Value_return이라는 노드를 생성합니다.
-
-
§ 15.2.4 포인터 디슈거링에 설명된 대로 포인터를 디슈거링합니다.
-
function 주소 공간의 포인터인 각 형식 매개변수에 대해 다음 노드를 생성합니다.
-
param_i_contents: 메모리 뷰 내용의 균일성을 나타냅니다.
-
Value_return_i_contents: 메모리 뷰 내용의 균일성에 대한 함수의 영향을 나타냅니다.
-
-
-
다음 절의 규칙(§ 15.2.5 함수 범위 변수 값 분석, § 15.2.6 문의 균일성 규칙, § 15.2.7 함수 호출의 균일성 규칙, § 15.2.8 식의 균일성 규칙)에 따라 함수의 구문을 순회하며 그래프에 노드와 에지를 추가합니다. 함수 본문의 시작 제어 흐름으로 CF_start를 사용합니다.
-
이 단계에서 추가되는 노드를 내부 노드라고 합니다.
-
-
다음과 같이 초기화합니다.
-
함수 태그를 NoRestriction으로 초기화합니다.
-
호출 지점 태그를 CallSiteNoRestriction으로 초기화합니다.
-
각 param_i의 매개변수 태그를 ParameterNoRestriction으로 초기화합니다.
-
각 param_i의 매개변수 반환 태그를 ParameterReturnNoRestriction으로 초기화합니다.
-
각 param_i의 포인터 매개변수 태그가 존재하면 PointerParameterNoRestriction으로 초기화합니다.
-
-
{오류, 경고, 정보} 순서의 각 심각도 S에 대해 다음을 수행합니다.
-
R.S를 RequiredToBeUniform.S에서 도달 가능한 방문하지 않은 노드 집합이라고 합니다.
-
R.S의 내부 노드를 방문한 것으로 표시합니다.
-
PTS를 RequiredToBeUniform.S와 연결된 잠재적 트리거 집합이라고 합니다.
-
R.S에 MayBeNonUniform 노드가 포함되면 균일성 실패를 트리거합니다.
-
PTS의 각 t에 대해 심각도가 S이고 트리거 규칙이 t인 진단을 트리거합니다.
-
-
그렇지 않으면:
-
R.S에 CF_start가 포함되고 호출 지점 태그가 초기화 이후 갱신되지 않았다면, 호출 지점 태그를 CallSiteRequiredToBeUniform.S로 설정하고 그 잠재적 트리거 집합을 PTS로 설정합니다.
-
R.S의 각 param_i에 대해 대응하는 매개변수 태그가 초기화 이후 갱신되지 않았다면, 해당 태그를 ParameterRequiredToBeUniform.S로 설정하고 그 잠재적 트리거 집합을 PTS로 설정합니다.
-
R.S의 각 param_i_contents에 대해 대응하는 매개변수 태그가 초기화 이후 갱신되지 않았다면, 해당 태그를 ParameterContentsRequiredToBeUniform.S로 설정하고 그 잠재적 트리거 집합을 PTS로 설정합니다.
-
-
-
모든 내부 노드를 방문하지 않은 상태로 표시합니다.
-
Value_return이 존재하면 VR을 Value_return에서 도달 가능한 노드 집합이라고 합니다.
-
VR에 MayBeNonUniform이 포함되면 함수 태그를 ReturnValueMayBeNonUniform으로 설정합니다.
-
VR의 각 param_i에 대해 대응하는 매개변수 반환 태그를 ParameterReturnContentsRequiredToBeUniform으로 설정합니다.
-
-
각 Value_return_i_contents 노드에 대해 VRi를 Value_return_i_contents에서 도달 가능한 노드 집합이라고 합니다.
-
VRi에 MayBeNonUniform이 포함되면 대응하는 포인터 매개변수 태그를 PointerParameterMayBeNonUniform으로 설정합니다.
-
참고: 이 시점에서 전체 그래프를 폐기할 수 있습니다. 위에서 설명한 태그만 기억하면 이 함수의 호출자를 분석할 수 있습니다. 그러나 그래프에는 더 유용한 정보를 담은 진단을 제공하는 데 사용할 수 있는 정보가 포함되어 있습니다. 예를 들어 한 함수의 값이 균일하다고 입증되지 않을 수 있으며, 이 값이 다른 함수에서 균일성 실패를 트리거하는 데 기여할 수 있습니다. 유용한 정보를 담은 진단은 비균일 값과 함께 진단의 트리거 위치에 있는 함수 호출을 설명합니다.
15.2.4. 포인터 디슈거링
function 주소 공간에 있는 포인터 타입의 각 매개변수는 매개변수를 역참조하는 것과 동등한 초깃값을 갖는 지역 변수 선언으로 디슈거링됩니다. 즉, function 주소 공간 포인터는 지역 변수 선언에 대한 별칭으로 간주됩니다. 초깃값 할당은 i번째 매개변수에 대해 param_i_contents로 향하는 에지를 생성합니다 (즉, V(e)는 param_i_contents입니다).
포인터 타입인 유효 값 타입을 가진 각 let 선언 L은 다음과 같이 디슈거링됩니다.
-
L의 초기화 식에 있는 각 하위 식 SE를 후위 순서 깊이 우선 순회로 방문합니다.
-
갱신되었을 수도 있는 L의 초기화 식을 기록합니다.
이 디슈거링은 포인터가 사용되는 각 위치에 포인터의 루트 식별자를 직접 드러내어 후속 분석을 단순화합니다.
참고: 균일성 분석을 위해 타입 검사는 이 디슈거링이 수행되기 전과 후에 모두 발생하는 것으로 설명됩니다.
fn foo ( p : ptr< function, array< f32, 4 >> , i : i32) -> f32{ let p1 = p ; var x = i ; let p2 = & (( * p1 )[ x ]); x = 0 ; * p2 = 5 ; return ( * p1 )[ x ]; } // 분석을 위해 foo와 동등한 버전입니다. fn foo_for_analysis ( p : ptr< function, array< f32, 4 >> , i : i32) -> f32{ var p_var = * p ; // p를 위한 변수를 도입합니다. let p1 = & p_var ; // p1에 이 변수를 사용합니다 var x = i ; let x_tmp1 = x ; // x의 값을 캡처합니다 let p2 = & ( p_var [ x_tmp1 ]); // p1의 초기화 식을 대입합니다 x = 0 ; * ( & ( p_var [ x_tmp1 ])) = 5 ; // p2의 초기화 식을 대입합니다 return ( * ( & p_var ))[ x ]; // p1의 초기화 식을 대입합니다 }
15.2.5. 함수 범위 변수 값 분석
특정 문장에서 각 함수 범위 변수의 값은 그 위치에 도달하는 할당과 경우에 따라 해당 변수의 초깃값을 기준으로 분석할 수 있습니다.
다음을 만족하면 할당은 전체 할당입니다.
그렇지 않으면 할당은 부분 할당입니다.
전체 참조는 다음 중 하나인 참조 타입의 식입니다.
전체 포인터는 다음 중 하나인 포인터 타입의 식입니다.
참고: 이 분석에서는 포인터 타입의 형식 매개변수가 전체 포인터일 수 있는 경우가 필요하지 않습니다.
전체 참조와 마찬가지로 전체 포인터는 대응하는 기원 변수 x의 모든 메모리 위치에 대한 메모리 뷰입니다.
전체 참조가 아닌 참조는 부분 참조입니다. 따라서 부분 참조는 다음 중 하나입니다.
단일 멤버를 가진 구조체 타입과 해당 타입을 저장하는 변수를 살펴보겠습니다.
struct S { member : i32; } fn foo () { var v : S ; }
그러면 v는 전체 참조이고 v.member는 부분 참조입니다.
두 메모리 뷰는 동일한 메모리 위치를 포괄하지만 v의 저장소 타입은
S이고 v.s의 저장소 타입은 i32입니다.
요소를 하나만 가진 배열에서도 비슷한 상황이 발생합니다.
fn foo () { var arr : array< i32, 1 > ; }
그러면 arr는 전체 참조이고 arr[0]은 부분 참조입니다.
두 메모리 뷰는 동일한 메모리 위치를 포괄하지만 arr의 저장소 타입은
array<i32,1>이고 arr[0]의 저장소 타입은
i32입니다.
분석을 단순화하기 위해 어떤 종류의 부분 참조를 통한 할당도 연관된 기원 변수의 모든 메모리 위치를 수정하지 않는 것으로 취급됩니다. 이로 인해 분석이 보수적으로 이루어지며, 엄밀히 필요한 것보다 더 많은 프로그램에서 균일성 실패가 트리거될 수 있습니다.
전체 스위즐 뷰는 다음 조건을 만족하는 스위즐 뷰 sv = (p, IndexList)로 평가되는 식입니다.
-
p는 N개 요소를 가진 벡터에 대한 전체 포인터입니다.
-
IndexList는 {0, ..., N-1}의 순열입니다.
참고: 전체 스위즐 뷰를 통해 할당하면 메모리에 있는 기반 벡터의 모든 요소를 덮어씁니다.
부분 스위즐 뷰는 전체 스위즐 뷰가 아닌 스위즐 뷰 타입의 식입니다.
참고: 전체 스위즐 뷰인지 여부는 기반 포인터 식의 전체성 및 IndexList에만 의존하고 이 둘은 모두 셰이더 생성 시점에 알려지므로, 셰이더 생성 시점에 판별할 수 있습니다. 이는 스위즐 뷰 식을 연쇄적으로 연결하는 경우에도 성립합니다.
전체 참조 또는 전체 스위즐 뷰를 통한 할당은 전체 할당입니다.
부분 참조 또는 부분 스위즐 뷰를 통한 할당은 부분 할당입니다.
후속 절의 균일성 규칙에서 RHSValue로 사용된 함수 범위 변수의 값을 언급하는 경우, 이는 RHSValue 식을 평가하기 전의 변수 값을 의미합니다. 후속 절의 균일성 규칙에서 LHSValue로 사용된 함수 범위 변수의 값을 언급하는 경우, 이는 해당 식이 나타나는 문장을 실행한 후의 변수 값을 의미합니다.
제어 흐름 문장이나 부분 할당으로 인해 변수에 대한 여러 할당이 해당 변수의 사용 위치에 도달할 수 있습니다. 분석에서는 각 제어 흐름 출구에 도달하는 할당 집합의 합집합을 구하여 제어 흐름 문장에서 빠져나오는 여러 할당을 결합합니다.
다음 표는 할당을 결합하는 규칙을 설명합니다.
균일성 그래프에서 각 결합은 결과 노드에서 값의 출처를 나타내는 노드로 향하는 에지입니다.
이 표는 임의의 변수 x를 기준으로 작성되었으며 다음 표기법을 사용합니다.
-
Vin(S)는 문장 S을 실행하기 전의
x값입니다. -
Vout(S)는 문장 S을 실행한 후의
x값입니다. -
Vout(prev)는 현재 문장을 실행하기 전의
x값입니다. -
Vin(next)는 다음 문장을 실행하기 전의
x값입니다. -
V(e)는 후속 절에서 설명하는 식의 값 노드입니다.
-
V(0)은
x의 유효 값 타입의 0 값입니다.
| 문장 | 결과 | 결과에서 나가는 에지 |
|---|---|---|
| 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), 동작이 {Continue}이고 제어를 s2로 전달하는 s1 내부의 모든 si에 대한 Vout(si) |
| loop { s1 continuing { s2 } } | Vin(next) | Break가 s1의 동작에 포함되는 경우
Vout(s2), 동작이 {Break}이고 제어를 next로 전달하는 s1 내부의 모든 si에 대한 Vout(si) |
| switch e { case _: s1 case _: s2 ... case _: s3 } | Vin(si) | Vout(prev) |
| switch e { case _: s1 case _: s2 ... case _: s3 } | Vin(next) | 동작에 Next 또는 Break가 포함되는 모든
si에 대한 Vout(si), 그리고 동작이 {Break}이고 제어를 next로 전달하는 sj 내부의 모든 문장에 대한 Vout(sj) |
다른 모든 문장(함수 호출 제외)에서 Vin(next)는 Vout(prev)와 동등합니다.
참고: 문장 동작 분석과 동일한 디슈거링이 적용됩니다.
15.2.6. 문장에 대한 균일성 규칙
문장을 분석하는 규칙은 문장 자체와 문장 시작 시점의 제어 흐름에 해당하는 노드 (아래에서는 "CF"로 표기)를 인수로 받아 다음 두 가지를 모두 반환합니다.
-
문장의 출구에서 제어 흐름에 해당하는 노드
-
그래프에 추가할 새로운 노드와 에지의 집합
아래 표에서 (CF1, S) => CF2는 "제어 흐름 CF1에서 시작하여 S에 대한 분석을
실행하고, 그래프에 필요한 변경 사항을 적용한 뒤, 결과 제어 흐름 노드의 이름을 CF2로
지정한다"라는 의미입니다.
마찬가지로 (CF1, E) => V는 "제어 흐름 CF1에서 시작하여 식 E에 대한 분석을
실행하고, 그래프에 필요한 변경 사항을 적용한 뒤, 결과 값 노드의 이름을 V로 지정한다"라는
의미입니다(식 분석은 다음 절 참조).
식에 대한 이러한 평가는 할당의 좌변에 속하지 않는 모든 식에 사용되며
RHSValue라고 합니다.
할당의 좌변에 속하는 식, 즉
LHSValue에
대해서도 유사한 규칙 집합이 있으며 이를 LHSValue: (CF, E) => L로 표기합니다.
이는 값의 균일성에 해당하는 노드를 계산하는 대신 할당 대상 변수의 균일성에 해당하는
노드를 계산합니다.
참고: LHSValue에는 증가 및 감소 문장에 있는 식이 포함됩니다.
참고: RHSValue에는 할당 문의 우변에 속하는 식이나, 할당·증가·감소 문장에 속하지 않는 식이 포함됩니다.
여러 에지를 생성해야 할 때는 X -> Y, X -> Z의 축약 표기로
X -> {Y, Z}를 사용합니다.
루프를 분석할 때는 다음 패턴을 사용합니다.
-
노드 CF'는 각 반복 시작 시점의 제어 흐름 균일성을 모델링합니다.
-
노드 CF1은 루프 본문 s1 끝의 제어 흐름 균일성을 모델링합니다.
-
노드 CF2는 continuing 블록 문장 s2 끝의 제어 흐름 균일성을 모델링합니다.
-
에지 CF' -> CF1 및 CF' -> CF2는 루프 끝의 제어 흐름 균일성이 다음 반복 시작 시점의 균일성에 영향을 미친다는 사실을 모델링합니다. 루프 본문 문장 s1이 break 또는 return만 수행하는 경우, 즉 s1의 동작이 {Break, Return}의 부분집합인 경우에는 이 에지가 없습니다.
-
CF' -> CF 에지는 적어도 일부 반복의 시작 시점에 있는 균일성이 제어 흐름이 전체 루프 문장에 도달할 때의 균일성에 의존한다는 사실을 모델링합니다.
-
전체 루프의 동작이 {Next}이면 루프가 끝날 때까지 모든 제어 흐름 분기가 해소된다고 가정합니다. 따라서 루프를 벗어날 때의 균일성이 루프에 처음 도달했을 때의 균일성과 일치한다는 사실을 모델링하기 위해 루프의 결과 제어 흐름 노드를 CF로 설정합니다.
-
참고: 문장 동작 분석에 따르면 루프의 동작은 {Next}, {Return}, {Next,Return} 중 하나입니다.
| 문장 | 새 노드 | 재귀 분석 | 결과 제어 흐름 노드 | 새 에지 |
|---|---|---|---|---|
| 빈 문장 | 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 | |||
| break; | ||||
| continue; | ||||
| break if e; | CFend | (CF, e) => V | CFend |
CFend -> V
참고: CFend에서
V로 향하는 에지는 조건 값이 비균일하면 이 |
| 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 | ||
f()인수가 없는 함수 호출 문장 | 함수 호출 분석을 호출합니다. (CF, f()) => Result | CF | ||
f(e1,...,eN)인수가 있는 함수 호출 문장 | 함수 호출 분석을 호출합니다. (CF, f(e1,...,eN)) => Result | CF |
이 분석을 위해 다음과 같이 처리합니다.
-
for루프는 디슈거링됩니다(§ 9.4.4 For 문 참조). -
while루프는 디슈거링됩니다(§ 9.4.5 While 문 참조). -
loop {s}는loop {s continuing {}}로 취급됩니다. -
else분기가 없는if문은 빈 else 분기가 있는 것처럼, 즉else {}로 끝나는 것처럼 취급됩니다. -
else if분기가 있는if문은 단순한if/else문이 중첩된 것처럼 취급됩니다. -
default로 시작하는 switch_clause는case _:로 시작하는 switch_clause와 동일하게 동작합니다.
성능을 극대화하기 위해 구현체는 흔히 비균일 제어 흐름의 양을 최소화하려고 합니다. 그러나 호출이 균일하다고 말할 수 있는 지점은 여러 요인에 따라 달라집니다. WGSL의 정적 분석은 문장의 동작이 {Next}인 경우 if, switch, loop 문이 끝날 때 균일 제어 흐름으로 돌아간다고 보수적으로 가정합니다. 앞의 표에서는 결과 제어 흐름 노드가 입력 제어 흐름 노드와 동일한 것으로 이를 모델링합니다.
15.2.7. 함수 호출에 대한 균일성 규칙
가장 복잡한 규칙은 함수 호출에 대한 규칙입니다.
-
CF를 함수 호출 식 시작 시점의 제어 흐름이라고 합니다.
-
각 인수에 대해 CF를 사용하여 대응하는 식 규칙을 적용합니다. 대응하는 값 노드의 이름을 arg_i로 지정합니다.
-
Result라는 새 노드를 생성합니다.
-
Result에서 CF로 향하는 에지를 추가합니다.
-
-
함수의 호출 지점 태그가 CallSiteRequiredToBeUniform.S이면 다음을 수행합니다.
-
RequiredToBeUniform.S에서 CF로 향하는 에지를 추가합니다.
-
호출 지점 태그의 잠재적 트리거 집합에 속한 멤버를 RequiredToBeUniform.S와 연관된 잠재적 트리거 집합에 추가합니다.
-
-
함수 태그가 ReturnValueMayBeNonUniform이면 Result에서 MayBeNonUniform으로 향하는 에지를 추가합니다.
-
각 인수 i에 대해 다음을 수행합니다.
-
대응하는 매개변수 태그가 ParameterRequiredToBeUniform.S이면 다음을 수행합니다.
-
RequiredToBeUniform.S에서 arg_i로 향하는 에지를 추가합니다.
-
매개변수 태그의 잠재적 트리거 집합에 속한 멤버를 RequiredToBeUniform.S와 연관된 잠재적 트리거 집합에 추가합니다.
-
-
매개변수 반환 태그가 ParameterReturnContentsRequiredToBeUniform이면 Result에서 arg_i로 향하는 에지를 추가합니다.
-
대응하는 매개변수의 포인터 매개변수 태그가 PointerParameterMayBeNonUniform이면 Vout(call)에서 MayBeNonUniform으로 향하는 에지를 추가합니다.
-
매개변수가 function 주소 공간의 포인터이면 Vout(call)에서 이전에 기록된 도달 가능한 매개변수에 대응하는 각 arg_i로 향하는 에지를 추가합니다.
-
매개변수 태그가 ParameterContentsRequiredToBeUniform.S이면 RequiredToBeUniform.S에서 Vout(call)로 향하는 에지를 추가합니다.
-
-
참고: Vout(call)의 정의는 § 15.2.5 함수 범위 변수 값 분석을 참조하십시오.
대부분의 내장 함수에는 다음 태그가 있습니다.
-
각 매개변수에 대해 다음을 갖습니다.
예외 목록은 다음과 같습니다.
-
§ 17.11 동기화 내장 함수의 함수 호출:
-
NoRestriction인 함수 태그를 가집니다.
-
다음 중 하나인 호출 지점 태그를 가집니다.
-
subgroup_uniformity가 지원되지 않거나 균일성 범위가 subgroup이 아닌 경우, 이름 없는 트리거 규칙으로 구성된 잠재적 트리거 집합을 갖는 CallSiteRequiredToBeUniform.error.
-
참고: 트리거 규칙에는 이름이 없으므로 필터링할 수 없습니다.
-
-
그렇지 않으면 CallSiteNoRestriction.
-
-
또한 subgroup_uniformity가 지원되지 않거나 균일성 범위가 subgroup이 아닌 경우, workgroupUniformLoad 호출에서 매개변수
p는 이름 없는 트리거 규칙으로 구성된 잠재적 트리거 집합을 갖는 ParameterRequiredToBeUniform.error인 매개변수 태그를 가집니다.
-
-
§ 17.6 도함수 내장 함수, § 17.7.8 textureSample, § 17.7.9 textureSampleBias, § 17.7.10 textureSampleCompare의 함수 호출:
-
ReturnValueMayBeNonUniform인 함수 태그를 가집니다.
-
다음과 같은 호출 지점 태그를 가집니다.
-
subgroup_uniformity가 지원되지 않거나 균일성 범위가 subgroup이 아닌 경우
-
DF를 호출 지점 위치와 트리거 규칙 derivative_uniformity에 대한 가장 가까운 둘러싸는 진단 필터라고 합니다.
-
DF가 존재하면 S를 DF의 새 심각도 매개변수라고 합니다.
-
S가 심각도 off이면 호출 지점 태그는 CallSiteNoRestriction입니다.
-
그렇지 않으면 호출 지점 태그는 CallSiteRequiredToBeUniform.S이며, derivative_uniformity 요소로 구성된 잠재적 트리거 집합을 가집니다.
-
-
그러한 DF가 없으면 호출 지점 태그는 CallSiteRequiredToBeUniform.error이며, derivative_uniformity 요소로 구성된 잠재적 트리거 집합을 가집니다.
-
-
그렇지 않으면 CallSiteNoRestriction.
-
-
-
-
CallSiteNoRestriction인 호출 지점 태그를 가집니다.
-
다음과 같은 함수 태그를 가집니다.
-
t매개변수에 대응하는 인수가 읽기-쓰기 스토리지 텍스처이면 ReturnValueMayBeNonUniform -
그렇지 않으면 NoRestriction
-
-
-
§ 17.12 서브그룹 내장 함수 또는 § 17.13 쿼드 연산의 함수 호출:
-
다음 중 하나인 함수 태그를 가집니다.
-
균일성 범위가 subgroup이고 함수가 다음 중 하나이면 NoRestriction입니다.
-
그렇지 않으면 ReturnValueMayBeNonUniform 입니다.
-
-
DF를 호출 지점 위치와 트리거 규칙 subgroup_uniformity에 대한 가장 가까운 둘러싸는 진단 필터라고 합니다.
-
다음과 같은 호출 지점 태그를 가집니다.
-
subgroup_uniformity가 지원되지 않거나 균일성 범위가 subgroup이면 다음을 수행합니다.
-
DF가 존재하면 S를 DF의 새 심각도 매개변수라고 합니다.
-
S가 심각도 off이면 호출 지점 태그는 CallSiteNoRestriction입니다.
-
그렇지 않으면 호출 지점 태그는 CallSiteRequiredToBeUniform.S이며, subgroup_uniformity 요소로 구성된 잠재적 트리거 집합을 가집니다.
-
-
그러한 DF가 없으면 호출 지점 태그는 CallSiteRequiredToBeUniform.error이며, subgroup_uniformity 요소로 구성된 잠재적 트리거 집합을 가집니다.
-
-
그렇지 않으면 CallSiteNoRestriction.
-
-
또한 subgroupShuffleUp 또는 subgroupShuffleDown 호출의 경우 매개변수
delta는 다음 중 하나인 매개변수 태그를 가집니다.-
subgroup_uniformity가 지원되지 않거나 균일성 범위가 subgroup이면 다음을 수행합니다.
-
DF가 존재하면 S를 DF의 새 심각도 매개변수라고 합니다.
-
S가 심각도 off이면 매개변수 태그는 NoRestriction입니다.
-
그렇지 않으면 매개변수 태그는 ParameterRequiredToBeUniform.S이며 subgroup_uniformity 요소로 구성된 잠재적 트리거 집합을 가집니다.
-
-
그러한 DF가 없으면 매개변수 태그는 ParameterRequiredToBeUniform.error이며, subgroup_uniformity 요소로 구성된 잠재적 트리거 집합을 가집니다.
-
-
그렇지 않으면 NoRestriction.
-
-
또한 subgroupShuffleXor 호출의 경우 매개변수
mask는 다음 중 하나인 매개변수 태그를 가집니다.-
subgroup_uniformity가 지원되지 않거나 균일성 범위가 subgroup이면 다음을 수행합니다.
-
DF가 존재하면 S를 DF의 새 심각도 매개변수라고 합니다.
-
S가 심각도 off이면 매개변수 태그는 NoRestriction입니다.
-
그렇지 않으면 매개변수 태그는 ParameterRequiredToBeUniform.S이며 subgroup_uniformity 요소로 구성된 잠재적 트리거 집합을 가집니다.
-
-
그러한 DF가 없으면 매개변수 태그는 ParameterRequiredToBeUniform.error이며, subgroup_uniformity 요소로 구성된 잠재적 트리거 집합을 가집니다.
-
-
그렇지 않으면 NoRestriction.
-
-
참고: WGSL 구현체는 함수 호출 전의 제어 흐름이 특정 범위에서 균일하면 함수 호출 후에도 균일하도록 보장합니다.
15.2.8. 식에 대한 균일성 규칙
식을 분석하는 규칙은 식 자체와 식 시작 시점의 제어 흐름에 대응하는 노드 (아래에서는 "CF"로 표기)를 인수로 받아 다음을 반환합니다.
-
식의 값에 대응하는 노드
-
그래프에 추가할 새 노드와 에지의 집합
| 식 | 새 노드 | 재귀 분석 | 결과 값 노드 | 새 에지 |
|---|---|---|---|---|
| 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)와 동등합니다 |
| 함수 범위 변수 "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 |
다음 내장 입력 변수는 균일한 것으로 간주됩니다.
서브그룹 균일성 범위에서는 다음 내장 입력 변수도 균일한 것으로 간주됩니다.
다른 모든 변수(내장 값 참조)는 비균일한 것으로 간주됩니다.
참고: 분석은 복합 타입의 컴포넌트를 개별적으로 분석하지 않으므로, 작성자는 균일한 내장 값을 다른 비균일 입력과 함께 그룹화하지 않아야 합니다.
| 식 | 새 노드 | 재귀 분석 | 결과 변수 노드 | 새 에지 |
|---|---|---|---|---|
| 함수 범위 변수 "x"로 해석되는 식별자 | Result | X는 이 식을 포함하는 문장의 출력 시점에서 "x"의 값에 대응하는 노드입니다. | Result |
Result -> {CF, X}
참고: "x"에 대해 X는
Vin(next)와 동등합니다 |
| 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. 제어 흐름의 모든 지점에 균일성 주석 달기
이 하위 절 전체는 비규범적입니다.
구현자가 전체 셰이더 제어 흐름의 각 지점이 균일한지 여부 (따라서 해당 위치에서 균일성을 요구하는 함수를 호출하는 것이 유효한지 여부)를 보여 주는 진단 모드를 개발자에게 제공하려는 경우 다음 방법을 제안합니다.
-
모든 함수의 그래프를 유지하면서 이전 하위 절에 설명된 (필수 규범적) 분석을 실행합니다.
-
모든 그래프의 모든 에지를 반전합니다.
-
진입점부터 시작하여, 한 함수의 모든 호출자를 방문하기 전에는 해당 함수를 방문하지 않는 방식으로 각 함수를 순회합니다.
-
MayBeNonUniform에서 하나 이상의 호출자에서 비균일했던 모든 인수로 향하는 에지를 추가합니다.
-
하나 이상의 호출자에서 함수가 비균일 제어 흐름 중에 호출되었다면 MayBeNonUniform에서 CF_start로 향하는 에지를 추가합니다.
-
MayBeNonUniform에서 도달 가능한 노드를 확인합니다. 방문한 모든 노드는 분석을 통해 균일함을 입증할 수 없는 식 또는 제어 흐름의 지점입니다.
-
이러한 도달 가능성 분석에서 방문하지 않은 모든 노드는 분석을 통해 균일하다고 입증할 수 있습니다 (따라서 해당 위치에서 도함수 또는 유사한 함수를 호출해도 안전합니다).
참고: 상향식 분석은 호출을 만났을 때 그래프에 어떤 에지를 추가할지 알려 주므로 여전히 필요합니다.
15.2.10. 예제
후속 예제의 그래프에서는 노드에 대해 다음 규칙을 사용합니다.
-
직사각형은 값 노드를 나타냅니다.
-
둥근 직사각형은 제어 흐름 노드를 나타냅니다.
15.2.10.1.
유효하지 않은 textureSample 함수 호출
이 예제는 textureSample 내장 함수 호출의 유효하지 않은 사용을
보여 줍니다.
함수 호출은 조건이 비균일 값(즉, 내장 값 position)에 의존하는 if 문 내부에서
이루어집니다.
유효하지 않은 의존성 연쇄는 빨간색으로 강조됩니다.
@group ( 0 ) @binding ( 0 ) var t : texture_2d< f32> ; @group ( 0 ) @binding ( 1 ) var s : sampler; @fragment fn main ( @builtin ( position) pos : vec4< f32> ) { if ( pos . x < 0.5 ) { // 유효하지 않은 textureSample 함수 호출입니다. _ = textureSample ( t , s , pos . xy ); } }
이 예제는 if 문 이후의 제어 흐름 균일성이 if 문 이전의 균일성과 같다는 것도 보여 줍니다
(CF_return이 CF_start에 연결됨).
즉, 진입점 시작 시 균일 제어 흐름으로 시작한다고 보장되므로 if 문 이후에는 제어 흐름이 다시
균일해집니다.
textureSample 함수 호출을 if 문 외부로 옮겼다면 프로그램은 유효했을 것입니다.
마찬가지로 if 문의 조건이 균일 값이었다면(예: 각 호출이 유니폼 버퍼에서 같은 값을 읽는
경우) 프로그램은 유효했을 것입니다.
15.2.10.2. 함수 범위 변수 균일성
이 예제는 함수 범위 변수의 값에 의존하는 유효한
배리어 함수 호출과 유효하지 않은 호출을 모두 보여 줍니다.
x의 값이 가변 모듈 범위 변수 a에서 파생되므로
workgroupBarrier는 유효하지 않습니다.
x의 값이 불변 모듈 범위 변수 b에서 파생되므로
storageBarrier는 유효합니다.
이 예제는 함수 범위 변수의 수명에서 서로 다른 균일성 기간을 구분하는
값 분석의 능력을 강조합니다.
또한 이 예제는 첫 번째 if 문이 끝난 후 제어 흐름이
다시 균일해짐을 명확히 보여 줍니다.
그래프의 해당 부분이 두 번째 if 문과 독립적이므로 이를 알 수 있습니다.
@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. 복합 값 분석의 한계
균일성 분석의 한 가지 한계는 복합 값의 컴포넌트를 독립적으로 추적하지 않는다는 것입니다. 즉, 비균일한 컴포넌트 값이 하나라도 있으면 분석은 전체 복합 값을 비균일한 것으로 취급하게 됩니다. 이 예제는 이 문제와 셰이더 작성자가 이 한계를 피하기 위해 사용할 수 있는 잠재적 해결 방법을 보여 줍니다.
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으로 향하는 경로가 없다는 점에서 이를 확인할 수 있습니다.
@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)에
의존하는 에지로 반복 간 의존성을 모델링합니다.
@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으로 이어지는 전체
유효하지 않은 경로의
부분 경로입니다.
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 ); } }
참고: 하위 그래프는 이해하기 쉽도록 예제에만 포함되었습니다.
15.3. 컴퓨트 셰이더와 워크그룹
워크그룹은 컴퓨트 셰이더 스테이지 진입점을 동시에 실행하며 workgroup 주소 공간의 셰이더 변수에 대한 접근을 공유하는 호출 집합입니다.
컴퓨트 셰이더의 워크그룹 그리드는 다음을 만족하는 정수 좌표 (i,j,k)의 점 집합입니다.
-
0 ≤ i < workgroup_size_x
-
0 ≤ j < workgroup_size_y
-
0 ≤ k < workgroup_size_z
여기서 (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)의 점 집합입니다.
-
0 ≤ CSi < workgroup_size_x × group_count_x
-
0 ≤ CSj < workgroup_size_y × group_count_y
-
0 ≤ CSk < workgroup_size_z × group_count_z
여기서 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 0은 왼쪽 위 호출입니다.
-
ID 1은 오른쪽 위 호출입니다.
-
ID 2는 왼쪽 아래 호출입니다.
-
ID 3은 오른쪽 아래 호출입니다.
참고: 쿼드 ID에 대한 내장 값 접근자는 없습니다.
일반적으로 프래그먼트 처리는 래스터화로 생성된 각 RasterizationPoint에 대해 프래그먼트 셰이더 호출을 하나 생성합니다. 그래픽 프리미티브의 가장자리 등에서는 쿼드를 완전히 채우기에 RasterizationPoint가 부족할 수 있습니다. 쿼드에 RasterizationPoint에 대응하는 호출이 1개, 2개 또는 3개뿐이면 프래그먼트 처리는 쿼드에서 채워지지 않은 각 위치에 대해 보조 호출을 생성하게 됩니다.
보조 호출은 관찰 가능한 효과가 제한됩니다. 보조 호출은 도함수 계산을 돕고 서브그룹 연산에 참여할 수 있습니다. 따라서 보조 호출에는 다음 제한이 적용됩니다.
-
storage 또는 handle 주소 공간에 대한 쓰기 접근(§ 14.5.1 메모리 연산도 참조)은 수행되지 않습니다.
-
진입점 반환 값은 GPURenderPipeline의 후속 단계에서 더 이상 처리되지 않습니다.
쿼드의 모든 호출이 보조 호출이 되면(예: 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 도함수 내장 함수에 설명된 내장 함수로 계산됩니다.
-
dpdx, dpdxCoarse 및 dpdxFine은 x축 방향의 편도함수를 계산합니다.
-
dpdy, dpdyCoarse 및 dpdyFine은 y축 방향의 편도함수를 계산합니다.
-
fwidth, fwidthCoarse 및 fwidthFine은 연관된 x 및 y 편도함수에 대한 맨해튼 메트릭을 계산합니다.
인접한 호출이 도함수를 계산하기 위해 협력하므로 이러한 함수는 프래그먼트 셰이더의 균일 제어 흐름에서만 호출해야 합니다. 이러한 함수 중 하나를 호출할 때마다 균일성 분석에서 호출이 균일 제어 흐름 중에 발생함을 입증할 수 없으면 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 이진 부동 소수점 타입은 확장 실수 수직선을 다음과 같이 근사합니다.
-
타입에는 유한한 값 집합이 있으며 다음과 같은 구별되는 범주를 포함합니다.
-
양의 유리수와 음의 유리수.
-
NaN 값. "숫자가 아님(Not a Number)"의 약자인 NaN은 유효하지 않은 연산의 결과를 나타냅니다. IEEE-754는 오류 보고와 관련된 사례를 구분하기 위해 신호 NaN과 조용한 NaN을 모두 요구합니다. WGSL은 이러한 오류 보고를 요구하지 않으며 NaN 대신 불확정 값을 산출할 수 있습니다. § 15.7.2 IEEE-754와의 차이점을 참조하십시오.
-
-
타입은 다음을 포함하는 연산을 지원합니다.
-
타입에는 다음과 같은 특징을 가진 비트 표현이 있습니다.
-
고정된 비트 폭. 각 값의 비트 표현에는 최상위 비트부터 최하위 비트까지 다음과 같이 정렬된 세 개의 연속된 비트 필드가 있습니다.
-
1비트 부호 필드.
-
고정 폭 지수 필드.
-
고정 폭 후행 유효 숫자 필드.
-
-
지수 필드의 해석과 관련된 정숫값 지수 바이어스.
-
부동 소수점 타입의 유한 범위는 구간 [low, high]입니다. 여기서 low는 해당 타입에서 가장 낮은 유한 값이고 high는 해당 타입에서 가장 높은 유한 값입니다.
관심 대상인 IEEE-754 부동 소수점 타입은 다음과 같습니다.
-
binary16:
-
지수 필드 폭 5
-
후행 유효 숫자 필드 폭 10
-
지수 바이어스 15
-
유한 범위: [−65504, 65504]
-
-
binary32:
-
지수 필드 폭 8
-
후행 유효 숫자 필드 폭 23
-
지수 바이어스 127
-
유한 범위: [ − (2 − 2−23) × 2127, (2 − 2−23) × 2127 ], 또는 근사적으로 [ − 3.4028235 × 1038, 3.4028235 × 1038 ].
-
-
binary64:
-
지수 필드 폭 11
-
후행 유효 숫자 필드 폭 52
-
지수 바이어스 1023
-
유한 범위: [ − (2 − 2−52) × 21023, (2 − 2−52) × 21023 ], 또는 근사적으로 [ − 1.798 × 10308, 1.798 × 10308 ].
-
다음 알고리즘은 부동 소수점 값의 비트 표현을 그에 대응하는 확장 실수 값 또는 NaN으로 매핑합니다.
알고리즘: 부동 소수점 비트 해석입력: Bits, 이진 부동 소수점 타입 값의 비트 표현.
출력: F, Bits가 나타내는 부동 소수점 값.
절차:
bias를 해당 타입의 지수 바이어스라고 합니다.
tsw를 해당 타입의 후행 유효 숫자 필드의 비트 폭이라고 합니다.
Bits를 부호 필드, 지수 필드 및 후행 유효 숫자 필드로 분할합니다.
Sign, E 및 T를 각각 해당 필드를 부호 없는 정수로 해석한 값이라고 합니다.
지수 필드의 모든 비트가 1이면 다음과 같습니다.
Sign = 0이고 T = 0이면 결과 F = +∞입니다.
Sign = 1이고 T = 0이면 결과 F = −∞입니다.
T ≠ 0이면 결과 F는 NaN입니다.
그렇지 않고 지수 필드의 모든 비트가 0이면 다음과 같습니다.
결과 F = (− 1)Sign × 2−bias × T × 2−tsw+1입니다.
T = 0이면 값은 0입니다.
각 부동 소수점 타입에는 양의 0과 음의 0이 모두 있습니다. 음의 0은 부호 비트가
1인 0 값입니다. 음의 0과 양의 0은 비교 시 같은 값입니다. IEEE-754는 WGSL에 중요하지 않은 특정 경계 사례를 나타내기 위해 음의 0을 사용합니다.T ≠ 0이면 값 F는 비정규입니다. (비정규화는 비정규의 동의어입니다.)
그렇지 않으면 지수 필드는 모든 비트가 1인 것도 아니고 모든 비트가 0인 것도 아닙니다.
결과 F = (− 1)Sign × 2(E−bias) × ( 1 + T × 2−tsw)입니다.
값 F는 정규입니다.
부동 소수점 연산의 정의역은 연산이 잘 정의되는 확장 실수 입력의 집합입니다.
-
예를 들어 수학 함수 √의 정의역은 구간 [0,+∞]입니다. √는 0보다 작은 입력에 대해 잘 정의되지 않습니다.
-
연산을 그 정의역 내부에서 평가하면 연산은 무한 정밀도의 확장 실수 중간 결과를 기준으로 정의되며, 이 값은 반올림을 통해 부동 소수점 결과로 변환됩니다.
-
연산을 그 정의역 외부에서 평가하면 IEEE-754의 기본 예외 처리 규칙은 구현체가 예외를 생성하고 NaN 값을 산출하도록 요구합니다. 이와 달리 WGSL은 부동 소수점 예외를 의무화하지 않으며 대신 불확정 값을 산출할 수 있습니다. § 15.7.2 IEEE-754와의 차이점을 참조하십시오.
반올림은 확장 실수 값 x를 부동 소수점 타입의 값 x'로 매핑합니다. x가 부동 소수점 타입에 속하면 반올림은 x를 자기 자신으로 매핑합니다. x = x'. x가 해당 타입의 유한 범위 밖에 있으면 반올림에서 오버플로가 발생할 수 있습니다. 그렇지 않으면 x'는 x보다 큰 가장 낮은 부동 소수점 값 또는 x보다 작은 가장 높은 부동 소수점 값 중 하나이며, 반올림 모드가 어느 값을 선택할지 결정합니다.
일반적으로 NaN 입력이 있는 연산은 NaN 출력을 산출합니다. 예외는 다음과 같습니다.
-
NaN은 다른 어떤 부동 소수점 값과도 같거나, 작거나, 크지 않습니다. 이러한 비교는 false를 산출합니다.
IEEE-754는 다음 다섯 종류의 예외를 정의합니다.
-
유효하지 않은 연산. 연산의 정의역 밖에 있는 확장 실수 입력에 대해 연산을 평가할 때 발생합니다. 이러한 연산은 NaN을 산출합니다. 유효하지 않은 연산의 예로는 0 × +∞ 및
sqrt(−1)가 있습니다. -
0으로 나누기. 유한한 피연산자에 대한 연산이 정확한 무한 결과를 갖는 것으로 정의될 때 발생합니다. 예로는 1 ÷ 0 및 log(0)이 있습니다.
-
오버플로. 중간 결과가 타입의 유한 범위를 초과할 때 발생합니다. § 15.7.3 부동 소수점 반올림 및 오버플로를 참조하십시오.
-
부정확. 반올림된 결과가 중간 결과와 다르거나 오버플로가 발생할 때 발생합니다.
15.7.2. IEEE-754와의 차이점
WGSL은 IEEE-754 표준을 따르지만 다음과 같은 차이가 있습니다.
-
부동 소수점 값 x를 정수 타입으로 변환할 때는 먼저 x를 대상 타입의 값 범위로 제한합니다. § 15.7.6 부동 소수점 변환을 참조하십시오.
-
부동 소수점 예외는 생성되지 않습니다.
-
신호 NaN은 생성되지 않을 수 있습니다. 중간 계산에서 신호 NaN은 조용한 NaN으로 변환될 수 있습니다.
-
유한 수학 가정:
-
셰이더 실행 전에 생성된 오버플로, 무한대 및 NaN은 오류를 생성하게 됩니다.
-
유한 값에 대한 상수 식 및 오버라이드 식은 IEEE-754 규칙에 따라 중간 결과 값으로 오버플로, 무한대 및 NaN을 생성하게 됩니다.
-
참고: 이 규칙은 오류를 일관되게 생성할 수 있도록 구현체가 이러한 종류의 식에 대해 정확도 한계 내에서 오버플로, 무한대 및 NaN을 신뢰할 수 있게 감지하도록 요구합니다.
-
-
부동 소수점 타입의 상수 식에서 오버플로가 발생하거나 해당 식이 NaN 또는 무한대로 평가되면 셰이더 생성 오류가 발생합니다.
-
부동 소수점 타입의 오버라이드 식에서 오버플로가 발생하거나 해당 식이 NaN 또는 무한대로 평가되면 파이프라인 생성 오류가 발생합니다.
-
-
구현체는 셰이더 실행 중에는 오버플로, 무한대 및 NaN이 존재하지 않는다고 가정할 수 있습니다.
-
-
구현체는 부동 소수점 0 값의 부호 필드를 무시할 수 있습니다. 즉, 양의 부호를 가진 0은 음의 부호를 가진 0처럼 동작할 수 있으며 그 반대도 마찬가지입니다.
-
0으로 플러시한다는 것은 부동 소수점 타입의 비정규 값을 해당 타입의 0 값으로 대체하는 것입니다.
-
§ 15.7.4 부동 소수점 정확도에 나열된 연산의 모든 입력 또는 출력은 0으로 플러시될 수 있습니다.
-
또한 § 17.2 비트 재해석 내장 함수, § 17.9 데이터 패킹 내장 함수 또는 § 17.10 데이터 언패킹 내장 함수에 나열된 연산의 중간 결과 값은 0으로 플러시될 수 있습니다.
-
다른 연산은 비정규 수를 보존해야 합니다.
-
-
연산의 정확도는 § 15.7.4 부동 소수점 정확도에 제시되어 있습니다.
-
WGSL의 일부 내장 함수는 대응하는 IEEE-754 연산과 의미 체계가 다릅니다. 이러한 경우는 필요에 따라 WGSL 내장 함수의 정의에 나열됩니다.
예를 들어 WGSL § 17.5.32 fma 함수는 일반적인 곱셈 (반올림 단계 포함)과 덧셈(또 다른 반올림 단계 포함)으로 확장될 수 있지만, IEEE-754
fusedMultiplyAdd연산은 마지막 반올림 단계만 발생하도록 요구합니다.
15.7.3. 부동 소수점 반올림 및 오버플로
오버플로가 발생하는 계산은 무한대 또는 가장 가까운 유한 값으로 반올림될 수 있습니다. 결과는 오버플로가 발생한 중간 결과 값의 크기와 평가가 셰이더 모듈 생성, 파이프라인 생성 또는 셰이더 실행 중 어느 시점에 발생하는지에 따라 달라집니다.
부동 소수점 타입 T에 대해 MAX(T)를 T의 가장 큰 양의 유한 값으로 정의하고, 2EMAX(T)를 T로 표현할 수 있는 가장 큰 2의 거듭제곱으로 정의합니다. 특히 EMAX(f32) = 127이고, EMAX(f16) = 15입니다.
X를 부동 소수점 계산에서 얻은 무한 정밀도의 중간 결과라고 합니다. 식의 최종 값은 다음과 같이 중간 결과 값 X' 및 X''를 거치는 두 단계로 결정됩니다.
X에서 반올림을 통해 T의 X'를 계산합니다.
-
X가 T의 유한 범위에 있으면 X'는 X를 올림하거나 내림한 결과입니다.
-
X가 NaN이면 X'는 NaN입니다.
-
MAX(T) < X < 2EMAX(T)+1이면 두 반올림 방향 중 하나를 사용합니다. X'는 MAX(T) 또는 +∞입니다.
-
2EMAX(T)+1 ≤ X이면 X' = +∞입니다.
-
참고: 이 절은 IEEE-754 규칙과 일치합니다.
-
-
−MAX(T) > X > −2EMAX(T)+1이면 두 반올림 방향 중 하나를 사용합니다. X'는 −MAX(T) 또는 −∞입니다.
-
−2EMAX(T)+1 ≥ X이면 X' = −∞입니다.
-
참고: 이 절은 IEEE-754 규칙과 일치합니다.
-
X'에서 식의 최종 값 X''를 계산하거나 프로그램 오류를 감지합니다.
-
X'가 무한대 또는 NaN이면 유한 수학 가정에 따라 다음과 같이 처리합니다.
-
그렇지 않으면 X'' = X'입니다.
15.7.4. 부동 소수점 정확도
-
x가 T에 속하면 x,
-
그렇지 않으면 다음 중 하나입니다.
-
x보다 큰 T의 가장 작은 값, 또는
-
x보다 작은 T의 가장 큰 값.
-
즉, 결과는 올림 또는 내림으로 반올림될 수 있습니다. WGSL은 반올림 모드를 지정하지 않습니다.
참고: 부동 소수점 타입에는 양의 무한대와 음의 무한대가 포함되므로 정확히 반올림된 결과는 유한하거나 무한할 수 있습니다.
참고: 무한한 정밀도로 계산한 연산 결과에는
배정밀도를 초과하는 정밀도가 필요할 수 있습니다.
이러한 사례의 예로 x=1.0 이고 y=1.17e-38(가장 작은 양의 정규
단정밀도 부동 소수점 수)인 x - y가 있습니다.
이 숫자들의 지수는 126만큼 떨어져 있습니다. IEEE-754
binary64(배정밀도) 형식의 유효
숫자에는 52비트만 있으므로
뺄셈을 수행할 때 y의 모든 유효 비트가 손실됩니다.
반올림 모드에 따라 이 사례와 y가 작지만 0이 아닌 여러 다른 사례에서 WGSL 식
x - y는 x와 같은 값을 산출할 수 있습니다.
[ECMASCRIPT]는 IEEE-754
roundTiesToEven 반올림 모드와 동등한 방식을 사용한다는 점에 유의하십시오.
부동 소수점 수 x의 최하위 자리 단위인
ULP는 다음과 같이
정의됩니다 [Muller2005].
-
x가 부동 소수점 타입의 유한 범위에 있으면 ULP(x)는a≤x≤b를 만족하는 서로 같지 않은 두 유한 부동 소수점 수a와b사이의 최소 거리입니다 (즉,ulp(x) = mina,b|b - a|). -
그렇지 않으면 ULP(x)는
|b - a|입니다. 여기서b와a는 표현 가능한 유한 부동 소수점 값 중 각각 가장 큰 값과 두 번째로 큰 값입니다.
연산의 정확도는 다음 다섯 가지 중 하나로 제시됩니다.
-
정확한 결과(부동 소수점이 아닌 결과 값의 경우).
-
절대 오차 한계.
-
ULP로 표현된 상대 오차 한계.
-
정확도를 상속하는 원본 식. 즉, 연산의 정확도는 주어진 WGSL 식을 평가한 정확도로 정의됩니다. 주어진 식은 해당 함수의 유효한 구현 중 하나일 뿐입니다.
상속 원본 식을 평가할 때 하위 식 평가는 반올림, 오버플로, 재결합, 융합 및 0으로 플러시에 관한 규칙을 포함하여 부동 소수점 평가에 대한 다른 규칙의 적용을 받습니다.
WebGPU 구현체는 더 높은 정확도 또는 극단적인 입력에 대한 더 큰 허용 범위를 갖도록 연산을 다르게 구현할 수 있습니다.
연산의 정확도가 입력 범위에 대해 지정된 경우 해당 범위 밖의 입력 값에 대해서는 정확도가 정의되지 않습니다.
허용되는 결과가 결과 타입의 유한 범위 밖에 있으면 § 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)
|
다음 중 더 나쁜 값:
|
다음 중 더 나쁜 값:
|
acosh(x)
| log(x + sqrt(x * x - 1.0))에서 상속됨
| |
asin(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)
|
정확히 반올림됨.
무한 정밀도의 결과는
| |
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는 부동 소수점 수학을 사용하며 determinant의 GPU 구현은 오버플로와 오차에 대한 견고성보다 속도와 단순성을 선호합니다. 예를 들어 단순한 2x2 행렬식 계산
( 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에서 도함수는 서로 다른 호출의 값 사이의 차이
( 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)
|
정확히 반올림됨
| |
min(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)
|
다음 중 더 나쁜 값:
| |
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 연산의 정확도는 다음과 같습니다.
-
대응하는 f32 연산에서 정확한 결과를 요구하면 정확한 결과가 필요합니다.
-
fract(x)의 오차는x - floor(x)에서 상속되며, 중간 계산은 AbstractFloat 연산으로 수행됩니다. -
그렇지 않으면 대응하는 f32 연산의 오차는 절대 오차, 상대 오차, 잠재적 구현에서 상속되는 오차 또는 이들의 조합입니다. 이 경우 AbstractFloat의 오차는 제한되지 않습니다.
-
그러나 AbstractFloat 연산의 오차는 절댓값 기준으로 대응하는 f32 연산의 오차 이하여야 합니다.
-
이 권장 사항은 예상 밖의 결과를 방지하기 위한 것입니다. 식의 타입을 f32에서 AbstractFloat로 변경할 때 정확도가 감소해서는 안 됩니다.
-
연산은 WebAssembly [WASM-CORE-2] 또는 ECMAScript [ECMASCRIPT] 환경에서 평가될 수 있으며, 이러한 사양은 대응하는 여러 숫자 계산에 대한 오차 한계를 지정하지 않습니다. 예를 들어 ECMAScript는 여러 부동 소수점 연산을 구현 근사 방식으로 지정합니다. 구현체에는 이상적인 결과를 근사하기 위해 노력할 것이 권장되지만 엄격한 요구 사항은 지정되지 않습니다.
-
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. 재결합 및 융합
재결합은 정확하게 계산했을 때 답이 같도록 식의 연산 순서를 변경하는 것입니다. 예를 들면 다음과 같습니다.
-
(a + b) + c는a + (b + c)로 재결합됩니다 -
(a - b) + c는(a + c) - b로 재결합됩니다 -
(a * b) / c는(a / c) * b로 재결합됩니다
그러나 부동 소수점으로 계산하면 결과가 같지 않을 수 있습니다. 재결합된 결과는 근사로 인해 부정확할 수 있으며, 중간 결과를 계산할 때 오버플로 또는 NaN을 트리거할 수 있습니다.
구현체는 연산을 재결합할 수 있습니다.
변환된 식이 원래 공식만큼 정확하다면 구현체는 연산을 융합할 수 있습니다. 예를 들어 일부 융합 곱셈-덧셈 구현은 곱셈 후 덧셈을 수행하는 것보다 더 정확할 수 있습니다.
15.7.6. 부동 소수점 변환
이 절에서는 출발지 또는 목적지 중 하나가 부동 소수점 타입인 스칼라 변환의 세부 사항을 설명합니다.
이 절에서 부동 소수점 타입은 다음 중 하나일 수 있습니다.
-
WGSL의 f32, f16 및 AbstractFloat 타입.
-
IEEE-754 부동 소수점 표준에서 정의한 이진 형식에 대응하는 가상 타입.
참고: WGSL의 f32 타입은 IEEE-754 binary32 형식에 대응하고, WGSL의 f16 타입은 IEEE-754 binary16 형식에 대응한다는 점을 기억하십시오.
스칼라 부동 소수점에서 정수로 변환 알고리즘은 다음과 같습니다.
부동 소수점 스칼라 값 X를 정수 스칼라 타입 T로 변환하려면 다음을 수행합니다.
참고: 즉, NaN이 아닌 경우 부동 소수점에서 정수로 변환할 때는 값을 대상 타입의 범위 내로 제한한 다음 0을 향해 반올림합니다. 이 제한 요구 사항은 WGSL이 의미 있는 결과를 의무화하지만 C와 C++에서는 정의되지 않은 동작을 산출하고 IEEE-754에서는 유효하지 않은 연산 예외와 NaN 결과를 의무화하는 사례 중 하나입니다.
-
3.9f를 u32로 변환하면 3u입니다
-
-1f를 u32로 변환하면 0u입니다
-
1e20f를 u32로 변환하면 u32에서 표현할 수 있는 가장 큰 부동 소수점 값인 4294967040u입니다
-
이는 최대 u32 값인 4294967295u보다 작다는 점에 유의하십시오
-
-3.9f를 i32로 변환하면 -3i입니다
-
1e20f를 i32로 변환하면 최대 i32 값인 2147483520i입니다
-
이는 최대 i32 값인 2147483647i보다 작다는 점에 유의하십시오
-
-1e20f를 i32로 변환하면 최소 i32 값인 i32(-2147483648)입니다
숫자 스칼라에서 부동 소수점으로 변환 알고리즘은 다음과 같습니다.
알고리즘: 부동 소수점으로의 숫자 스칼라 변환입력:
X, 타입이 S인 숫자 스칼라 값
T, 목적지 부동 소수점 타입.
출력: XOut, X를 타입 T로 변환한 결과. 또는 오류를 생성합니다.
절차:
X가 출발지 타입 S의 NaN이면 XOut은 타입 T의 NaN입니다.
X를 목적지 타입 T로 정확히 표현할 수 있으면 XOut은 X와 같은 T의 값입니다.
그렇지 않으면 X를 T로 정확히 표현할 수 없습니다.
X가 T의 인접한 두 유한 값 사이에 있으면 XOut은 두 값 중 하나입니다. WGSL은 표현 가능한 두 값 중 높은 값과 낮은 값 가운데 어느 것을 선택하는지 지정하지 않으며, 이러한 변환의 서로 다른 인스턴스에서 서로 다르게 선택할 수 있습니다.
그렇지 않으면 X는 목적지 타입의 유한 범위 밖에 있습니다.
X에 대한 식이 오버라이드 식이면 파이프라인 생성 오류가 발생합니다.
그렇지 않으면 변환은 다음과 같이 진행됩니다.
X'를 원래 값 X로 설정합니다.
출발지 타입 S가 목적지 타입 T보다 유효 숫자 비트가 많은 부동 소수점 타입이면 출발지 값 X의 추가 유효 숫자 비트를 폐기할 수 있습니다(즉, 해당 비트를 0인 것처럼 취급할 수 있습니다). 이에 따라 X'를 갱신합니다.
X'가 목적지 타입 T의 가장 큰 양의 유한 값 또는 가장 작은 음의 유한 값이면 XOut = X'로 설정합니다.
그렇지 않으면 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]에서
상속됩니다.
이 식은 두 번의 부동 소수점 곱셈과 한 번의 부동 소수점 덧셈을 사용합니다.
-
부동 소수점 곱셈은 한 피연산자가 0이고 다른 피연산자가 무한대인 경우를 제외하면 확장 실수 전체에서 잘 정의됩니다.
-
부동 소수점 덧셈은 두 피연산자가 서로 반대 부호의 무한대인 경우를 제외하면 잘 정의됩니다.
-
따라서 정의역은 다음 경우를 제외한 확장 실수 2요소 벡터 a와 b의 모든 쌍입니다.
-
곱셈에서 암시되는 경우:
-
a[i]가 0이고 b[i]가 무한대입니다.
-
a[i]가 무한대이고 b[i]가 0입니다.
-
-
덧셈에서 암시되는 경우:
-
a[0] × b[0]이 +∞이고 a[1] × b[1]이 +∞입니다
-
a[0] × b[0]이 −∞이고 a[1] × b[1]이 −∞입니다
-
-
16. 키워드 및 토큰 요약
16.1. 키워드 요약
-
alias -
break -
case -
const -
const_assert -
continue -
continuing -
default -
diagnostic -
discard -
else -
enable -
false -
fn -
for -
if -
let -
loop -
override -
requires -
return -
struct -
switch -
true -
var -
while
16.2. 예약어
예약어는 향후 사용을 위해 예약된 토큰입니다. WGSL 모듈에는 예약어가 포함되어서는 안 됩니다.
다음은 예약어입니다.
| '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. 구문 토큰
구문 토큰은 다음 용도로 사용하는 특수 코드 포인트의 시퀀스입니다.
-
식 연산자를 표기하거나,
-
다른 문법 요소를 그룹화하거나 순서대로 배열하거나 구분하는 문장 부호로 사용합니다.
구문 토큰은 다음과 같습니다.
-
'&'(코드 포인트:U+0026) -
'&&'(코드 포인트:U+0026U+0026) -
'->'(코드 포인트:U+002DU+003E) -
'@'(코드 포인트:U+0040) -
'/'(코드 포인트:U+002F) -
'!'(코드 포인트:U+0021) -
'['(코드 포인트:U+005B) -
']'(코드 포인트:U+005D) -
'{'(코드 포인트:U+007B) -
'}'(코드 포인트:U+007D) -
':'(코드 포인트:U+003A) -
','(코드 포인트:U+002C) -
'='(코드 포인트:U+003D) -
'=='(코드 포인트:U+003DU+003D) -
'!='(코드 포인트:U+0021U+003D) -
'>'(코드 포인트:U+003E) (템플릿 모호성 해소를 위한_greater_than도 있음) -
'>='(코드 포인트:U+003EU+003D) (템플릿 모호성 해소를 위한_greater_than_equal도 있음) -
'>>'(코드 포인트:U+003EU+003E) (템플릿 모호성 해소를 위한_shift_right도 있음) -
'<'(코드 포인트:U+003C) (템플릿 모호성 해소를 위한_less_than도 있음) -
'<='(코드 포인트:U+003CU+003D) (템플릿 모호성 해소를 위한_less_than_equal도 있음) -
'<<'(코드 포인트:U+003CU+003C) (템플릿 모호성 해소를 위한_shift_left도 있음) -
'%'(코드 포인트:U+0025) -
'-'(코드 포인트:U+002D) -
'--'(코드 포인트:U+002DU+002D) -
'.'(코드 포인트:U+002E) -
'+'(코드 포인트:U+002B) -
'++'(코드 포인트:U+002BU+002B) -
'|'(코드 포인트:U+007C) -
'||'(코드 포인트:U+007CU+007C) -
'('(코드 포인트:U+0028) -
')'(코드 포인트:U+0029) -
';'(코드 포인트:U+003B) -
'*'(코드 포인트:U+002A) -
'~'(코드 포인트:U+007E) -
'_'(코드 포인트:U+005F) -
'^'(코드 포인트:U+005E) -
'+='(코드 포인트:U+002BU+003D) -
'-='(코드 포인트:U+002DU+003D) -
'*='(코드 포인트:U+002AU+003D) -
'/='(코드 포인트:U+002FU+003D) -
'%='(코드 포인트:U+0025U+003D) -
'&='(코드 포인트:U+0026U+003D) -
'|='(코드 포인트:U+007CU+003D) -
'^='(코드 포인트:U+005EU+003D) -
'>>='(코드 포인트:U+003EU+003EU+003D) (템플릿 모호성 해소를 위한_shift_right_assign도 있음) -
'<<='(코드 포인트:U+003CU+003CU+003D) (템플릿 모호성 해소를 위한_shift_left_assign도 있음) -
_template_args_end-
텍스트:
'>'(코드 포인트:U+003E) -
이 토큰은 텍스트상 greater_than 구문 토큰과 같습니다.
-
이 토큰은 템플릿 목록 모호성 해소 과정에서 생성되며 템플릿 목록의 마지막 토큰으로 사용됩니다.
-
-
_template_args_start-
텍스트:
'<'(코드 포인트:U+003C) -
이 토큰은 텍스트상 less_than 구문 토큰과 같습니다.
-
이 토큰은 템플릿 목록 모호성 해소 과정에서 생성되며 템플릿 목록의 첫 번째 토큰으로 사용됩니다.
-
-
_disambiguate_template-
텍스트: 없음
-
§ 3.1 구문 분석에 제시된 표준 파서 공식에서 이 토큰은 아무 역할도 하지 않으며 사실상 무시됩니다. 이를 무시하기 위해 스캐너는 항상 이 토큰을 빈 문자열과 성공적으로 일치시킵니다.
-
§ 3.1 구문 분석에 제시된 대체 구문 분석 공식에서 이 토큰은 해당 절에 설명된 대로 스캐너가 요청 시 템플릿 목록 검색을 수행하도록 트리거합니다.
-
17. 내장 함수
일부 함수는 구현체에서 제공하는 미리 선언된 함수이므로 WGSL 모듈에서 언제나 사용할 수 있습니다. 이러한 함수를 내장 함수라고 합니다.
내장 함수는 모두 같은 이름을 갖지만 형식 매개변수의 개수, 순서 및 타입으로 구분되는 함수 패밀리입니다. 이러한 서로 다른 함수 변형 각각은 오버로드입니다.
참고: 각 사용자 정의 함수에는 오버로드가 하나만 있습니다.
각 오버로드는 아래에서 다음 항목을 통해 설명됩니다.
내장 함수를 호출할 때 함수의 모든 인수는 함수 평가가 시작되기 전에 평가됩니다. § 11.2 함수 호출을 참조하십시오.
17.1. 생성자 내장 함수
값 생성자 내장 함수는 주어진 타입의 값을 명시적으로 생성합니다.
WGSL은 모든 미리 선언된 타입과 모든 생성 가능 구조체 타입에 값 생성자를 제공합니다. 이러한 생성자 내장 함수의 철자는 타입 또는 해당 타입의 타입 별칭과 같습니다. 이러한 내장 함수를 사용하는 모든 위치에서 식별자는 타입 또는 타입 별칭의 범위 내에 있어야 하며, 식별자는 다른 선언으로 해석되어서는 안 됩니다.
참고: frexp, modf 및 atomicCompareExchangeWeak가 반환하는 구조체 타입은 WGSL 모듈에 작성할 수 없습니다.
참고: 해당 타입의 값 선언은 WGSL 텍스트의 그 문장에서 유효해야 합니다.
WGSL은 두 종류의 값 생성자를 제공합니다.
17.1.1. 0 값 내장 함수
각 구체 생성 가능 타입 T에는 고유한
0 값과,
WGSL에서 타입 뒤에 빈 괄호 쌍을 붙여 작성하는 대응 내장 함수
T ()가 있습니다.
추상 숫자 타입에도 0
값이 있지만 이에 접근하는
내장 함수는 없습니다.
0 값은 다음과 같습니다.
-
bool()은false입니다 -
i32()는 0i입니다 -
u32()는 0u입니다 -
f32()는 0.0f입니다 -
f16()는 0.0h입니다 -
타입이 T인 N개 컴포넌트 벡터의 0 값은 T의 0 값으로 구성된 N개 컴포넌트 벡터입니다.
-
타입이 T인 C열 R행 행렬의 0 값은 해당 차원을 가지며 T의 0 값으로 채워진 행렬입니다.
-
요소 타입이 E인 생성 가능 N요소 배열의 0 값은 E의 0 값으로 구성된 N요소 배열입니다.
-
생성 가능 구조체 타입 S의 0 값은 멤버가 0 값인 구조체 값 S입니다.
-
AbstractInt의 0 값은 0입니다.
-
AbstractFloat의 0 값은 0.0입니다.
참고: WGSL에는 원자 타입, 런타임 크기 배열, 버퍼 또는 기타 생성 가능하지 않은 타입을 위한 0 내장 함수가 없습니다.
| 오버로드 |
|
| 매개변수화 | T는 구체 생성 가능 타입입니다. |
| 설명 | 타입 T의 0 값을
생성합니다.
|
참고: AbstractInt의 0으로 채워진 벡터는
vec2(), vec3() 및 vec4()로 작성할 수 있습니다.
vec2< f32> () // 두 f32 컴포넌트로 구성된 0 값 벡터입니다. vec2< f32> ( 0.0 , 0.0 ) // 같은 값을 명시적으로 작성했습니다. vec3< i32> () // 세 i32 컴포넌트로 구성된 0 값 벡터입니다. vec3< i32> ( 0 , 0 , 0 ) // 같은 값을 명시적으로 작성했습니다.
array< bool, 2 > () // 두 불리언으로 구성된 0 값 배열입니다. array< bool, 2 > ( false , false ) // 같은 값을 명시적으로 작성했습니다.
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
| 오버로드 |
|
| 매개변수화 | T는 구체이고 생성 가능합니다
|
| 설명 |
요소로 배열을
생성합니다.
참고: array<T,N>의 요소 수는 생성자 인수의 수와 같아 셰이더 생성 시점에 완전히 결정되므로 생성 가능합니다. |
| 오버로드 |
|
| 매개변수화 | T는 생성
가능합니다
|
| 설명 |
요소로 배열을
생성합니다.
컴포넌트 타입은 요소의 타입에서 추론됩니다. 배열의 크기는 요소 수로 결정됩니다. |
17.1.2.2. bool
| 오버로드 |
|
| 매개변수화 | T는 스칼라 타입입니다.
|
| 설명 |
bool 값을 생성합니다.
|
17.1.2.3. f16
| 오버로드 |
|
| 매개변수화 | T는 스칼라 타입입니다
|
| 설명 |
f16 값을 생성합니다.
|
17.1.2.4. f32
| 오버로드 |
|
| 매개변수화 | T는 구체 스칼라 타입입니다
|
| 설명 |
f32 값을 생성합니다.
|
17.1.2.5. i32
| 오버로드 |
|
| 매개변수화 | T는 스칼라 타입입니다
|
| 설명 |
i32 값을 생성합니다.
|
17.1.2.6. mat2x2
| 오버로드 |
|
| 매개변수화 | T는 f16 또는 f32입니다S는 AbstractFloat, f16 또는 f32입니다
|
| 설명 |
2x2 열 우선 행렬의 생성자입니다.
|
| 오버로드 |
|
| 매개변수화 | T는 AbstractFloat, f16 또는 f32입니다
|
| 설명 | 열 벡터로 2x2 열 우선 행렬을 생성합니다. |
| 오버로드 |
|
| 매개변수화 | T는 AbstractFloat, f16 또는 f32입니다
|
| 설명 |
요소로 2x2 열 우선 행렬을 생성합니다.
mat2x2(vec2(e1,e2), vec2(e3,e4))와 같습니다. |
17.1.2.7. mat2x3
| 오버로드 |
|
| 매개변수화 | T는 f16 또는 f32입니다S는 AbstractFloat, f16 또는 f32입니다
|
| 설명 |
2x3 열 우선 행렬의 생성자입니다.
|
| 오버로드 |
|
| 매개변수화 | T는 AbstractFloat, f16 또는 f32입니다
|
| 설명 | 열 벡터로 2x3 열 우선 행렬을 생성합니다. |
| 오버로드 |
|
| 매개변수화 | T는 AbstractFloat, f16 또는 f32입니다
|
| 설명 |
요소로 2x3 열 우선 행렬을 생성합니다.
mat2x3(vec3(e1,e2,e3), vec3(e4,e5,e6))와 같습니다. |
17.1.2.8. mat2x4
| 오버로드 |
|
| 매개변수화 | T는 f16 또는 f32입니다S는 AbstractFloat, f16 또는 f32입니다
|
| 설명 |
2x4 열 우선 행렬의 생성자입니다.
|
| 오버로드 |
|
| 매개변수화 | T는 AbstractFloat, f16 또는 f32입니다
|
| 설명 | 열 벡터로 2x4 열 우선 행렬을 생성합니다. |
| 오버로드 |
|
| 매개변수화 | T는 AbstractFloat, f16 또는 f32입니다
|
| 설명 |
요소로 2x4 열 우선 행렬을 생성합니다.
mat2x4(vec4(e1,e2,e3,e4), vec4(e5,e6,e7,e8))와 같습니다. |
17.1.2.9. mat3x2
| 오버로드 |
|
| 매개변수화 | T는 f16 또는 f32입니다S는 AbstractFloat, f16 또는 f32입니다
|
| 설명 |
3x2 열 우선 행렬의 생성자입니다.
|
| 오버로드 |
|
| 매개변수화 | T는 AbstractFloat, f16 또는 f32입니다
|
| 설명 | 열 벡터로 3x2 열 우선 행렬을 생성합니다. |
| 오버로드 |
|
| 매개변수화 | T는 AbstractFloat, f16 또는 f32입니다
|
| 설명 |
요소로 3x2 열 우선 행렬을 생성합니다.
mat3x2(vec2(e1,e2), vec2(e3,e4), vec2(e5,e6))와 같습니다. |
17.1.2.10.
mat3x3
| 오버로드 |
|
| 매개변수화 | T는 f16 또는 f32입니다S는 AbstractFloat, f16 또는 f32입니다
|
| 설명 |
3x3 열 우선 행렬의 생성자입니다.
|
| 오버로드 |
|
| 매개변수화 | T는 AbstractFloat, f16 또는 f32입니다
|
| 설명 | 열 벡터로 3x3 열 우선 행렬을 생성합니다. |
| 오버로드 |
|
| 매개변수화 | T는 AbstractFloat, f16 또는 f32입니다
|
| 설명 |
요소로 3x3 열 우선 행렬을 생성합니다.
mat3x3(vec3(e1,e2,e3), vec3(e4,e5,e6), vec3(e7,e8,e9))와 같습니다. |
17.1.2.11.
mat3x4
| 오버로드 |
|
| 매개변수화 | T는 f16 또는 f32입니다S는 AbstractFloat, f16 또는 f32입니다
|
| 설명 |
3x4 열 우선 행렬의 생성자입니다.
|
| 오버로드 |
|
| 매개변수화 | T는 AbstractFloat, f16 또는 f32입니다
|
| 설명 | 열 벡터로 3x4 열 우선 행렬을 생성합니다. |
| 오버로드 |
|
| 매개변수화 | 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
| 오버로드 |
|
| 매개변수화 | T는 f16 또는 f32입니다S는 AbstractFloat, f16 또는 f32입니다
|
| 설명 |
4x2 열 우선 행렬의 생성자입니다.
|
| 오버로드 |
|
| 매개변수화 | T는 AbstractFloat, f16 또는 f32입니다
|
| 설명 | 열 벡터로 4x2 열 우선 행렬을 생성합니다. |
| 오버로드 |
|
| 매개변수화 | T는 AbstractFloat, f16 또는 f32입니다
|
| 설명 |
요소로 4x2 열 우선 행렬을 생성합니다.
mat4x2(vec2(e1,e2), vec2(e3,e4), vec2(e5,e6), vec2(e7,e8))와 같습니다. |
17.1.2.13.
mat4x3
| 오버로드 |
|
| 매개변수화 | T는 f16 또는 f32입니다S는 AbstractFloat, f16 또는 f32입니다
|
| 설명 |
4x3 열 우선 행렬의 생성자입니다.
|
| 오버로드 |
|
| 매개변수화 | T는 AbstractFloat, f16 또는 f32입니다
|
| 설명 | 열 벡터로 4x3 열 우선 행렬을 생성합니다. |
| 오버로드 |
|
| 매개변수화 | 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
| 오버로드 |
|
| 매개변수화 | T는 f16 또는 f32입니다S는 AbstractFloat, f16 또는 f32입니다
|
| 설명 |
4x4 열 우선 행렬의 생성자입니다.
|
| 오버로드 |
|
| 매개변수화 | T는 AbstractFloat, f16 또는 f32입니다
|
| 설명 | 열 벡터로 4x4 열 우선 행렬을 생성합니다. |
| 오버로드 |
|
| 매개변수화 | 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. 구조체
| 오버로드 |
|
| 매개변수화 | S는 타입이 T1 ... TN인 멤버를 가진 생성 가능 구조체 타입입니다.
|
| 설명 | 멤버로 타입 S의 구조체를 생성합니다.
|
17.1.2.16. u32
| 오버로드 |
|
| 매개변수화 | T는 스칼라 타입입니다
|
| 설명 |
u32 값을 생성합니다.
|
|
참고: AbstractInt의
오버로드는 |
17.1.2.17. vec2
| 오버로드 |
|
| 매개변수화 | T는 구체 스칼라입니다S는 스칼라입니다
|
| 설명 | e를 두 컴포넌트 모두로 사용하는 2컴포넌트 벡터를 생성합니다.
|
| 오버로드 |
|
| 매개변수화 | T는 구체 스칼라입니다S는 스칼라입니다
|
| 설명 |
e.x와 e.y를 컴포넌트로 사용하는 2컴포넌트 벡터를 컴포넌트별로 생성합니다.
|
| 오버로드 |
|
| 매개변수화 | T는 스칼라입니다
|
| 설명 | e1과 e2를 컴포넌트로 사용하는 2컴포넌트 벡터를 컴포넌트별로 생성합니다.
|
| 오버로드 |
|
| 매개변수화 | T는 AbstractInt입니다
|
| 설명 | vec2(0,0) 값을 반환합니다.
|
17.1.2.18. vec3
| 오버로드 |
|
| 매개변수화 | T는 구체 스칼라입니다S는 스칼라입니다
|
| 설명 | e를 모든 컴포넌트로 사용하는 3컴포넌트 벡터를 생성합니다.
|
| 오버로드 |
|
| 매개변수화 | T는 구체 스칼라입니다S는 스칼라입니다
|
| 설명 |
e.x, e.y, e.z를 컴포넌트로 사용하는 3컴포넌트
벡터를 컴포넌트별로 생성합니다.
|
| 오버로드 |
|
| 매개변수화 | T는 스칼라입니다
|
| 설명 | e1, e2, e3를 컴포넌트로 사용하는 3컴포넌트
벡터를 컴포넌트별로 생성합니다.
|
| 오버로드 |
|
| 매개변수화 | T는 스칼라입니다
|
| 설명 | v1.x, v1.y, e1을 컴포넌트로 사용하는 3컴포넌트
벡터를 컴포넌트별로 생성합니다.
|
| 오버로드 |
|
| 매개변수화 | T는 스칼라입니다
|
| 설명 | e1, v1.x, v1.y를 컴포넌트로 사용하는 3컴포넌트
벡터를 컴포넌트별로 생성합니다.
|
| 오버로드 |
|
| 매개변수화 | T는 AbstractInt입니다
|
| 설명 | vec3(0,0,0) 값을 반환합니다.
|
17.1.2.19. vec4
| 오버로드 |
|
| 매개변수화 | T는 구체 스칼라입니다S는 스칼라입니다
|
| 설명 | e를 모든 컴포넌트로 사용하는 4컴포넌트 벡터를 생성합니다.
|
| 오버로드 |
|
| 매개변수화 | T는 구체 스칼라입니다S는 스칼라입니다
|
| 설명 |
e.x, e.y, e.z, e.w를 컴포넌트로
사용하는 4컴포넌트 벡터를 컴포넌트별로 생성합니다.
|
| 오버로드 |
|
| 매개변수화 | T는 스칼라입니다
|
| 설명 | e1, e2, e3, e4를 컴포넌트로 사용하는
4컴포넌트 벡터를
컴포넌트별로 생성합니다.
|
| 오버로드 |
|
| 매개변수화 | T는 스칼라입니다
|
| 설명 | e1, v1.x, v1.y, e2를 컴포넌트로
사용하는 4컴포넌트 벡터를 컴포넌트별로 생성합니다.
|
| 오버로드 |
|
| 매개변수화 | T는 스칼라입니다
|
| 설명 | e1, e2, v1.x, v1.y를 컴포넌트로
사용하는 4컴포넌트 벡터를 컴포넌트별로 생성합니다.
|
| 오버로드 |
|
| 매개변수화 | T는 스칼라입니다
|
| 설명 | v1.x, v1.y, v2.x, v2.y를 컴포넌트로
사용하는 4컴포넌트 벡터를 컴포넌트별로 생성합니다.
|
| 오버로드 |
|
| 매개변수화 | T는 스칼라입니다
|
| 설명 | 컴포넌트별로
v1.x, v1.y,
e1, e2를 컴포넌트로 사용하는 4컴포넌트 벡터를 생성합니다.
|
| 오버로드 |
|
| 매개변수화 | T는 스칼라입니다
|
| 설명 | 컴포넌트별로
v1.x, v1.y,
v1.z, e1을 컴포넌트로 사용하는 4컴포넌트 벡터를 생성합니다.
|
| 오버로드 |
|
| 매개변수화 | T는 스칼라입니다
|
| 설명 | 컴포넌트별로
e1, v1.x,
v1.y, v1.z를 컴포넌트로 사용하는 4컴포넌트 벡터를 생성합니다.
|
| 오버로드 |
|
| 매개변수화 | T는 AbstractInt입니다
|
| 설명 | vec4(0,0,0,0) 값을 반환합니다.
|
17.2. 비트 재해석 내장 함수
17.2.1. bitcast
bitcast 내장 함수는 한 타입 값의 비트 표현을 다른 타입의 값으로
재해석하는 데 사용됩니다.
내부 레이아웃 규칙은 § 14.4.4 값의 내부 레이아웃에 설명되어 있습니다.
| 오버로드 |
|
| 매개변수화 | T는 구체 숫자 스칼라 또는 구체 숫자 벡터입니다
|
| 설명 | 항등 변환입니다.T가 벡터이면 컴포넌트별입니다.결과는 e입니다.
|
| 오버로드 |
|
| 매개변수화 | S는 i32, u32 또는 f32입니다T는 S가 아니며 i32, u32 또는 f32입니다
|
| 설명 | 비트를 T로 재해석합니다.결과는 e의 비트를 T 값으로 재해석한 것입니다.
|
| 오버로드 |
|
| 매개변수화 | S는 i32, u32 또는 f32입니다T는 S가 아니며 i32, u32 또는 f32입니다
|
| 설명 | 비트를 T로 컴포넌트별 재해석합니다.결과는 e의 비트를 vecN<T> 값으로 재해석한 것입니다.
|
| 오버로드 |
|
| 매개변수화 | |
| 설명 |
e를 u32로 표현할 수 있으면 항등
연산이고,
그렇지 않으면 셰이더 생성 오류를 생성합니다.
즉, u32(e)와 같은 결과를 생성합니다.
|
| 오버로드 |
|
| 매개변수화 | T는 i32, u32 또는 f32입니다
|
| 설명 | 비트를 T로 컴포넌트별 재해석합니다.결과는 내부 레이아웃 규칙에 따라 e의 32비트를 T 값으로
재해석한 것입니다.
|
| 오버로드 |
|
| 매개변수화 | T는 i32, u32 또는 f32입니다 |
| 설명 | 비트를 T로 컴포넌트별 재해석합니다.결과는 내부 레이아웃 규칙에 따라 e의 64비트를 T 값으로
재해석한 것입니다.
|
| 오버로드 |
|
| 매개변수화 | T는 i32, u32 또는 f32입니다
|
| 설명 | 비트를 f16으로 컴포넌트별
재해석합니다. 결과는 내부 레이아웃 규칙에 따라 e의 32비트를 f16 값으로 재해석한 것입니다.
|
| 오버로드 |
|
| 매개변수화 | T는 i32, u32 또는 f32입니다
|
| 설명 | 비트를 vec2<f16>으로 컴포넌트별 재해석합니다.결과는 내부 레이아웃 규칙에 따라 e의 64비트를 f16 값으로 재해석한 것입니다.
|
17.3. 논리 내장 함수
17.3.1. all
| 오버로드 |
|
| 설명 | e의 각 컴포넌트가 true이면 true를 반환합니다.
|
| 오버로드 |
|
| 설명 | e를 반환합니다.
|
17.3.2. any
| 오버로드 |
|
| 설명 | e의 컴포넌트 중 하나라도 true이면 true를 반환합니다.
|
| 오버로드 |
|
| 설명 | e를 반환합니다.
|
17.3.3. select
| 오버로드 |
|
| 매개변수화 | T는 스칼라 또는
벡터입니다
|
| 설명 | cond가 true이면 t를 반환하고, 그렇지 않으면 f를
반환합니다.
|
| 오버로드 |
|
| 매개변수화 | T는 스칼라입니다
|
| 설명 | 컴포넌트별 선택입니다. 결과
컴포넌트
i는 select(f[i], t[i], cond[i])로 평가됩니다.
|
17.4. 배열 내장 함수
17.4.1.
arrayLength
| 오버로드 |
|
| 매개변수화 |
E는 런타임
크기 배열의 요소 타입입니다.AS는 storage, uniform
또는 workgroup 중 하나입니다.액세스 모드 AM은 read
또는 read_write이며
AS에 유효해야 합니다.
참고: |
| 설명 |
런타임 크기 배열의 요소 수인
NRuntime을
반환합니다.
§ 13.3.4 버퍼 바인딩이 런타임 크기 배열 요소 수를 결정함을 참조하십시오.
|
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
| 오버로드 |
|
| 매개변수화 | S는 AbstractInt, AbstractFloat, i32, u32, f32 또는 f16입니다 T는 S 또는 vecN<S>입니다 |
| 설명 |
e의 절댓값입니다.
T가 벡터이면 컴포넌트별입니다.
|
17.5.2. acos
| 오버로드 |
|
| 매개변수화 | S는 AbstractFloat, f32 또는 f16입니다 T는 S 또는 vecN<S>입니다 |
| 설명 |
e의 역코사인(cos-1)의 주값을 라디안 단위로 반환합니다.즉, cos(x) = e가 되도록 0 ≤ x ≤ π인
x를 근사합니다.
|
| 스칼라 정의역 | 구간 [−1, 1] |
17.5.3. acosh
| 오버로드 |
|
| 매개변수화 | S는 AbstractFloat, f32 또는 f16입니다 T는 S 또는 vecN<S>입니다 |
| 설명 |
x의 역쌍곡코사인(cosh-1)을 쌍곡각으로 반환합니다.즉, cosh(a) = x가 되도록 0 ≤ a ≤ +∞인
a를 근사합니다.
|
| 스칼라 정의역 | 구간 [1, +∞] |
17.5.4. asin
| 오버로드 |
|
| 매개변수화 | S는 AbstractFloat, f32 또는 f16입니다 T는 S 또는 vecN<S>입니다 |
| 설명 |
e의 역사인(sin-1)의 주값을 라디안 단위로 반환합니다.즉, sin(x) = e가 되도록 -π/2 ≤ x ≤
π/2인 x를 근사합니다.
|
| 스칼라 정의역 | 구간 [−1, 1] |
17.5.5. asinh
| 오버로드 |
|
| 매개변수화 | S는 AbstractFloat, f32 또는 f16입니다 T는 S 또는 vecN<S>입니다 |
| 설명 |
y의 역쌍곡사인(sinh-1)을 쌍곡각으로 반환합니다.즉, sinh(y) = a가 되는 a를
근사합니다.
|
17.5.6. atan
| 오버로드 |
|
| 매개변수화 | S는 AbstractFloat, f32 또는 f16입니다 T는 S 또는 vecN<S>입니다 |
| 설명 |
e의 역탄젠트(tan-1)의 주값을 라디안 단위로 반환합니다.즉, tan(x) = e가 되도록 − π/2 ≤
x ≤ π/2인 x를 근사합니다.
|
17.5.7. atanh
| 오버로드 |
|
| 매개변수화 | S는 AbstractFloat, f32 또는 f16입니다 T는 S 또는 vecN<S>입니다 |
| 설명 |
t의 역쌍곡탄젠트(tanh-1)를 쌍곡각으로 반환합니다.즉, tanh(a) = t가 되는 a를
근사합니다.
|
| 스칼라 정의역 | 구간 [−1, 1] |
17.5.8. atan2
| 오버로드 |
|
| 매개변수화 | S는 AbstractFloat, f32 또는 f16입니다 T는 S 또는 vecN<S>입니다 |
| 설명 |
탄젠트가 y÷x인 [-π, π] 구간의 각을 라디안 단위로 반환합니다.
결과로 선택되는 사분면은
참고: 다음의 경우 결과의 오차에는 상한이 없습니다.
|
17.5.9. ceil
| 오버로드 |
|
| 매개변수화 | S는 AbstractFloat, f32 또는 f16입니다 T는 S 또는 vecN<S>입니다 |
| 설명 | e의 올림값을 반환합니다.
T가 벡터이면 컴포넌트별입니다.
|
17.5.10. clamp
| 오버로드 |
|
| 매개변수화 | S는 AbstractInt, AbstractFloat, i32, u32, f32 또는 f16입니다 T는 S 또는 vecN<S>입니다 |
| 설명 |
e의 값을 범위 내로 제한합니다.
|
17.5.11. cos
| 오버로드 |
|
| 매개변수화 | S는 AbstractFloat, f32 또는 f16입니다 T는 S 또는 vecN<S>입니다 |
| 설명 | e가 라디안 단위일 때 e의 코사인을 반환합니다.
T가 벡터이면 컴포넌트별입니다.
|
| 스칼라 정의역 | 구간 (−∞, +∞) |
17.5.12. cosh
| 오버로드 |
|
| 매개변수화 | S는 AbstractFloat, f32 또는 f16입니다 T는 S 또는 vecN<S>입니다 |
| 설명 |
a가 쌍곡각일 때 a의 쌍곡코사인을 반환합니다.
순수 수학 함수 (ea + e−a)÷2를 근사하지만,
반드시 이 방식으로 계산되는 것은 아닙니다.
|
17.5.13.
countLeadingZeros
| 오버로드 |
|
| 매개변수화 | T는 i32, u32, vecN<i32> 또는 vecN<u32>입니다
|
| 설명 | T가 스칼라 타입일 때 e의 최상위 비트에서 시작하는
연속된 0비트의 수입니다.T가 벡터이면 컴포넌트별입니다.일부 언어에서는 "clz"라고도 합니다. |
17.5.14.
countOneBits
| 오버로드 |
|
| 매개변수화 | T는 i32, u32, vecN<i32> 또는 vecN<u32>입니다
|
| 설명 | e의 표현에 포함된 1비트의 수입니다."population count"라고도 합니다. T가 벡터이면 컴포넌트별입니다.
|
17.5.15.
countTrailingZeros
| 오버로드 |
|
| 매개변수화 | T는 i32, u32, vecN<i32> 또는 vecN<u32>입니다
|
| 설명 | T가 스칼라 타입일 때 e의 최하위 비트에서 시작하는
연속된 0비트의 수입니다.T가 벡터이면 컴포넌트별입니다.일부 언어에서는 "ctz"라고도 합니다. |
17.5.16. cross
| 오버로드 |
|
| 매개변수화 | T는 AbstractFloat, f32 또는 f16입니다
|
| 설명 | e1과 e2의 외적을 반환합니다.
|
| 정의역 |
가능한 구현으로 주어진 선형 항에서 유도됩니다.
|
17.5.17. degrees
| 오버로드 |
|
| 매개변수화 | S는 AbstractFloat, f32 또는 f16입니다 T는 S 또는 vecN<S>입니다 |
| 설명 | e1 × 180 ÷ π를 근사하여 라디안을 도로 변환합니다.
T가 벡터이면 컴포넌트별입니다
|
17.5.18.
determinant
| 오버로드 |
|
| 매개변수화 | T는 AbstractFloat, f32 또는 f16입니다
|
| 설명 | e의 행렬식을 반환합니다.
|
| 정의역 | 행렬식의 표준 수학적 정의에 있는 선형 항에서 유도됩니다. |
17.5.19. distance
| 오버로드 |
|
| 매개변수화 | S는 AbstractFloat, f32 또는 f16입니다 T는 S 또는 vecN<S>입니다 |
| 설명 |
e1과 e2 사이의 거리(예:
length(e1 - e2))를 반환합니다.
정의역은 뺄셈
e1−e2가 유효한 모든 벡터
(e1,e2)입니다.
즉, 일부 컴포넌트 |
17.5.20. dot
| 오버로드 |
|
| 매개변수화 | T는 AbstractInt, AbstractFloat, i32, u32, f32 또는 f16입니다
|
| 설명 | e1과 e2의 내적을 반환합니다.
|
| 정의역 | e1[i] × e2[i] 항의 합에 있는 선형 항에서 유도됩니다. |
17.5.21.
dot4U8Packed
| 오버로드 |
|
| 설명 | e1과 e2는 4개의 8비트 부호 없는 정수 컴포넌트를 가진
벡터로 해석됩니다.
이 두 벡터의 부호 없는 정수 내적을 반환합니다.
|
17.5.22.
dot4I8Packed
| 오버로드 |
|
| 설명 | e1과 e2는 4개의 8비트 부호 있는 정수 컴포넌트를 가진
벡터로 해석됩니다.
이 두 벡터의 부호 있는 정수 내적을 반환합니다. 곱셈을 수행하기 전에 각 컴포넌트를
i32로 부호 확장한 다음 WGSL i32에서 덧셈 연산을 수행합니다(결과가 수학적으로
-65024에서 65536까지의 범위에 있도록 보장되고, 이 범위는 i32로 표현할 수 있는
숫자의 범위 안에 있으므로 덧셈은 오버플로될 수 없습니다).
|
17.5.23. exp
| 오버로드 |
|
| 매개변수화 | S는 AbstractFloat, f32 또는 f16입니다 T는 S 또는 vecN<S>입니다 |
| 설명 | e1의 자연 지수(예:
ee1)를 반환합니다.
T가 벡터이면 컴포넌트별입니다.
|
17.5.24. exp2
| 오버로드 |
|
| 매개변수화 | S는 AbstractFloat, f32 또는 f16입니다 T는 S 또는 vecN<S>입니다 |
| 설명 | 2를 e제곱한 값(예: 2e)을 반환합니다.
T가 벡터이면 컴포넌트별입니다.
|
17.5.25.
extractBits (부호 있음)
| 오버로드 |
|
| 매개변수화 | T는 i32 또는 vecN<i32>입니다
|
| 설명 |
부호 확장을 사용하여 정수에서 비트를 읽습니다.
T가 벡터이면 컴포넌트별입니다.
|
17.5.26.
extractBits (부호 없음)
| 오버로드 |
|
| 매개변수화 | T는 u32 또는 vecN<u32>입니다
|
| 설명 |
부호 확장 없이 정수에서 비트를 읽습니다.
T가 벡터이면 컴포넌트별입니다.
|
17.5.27.
faceForward
| 오버로드 |
|
| 매개변수화 | T는 vecN<AbstractFloat>, vecN<f32> 또는 vecN<f16>입니다
|
| 설명 | dot(e2, e3)가 음수이면 e1을 반환하고, 그렇지 않으면
-e1을 반환합니다.
|
| 정의역 | 정의역 제한은 dot(e2,e3) 연산에서 발생하며, e2[i] ×
e3[i] 항의 합에 있는 선형 항에서 유도됩니다.
|
17.5.28. firstLeadingBit (부호 있음)
| 오버로드 |
|
| 매개변수화 | T는 i32 또는 vecN<i32>입니다
|
| 설명 |
스칼라 T의 결과는 다음과 같습니다.
|
|
참고: 부호 있는 정수는 2의 보수 표현을 사용하므로 부호 비트가 최상위 비트 위치에 나타납니다. |
17.5.29. firstLeadingBit (부호 없음)
| 오버로드 |
|
| 매개변수화 | T는 u32 또는 vecN<u32>입니다
|
| 설명 |
스칼라 T의 결과는 다음과 같습니다.
T가 벡터이면 컴포넌트별입니다.
|
17.5.30.
firstTrailingBit
| 오버로드 |
|
| 매개변수화 | T는 i32, u32, vecN<i32> 또는 vecN<u32>입니다
|
| 설명 |
스칼라 T의 결과는 다음과 같습니다.
T가 벡터이면 컴포넌트별입니다.
|
17.5.31. floor
| 오버로드 |
|
| 매개변수화 | S는 AbstractFloat, f32 또는 f16입니다 T는 S 또는 vecN<S>입니다 |
| 설명 | e의 내림값을 반환합니다.
T가 벡터이면 컴포넌트별입니다.
|
17.5.32. fma
| 오버로드 |
|
| 매개변수화 | S는 AbstractFloat, f32 또는 f16입니다 T는 S 또는 vecN<S>입니다 |
| 설명 |
e1 * e2 + e3을 반환합니다.
T가 벡터이면 컴포넌트별입니다.
참고: 참고:
IEEE-754
|
| 정의역 | e2 × e2 + e3 표현식의 선형 항에서 유도됩니다. |
17.5.33. fract
| 오버로드 |
|
| 매개변수화 | S는 AbstractFloat, f32 또는 f16입니다 T는 S 또는 vecN<S>입니다 |
| 설명 | e - floor(e)로 계산된 e의 소수 부분을 반환합니다.T가 벡터이면 컴포넌트별입니다.
|
|
참고: 유효한 결과는 닫힌 구간
[0, 1.0]에 있습니다.
예를 들어 |
17.5.34. frexp
| 오버로드 |
|
| 매개변수화 | T는 f32입니다
|
| 설명 |
e를 분수와 지수로 분할합니다.
다음과 같이 정의된
참고: |
|
참고:
|
| 오버로드 |
|
| 매개변수화 | T는 f16입니다
|
| 설명 |
e를 분수와 지수로 분할합니다.
다음과 같이 정의된 것으로 간주되는
참고: |
|
참고:
|
| 오버로드 |
|
| 매개변수화 | T는 AbstractFloat입니다
|
| 설명 |
e를 분수와 지수로 분할합니다.
참고: 무한대 또는 NaN이 되는 AbstractFloat 표현식은 셰이더 생성 오류를 발생시킵니다. 다음과 같이 정의된
참고: |
|
참고:
|
| 오버로드 |
|
| 매개변수화 | T는 vecN<f32>입니다
|
| 설명 |
e의 컴포넌트 ei를 분수와 지수로 분할합니다.
다음과 같이 정의된
참고: |
|
참고:
|
| 오버로드 |
|
| 매개변수화 | T는 vecN<f16>입니다
|
| 설명 |
e의 컴포넌트 ei를 분수와 지수로 분할합니다.
다음과 같이 정의된 것으로 간주되는
참고: |
|
참고:
|
| 오버로드 |
|
| 매개변수화 | T는 vecN<AbstractFloat>입니다
|
| 설명 |
e의 컴포넌트 ei를 분수와 지수로 분할합니다.
참고: 무한대 또는 NaN이 되는 AbstractFloat 표현식은 셰이더 생성 오류를 발생시킵니다. 다음과 같이 정의된
참고: |
|
참고:
|
17.5.35.
insertBits
| 오버로드 |
|
| 매개변수화 | T는 i32, u32, vecN<i32> 또는 vecN<u32>입니다
|
| 설명 |
정수의 비트를 설정합니다.
T가 벡터이면 컴포넌트별입니다.
|
17.5.36.
inverseSqrt
| 오버로드 |
|
| 매개변수화 | S는 AbstractFloat, f32 또는 f16입니다 T는 S 또는 vecN<S>입니다 |
| 설명 | sqrt(e)의 역수를 반환합니다.
T가 벡터이면 컴포넌트별입니다.
|
| 스칼라 정의역 | 구간 [0, +∞] |
17.5.37. ldexp
| 오버로드 |
|
| 매개변수화 |
S는 AbstractFloat, f32 또는 f16입니다 T는 S 또는 vecN<S>입니다 I는 AbstractInt, i32, vecN<AbstractInt> 또는 vecN<i32>입니다T가 벡터인 경우에만 I가 벡터입니다I도 추상인 경우에만 T가 추상일 수 있으며 그 반대도 같습니다
참고: 어느 한 매개변수가 구체이면 다른 매개변수는 해당되는 경우 자동 변환을 거쳐 구체 타입이 되고, 결과는 구체 타입이 됩니다. |
| 설명 |
다음 경우를 제외하고 e1 * 2e2를 반환합니다.
여기서 bias는 부동 소수점 형식의 지수 바이어스입니다.
x = ldexp(frexp(x).fract, frexp(x).exp)
참고: |
17.5.38. length
| 오버로드 |
|
| 매개변수화 | S는 AbstractFloat, f32 또는 f16입니다 T는 S 또는 vecN<S>입니다 |
| 설명 |
e의 길이를 반환합니다.T가 스칼라이면
e의 절댓값으로 평가됩니다.T가 벡터 타입이면 sqrt(e[0]2
+ e[1]2 + ...)로 평가됩니다.
참고: 스칼라의 경우
|
17.5.39. log
| 오버로드 |
|
| 매개변수화 | S는 AbstractFloat, f32 또는 f16입니다 T는 S 또는 vecN<S>입니다 |
| 설명 | e의 자연로그를 반환합니다.
T가 벡터이면 컴포넌트별입니다.
|
| 스칼라 정의역 | 구간 [0, +∞] |
17.5.40. log2
| 오버로드 |
|
| 매개변수화 | S는 AbstractFloat, f32 또는 f16입니다 T는 S 또는 vecN<S>입니다 |
| 설명 | e의 밑이 2인 로그를 반환합니다.
T가 벡터이면 컴포넌트별입니다.
|
| 스칼라 정의역 | 구간 [0, +∞] |
17.5.41.
max
| 오버로드 |
|
| 매개변수화 | S는 AbstractInt, AbstractFloat, i32, u32, f32 또는 f16입니다 T는 S 또는 vecN<S>입니다 |
| 설명 |
e1이 e2보다 작으면 e2를 반환하고, 그렇지 않으면
e1을 반환합니다.
T가 벡터이면 컴포넌트별입니다.
|
17.5.42.
min
| 오버로드 |
|
| 매개변수화 | S는 AbstractInt, AbstractFloat, i32, u32, f32 또는 f16입니다 T는 S 또는 vecN<S>입니다 |
| 설명 |
e2가 e1보다 작으면 e2를 반환하고, 그렇지 않으면
e1을 반환합니다.
T가 벡터이면 컴포넌트별입니다.
|
17.5.43. mix
| 오버로드 |
|
| 매개변수화 | 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]. |
| 오버로드 |
|
| 매개변수화 | T는 AbstractFloat, f32 또는 f16입니다T2는 vecN<T>입니다
|
| 설명 | 각 컴포넌트에 스칼라 혼합 계수 e3을 사용하여 e1과
e2를 컴포넌트별로 선형 혼합한 값을 반환합니다.mix(e1, e2, T2(e3))와 같습니다.
|
| 정의역 | 다음 표현식의 선형 항에서 유도됩니다. e1[i] × (1 − e3) + e2[i] × e3. |
17.5.44. modf
| 오버로드 |
|
| 매개변수화 | T는 f32입니다
|
| 설명 |
e를 소수 부분과 정수 부분으로 분할합니다.
정수 부분은 trunc( 다음과 같이 정의된
|
|
참고:
|
| 오버로드 |
|
| 매개변수화 | T는 f16입니다
|
| 설명 |
e를 소수 부분과 정수 부분으로 분할합니다.
정수 부분은 trunc( 다음과 같이 정의된 것으로 간주되는
|
|
참고:
|
| 오버로드 |
|
| 매개변수화 | T는 AbstractFloat입니다
|
| 설명 |
e를 소수 부분과 정수 부분으로 분할합니다.
정수 부분은 trunc( 다음과 같이 정의된
|
|
참고:
|
| 오버로드 |
|
| 매개변수화 | T는 vecN<f32>입니다
|
| 설명 |
e의 컴포넌트를 소수 부분과 정수 부분으로 분할합니다.
정수 부분과 소수 부분의 다음과 같이 정의된
|
|
참고:
|
| 오버로드 |
|
| 매개변수화 | T는 vecN<f16>입니다
|
| 설명 |
e의 컴포넌트를 소수 부분과 정수 부분으로 분할합니다.
정수 부분과 소수 부분의 다음과 같이 정의된 것으로 간주되는
|
|
참고:
|
| 오버로드 |
|
| 매개변수화 | T는 vecN<AbstractFloat>입니다
|
| 설명 |
e의 컴포넌트를 소수 부분과 정수 부분으로 분할합니다.
정수 부분과 소수 부분의 다음과 같이 정의된
|
|
참고:
|
17.5.45.
normalize
| 오버로드 |
|
| 매개변수화 | T는 AbstractFloat, f32 또는 f16입니다
|
| 설명 |
e와 같은 방향의 단위 벡터를 반환합니다.
정의역은 영벡터를 제외한 모든 벡터입니다. |
17.5.46. pow
| 오버로드 |
|
| 매개변수화 | S는 AbstractFloat, f32 또는 f16입니다 T는 S 또는 vecN<S>입니다 |
| 설명 | e1을 e2제곱한 값을 반환합니다.
T가 벡터이면 컴포넌트별입니다.
|
| 스칼라 정의역 |
다음을 제외한 모든 확장 실수
쌍
(x,y)의 집합입니다.
이 규칙은 결과가 |
17.5.47.
quantizeToF16
| 오버로드 |
|
| 매개변수화 | T는 f32 또는 vecN<f32>입니다
|
| 설명 |
32비트 부동 소수점 값 e를 e가 IEEE-754 binary16 값으로 변환된 다음
다시 IEEE-754 binary32 값으로 변환된 것처럼 양자화합니다.
중간 binary16 값은 0으로 플러시될 수 있습니다. 즉, 중간 binary16 값이 서브노멀이면 최종 결과가 0일 수 있습니다. § 15.7.6 부동 소수점 변환을 참조하십시오.
|
|
참고: vec2<f32>의 경우는
|
17.5.48. radians
| 오버로드 |
|
| 매개변수화 | S는 AbstractFloat, f32 또는 f16입니다 T는 S 또는 vecN<S>입니다 |
| 설명 | e1 × π ÷ 180을 근사하여 도를 라디안으로 변환합니다.
T가 벡터이면 컴포넌트별입니다
|
17.5.49. reflect
| 오버로드 |
|
| 매개변수화 | T는 vecN<AbstractFloat>, vecN<f32> 또는 vecN<f16>입니다
|
| 설명 | 입사 벡터 e1과 표면 방향 e2에 대해 반사 방향
e1 - 2 * dot(e2, e1) * e2를 반환합니다.
|
17.5.50. refract
| 오버로드 |
|
| 매개변수화 | 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
| 오버로드 |
|
| 매개변수화 | T는 i32, u32, vecN<i32> 또는 vecN<u32>입니다
|
| 설명 | e의 비트를 역순으로 바꿉니다. 결과의 k 위치에 있는 비트는
e의 31 -k 위치에 있는 비트와 같습니다.T가 벡터이면 컴포넌트별입니다.
|
17.5.52. round
| 오버로드 |
|
| 매개변수화 | S는 AbstractFloat, f32 또는 f16입니다 T는 S 또는 vecN<S>입니다 |
| 설명 | 결과는 부동 소수점 값으로 나타낸 e에 가장 가까운 정수
k입니다.e가 정수 k와 k + 1의 정확히 중간에 있으면
k가 짝수일 때 결과는 k이고, k가 홀수일 때
결과는 k + 1입니다.T가 벡터이면 컴포넌트별입니다.
|
17.5.53.
saturate
| 오버로드 |
|
| 매개변수화 | S는 AbstractFloat, f32 또는 f16입니다 T는 S 또는 vecN<S>입니다 |
| 설명 | clamp(e, 0.0, 1.0)을 반환합니다.
T가 벡터이면 컴포넌트별입니다.
|
17.5.54. sign
| 오버로드 |
|
| 매개변수화 | S는 AbstractInt, AbstractFloat, i32, f32 또는 f16입니다 T는 S 또는 vecN<S>입니다 |
| 설명 |
결과는 다음과 같습니다.
|
17.5.55. sin
| 오버로드 |
|
| 매개변수화 | S는 AbstractFloat, f32 또는 f16입니다 T는 S 또는 vecN<S>입니다 |
| 설명 | e가 라디안 단위일 때 e의 사인을 반환합니다.
T가 벡터이면 컴포넌트별입니다.
|
| 스칼라 정의역 | 구간 (−∞, +∞) |
17.5.56. sinh
| 오버로드 |
|
| 매개변수화 | S는 AbstractFloat, f32 또는 f16입니다 T는 S 또는 vecN<S>입니다 |
| 설명 |
a가 쌍곡각일 때 a의 쌍곡사인을 반환합니다.
순수 수학 함수
(ea − e−a)÷2를 근사하지만,
반드시 이 방식으로 계산되는 것은 아닙니다.
|
17.5.57.
smoothstep
| 오버로드 |
|
| 매개변수화 | S는 AbstractFloat, f32 또는 f16입니다 T는 S 또는 vecN<S>입니다 |
| 설명 |
0과 1 사이의 부드러운 에르미트 보간을 반환합니다.
T가 벡터이면 컴포넌트별입니다.
스칼라 정성적으로는 다음과 같습니다.
|
17.5.58. sqrt
| 오버로드 |
|
| 매개변수화 | S는 AbstractFloat, f32 또는 f16입니다 T는 S 또는 vecN<S>입니다 |
| 설명 | e의 제곱근을 반환합니다.
T가 벡터이면 컴포넌트별입니다.
|
| 스칼라 정의역 | 구간 [0, +∞] |
17.5.59. step
| 오버로드 |
|
| 매개변수화 | S는 AbstractFloat, f32 또는 f16입니다 T는 S 또는 vecN<S>입니다 |
| 설명 | edge ≤ x이면 1.0을 반환하고, 그렇지 않으면 0.0을 반환합니다.
T가 벡터이면 컴포넌트별입니다.
|
17.5.60. tan
| 오버로드 |
|
| 매개변수화 | S는 AbstractFloat, f32 또는 f16입니다 T는 S 또는 vecN<S>입니다 |
| 설명 | e가 라디안 단위일 때 e의 탄젠트를 반환합니다.
T가 벡터이면 컴포넌트별입니다.
|
| 스칼라 정의역 | 구간 (−∞, +∞) |
17.5.61. tanh
| 오버로드 |
|
| 매개변수화 | S는 AbstractFloat, f32 또는 f16입니다 T는 S 또는 vecN<S>입니다 |
| 설명 |
a가 쌍곡각일 때 a의 쌍곡탄젠트를
반환합니다.
순수 수학 함수
(ea − e−a) ÷ (ea +
e−a)를 근사하지만,
반드시 이 방식으로 계산되는 것은 아닙니다.
|
17.5.62.
transpose
| 오버로드 |
|
| 매개변수화 | T는 AbstractFloat, f32 또는 f16입니다
|
| 설명 | e의 전치 행렬을 반환합니다.
|
17.5.63. trunc
| 오버로드 |
|
| 매개변수화 | S는 AbstractFloat, f32 또는 f16입니다 T는 S 또는 vecN<S>입니다 |
| 설명 | truncate(e), 즉
절댓값이
e의 절댓값보다 작거나 같은 가장 가까운 정수를 반환합니다.
T가 벡터이면 컴포넌트별입니다.
|
17.6. 도함수 내장 함수
§ 15.6.2 도함수를 참조하십시오.
이러한 함수의 호출은 다음과 같습니다.
17.6.1. dpdx
| 오버로드 |
|
| 매개변수화 | T는 f32 또는 vecN<f32>입니다
|
| 설명 |
창 x 좌표에 대한 e의 편미분입니다.
결과는 dpdxFine(e) 또는 dpdxCoarse(e) 중 하나와 같습니다.
|
17.6.2. dpdxCoarse
| 오버로드 |
|
| 매개변수화 | T는 f32 또는 vecN<f32>입니다
|
| 설명 |
국소 차이를 사용하여 창 x 좌표에 대한 e의 편미분을 반환합니다.
이로 인해 dpdxFine(e)보다 고유한 위치가 더 적을 수 있습니다.
|
17.6.3. dpdxFine
| 오버로드 |
|
| 매개변수화 | T는 f32 또는 vecN<f32>입니다
|
| 설명 |
창 x 좌표에 대한 e의 편미분을 반환합니다.
|
17.6.4. dpdy
| 오버로드 |
|
| 매개변수화 | T는 f32 또는 vecN<f32>입니다
|
| 설명 |
창 y 좌표에 대한 e의 편미분입니다.
결과는 dpdyFine(e) 또는 dpdyCoarse(e) 중 하나와 같습니다.
|
17.6.5. dpdyCoarse
| 오버로드 |
|
| 매개변수화 | T는 f32 또는 vecN<f32>입니다
|
| 설명 |
국소 차이를 사용하여 창 y 좌표에 대한 e의 편미분을 반환합니다.
이로 인해 dpdyFine(e)보다 고유한 위치가 더 적을 수 있습니다.
|
17.6.6. dpdyFine
| 오버로드 |
|
| 매개변수화 | T는 f32 또는 vecN<f32>입니다
|
| 설명 |
창 y 좌표에 대한 e의 편미분을 반환합니다.
|
17.6.7. fwidth
| 오버로드 |
|
| 매개변수화 | T는 f32 또는 vecN<f32>입니다
|
| 설명 |
abs(dpdx(e)) + abs(dpdy(e))를 반환합니다.
|
17.6.8.
fwidthCoarse
| 오버로드 |
|
| 매개변수화 | T는 f32 또는 vecN<f32>입니다
|
| 설명 |
abs(dpdxCoarse(e)) + abs(dpdyCoarse(e))를 반환합니다.
|
17.6.9. fwidthFine
| 오버로드 |
|
| 매개변수화 | 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>입니다
|
|
|
ST는 i32, u32 또는 f32입니다 T는 texture_1d<ST>입니다
|
|
| 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입니다
|
|
|
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입니다
|
|
| ST는 i32, u32 또는 f32입니다 F는 텍셀 형식입니다 A는 액세스 모드입니다 T는 texture_3d<ST> 또는
texture_storage_3d<F,A>입니다
|
|
|
ST는 i32, u32 또는 f32입니다 T는 texture_3d<ST>입니다
|
|
매개변수:
t
| 샘플링된, 멀티샘플링된, 깊이, 스토리지 또는 외부 텍스처입니다. |
level
|
밉 레벨이며, 레벨 0은
텍스처의 전체 크기 버전을 포함합니다. 생략하면 레벨 0의 크기를 반환합니다. |
반환값:
텍스처의 좌표 크기입니다.
즉, 결과는 밉 레벨 수, 배열 크기 및 샘플 수를 제외한 논리적 텍셀 주소 좌표의 정수 경계를 제공합니다.
큐브 기반 텍스처의 경우 결과는 큐브 각 면의 크기입니다. 큐브 면은 정사각형이므로 결과의 x 및 y 컴포넌트는 같습니다.
level이 [0, textureNumLevels(t)) 범위 밖에 있으면 반환 타입의 부정 값이 반환될 수 있습니다.
17.7.2. textureGather
텍스처 수집 연산은 2D, 2D 배열, 큐브 또는 큐브 배열 텍스처에서 읽어 다음과 같이 4컴포넌트 벡터를 계산합니다.
-
밉 레벨 0에서 선형 필터링을 사용하는 샘플링 연산에 사용될 4개의 텍셀을 찾습니다.
-
지정된 좌표, 배열 인덱스(있는 경우) 및 오프셋(있는 경우)을 사용합니다.
-
텍스처 공간 좌표 (u,v)를 고려할 때 텍셀은 서로 인접하여 정사각형을 이룹니다.
-
텍스처 가장자리, 큐브 면 가장자리 또는 큐브 모서리에서 선택된 텍셀은 일반적인 텍스처 샘플링과 같이 처리됩니다.
-
-
각 텍셀에서 한 채널을 읽고 스칼라 값으로 변환합니다.
-
깊이 텍스처가 아닌 경우 0 기반
component매개변수가 사용할 채널을 지정합니다.-
텍스처 형식이 지정된 채널을 지원하는 경우, 즉
component개보다 많은 채널을 가진 경우:-
텍셀 값이
v일 때 스칼라 값v[component]를 생성합니다.
-
-
그렇지 않으면 다음과 같습니다.
-
component가 1 또는 2이면 0.0을 생성합니다. -
component가 3(알파 채널)이면 1.0을 생성합니다.
-
-
-
깊이 텍스처의 경우 텍셀 값을 생성합니다. (깊이 텍스처에는 채널이 하나만 있습니다.)
-
-
이전 단계에서 생성된 스칼라를 다음과 같이 텍셀의 상대 좌표에 따라 컴포넌트로 배열하여 4컴포넌트 벡터를 생성합니다.
-
결과 컴포넌트 상대 텍셀 좌표 x (umin,vmax) y (umax,vmax) z (umax,vmin) w (umin,vmin)
-
4개의 텍셀은 WebGPU 샘플러 설명자에 설명된 샘플링 영역을 형성합니다.
| 매개변수화 | 오버로드 |
|---|---|
| C는 i32 또는 u32입니다 ST는 i32, u32 또는 f32입니다 |
|
| C는 i32 또는 u32입니다 ST는 i32, u32 또는 f32입니다 |
|
| C는 i32 또는 u32입니다 A는 i32 또는 u32입니다 ST는 i32, u32 또는 f32입니다 |
|
| C는 i32 또는 u32입니다 A는 i32 또는 u32입니다 ST는 i32, u32 또는 f32입니다 |
|
| C는 i32 또는 u32입니다 ST는 i32, u32 또는 f32입니다 |
|
| C는 i32 또는 u32입니다 A는 i32 또는 u32입니다 ST는 i32, u32 또는 f32입니다 |
|
| |
| |
| |
| A는 i32 또는 u32입니다 |
|
| A는 i32 또는 u32입니다 |
|
| A는 i32 또는 u32입니다 |
|
매개변수:
component
|
깊이 텍스처가 아닌 경우에만 적용됩니다.
선택한 텍셀에서 읽을 채널의 인덱스입니다. 제공된 경우 component 표현식은 상수 표현식
(예: 1)이어야 합니다.값은 0 이상 3 이하여야 합니다. 이 범위를 벗어난 값은 셰이더 생성 오류를 발생시킵니다. |
t
| 읽을 샘플링된 또는 깊이 텍스처입니다. |
s
| 샘플러 타입입니다. |
coords
| 텍스처 좌표입니다. |
array_index
|
0 기반 텍스처 배열 인덱스입니다. 이 값은 [0, textureNumLayers(t) - 1] 범위로 제한됩니다.
|
offset
|
텍스처를 샘플링하기 전에 정규화되지 않은 텍스처 좌표에 적용되는 선택적 텍셀
오프셋입니다. 이 오프셋은 모든 텍스처 래핑 모드를 적용하기 전에 적용됩니다.offset 표현식은 상수 표현식(예:
vec2<i32>(1, 2))이어야 합니다.각 offset 컴포넌트는 -8 이상 7 이하여야 합니다. 이 범위를 벗어난 값은 셰이더
생성 오류를 발생시킵니다.
|
반환값:
위에서 설명한 대로 선택한 텍셀의 지정된 채널에서 추출한 컴포넌트를 가진 4컴포넌트 벡터입니다.
@group ( 0 ) @binding ( 0 ) var t : texture_2d< f32> ; @group ( 0 ) @binding ( 1 ) var dt : texture_depth_2d; @group ( 0 ) @binding ( 2 ) var s : sampler; fn gather_x_components ( c : vec2< f32> ) -> vec4< f32> { return textureGather ( 0 , t , s , c ); } fn gather_y_components ( c : vec2< f32> ) -> vec4< f32> { return textureGather ( 1 , t , s , c ); } fn gather_z_components ( c : vec2< f32> ) -> vec4< f32> { return textureGather ( 2 , t , s , c ); } fn gather_depth_components ( c : vec2< f32> ) -> vec4< f32> { return textureGather ( dt , s , c ); }
17.7.3.
textureGatherCompare
텍스처 수집 비교 연산은 깊이 텍스처의 4개 텍셀에 대해 깊이 비교를 수행하고 다음과 같이 결과를 단일 벡터로 수집합니다.
-
밉 레벨 0에서 선형 필터링을 사용하는 깊이 샘플링 연산에 사용될 4개의 텍셀을 찾습니다.
-
지정된 좌표, 배열 인덱스(있는 경우) 및 오프셋(있는 경우)을 사용합니다.
-
텍스처 공간 좌표 (u,v)를 고려할 때 텍셀은 서로 인접하여 정사각형을 이룹니다.
-
텍스처 가장자리, 큐브 면 가장자리 또는 큐브 모서리에서 선택된 텍셀은 일반적인 텍스처 샘플링과 같이 처리됩니다.
-
-
각 텍셀에 대해 비교 샘플러 매개변수의 제어에 따라 깊이 참조 값과 비교하여 0.0 또는 1.0 값을 생성합니다.
-
컴포넌트가 다음과 같은 상대 텍셀 좌표를 가진 텍셀의 비교 결과인 4컴포넌트 벡터를 생성합니다.
-
결과 컴포넌트 상대 텍셀 좌표 x (umin,vmax) y (umax,vmax) z (umax,vmin) w (umin,vmin)
-
| 매개변수화 | 오버로드 |
|---|---|
| |
| |
| A는 i32 또는 u32입니다 |
|
| A는 i32 또는 u32입니다 |
|
| |
| A는 i32 또는 u32입니다 |
|
매개변수:
t
| 읽을 깊이 텍스처입니다. |
s
| 비교 샘플러입니다. |
coords
| 텍스처 좌표입니다. |
array_index
|
0 기반 텍스처 배열 인덱스입니다. 이 값은 [0, textureNumLayers(t) - 1] 범위로 제한됩니다.
|
depth_ref
| 샘플링된 깊이 값과 비교할 참조 값입니다. |
offset
|
텍스처를 샘플링하기 전에 정규화되지 않은 텍스처 좌표에 적용되는 선택적 텍셀
오프셋입니다. 이 오프셋은 모든 텍스처 래핑 모드를 적용하기 전에 적용됩니다.offset 표현식은 상수 표현식(예:
vec2<i32>(1, 2))이어야 합니다.각 offset 컴포넌트는 -8 이상 7 이하여야 합니다. 이 범위를 벗어난 값은 셰이더
생성 오류를 발생시킵니다.
|
반환값:
위에서 설명한 대로 선택한 텍셀의 비교 결과를 가진 4컴포넌트 벡터입니다.
@group ( 0 ) @binding ( 0 ) var dt : texture_depth_2d; @group ( 0 ) @binding ( 1 ) var s : sampler; fn gather_depth_compare ( c : vec2< f32> , depth_ref : f32) -> vec4< f32> { return textureGatherCompare ( dt , s , c , depth_ref ); }
17.7.4. textureLoad
샘플링이나 필터링 없이 텍스처에서 단일 텍셀을 읽습니다.
| 매개변수화 | 오버로드 |
|---|---|
| C는 i32 또는 u32입니다 L은 i32 또는 u32입니다 ST는 i32, u32 또는 f32입니다 |
|
| C는 i32 또는 u32입니다 L은 i32 또는 u32입니다 ST는 i32, u32 또는 f32입니다 |
|
| C는 i32 또는 u32입니다 A는 i32 또는 u32입니다 L은 i32 또는 u32입니다 ST는 i32, u32 또는 f32입니다 |
|
| C는 i32 또는 u32입니다 L은 i32 또는 u32입니다 ST는 i32, u32 또는 f32입니다 |
|
| C는 i32 또는 u32입니다 S는 i32 또는 u32입니다 ST는 i32, u32 또는 f32입니다 |
|
| C는 i32 또는 u32입니다 L은 i32 또는 u32입니다 |
|
| C는 i32 또는 u32입니다 A는 i32 또는 u32입니다 L은 i32 또는 u32입니다 |
|
| C는 i32 또는 u32입니다 S는 i32 또는 u32입니다 |
|
| C는 i32 또는 u32입니다 |
|
| C는 i32 또는 u32입니다 AM은 read 또는 read_write입니다 CF는 스토리지 텍셀 형식 F에 따라 달라집니다. 텍셀 형식과 채널 형식의 매핑은 텍셀 형식 표를 참조하십시오. |
|
| C는 i32 또는 u32입니다 AM은 read 또는 read_write입니다 CF는 스토리지 텍셀 형식 F에 따라 달라집니다. 텍셀 형식과 채널 형식의 매핑은 텍셀 형식 표를 참조하십시오. |
|
| C는 i32 또는 u32입니다 AM은 read 또는 read_write입니다 A는 i32 또는 u32입니다 CF는 스토리지 텍셀 형식 F에 따라 달라집니다. 텍셀 형식과 채널 형식의 매핑은 텍셀 형식 표를 참조하십시오. |
|
| C는 i32 또는 u32입니다 AM은 read 또는 read_write입니다 CF는 스토리지 텍셀 형식 F에 따라 달라집니다. 텍셀 형식과 채널 형식의 매핑은 텍셀 형식 표를 참조하십시오. |
|
매개변수:
t
| 샘플링된, 멀티샘플링된, 깊이, 스토리지 또는 외부 텍스처입니다 |
coords
| 0 기반 텍셀 좌표입니다. |
array_index
| 0 기반 텍스처 배열 인덱스입니다. |
level
| 밉 레벨이며, 레벨 0은 텍스처의 전체 크기 버전을 포함합니다. |
sample_index
| 멀티샘플링된 텍스처의 0 기반 샘플 인덱스입니다. |
반환값:
필터링되지 않은 텍셀 데이터입니다.
다음의 경우 논리적 텍셀 주소가 유효하지 않습니다.
-
coords의 요소가 해당 요소의[0, textureDimensions(t, level))범위 밖에 있거나 -
array_index가[0, textureNumLayers(t))범위 밖에 있거나 -
level이[0, textureNumLevels(t))범위 밖에 있거나 -
sample_index가[0, textureNumSamples(s))범위 밖에 있는 경우입니다
논리적 텍셀 주소가 유효하지 않으면 내장 함수는 다음 중 하나를 반환합니다.
-
텍스처 경계 내의 어떤 텍셀에 대한 데이터입니다.
-
깊이 텍스처가 아닌 경우 다음 중 하나입니다.
-
깊이 텍스처의 경우 0.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>입니다
|
|
매개변수:
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입니다
|
|
매개변수:
t
| 샘플링된 또는 깊이 텍스처입니다. |
반환값:
텍스처의 밉 레벨 수입니다.
17.7.7. textureNumSamples
멀티샘플링된 텍스처에서 텍셀당 샘플 수를 반환합니다.
| 매개변수화 | 오버로드 |
|---|---|
| ST는 i32, u32 또는 f32입니다 T는 texture_multisampled_2d<ST>
또는 texture_depth_multisampled_2d입니다
|
|
매개변수:
t
| 멀티샘플링된 텍스처입니다. |
반환값:
멀티샘플링된 텍스처의 샘플 수입니다.
17.7.8. textureSample
텍스처를 샘플링합니다.
균일성 분석이 이 함수의 호출이 균일 제어 흐름에 있음을 증명할 수 없으면 derivative_uniformity 진단이 트리거됩니다.
| 매개변수화 | 오버로드 |
|---|---|
| |
| |
| |
| A는 i32 또는 u32입니다 |
|
| A는 i32 또는 u32입니다 |
|
T는 texture_3d<f32> 또는 texture_cube<f32>입니다
|
|
| |
| A는 i32 또는 u32입니다 |
|
| |
| |
| A는 i32 또는 u32입니다 |
|
| A는 i32 또는 u32입니다 |
|
| |
| A는 i32 또는 u32입니다 |
|
매개변수:
t
| 샘플링할 샘플링된 또는 깊이 텍스처입니다. |
s
| 샘플러 타입입니다. |
coords
| 샘플링에 사용되는 텍스처 좌표입니다. |
array_index
|
샘플링할 0 기반 텍스처 배열 인덱스입니다. 이 값은 [0, textureNumLayers(t) - 1] 범위로 제한됩니다.
|
offset
|
텍스처를 샘플링하기 전에 정규화되지 않은 텍스처 좌표에 적용되는 선택적 텍셀
오프셋입니다. 이 오프셋은 모든 텍스처 래핑 모드를 적용하기 전에 적용됩니다.offset 표현식은 상수 표현식(예:
vec2<i32>(1, 2))이어야 합니다.각 offset 컴포넌트는 -8 이상 7 이하여야 합니다. 이 범위를 벗어난 값은 셰이더
생성 오류를 발생시킵니다.
|
반환값:
샘플링된 값입니다.
17.7.9. textureSampleBias
밉 레벨에 바이어스를 적용하여 텍스처를 샘플링합니다.
반드시 프래그먼트 셰이더 스테이지에서만 사용해야 합니다.
균일성 분석에서 이 함수 호출이 균일 제어 흐름에 있음을 증명할 수 없으면, derivative_uniformity 진단이 트리거됩니다.
| 매개변수화 | 오버로드 |
|---|---|
| |
| |
| A는 i32 또는 u32입니다 |
|
| A는 i32 또는 u32입니다 |
|
T는 texture_3d<f32> 또는 texture_cube<f32>입니다
|
|
| |
| A는 i32 또는 u32입니다 |
|
매개변수:
t
| 샘플링할 샘플링된 텍스처입니다. |
s
| 샘플러 타입입니다. |
coords
| 샘플링에 사용되는 텍스처 좌표입니다. |
array_index
|
샘플링할 0 기반 텍스처 배열 인덱스입니다. 이 값은 [0, textureNumLayers(t) - 1] 범위로
제한됩니다.
|
bias
|
샘플링 전에 밉 레벨에 적용할 바이어스입니다. 이 값은 [-16.0, 15.99] 범위로
제한됩니다.
|
offset
|
텍스처를 샘플링하기 전에 정규화되지 않은 텍스처 좌표에 적용되는
선택적 텍셀 오프셋입니다. 이 오프셋은 모든 텍스처 래핑 모드를
적용하기 전에 적용됩니다.offset 표현식은 반드시 상수 표현식이어야 합니다(예:
vec2<i32>(1, 2)).각 offset 컴포넌트는 반드시 -8 이상이고
7 이하여야 합니다. 이 범위를 벗어난
값은 셰이더 생성 오류를 발생시킵니다.
|
반환:
샘플링된 값입니다.
17.7.10.
textureSampleCompare
깊이 텍스처를 샘플링하고 샘플링된 깊이 값을 참조 값과 비교합니다.
반드시 프래그먼트 셰이더 스테이지에서만 사용해야 합니다.
균일성 분석에서 이 함수 호출이 균일 제어 흐름에 있음을 증명할 수 없으면, derivative_uniformity 진단이 트리거됩니다.
| 매개변수화 | 오버로드 |
|---|---|
| |
| |
| A는 i32 또는 u32입니다 |
|
| A는 i32 또는 u32입니다 |
|
| |
| A는 i32 또는 u32입니다 |
|
매개변수:
t
| 샘플링할 깊이 텍스처입니다. |
s
| sampler_comparison 타입입니다. |
coords
| 샘플링에 사용되는 텍스처 좌표입니다. |
array_index
|
샘플링할 0 기반 텍스처 배열 인덱스입니다. 이 값은 [0, textureNumLayers(t) - 1] 범위로
제한됩니다.
|
depth_ref
| 샘플링된 깊이 값과 비교할 참조 값입니다. |
offset
|
텍스처를 샘플링하기 전에 정규화되지 않은 텍스처 좌표에 적용되는
선택적 텍셀 오프셋입니다. 이 오프셋은 모든 텍스처
래핑 모드를 적용하기 전에 적용됩니다.offset 표현식은 반드시 상수 표현식이어야 합니다(예:
vec2<i32>(1, 2)).각 offset 컴포넌트는 반드시 -8 이상이고
7 이하여야 합니다. 이 범위를 벗어난
값은 셰이더 생성 오류를 발생시킵니다.
|
반환:
[0.0..1.0] 범위의 값입니다.
샘플링된 각 텍셀은 sampler_comparison에 정의된 비교
연산자를 사용하여 참조 값과 비교되며, 그 결과 각 텍셀에 대해 0 또는
1
값이 생성됩니다.
샘플러가 이중 선형 필터링을 사용하는 경우 반환 값은 이러한 값의 필터링된 평균이고, 그렇지 않으면 단일 텍셀의 비교 결과가 반환됩니다.
17.7.11.
textureSampleCompareLevel
깊이 텍스처를 샘플링하고 샘플링된 깊이 값을 참조 값과 비교합니다.
| 매개변수화 | 오버로드 |
|---|---|
| |
| |
| A는 i32 또는 u32입니다 |
|
| A는 i32 또는 u32입니다 |
|
| |
| A는 i32 또는 u32입니다 |
|
매개변수:
t
| 샘플링할 깊이 텍스처입니다. |
s
| sampler_comparison 타입입니다. |
coords
| 샘플링에 사용되는 텍스처 좌표입니다. |
array_index
|
샘플링할 0 기반 텍스처 배열 인덱스입니다. 이 값은 [0, textureNumLayers(t) - 1] 범위로
제한됩니다.
|
depth_ref
| 샘플링된 깊이 값과 비교할 참조 값입니다. |
offset
|
텍스처를 샘플링하기 전에 정규화되지 않은 텍스처 좌표에 적용되는
선택적 텍셀 오프셋입니다. 이 오프셋은 모든 텍스처
래핑 모드를 적용하기 전에 적용됩니다.offset 표현식은 반드시 상수 표현식이어야 합니다(예:
vec2<i32>(1, 2)).각 offset 컴포넌트는 반드시 -8 이상이고
7 이하여야 합니다. 이 범위를 벗어난
값은 셰이더 생성 오류를 발생시킵니다.
|
반환:
[0.0..1.0] 범위의 값입니다.
textureSampleCompareLevel 함수는 다음 사항을 제외하면 textureSampleCompare와
같습니다.
-
textureSampleCompareLevel은 항상 밉 레벨 0에서 텍셀을 샘플링합니다.-
이 함수는 도함수를 계산하지 않습니다.
-
textureSampleCompareLevel을 균일 제어 흐름에서 호출해야 한다는 요구사항은 없습니다.
-
-
textureSampleCompareLevel은 모든 셰이더 스테이지에서 호출할 수 있습니다.
17.7.12.
textureSampleGrad
명시적 그래디언트를 사용하여 텍스처를 샘플링합니다.
| 매개변수화 | 오버로드 |
|---|---|
| |
| |
| A는 i32 또는 u32입니다 |
|
| A는 i32 또는 u32입니다 |
|
T는 texture_3d<f32> 또는 texture_cube<f32>입니다
|
|
| |
| A는 i32 또는 u32입니다 |
|
매개변수:
t
| 샘플링할 샘플링된 텍스처입니다. |
s
| 샘플러입니다. |
coords
| 샘플링에 사용되는 텍스처 좌표입니다. |
array_index
|
샘플링할 0 기반 텍스처 배열 인덱스입니다. 이 값은 [0, textureNumLayers(t) - 1] 범위로
제한됩니다.
|
ddx
| 샘플링 위치를 계산하는 데 사용되는 x 방향 도함수 벡터입니다. |
ddy
| 샘플링 위치를 계산하는 데 사용되는 y 방향 도함수 벡터입니다. |
offset
|
텍스처를 샘플링하기 전에 정규화되지 않은 텍스처 좌표에 적용되는
선택적 텍셀 오프셋입니다. 이 오프셋은 모든 텍스처
래핑 모드를 적용하기 전에 적용됩니다.offset 표현식은 반드시 상수 표현식이어야 합니다(예:
vec2<i32>(1, 2)).각 offset 컴포넌트는 반드시 -8 이상이고
7 이하여야 합니다. 이 범위를 벗어난
값은 셰이더 생성 오류를 발생시킵니다.
|
반환:
샘플링된 값입니다.
17.7.13.
textureSampleLevel
명시적 밉 레벨을 사용하여 텍스처를 샘플링합니다.
| 매개변수화 | 오버로드 |
|---|---|
| |
| |
| |
| A는 i32 또는 u32입니다 |
|
| A는 i32 또는 u32입니다 |
|
T는 texture_3d<f32> 또는 texture_cube<f32>입니다
|
|
| |
| A는 i32 또는 u32입니다 |
|
| L은 i32 또는 u32입니다 |
|
| L은 i32 또는 u32입니다 |
|
| A는 i32 또는 u32입니다 L은 i32 또는 u32입니다 |
|
| A는 i32 또는 u32입니다 L은 i32 또는 u32입니다 |
|
| L은 i32 또는 u32입니다 |
|
| A는 i32 또는 u32입니다 L은 i32 또는 u32입니다 |
|
매개변수:
t
| 샘플링할 샘플링된 또는 깊이 텍스처입니다. |
s
| 샘플러 타입입니다. |
coords
| 샘플링에 사용되는 텍스처 좌표입니다. |
array_index
|
샘플링할 0 기반 텍스처 배열 인덱스입니다. 이 값은 [0, textureNumLayers(t) - 1] 범위로
제한됩니다.
|
level
|
밉 레벨이며, 레벨 0에는 텍스처의 전체 크기 버전이 포함됩니다.
level이 f32인 함수에서는 형식이
텍스처 형식 기능에 따라 필터링 가능한 경우
소수 값이 두 레벨 사이를 보간할 수 있습니다.
|
offset
|
텍스처를 샘플링하기 전에 정규화되지 않은 텍스처 좌표에 적용되는
선택적 텍셀 오프셋입니다. 이 오프셋은 모든 텍스처
래핑 모드를 적용하기 전에 적용됩니다.offset 표현식은 반드시 상수 표현식이어야 합니다(예:
vec2<i32>(1, 2)).각 offset 컴포넌트는 반드시 -8 이상이고
7 이하여야 합니다. 이 범위를 벗어난
값은 셰이더 생성 오류를 발생시킵니다.
|
반환:
샘플링된 값입니다.
17.7.14.
textureSampleBaseClampToEdge
아래 설명과 같이 텍스처 좌표를 가장자리로 제한하여 기본 레벨에서 텍스처 뷰를 샘플링합니다.
| 매개변수화 | 오버로드 |
|---|---|
T는 texture_2d<f32> 또는 texture_external입니다
|
|
매개변수:
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에 따라 달라집니다. 텍셀 형식에서 채널 형식으로의 매핑은 텍셀 형식 표를 참조하십시오. |
|
| F는 텍셀
형식입니다 C는 i32 또는 u32입니다 AM은 write 또는 read_write입니다 CF는 스토리지 텍셀 형식 F에 따라 달라집니다. 텍셀 형식에서 채널 형식으로의 매핑은 텍셀 형식 표를 참조하십시오. |
|
| F는 텍셀
형식입니다 C는 i32 또는 u32입니다 AM은 write 또는 read_write입니다 A는 i32 또는 u32입니다 CF는 스토리지 텍셀 형식 F에 따라 달라집니다. 텍셀 형식에서 채널 형식으로의 매핑은 텍셀 형식 표를 참조하십시오. |
|
| F는 텍셀
형식입니다 C는 i32 또는 u32입니다 AM은 write 또는 read_write입니다 CF는 스토리지 텍셀 형식 F에 따라 달라집니다. 텍셀 형식에서 채널 형식으로의 매핑은 텍셀 형식 표를 참조하십시오. |
|
매개변수:
t
| 쓰기 전용 스토리지 텍스처 또는 읽기-쓰기 스토리지 텍스처입니다 |
coords
|
0 기반 텍셀 좌표입니다. |
array_index
| 0 기반 텍스처 배열 인덱스입니다. |
value
|
새 텍셀 값입니다.
value는 역 채널 전달 함수를 사용하여 변환됩니다.
|
참고:
논리적 텍셀 주소는 다음 경우 유효하지 않습니다.
-
coords의 요소가 해당 요소에 대한[0, textureDimensions(t))범위를 벗어나거나, -
array_index가[0, textureNumLayers(t))범위를 벗어난 경우
논리적 텍셀 주소가 유효하지 않으면 내장 함수는 실행되지 않습니다.
17.8. 원자 내장 함수
원자 내장 함수는 원자 객체를 읽거나, 쓰거나, 읽기-수정-쓰기 하는 데 사용할 수 있습니다. 이는 § 6.2.8 원자 타입에 허용되는 유일한 연산입니다.
모든 원자 내장 함수는 relaxed 메모리
순서를 사용합니다. 이는 동기화 및 순서 보장이 동일한 메모리 위치에서 작동하는 원자 연산 사이에만 적용됨을 의미합니다.
원자 메모리 액세스와 비원자 메모리 액세스 사이 또는 서로 다른 메모리 위치에서 작동하는
원자 액세스 사이에는 동기화나 순서 보장이 적용되지 않습니다.
원자 내장 함수는 버텍스 셰이더 스테이지에서 사용해서는 안 됩니다.
모든 원자 내장 함수의 atomic_ptr 매개변수에 대한 주소 공간 AS는
반드시 storage 또는
workgroup이어야 합니다.
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. 원자 읽기-수정-쓰기 산술 및 논리 함수
각 함수는 다음 단계를 원자적으로 수행합니다.
-
atomic_ptr이 가리키는 원래 값을 로드합니다. -
함수 이름에 해당하는 연산(예: 최댓값)을 값 v와 수행하여 새 값을 얻습니다.
-
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 연산을 원자적으로 수행하고, 연산 전에 원자 객체에 저장되어 있던
원래 값을 반환합니다.
// 모든 연산은 원자적으로 수행됩니다 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 연산을 원자적으로 수행하고, 연산 전에 원자 객체에 저장되어 있던
원래 값을 반환합니다.
// 모든 연산은 원자적으로 수행됩니다 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 연산을 원자적으로 수행하고, 연산 전에 원자 객체에 저장되어 있던
원래 값을 반환합니다.
// 모든 연산은 원자적으로 수행됩니다 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 타입으로 값을 명시적으로 선언할 수는 없지만,
값에서 이 타입을 추론할 수 있습니다.
다음 단계를 원자적으로 수행합니다.
-
atomic_ptr이 가리키는 원래 값을 로드합니다. -
동등 연산을 사용하여 원래 값과 값
cmp를 비교합니다. -
동등 비교 결과가
true인 경우에만 값v를 저장합니다.
두 멤버로 구성된 구조체를 반환합니다. 첫 번째 멤버 old_value는
연산 전 원자 객체의 원래 값이고, 두 번째 멤버 exchanged는
비교가 성공했는지를 나타냅니다.
// 모든 연산은 원자적으로 수행됩니다 fn atomicCompareExchangeWeak ( atomic_ptr : ptr< AS , atomic< T > , read_write> , cmp : T , v : T ) -> _atomic_compare_exchange_result < T > { let old = * atomic_ptr ; // 이 비교는 허위로 실패할 수 있습니다. let comparison = old == cmp ; if comparison { * atomic_ptr = v ; } return _atomic_compare_exchange_result < T > ( old , comparison ); }
참고: 일부 구현에서는 동등 비교가 허위로
실패할 수 있습니다. 즉, 결과 벡터의 첫 번째 컴포넌트가
cmp와 같더라도 결과 벡터의 두 번째 컴포넌트가 false일 수 있습니다.
17.9. 데이터 패킹 내장 함수
데이터 패킹 내장 함수는 WGSL의 타입에 직접 대응하지 않는 데이터 형식을 사용하여 값을 인코딩하는 데 사용할 수 있습니다. 이를 통해 프로그램이 조밀하게 패킹된 여러 값을 메모리에 쓸 수 있으므로 셰이더의 메모리 대역폭 요구량을 줄일 수 있습니다.
각 내장 함수는 여러 입력 값에 채널 전달 함수의 역함수를 적용한 다음 그 결과를 하나의 출력 값으로 결합합니다.
참고: unorm 값을 패킹할 때 정규화된 부동 소수점 값은 구간 [0.0, 1.0]에 있습니다.
참고: snorm 값을 패킹할 때 정규화된 부동 소수점 값은 구간 [-1.0, 1.0]에 있습니다.
17.9.1.
pack4x8snorm
| 오버로드 |
|
| 설명 |
정규화된 네 개의 부동 소수점 값을 8비트 부호 있는 정수로 변환한 다음
하나의 u32 값으로 결합합니다.
입력의 컴포넌트 |
17.9.2.
pack4x8unorm
| 오버로드 |
|
| 설명 |
정규화된 네 개의 부동 소수점 값을 8비트 부호 없는 정수로 변환한 다음
하나의 u32 값으로 결합합니다.
입력의 컴포넌트 |
17.9.3. pack4xI8
| 오버로드 |
|
| 설명 |
e의 각 컴포넌트에서 하위 8비트를 u32
값으로 패킹하고 사용하지 않는 모든 비트를 버립니다.
입력의 컴포넌트 |
17.9.4. pack4xU8
| 오버로드 |
|
| 설명 |
e의 각 컴포넌트에서 하위 8비트를 u32
값으로 패킹하고 사용하지 않는 모든 비트를 버립니다.
입력의 컴포넌트 |
17.9.5.
pack4xI8Clamp
| 오버로드 |
|
| 설명 |
e의 각 컴포넌트를 [-128, 127] 범위로 제한한 다음 각
컴포넌트의 하위 8비트를 u32 값으로 패킹합니다.
입력의 컴포넌트 |
17.9.6.
pack4xU8Clamp
| 오버로드 |
|
| 설명 |
e의 각 컴포넌트를 [0, 255] 범위로 제한한 다음 각
컴포넌트의 하위 8비트를 u32 값으로 패킹합니다.
입력의 컴포넌트 |
17.9.7.
pack2x16snorm
| 오버로드 |
|
| 설명 | 정규화된 두 부동 소수점 값을 16비트 부호 있는 정수로 변환한 다음
하나의 u32 값으로 결합합니다.입력의 컴포넌트 e[i]는 16비트 2의 보수 정숫값
⌊ 0.5 + 32767 × min(1, max(-1, e[i])) ⌋로 변환된 다음 결과의
16 × i번 비트부터
16 × i + 15번 비트까지 배치됩니다.
|
17.9.8.
pack2x16unorm
| 오버로드 |
|
| 설명 | 정규화된 두 부동 소수점 값을 16비트 부호 없는 정수로 변환한 다음
하나의 u32 값으로 결합합니다.입력의 컴포넌트 e[i]는 16비트 부호 없는 정숫값
⌊ 0.5 + 65535 × min(1, max(0, e[i])) ⌋로 변환된 다음 결과의
16 × i번 비트부터
16 × i + 15번 비트까지 배치됩니다.
|
17.9.9.
pack2x16float
| 오버로드 |
|
| 설명 |
두 부동 소수점 값을 반정밀도 부동 소수점 수로 변환한 다음
하나의 u32 값으로 결합합니다.입력의 컴포넌트 e[i]는 IEEE-754 binary16
값으로 변환된 다음 결과의
16 × i번 비트부터
16 × i + 15번 비트까지 배치됩니다.
§ 15.7.6 부동 소수점 변환을 참조하십시오.
|
17.10. 데이터 언패킹 내장 함수
데이터 언패킹 내장 함수는 WGSL의 타입에 직접 대응하지 않는 데이터 형식의 값을 디코딩하는 데 사용할 수 있습니다. 이를 통해 프로그램이 조밀하게 패킹된 여러 값을 메모리에서 읽을 수 있으므로 셰이더의 메모리 대역폭 요구량을 줄일 수 있습니다.
각 내장 함수는 입력 값을 채널로 분할한 다음 각 채널에 채널 전달 함수를 적용합니다.
참고: unorm 값을 언패킹할 때 정규화된 부동 소수점 결과는 구간 [0.0, 1.0]에 있습니다.
참고: snorm 값을 언패킹할 때 정규화된 부동 소수점 결과는 구간 [-1.0, 1.0]에 있습니다.
17.10.1.
unpack4x8snorm
| 오버로드 |
|
| 설명 | 32비트 값을 네 개의 8비트 청크로 분해한 다음 각 청크를
부호 있는 정규화 부동 소수점 값으로 재해석합니다. 결과의 컴포넌트 i는 max(v ÷ 127, -1)입니다. 여기서 v는
e의 8×i번 비트부터 8×i + 7번 비트까지를
2의 보수 부호 있는 정수로 해석한 값입니다.
|
17.10.2.
unpack4x8unorm
| 오버로드 |
|
| 설명 | 32비트 값을 네 개의 8비트 청크로 분해한 다음 각 청크를
부호 없는 정규화 부동 소수점 값으로 재해석합니다. 결과의 컴포넌트 i는 v ÷ 255입니다. 여기서 v는
e의 8×i번 비트부터 8×i + 7번 비트까지를
부호 없는 정수로 해석한 값입니다.
|
17.10.3.
unpack4xI8
| 오버로드 |
|
| 설명 | e는 네 개의 8비트 부호 있는 정수 컴포넌트로 구성된 벡터로 해석됩니다.
e를 부호 확장하여 vec4<i32>로 언패킹합니다.
|
17.10.4.
unpack4xU8
| 오버로드 |
|
| 설명 | e는 네 개의 8비트 부호 없는 정수 컴포넌트로 구성된 벡터로 해석됩니다.
e를 0 확장하여 vec4<u32>로 언패킹합니다.
|
17.10.5.
unpack2x16snorm
| 오버로드 |
|
| 설명 | 32비트 값을 두 개의 16비트 청크로 분해한 다음 각 청크를
부호 있는 정규화 부동 소수점 값으로 재해석합니다. 결과의 컴포넌트 i는 max(v ÷ 32767, -1)입니다. 여기서 v는
e의 16×i번 비트부터 16×i + 15번 비트까지를
2의 보수 부호 있는 정수로 해석한 값입니다.
|
17.10.6.
unpack2x16unorm
| 오버로드 |
|
| 설명 | 32비트 값을 두 개의 16비트 청크로 분해한 다음 각 청크를
부호 없는 정규화 부동 소수점 값으로 재해석합니다. 결과의 컴포넌트 i는 v ÷ 65535입니다. 여기서 v는
e의 16×i번 비트부터 16×i + 15번 비트까지를
부호 없는 정수로 해석한 값입니다.
|
17.10.7.
unpack2x16float
| 오버로드 |
|
| 설명 | 32비트 값을 두 개의 16비트 청크로 분해하고 각 청크를
부동 소수점 값으로 재해석합니다. 결과의 컴포넌트 i는 v의 f32 표현입니다.
여기서 v는 e의 16×i번 비트부터
16×i + 15번 비트까지를
IEEE-754 binary16
값으로 해석한 것입니다.
§ 15.7.6 부동 소수점 변환을 참조하십시오.
|
17.11. 동기화 내장 함수
모든 동기화 함수는 획득/해제 메모리 순서를 사용하는 제어 배리어를 실행합니다. 즉, 모든 동기화 함수와 영향을 받는 메모리 및 원자 연산은 동기화 함수를 기준으로 프로그램 순서에 따라 정렬됩니다. 또한 동기화 함수보다 프로그램 순서상 앞에 있는 영향을 받는 메모리 및 원자 연산은 동기화 함수보다 프로그램 순서상 뒤에 있는 영향을 받는 메모리 또는 원자 연산이 워크그룹의 멤버에 의해 실행되기 전에 워크그룹의 다른 모든 스레드에 표시되어야 합니다.
모든 동기화 함수는 Workgroup 메모리
범위를 사용합니다.
모든 동기화 함수의 실행 범위는
Workgroup입니다.
모든 동기화 함수는 반드시
컴퓨트 셰이더 스테이지에서만 사용해야 합니다.
모든 동기화 함수는 반드시
균일 제어
흐름에서만 호출해야 합니다.
17.11.1.
storageBarrier
| 오버로드 |
|
| 설명 | storage 주소 공간의 메모리 및 원자 연산에 영향을 주는 제어 배리어 동기화 함수를 실행합니다. |
17.11.2.
textureBarrier
| 오버로드 |
|
| 설명 | handle 주소 공간의 메모리 연산에 영향을 주는 제어 배리어 동기화 함수를 실행합니다. |
17.11.3.
workgroupBarrier
| 오버로드 |
|
| 설명 | workgroup 주소 공간의 메모리 및 원자 연산에 영향을 주는 제어 배리어 동기화 함수를 실행합니다. |
17.11.4.
workgroupUniformLoad
| 오버로드 |
|
| 매개변수화 | T는 구체 생성 가능 타입입니다.
|
| 설명 |
p가 가리키는 값을 워크그룹의 모든 호출에 반환합니다.
반환 값은 균일합니다.
p는 반드시 균일 값이어야 합니다.
|
| 오버로드 |
|
| 설명 |
p가 가리키는 값을 원자적으로 로드하여 워크그룹의 모든 호출에
반환합니다.
반환 값은 균일합니다.
p는 반드시 균일 값이어야 합니다.
|
17.12. 서브그룹 내장 함수
§ 15.6.3 서브그룹 연산을 참조하십시오.
이러한 함수 호출은:
-
균일성 분석에서 호출이 균일 제어 흐름에 있음을 증명할 수 없으면 subgroup_uniformity 진단을 트리거합니다.
참고: 컴퓨트 셰이더 스테이지에서 균일 제어 흐름의 범위는 워크그룹입니다. 프래그먼트 셰이더 스테이지에서 균일 제어 흐름의 범위는 드로 명령입니다. 이 두 범위는 모두 서브그룹보다 큽니다.
17.12.1.
subgroupAdd
| 오버로드 |
|
| 전제 조건 | T는 구체 숫자 스칼라 또는 구체 숫자 벡터입니다
|
| 설명 |
축약 연산입니다. |
17.12.1.1. subgroupExclusiveAdd
| 오버로드 |
|
| 전제 조건 | T는 구체 숫자 스칼라 또는 구체 숫자 벡터입니다
|
| 설명 |
배타적 접두사 스캔 연산입니다. 서브그룹의
활성 호출 중
서브그룹 호출 ID가 현재
호출의 ID보다 작은 모든 호출에 대한 활성 호출 중 ID가 가장 작은 호출에 대해 반환되는 값은
|
17.12.1.2. subgroupInclusiveAdd
| 오버로드 |
|
| 전제 조건 | T는 구체 숫자 스칼라 또는 구체 숫자 벡터입니다
|
| 설명 |
포괄적 접두사 스캔 연산입니다. 서브그룹의
활성 호출 중
서브그룹 호출 ID가
현재 호출의 ID보다 작거나 같은 모든 호출에 대한 참고:
|
17.12.2.
subgroupAll
| 오버로드 |
|
| 설명 | 서브그룹의 모든
활성 호출에서
e가
true이면 true를 반환합니다.
|
17.12.3.
subgroupAnd
| 오버로드 |
|
| 전제 조건 | T는 i32, u32, vecN<i32> 또는 vecN<u32>입니다
|
| 설명 |
축약 연산입니다. |
17.12.4.
subgroupAny
| 오버로드 |
|
| 설명 | 서브그룹의
활성 호출 중
하나라도 e가
true이면 true를 반환합니다.
|
17.12.5.
subgroupBallot
| 오버로드 |
|
| 설명 |
서브그룹에서 pred가
true인
활성 호출의 비트
마스크를 반환합니다.반환 값의 x 컴포넌트에는 호출 0부터 31까지가 포함됩니다. 각 컴포넌트에서 ID는 비트 위치를 기준으로 오름차순입니다 (예: ID 32는 y 컴포넌트의 비트 위치 0에 있습니다). |
17.12.6.
subgroupBroadcast
| 오버로드 |
|
| 전제 조건 | T는 구체 숫자 스칼라 또는 구체 숫자 벡터입니다I는 u32 또는 i32입니다
|
| 설명 |
서브그룹에서 서브그룹 호출
ID가 id와 일치하는 호출의 e 값을
서브그룹의 모든 활성 호출에
반환합니다.
참고: 상수가 아닌 버전의
|
17.12.6.1. subgroupBroadcastFirst
| 오버로드 |
|
| 전제 조건 | T는 구체 숫자 스칼라 또는 구체 숫자 벡터입니다
|
| 설명 | 서브그룹의 활성 호출 중
서브그룹
호출 ID가 가장 작은 호출의
e 값을 서브그룹의 모든 활성 호출에 반환합니다.
|
17.12.7.
subgroupElect
| 오버로드 |
|
| 설명 | 현재 호출이 서브그룹의 활성 호출 중 가장
작은 서브그룹 호출 ID를 가지면
true를 반환합니다.
|
17.12.8.
subgroupMax
| 오버로드 |
|
| 전제 조건 | T는 구체 숫자 스칼라 또는 구체 숫자 벡터입니다
|
| 설명 |
축약 연산입니다. |
17.12.9.
subgroupMin
| 오버로드 |
|
| 전제 조건 | T는 구체 숫자 스칼라 또는 구체 숫자 벡터입니다
|
| 설명 |
축약 연산입니다. |
17.12.10.
subgroupMul
| 오버로드 |
|
| 전제 조건 | T는 구체 숫자 스칼라 또는 구체 숫자 벡터입니다
|
| 설명 |
축약 연산입니다. |
17.12.10.1. subgroupExclusiveMul
| 오버로드 |
|
| 전제 조건 | T는 구체 숫자 스칼라 또는 구체 숫자 벡터입니다
|
| 설명 |
배타적 접두사 스캔 연산입니다. 서브그룹의 활성 호출
중 서브그룹 호출 ID가 현재 호출의
ID보다 작은 모든 호출에 대한 활성 호출 중 ID가 가장 작은 호출에 대해 반환되는 값은
|
17.12.10.2. subgroupInclusiveMul
| 오버로드 |
|
| 전제 조건 | T는 구체 숫자 스칼라 또는 구체 숫자 벡터입니다
|
| 설명 |
포괄적 접두사 스캔 연산입니다. 서브그룹의 활성 호출
중 서브그룹 호출 ID가 현재 호출의
ID보다 작거나 같은 모든 호출에 대한 참고:
|
17.12.11.
subgroupOr
| 오버로드 |
|
| 전제 조건 | T는 i32, u32, vecN<i32> 또는 vecN<u32>입니다
|
| 설명 |
축약 연산입니다. |
17.12.12.
subgroupShuffle
| 오버로드 |
|
| 전제 조건 | T는 구체 숫자 스칼라 또는 구체 숫자 벡터입니다I는 u32 또는 i32입니다
|
| 설명 |
서브그룹 호출
ID가 id와 일치하는 호출의 e를 반환합니다.
|
17.12.12.1. subgroupShuffleDown
| 오버로드 |
|
| 전제 조건 | T는 구체 숫자 스칼라 또는 구체 숫자 벡터입니다
|
| 설명 |
현재 호출에 대해 서브그룹 호출
ID가 subgroup_invocation_id + delta와 일치하는 호출의
e를 반환합니다.
|
17.12.12.2. subgroupShuffleUp
| 오버로드 |
|
| 전제 조건 | T는 구체 숫자 스칼라 또는 구체 숫자 벡터입니다
|
| 설명 |
현재 호출에 대해 서브그룹 호출
ID가 subgroup_invocation_id - delta와 일치하는 호출의
e를 반환합니다.
|
17.12.12.3. subgroupShuffleXor
| 오버로드 |
|
| 전제 조건 | T는 구체 숫자 스칼라 또는 구체 숫자 벡터입니다
|
| 설명 |
현재 호출에 대해 서브그룹 호출
ID가 subgroup_invocation_id ^ mask와 일치하는 호출의
e를 반환합니다.
|
17.12.13.
subgroupXor
| 오버로드 |
|
| 전제 조건 | T는 i32, u32, vecN<i32> 또는 vecN<u32>입니다
|
| 설명 |
축약 연산입니다. |
17.13. 쿼드 연산
§ 15.6.4 쿼드 연산을 참조하십시오.
이러한 함수 호출은:
-
균일성 분석에서 호출이 균일 제어 흐름에 있음을 증명할 수 없으면 subgroup_uniformity 진단을 트리거합니다.
참고: 컴퓨트 셰이더 스테이지에서 균일 제어 흐름의 범위는 워크그룹입니다. 프래그먼트 셰이더 스테이지에서 균일 제어 흐름의 범위는 드로 명령입니다. 이 두 범위는 모두 쿼드보다 큽니다.
17.13.1.
quadBroadcast
| 오버로드 |
|
| 전제 조건 | T는 구체 숫자 스칼라 또는 구체 숫자 벡터입니다I는 u32 또는 i32입니다
|
| 설명 |
쿼드에서 쿼드 호출
ID가
id와 일치하는 호출의 e 값을 쿼드의 모든 활성 호출에 반환합니다.
참고: subgroupBroadcast와 달리 현재는 상수가 아닌 대안이 없습니다. |
17.13.2.
quadSwapDiagonal
| 오버로드 |
|
| 전제 조건 | T는 구체 숫자 스칼라 또는 구체 숫자 벡터입니다
|
| 설명 |
반대 좌표에 있는 쿼드 호출의 e 값을
반환합니다.
즉:
|
17.13.3.
quadSwapX
| 오버로드 |
|
| 전제 조건 | T는 구체 숫자 스칼라 또는 구체 숫자 벡터입니다
|
| 설명 |
같은 X 차원을 공유하는 쿼드 호출의 e
값을 반환합니다.
즉:
|
17.13.4.
quadSwapY
| 오버로드 |
|
| 전제 조건 | T는 구체 숫자 스칼라 또는 구체 숫자 벡터입니다
|
| 설명 |
같은 Y 차원을 공유하는 쿼드 호출의 e
값을 반환합니다.
즉:
|
17.14. 버퍼 뷰 내장 함수
이러한 함수에는 모두 buffer_view 언어 기능이 필요합니다.
이러한 함수는 버퍼에 대한 포인터에서 작동합니다. bufferView와 bufferArrayView는 버퍼의 불투명한 데이터를 다른 호스트 공유 가능 데이터 타입으로 재해석합니다. 결과 포인터는 다른 포인터처럼 사용할 수 있습니다.
ArrayOffset(T)을 다음과 같이 정의합니다.
-
T가 마지막 멤버가 런타임 크기 배열(array<E>)인 구조체이면 OffsetOfMember(T, lastMemberIndex)
-
그렇지 않으면 0
MinTypeSize(T)을 다음과 같이 정의합니다.
-
T가 마지막 멤버가 런타임 크기 배열인 구조체이면 ArrayOffset(T) + StrideOf(array<E>)
함수 호출에 대한 버퍼 포인터 인수는 매개변수 타입으로 자동 변환될 수 있으므로, 구현은 유효하지 않은 메모리 참조를 검사하고 올바른 결과를 보장하기 위해 프로시저 간 분석을 사용합니다. 모든 버퍼 뷰 내장 함수에 사용되는 버퍼 크기는 호출에 사용된 특정 원본 변수에서 발견되는 최소 버퍼 크기입니다. 이는 동적 개념이므로 구현은 내장 함수의 특정 인스턴스에 대해 이 값이 올바르게 결정되도록 보장합니다. 크기는 다음 중 최솟값입니다.
참고: 구현이 unrestricted_pointer_parameters 언어 기능을 지원하지 않으면 내장 함수 인수의 루트 식별자는 원본 변수여야 합니다.
참고: 버퍼 크기는 함수에 전달될 때 더 크게 만들 수 없습니다.
17.14.1.
bufferView
| 오버로드 |
|
| 전제 조건 |
AS는 storage, uniform 또는
workgroup 중 하나입니다.AM은 AS에 유효한 액세스 모드입니다.
|
| 설명 |
p 시작 지점에서 offset바이트 떨어진 메모리
뷰를 T 타입으로 재해석합니다.
즉, p와 연결된 메모리 위치가
[0, bufferLength(p)) 범위에 있으면 결과와 연결된 메모리 위치는 저장 타입이 T인
[offset, bufferLength(p)) 범위에 있습니다.
MinTypeSize(
참고: 이는 uniform_buffer_standard_layout 언어 기능과 상호작용합니다. |
| 오버로드 |
|
| 전제 조건 |
AS는 storage, uniform 또는
workgroup 중 하나입니다.AM은 AS에 유효한 액세스 모드입니다.
|
| 설명 |
p 시작 지점에서 offset바이트 떨어진 메모리
뷰를 T 타입으로 재해석합니다.
즉, p와 연결된 메모리 위치가
[0, bufferLength(p)) 범위에 있으면 결과와 연결된 메모리 위치는 저장 타입이 T인
[offset, bufferLength(p)) 범위에 있습니다.
MinTypeSize(
참고: 이는 uniform_buffer_standard_layout 언어 기능과 상호작용합니다. |
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
| 오버로드 |
|
| 전제 조건 |
AS는 storage, uniform 또는
workgroup 중 하나입니다.AM은 AS에 유효한 액세스 모드입니다.
|
| 설명 |
p 시작 지점에서 offset바이트 떨어진 곳부터
size바이트에 해당하는 메모리 뷰를
T 타입으로 재해석합니다.
즉, p와 연결된 메모리 위치가
[0, bufferLength(p)) 범위에 있으면 결과와 연결된 메모리 위치는 저장 타입이
T인 [offset, offset + size) 범위에 있습니다.
MinTypeSize(
참고: 이는 uniform_buffer_standard_layout 언어 기능과 상호작용합니다. (
|
| 오버로드 |
|
| 전제 조건 |
AS는 storage, uniform 또는
workgroup 중 하나입니다.AM은 AS에 유효한 액세스 모드입니다.
|
| 설명 |
p 시작 지점에서 offset바이트 떨어진 곳부터
size바이트에 해당하는 메모리 뷰를
T 타입으로 재해석합니다.
즉, p와 연결된 메모리 위치가
[0, bufferLength(p)) 범위에 있으면 결과와 연결된 메모리 위치는 저장 타입이
T인 [offset, offset + size) 범위에 있습니다.
MinTypeSize(
MinTypeSize(
참고: 이는 uniform_buffer_standard_layout 언어 기능과 상호작용합니다. (
|
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
| 오버로드 |
|
| 전제 조건 |
AS는 storage, uniform 또는
workgroup 중 하나입니다.AM은 AS에 유효한 액세스 모드입니다.
|
| 설명 |
프로시저 간 분석 중 발견된 p가 가리키는 버퍼의 최소 크기를 반환하거나,
런타임 크기
버퍼만 발견된 경우 WebGPU GPUBuffer의
크기를 반환합니다.
|
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 토큰으로 구분됩니다.
간결성을 위해 많은 토큰 정의는 반복하지 않습니다. 명세 본문의 토큰 정의를 사용하십시오.
'+'
| '-'
'(' ( expression ( ',' expression )* ',' ? )?
')'
| '='
| '@' 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 ',' ?
')'
'&' unary_expression ( '&'
unary_expression )*
| '^' unary_expression ( '^' unary_expression )*
| '|' unary_expression ( '|' unary_expression )*
'false'
| 'true'
template_elaborated_ident.post.ident
'(' ( expression ( ',' expression )* ',' ? )?
')'
| 'default'
'.' member_ident component_or_swizzle_specifier
?
| '.' swizzle_name component_or_swizzle_specifier
?
| '[' expression ']' component_or_swizzle_specifier
?
| '%='
| '&='
| '*='
| '+='
| '-='
| '/='
| '^='
| '|='
'@' 'compute'
'@' 'const'
/0[iu]?/
| /[1-9][0-9]*[iu]?/
'(' ident_pattern_token ',' diagnostic_rule_name ','
? ')'
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
)*
'@' 'fragment'
'const_assert' ';'
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 )* ',' ?
'}'
'diagnostic' '(' ident_pattern_token ',' diagnostic_rule_name
',' ? ')' ';'
| 'enable' ident_pattern_token ( ',' ident_pattern_token )* ',' ?
';'
| 'requires' ident_pattern_token ( ',' ident_pattern_token )* ',' ?
';'
attribute * 'override' optionally_typed_ident (
'=' expression )?
| 'const' optionally_typed_ident
'=' expression
'@' 'interpolate' '(' ident_pattern_token
',' ? ')'
| '@' 'interpolate' '(' ident_pattern_token
',' ident_pattern_token ',' ?
')'
'@' 'invariant'
core_lhs_expression component_or_swizzle_specifier ?
| '&' lhs_expression
| '*' lhs_expression
'%'
| '*'
| '/'
'@' 'must_use'
ident ( ':' type_specifier )?
attribute * ident
':' type_specifier
ident template_elaborated_ident.post.ident
| ident template_elaborated_ident.post.ident argument_expression_list
| literal
| '(' 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
( multiplicative_operator unary_expression )* ( additive_operator unary_expression ( multiplicative_operator unary_expression )* )*
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
| 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 ? ';'
'case' case_selector ( ',' case_selector )* ',' ?
':' ? compound_statement
| 'default' ':' ? compound_statement
/[rgba]/
| /[rgba][rgba]/
| /[rgba][rgba][rgba]/
| /[rgba][rgba][rgba][rgba]/
| /[xyzw]/
| /[xyzw][xyzw]/
| /[xyzw][xyzw][xyzw]/
| /[xyzw][xyzw][xyzw][xyzw]/
( _template_args_start template_arg_expression (
',' expression )* ',' ? _template_args_end )?
global_directive * ( global_decl | global_assert | ';' ) *
ident ( _template_args_start template_arg_expression (
',' expression )* ',' ? _template_args_end )?
primary_expression component_or_swizzle_specifier ?
| '!' unary_expression
| '&' unary_expression
| '*' unary_expression
| '-' unary_expression
| '~' unary_expression
'var' ( _template_args_start expression ( ',' expression )* ',' ? _template_args_end )? optionally_typed_ident
| variable_decl '=' expression
| 'const' optionally_typed_ident
'=' expression
| 'let' optionally_typed_ident
'=' expression
lhs_expression ( '=' | compound_assignment_operator
) expression
| lhs_expression '++'
| lhs_expression '--'
| '_' '=' expression
'@' 'vertex'
'@' 'workgroup_size' '(' expression ',' ?
')'
| '@' 'workgroup_size' '(' expression ',' expression ',' ?
')'
| '@' 'workgroup_size' '(' expression ',' expression ',' expression ',' ?
')'
부록 A:
text/wgsl 미디어 타입
인터넷 할당 번호 관리 기관(IANA)은 [IANA-MEDIA-TYPES]에서 미디어 타입 레지스트리를 관리합니다.
다음은 WGSL 모듈을 위한 text/wgsl 미디어 타입의 정의입니다.
이 미디어 타입은 IANA에 등록되어 있으며,
https://www.iana.org/assignments/media-types/text/wgsl에서
확인할 수 있습니다.
- 타입 이름
-
text
- 하위 타입 이름
-
wgsl
- 필수 매개변수
-
해당 없음
- 선택적 매개변수
-
없음
- 인코딩 고려사항
-
binary
WGSL은 바이트 순서 표시(BOM) 없이 UTF-8 인코딩을 사용하는 유니코드 텍스트입니다. § 3 텍스트 구조를 참조하십시오.
- 보안 고려사항:
-
WebGPU 셰이딩 언어(WGSL)는 WebGPU API의 문맥에서 실행되는 GPU 코드를 위한 프로그래밍 언어입니다. 보안 고려사항은 [WebGPU] 2.1절 보안 고려사항을 참조하십시오. 개인정보 보호 고려사항은 [WebGPU] 2.2절 개인정보 보호 고려사항을 참조하십시오.
- 상호운용성 고려사항:
-
WebGPU 구현은 서로 다른 기능을 가질 수 있으며, 이러한 차이는 WGSL 프로그램에서 사용할 수 있는 기능에 영향을 줄 수 있습니다. [WebGPU] 3.6절 선택적 기능과 § 4.1.2 언어 확장을 참조하십시오.
구현은 이 등록이 이후 버전의 WGSL에도 적용되는 것처럼 동작할 것으로 예상되며, 공개된 명세 참조도 이에 따라 수시로 갱신될 수 있습니다. 이러한 기대는 미디어 타입 등록에서는 이례적이지만 널리 사용되는 업계 관행과 일치합니다.
- 공개된 명세:
-
WebGPU 셰이딩 언어
- 이 미디어 타입을 사용하는 애플리케이션:
-
WebGPU 구현입니다. 웹 브라우저가 포함될 것으로 예상됩니다.
- 프래그먼트 식별자 고려사항
-
없음
- 추가 정보:
-
매직 넘버: 없음
파일 확장자:
.wgslMacintosh 파일 타입 코드:
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