1. 소개
WebGPU 셰이딩 언어(WGSL)는 [WebGPU]를 위한 셰이더 언어입니다. 즉, WebGPU API를 사용하는 애플리케이션은 GPU에서 실행되는 셰이더라고 하는 프로그램을 WGSL을 사용하여 표현합니다.
// 점 광원으로 텍스처가 적용된 지오메트리를 조명하는 프래그먼트 셰이더입니다. // 스토리지 버퍼 바인딩의 광원입니다. struct PointLight { position: vec3f, color : vec3f, } struct LightStorage { pointCount : u32, point : array< PointLight > , } @group ( 0 ) @binding ( 0 ) var < storage> lights : LightStorage ; // 텍스처와 샘플러입니다. @group ( 1 ) @binding ( 0 ) var baseColorSampler : sampler; @group ( 1 ) @binding ( 1 ) var baseColorTexture : texture_2d< f32> ; // 함수 인수는 버텍스 셰이더에서 전달된 값입니다. @fragment fn fragmentMain ( @location ( 0 ) worldPos : vec3f, @location ( 1 ) normal : vec3f, @location ( 2 ) uv : vec2f) -> @location ( 0 ) vec4f{ // 텍스처에서 표면의 기본 색상을 샘플링합니다. let baseColor = textureSample ( baseColorTexture , baseColorSampler , uv ); let N = normalize ( normal ); var surfaceColor = vec3f( 0 ); // 장면의 점 광원을 순회합니다. for ( var i = 0u ; i < lights . pointCount ; i ++ ) { let worldToLight = lights . point [ i ]. position- worldPos ; let dist = length ( worldToLight ); let dir = normalize ( worldToLight ); // 이 광원이 표면 색상에 기여하는 정도를 결정합니다. let radiance = lights . point [ i ]. color * ( 1 / pow ( dist , 2 )); let nDotL = max ( dot ( N , dir ), 0 ); // 표면 색상에 광원의 기여도를 누적합니다. surfaceColor += baseColor . rgb * radiance * nDotL ; } // 누적된 표면 색상을 반환합니다. return vec4( surfaceColor , baseColor . a ); }
1.1. 개요
WebGPU는 GPU 명령의 형태로 작업 단위를 GPU에 전달합니다. WGSL은 두 종류의 GPU 명령과 관련됩니다.
두 종류의 파이프라인 모두 WGSL로 작성된 셰이더를 사용합니다.
셰이더는 파이프라인에서 셰이더 스테이지를 실행하는 WGSL 프로그램의 부분입니다. 셰이더는 다음으로 구성됩니다.
-
진입점에서 시작하여 호출되는 모든 함수의 추이적 폐쇄입니다. 이 집합에는 사용자 정의 함수와 내장 함수가 모두 포함됩니다. (보다 엄밀한 정의는 "셰이더 스테이지의 함수"를 참조하십시오.)
-
이 모든 함수가 정적으로 접근하는 변수 및 상수의 집합입니다.
-
이 모든 함수, 변수 및 상수를 정의하거나 분석하는 데 사용되는 유형의 집합입니다.
참고: WGSL 프로그램에는 진입점이 필수는 아닙니다. 그러나
GPUProgrammableStage를
생성하려면 진입점이 필요하므로 이러한 프로그램은 API에서 실행할 수 없습니다.
셰이더 스테이지를 실행할 때 구현은 다음을 수행합니다.
-
모듈 범위에서 선언된 상수의 값을 계산합니다.
-
리소스를 셰이더의 리소스 인터페이스에 있는 변수에 바인딩하여 실행 중에 해당 리소스의 내용을 셰이더에서 사용할 수 있도록 합니다.
-
다른 모듈 범위 변수에 메모리를 할당하고 해당 메모리를 지정된 초기값으로 채웁니다.
-
진입점의 형식 매개변수가 존재하는 경우 셰이더 스테이지의 입력으로 채웁니다.
-
진입점의 반환 값이 존재하는 경우 셰이더 스테이지의 출력에 연결합니다.
-
그런 다음 진입점을 호출합니다.
WGSL 프로그램은 다음으로 구성됩니다.
-
지시문: 모듈 수준의 동작 제어를 지정합니다.
-
함수: 실행 동작을 지정합니다.
-
문: 선언 또는 실행 가능한 동작의 단위입니다.
-
리터럴: 순수한 수학적 값을 나타내는 텍스트 표현입니다.
-
상수: 각각 특정 시점에 계산된 값의 이름을 제공합니다.
-
변수: 각각 값을 보유하는 메모리의 이름을 제공합니다.
-
표현식: 각각 값 집합을 결합하여 결과 값을 생성합니다.
-
유형: 각각 다음을 설명합니다.
-
값의 집합.
-
지원되는 표현식에 대한 제약 조건.
-
해당 표현식의 의미론.
-
-
속성: 객체를 수정하여 다음과 같은 추가 정보를 지정합니다.
참고: 현재 WGSL 프로그램은 하나의 WGSL 모듈로 구성됩니다.
WGSL은 명령형 언어입니다. 동작은 실행할 문의 순서로 지정됩니다. 문은 다음을 수행할 수 있습니다.
-
변수의 내용을 수정합니다.
-
구조적 프로그래밍 구문을 사용하여 실행 순서를 수정합니다.
-
위 동작의 일부로 값을 계산하기 위해 표현식을 평가합니다.
WGSL은 정적 유형 언어입니다. 특정 표현식으로 계산되는 각 값은 프로그램 소스만 검사하여 결정되는 특정 유형에 속합니다.
WGSL에는 불리언과 숫자 (정수 및 부동 소수점)를 설명하는 유형이 있습니다. 이러한 유형은 복합 유형 (벡터, 행렬, 배열, 구조체)으로 집계할 수 있습니다. WGSL에는 고유한 연산을 제공하는 특수 유형(예: 원자적 유형)이 있습니다. WGSL은 메모리에 저장할 수 있는 유형을 메모리 뷰로 설명합니다. WGSL은 일반적으로 사용되는 렌더링 유형을 텍스처 및 샘플러 형태로 제공합니다. 이러한 유형에는 그래픽 렌더링에 일반적으로 제공되는 GPU 하드웨어를 노출하기 위한 관련 내장 함수가 있습니다.
WGSL은 암시적 변환과 승격을 매우 제한적으로 지원합니다. 추상 유형과 버퍼 포인터가 함수 호출에 인수로 전달될 때만 암시적 변환 및 승격을 제공합니다. 하나의 구체적 숫자 또는 불리언 유형에서 다른 유형으로 값을 변환하려면 명시적 변환, 값 생성자, 또는 비트 재해석이 필요합니다. 그러나 WGSL은 스칼라 유형을 벡터 유형으로 승격하는 제한적인 기능을 제공합니다. 이는 복합 유형에도 적용됩니다.
셰이더 스테이지의 작업은 하나 이상의 호출로 분할되며, 각 호출은 진입점을 실행하지만 약간 서로 다른 조건에서 실행됩니다. 셰이더 스테이지의 호출은 특정 변수에 대한 접근을 공유합니다.
-
스테이지의 모든 호출은 셰이더 인터페이스의 리소스를 공유합니다.
-
컴퓨트 셰이더에서 동일한 워크그룹의 호출은 workgroup 주소 공간의 변수를 공유합니다. 서로 다른 워크그룹의 호출은 해당 변수를 공유하지 않습니다.
그러나 호출은 호출을 다른 호출과 구별하기 위한 식별 값을 제공하는 내장 입력을 포함하여 서로 다른 셰이더 스테이지 입력 집합에 대해 동작합니다. 각 호출에는 private 및 function 주소 공간의 변수 형태로 독립적인 자체 메모리 공간이 있습니다.
셰이더 스테이지 내의 호출은 동시에 실행되며 흔히 병렬로 실행될 수 있습니다. 셰이더 작성자는 셰이더 스테이지의 호출이 동적으로 다음을 수행하도록 보장할 책임이 있습니다.
-
텍스처 샘플링과 제어 배리어를 포함한 특정 기본 연산의 균일성 요구 사항을 충족합니다.
-
데이터 경합을 방지하기 위해 공유 변수에 대한 잠재적으로 충돌하는 접근을 조정합니다.
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는 변경되지 않습니다.
-
-
off 심각도를 가진 진단을 버립니다.
-
남은 진단 중 적어도 하나인 DI의 심각도가 info인 경우 다음을 수행합니다.
-
트리거 규칙이 동일한 다른 info 진단은 원래 진단 DI만 남기고 버릴 수 있습니다.
-
-
남은 진단 중 적어도 하나인 DW의 심각도가 warning인 경우 다음을 수행합니다.
-
남은 진단 중 적어도 하나의 심각도가 error인 경우 다음을 수행합니다.
-
셰이더 모듈 생성 시점에 처리하는 경우 남은 진단은 WebGPU
GPUCompilationInfo객체의messages멤버를 채웁니다. -
파이프라인 생성 중에 처리하는 경우 error 진단은
GPUProgrammableStage를 검증할 때 WebGPU 검증 실패를 발생시킵니다.
참고: 이 규칙은 오류가 감지되는 즉시 구현이 WGSL 모듈 처리를 중단할 수 있도록 허용합니다. 또한 특정 종류의 경고에 대한 분석은 첫 번째 경고에서 중단할 수 있고, 특정 종류의 정보 진단에 대한 분석은 첫 번째 발생에서 중단할 수 있습니다. WGSL은 서로 다른 종류의 분석을 수행하는 순서나 단일 분석 내의 순서를 규정하지 않습니다. 따라서 동일한 WGSL 모듈에 대해 서로 다른 구현이 동일한 심각도의 서로 다른 진단 인스턴스를 보고할 수 있습니다.
2.3.2. 필터링 가능한 트리거 규칙
대부분의 진단은 무조건 WebGPU 애플리케이션에 보고됩니다. 일부 종류의 진단은 해당 트리거 규칙의 이름을 지정하는 등의 방법으로 필터링할 수 있습니다. 다음 표에는 필터링할 수 있는 표준 트리거 규칙 집합이 나열되어 있습니다.
| 필터링 가능한 트리거 규칙 | 기본 심각도 | 트리거 위치 | 설명 |
|---|---|---|---|
| derivative_uniformity | error | 도함수를 계산하는 내장 함수에 대한 호출 위치. 즉, 다음 중 하나를 호출하는 위치입니다. |
내장 함수 호출이 도함수를 계산하지만 균일성 분석이
해당 호출이 균일한 제어 흐름에서 발생함을 증명할 수 없습니다.
§ 15.2 균일성을 참조하십시오. |
| subgroup_uniformity | error | 서브그룹 또는 쿼드 내장 함수에 대한 호출 위치. |
서브그룹 또는 쿼드 내장 함수 호출이지만 균일성 분석이
해당 호출이 균일한 제어 흐름에서 발생함을 증명할 수 없습니다.
또한 균일성 분석이 다음 매개변수 값이 균일함을
증명할 수 없는 경우도 포함됩니다.
§ 15.2 균일성을 참조하십시오. |
단일 진단 이름 토큰으로 구성된 인식되지 않는 트리거 규칙을 사용하면 사용자 에이전트가 경고를 트리거하는 것이 좋습니다.
구현은 여기에서 지정되지 않은 트리거 규칙을 지원할 수 있습니다. 단, diagnostic_rule_name의 다중 토큰 형식을 사용하여 작성해야 합니다. 다중 토큰 형식으로 작성된 인식되지 않는 트리거 규칙을 사용하면 그 자체로 진단을 트리거할 수 있습니다.
이 명세의 향후 버전은 특정 규칙을 제거하거나 기본 심각도를 낮추고
(즉, 현재 기본값을 덜 심각한 기본값으로 대체하고) 여전히 하위 호환성을 충족하는 것으로
간주될 수 있습니다.
예를 들어 향후 WGSL 버전은 derivative_uniformity의 기본 심각도를
error에서 warning 또는 info로 변경할 수 있습니다.
명세가 이렇게 변경된 후에도 이전에 유효했던 프로그램은 계속 유효합니다.
2.3.3. 진단 필터링
필터링 가능한 트리거 규칙을 가진 진단이 트리거되면, WGSL은 진단을 버리거나 심각도를 수정하는 메커니즘을 제공합니다.
진단 필터 DF에는 세 개의 매개변수가 있습니다.
진단 필터 DF(AR,NS,TR)을 진단 D에 적용하면 다음과 같은 효과가 있습니다.
범위 진단
필터는 진단 필터 중
영향 범위가 지정된
소스 텍스트 범위인 필터입니다.
범위 진단 필터는 다음 표에 지정된 대로 영향받는 소스 범위의 시작 부분에
@diagnostic 속성으로 지정합니다.
@diagnostic 속성은 다른 위치에 나타나서는 안 됩니다.
| 배치 | 영향 범위 |
|---|---|
| 복합문의 시작. | 복합문. |
| 함수 선언의 시작. | 함수 선언. |
| if 문의 시작. | if 문: if_clause와 연결된 모든 else_if_clause 및 else_clause 절과 모든 제어 조건 표현식. |
| switch 문의 시작. | switch 문: 선택자 표현식과 switch_body. |
| switch_body의 시작. | switch_body. |
| loop 문의 시작. | loop 문. |
| while 문의 시작. | while 문: 조건 표현식과 루프 본문 모두. |
| for 문의 시작. | for 문: for_header와 루프 본문. |
loop, while 또는 for 루프의 루프 본문의 여는
중괄호('{')
바로 앞.
| 루프 본문. |
| continuing_compound_statement의 시작. | continuing_compound_statement. |
참고: 다음도 복합문입니다. 함수 본문, case 절, 독립 default 절, while 및 for 루프의 본문, 그리고 if_clause, else_if_clause 및 else_clause의 본문.
var < private> d : f32; fn helper () -> vec4< f32> { // "if" 본문에서 derivative_uniformity 진단을 // 비활성화합니다. if ( d < 0.5 ) @diagnostic ( off , derivative_uniformity ) { return textureSample ( t , s , vec2( 0 , 0 )); } return vec4( 0.0 ); }
전역 진단 필터를 사용하여 전체 WGSL 모듈에 진단 필터를 적용할 수 있습니다.
diagnostic ( off , derivative_uniformity ); var < private> d : f32; fn helper () -> vec4< f32> { if ( d < 0.5 ) { // 여기에서는 전역 진단 필터에 의해 // derivative_uniformity 진단이 비활성화됩니다. return textureSample ( t , s , vec2( 0 , 0 )); } else { // derivative_uniformity 진단의 심각도를 'warning'으로 설정합니다. @diagnostic ( warning , derivative_uniformity ) { return textureSample ( t , s , vec2( 0 , 0 )); } } return vec4( 0.0 ); }
두 진단 필터 DF(AR1,NS1,TR1) 및 DF(AR2,NS2,TR2)는 다음 조건에서 충돌합니다.
-
(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 문에 대해 default 절을 포함한 case 값 수의 합입니다. | 1023 |
| 단일 셰이더에서 정적으로 접근되는 private 주소 공간에 인스턴스화된 모든 변수의 결합된 최대 바이트 크기 | 8192 |
| 단일 함수에 선언된 function 주소 공간에 인스턴스화된 모든 변수의 결합된 최대 바이트 크기 | 8192 |
|
단일 셰이더에서
정적으로
접근되는
workgroup 주소 공간에 인스턴스화된
모든 변수의
결합된 최대 바이트 크기
이 제한의 목적상 고정 풋프린트 배열은 override 값을 대입할 때 생성 시 고정 풋프린트 배열로 취급됩니다. 이는 WebGPU maxComputeWorkgroupStorageSize 제한을 독립적인 WGSL 제한으로 매핑합니다. | 16384 |
|
즉시 데이터 변수의 최대 바이트 크기.
이는 WebGPU maxImmediateSize 제한을 독립적인 WGSL 제한으로 매핑합니다. | 64 |
| 배열 유형의 값 생성자 표현식의 최대 요소 수 | 2047 |
3. 텍스트 구조
text/wgsl 미디어 유형은 콘텐츠를 WGSL 모듈로 식별하는 데 사용됩니다.
부록 A: text/wgsl 미디어 유형을 참조하십시오.
WGSL 모듈은 바이트 순서 표시(BOM)가 없는 UTF-8 인코딩의 유니코드 텍스트입니다.
WGSL 모듈 텍스트는 유니코드 코드 포인트의 시퀀스로 구성되며, 연속된 비어 있지 않은 집합으로 그룹화되어 다음을 형성합니다.
프로그램 텍스트에는 null 코드 포인트(U+0000)가 포함되어서는
안 됩니다.
3.1. 구문 분석
WGSL 모듈을 구문 분석하려면 다음을 수행합니다.
주석을 제거합니다.
첫 번째 주석을 공백 코드 포인트(
U+0020)로 대체합니다.주석이 남아 있지 않을 때까지 반복합니다.
§ 3.9 템플릿 목록의 알고리즘을 사용하여 템플릿 목록을 찾습니다. 이 단계는
'<'(U+003C) 및'>'(U+003E) 코드 포인트가 템플릿 목록 구분 기호로 사용되는 경우와 비교 연산자 등 다른 용도로 사용되는 경우를 구분합니다.전체 텍스트를 구문 분석하여 translation_unit 문법 규칙과 일치시키려고 시도합니다. 구문 분석은 다음 사용자 지정을 포함한 LALR(1) 파서(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이 아닌 십진 숫자 시퀀스. -
0x또는0X뒤에 16진 숫자 시퀀스.
-
-
그 뒤에 선택적인
i또는u접미사.
참고: 0이 아닌 정수 리터럴 앞의 0(예: 012)은 금지됩니다. 이는 다른 언어의 선행 0이 8진수를 의미하는 표기법과의 혼동을 방지하기 위한 것입니다.
/0[iu]?/
| /[1-9][0-9]*[iu]?/
/0[xX][0-9a-fA-F]+[iu]?/
부동 소수점 리터럴은 십진 부동 소수점 리터럴 또는 16진 부동 소수점 리터럴입니다.
부동 소수점 리터럴에는 두 개의 논리적 부분이 있습니다. 분수를 나타내는 가수와 선택적인 지수입니다. 대략적으로 리터럴의 값은 가수에 밑을 주어진 지수만큼 거듭제곱한 값을 곱한 것입니다. 가수의 숫자가 0이 아니거나, 그 왼쪽과 오른쪽에 모두 0이 아닌 가수 숫자가 있는 경우 그 숫자는 유효합니다. 유효 숫자는 왼쪽에서 오른쪽으로 셉니다. N번째 유효 숫자의 왼쪽에는 N-1개의 유효 숫자가 있습니다.
십진 부동 소수점 리터럴은 다음과 같습니다.
-
숫자 시퀀스로 지정되며 그 사이 어딘가에 선택적인 소수점(
.)이 있는 가수. 가수는 10진법 표기에서 분수를 나타냅니다. -
그 다음 다음으로 구성된 선택적 지수 접미사:
-
e또는E. -
그 다음 선택적인 선행 부호(
+또는-)가 있는 십진수로 지정된 지수. -
그 다음 선택적인
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의 지수 거듭제곱을 곱한 값입니다. 지수가 지정되지 않은 경우 지수 0으로 간주합니다.
참고: 십진 가수는 20개의 십진 숫자 이후에 잘리며 분수에 약 log(10)/log(2)×20 ≈ 66.4개의 유효 비트를 보존합니다.
16진 부동 소수점 리터럴은 다음과 같습니다.
-
0x또는0X접두사 -
그 다음 16진 숫자 시퀀스로 지정되고 그 사이 어딘가에 선택적인 16진 소수점 (
.)이 있는 가수. 가수는 16진법 표기에서 분수를 나타냅니다. -
그 다음 다음으로 구성된 선택적 지수 접미사:
-
p또는P -
그 다음 선택적인 선행 부호(
+또는-)가 있는 십진수로 지정된 지수. -
그 다음 선택적인
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접미사가 있는 십진 부동 소수점 리터럴이 대상 유형을 오버플로하는 경우. -
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+003D)로 시작하지 않으므로 이전 코드 포인트는 템플릿 목록의 시작일 수 없습니다. 현재 코드 포인트와 이전 코드 포인트가'<='비교 연산자를 형성한다고 가정합니다. 이후 단계에서 이를 대입으로 잘못 인식하지 않도록'='(U+003D) 코드 포인트를 건너뜁니다.Pending 스택의 맨 위 항목을 팝합니다.
CurrentPosition을 이 코드 포인트 뒤로 이동시키고 루프의 다음 반복을 시작합니다.
루프의 다음 반복을 시작합니다.
CurrentPosition에
'>'(U+003E)가 나타나면 다음을 수행합니다:
참고: 이 코드 포인트는 템플릿 목록의 끝 후보입니다.
Pending이 비어 있지 않다면, 맨 위 항목을 T라고 하고, T.depth가 NestingDepth와 같으면 다음을 수행합니다:
참고: 이 코드 포인트는 시작 위치가 T에 기록된 현재 템플릿 목록을 끝냅니다.
TemplateList(start_position=T.position, end_position=CurrentPosition)를 DiscoveredTemplateLists에 추가합니다.
T를 Pending 스택에서 팝합니다.
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+003E) 코드 포인트(B 뒤)를 검사한 후에는
'=' (U+003D) 코드 포인트를 대입의 일부로 간주하지 않도록 특별히 인식해야 합니다.
참고:
A<(B!=C)>라는 구문을 검사할 때, 첫 번째 '<' (U+003C)
코드 포인트에서 시작해 마지막 '>' (U+003E) 코드 포인트에서 끝나는 하나의 템플릿 목록이 있으며,
템플릿 인수는 B!=C입니다.
'!' (U+0021) 코드 포인트('B' 뒤)를 검사한 후에는
'=' (U+003D) 코드 포인트를 대입의 일부로 간주하지 않도록 특별히 인식해야 합니다.
참고:
A<(B==C)>라는 구문을 검사할 때, 첫 번째 '<' (U+003C)
코드 포인트에서 시작해 마지막 '>' (U+003E) 코드 포인트에서 끝나는 하나의 템플릿 목록이 있으며,
템플릿 인수는 B==C입니다.
첫 번째 '=' (U+003D) 코드 포인트('B' 뒤)를 검사한 후에는 두 번째
'=' (U+003D) 코드 포인트를 어느 쪽도 대입의 일부로 간주하지 않도록 특별히 인식해야 합니다.
템플릿 목록 탐색이 완료된 후, 구문 분석은 각 템플릿 목록을 template_list 문법 규칙과 일치시키려고 시도합니다.
_template_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. 활성화 확장
활성화 확장은 다음 조건에서만 기능을 사용할 수 있는 확장입니다:
-
구현이 이를 지원하고,
-
셰이더가 enable 지시문을 통해 명시적으로 요청하며,
-
해당 WebGPU
GPUFeatureName이GPUDevice를 생성할 때 요청된 필수 기능 중 하나였을 때입니다.
활성화 확장은 보편적으로 지원되지 않는 하드웨어 기능을 노출하기 위한 것입니다.
enable 지시문은 하나 이상의 활성화 확장 지원을 켜는 지시문입니다. 구현이 나열된 모든 활성화 확장을 지원하지 않으면 셰이더 생성 오류가 발생합니다.
'enable' enable_extension_list ';'
다른 지시문과 마찬가지로 enable 지시문이 존재하는 경우 모든 선언 및 const 어설션보다 먼저 나타나야 합니다. 확장 이름은 식별자가 아닙니다: 선언으로 해석되지 않습니다.
유효한 활성화 확장은 다음 표에 나열되어 있습니다.
| WGSL 활성화 확장 | WebGPU GPUFeatureName
| 설명 |
|---|---|---|
f16
| "shader-f16" | f16 유형을 WGSL 모듈에서 유효하게 사용할 수 있습니다. 그렇지 않으면 f16을 (직접 또는 간접적으로) 사용하면 셰이더 생성 오류가 발생합니다. |
clip_distances
| "clip-distances" | 내장 변수 clip_distances를 WGSL 모듈에서 유효하게 사용할 수 있습니다. 그렇지 않으면 clip_distances를 사용하면 셰이더 생성 오류가 발생합니다. |
dual_source_blending
| "dual-source-blending" | 속성 blend_src를 WGSL 모듈에서 유효하게 사용할 수 있습니다. 그렇지 않으면 blend_src를 사용하면 셰이더 생성 오류가 발생합니다. |
subgroups
| "subgroups" | WGSL 모듈에서 서브그룹 내장 값, 서브그룹 내장 함수, 및 쿼드 내장 함수를 유효하게 사용할 수 있습니다. 그렇지 않으면 이를 사용하면 셰이더 생성 오류가 발생합니다. |
primitive_index
| "primitive-index"
| 내장 변수 primitive_index를 WGSL 모듈에서 유효하게 사용할 수 있습니다. 그렇지 않으면 primitive_index를 사용하면 셰이더 생성 오류가 발생합니다. |
subgroup_size_control
| "subgroup-size-control"
| 속성 subgroup_size를 WGSL 모듈에서 유효하게 사용할 수 있습니다.
그렇지 않으면 subgroup_size를 사용하면 셰이더 생성 오류가 발생합니다.
subgroup_size_control이 활성화되면
subgroups가 자동으로 활성화됩니다.
|
atomic_vec2u_min_max
| "atomic-vec2u-min-max"
| 내장 함수 atomicStoreMin 및 atomicStoreMax를 storage 주소 공간의 atomic<vec2<u32>> 유형에 유효하게 사용할 수 있습니다. 그렇지 않으면 이를 사용하면 셰이더 생성 오류가 발생합니다. |
// 임의 정밀도 부동 소수점 유형을 위한 가상의 확장을 활성화합니다. enable arbitrary_precision_float ; enable arbitrary_precision_float ; // 중복된 enable 지시문도 허용됩니다. // 반올림 모드를 제어하는 가상의 확장을 활성화합니다. enable rounding_mode ; // arbitrary_precision_float가 다음 사용을 활성화한다고 가정합니다: // - 유형 f<E,M> // - 함수 반환, 형식 매개변수 및 let 선언의 유형으로 사용 // - AbstractFloat로부터의 값 생성자로 사용 // - 나눗셈 연산자 /의 피연산자로 사용 // @rounding_mode 속성이 rounding_mode enable 지시문에 의해 활성화된다고 가정합니다. @rounding_mode ( round_to_even ) fn halve_it ( x : f < 8 , 7 > ) -> f < 8 , 7 > { let two = f < 8 , 7 > ( 2 ); return x / 2 ; // 최근접 짝수 반올림 모드를 사용합니다. }
4.1.2. 언어 확장
언어 확장은 구현이 지원하는 경우 자동으로 사용할 수 있는 확장입니다. 프로그램이 이를 명시적으로 요청할 필요는 없습니다.
언어 확장은 모든 WebGPU 구현에서 합리적으로 지원할 수 있는 기능을 포함합니다. 기능이 보편적으로 지원되지 않는다면, 이는 일부 WebGPU 구현이 아직 이를 구현하지 않았기 때문입니다.
참고: 예를 들어 do-while 루프는 언어 확장이 될 수 있습니다.
WebGPU GPU
객체의 wgslLanguageFeatures
멤버는 구현이 지원하는
언어 확장
집합을 나열합니다.
requires 지시문은 하나 이상의 언어 확장을 프로그램이 사용함을 문서화하는 지시문입니다. 이는 구현이 노출하는 기능을 변경하지 않습니다. 구현이 필수 확장 중 하나를 지원하지 않으면 셰이더 생성 오류가 발생합니다.
WGSL 모듈은 requires 지시문을 사용하여 이식성 부족 가능성을 알리고, 이식성을 위한 의도된 최소 기준을 알릴 수 있습니다.
참고: WebGPU 구현 외부의 도구는 프로그램이 사용하는 모든 언어 확장이 프로그램의 requires 지시문으로 포함되는지 확인할 수 있습니다.
'requires' 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도
지원되는 경우 포인터에서도 동작합니다. |
| atomic_vec2u_min_max | atomic<vec2<u32>> 객체에서 atomicStoreMin 및 atomicStoreMax 내장 함수를 지원합니다. |
참고: 의도는 시간이 지남에 따라 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비트 부호 없는 정수 값의 집합은 이 명세에서
u32로 표기되며 WGSL 모듈에서도 동일하게 표기됩니다. -
구조체 유형 또는 구조체를 포함하는 유형은 표기가 다릅니다.
일부 WGSL 유형은 소스 프로그램을 분석하고 프로그램의 런타임 동작을 결정하는 데만 사용됩니다. 이 명세에서는 이러한 유형을 설명하지만 WGSL 소스 텍스트에는 나타나지 않습니다.
참고: 참조 유형은 WGSL 모듈에 작성되지 않습니다. § 6.5.3 참조 및 포인터 유형을 참조하십시오.
참고: 스위즐 뷰 유형은 WGSL 모듈에 작성되지 않습니다. § 6.5.4 스위즐 뷰 유형을 참조하십시오.
6.1. 유형 검사
WGSL 값은 표현식을 평가하여 계산됩니다.
표현식은 이름이
"expression"으로 끝나는 WGSL 문법 규칙 중 하나로 구문 분석되는 소스 텍스트의 구간입니다.
표현식 E는 바깥 표현식 E 안에 적절하게 포함된 표현식인
하위 표현식을 포함할 수 있습니다.
최상위
표현식은 그 자체가 하위 표현식이 아닌 표현식입니다.
§ 8.19 표현식 문법 요약을 참조하십시오.
표현식 평가에서 생성되는 특정 값은 다음에 따라 달라집니다:
-
정적 컨텍스트: 표현식을 둘러싼 소스 텍스트, 그리고
-
동적 컨텍스트: 표현식을 평가하는 호출의 상태와 해당 호출이 실행되는 실행 컨텍스트.
특정 표현식을 평가하여 나올 수 있는 값은 항상 특정 WGSL 유형에 속하며, 이를 표현식의 정적 유형이라고 합니다. WGSL의 규칙은 표현식의 정적 유형이 표현식의 정적 컨텍스트에만 의존하도록 설계되어 있습니다.
유형 단언은 일부 WGSL 소스 표현식을 WGSL 유형에 매핑하는 것입니다. 표기법
e : T
은 T가 WGSL 표현식 e의 정적 유형임을 의미하는 유형 단언입니다.
참고: 유형 단언은 프로그램 텍스트에 대한 사실의 진술입니다. 런타임 검사가 아닙니다.
문은 종종 표현식을 사용하며 해당 표현식의 정적 유형에 요구 사항을 둘 수 있습니다. 예를 들면 다음과 같습니다:
성공적으로 구문 분석된 WGSL 모듈의 유형 검사는 각 표현식을 정적 유형에 매핑하고 각 문의 유형 요구 사항이 충족되는지 확인하는 과정입니다. 유형 검사가 실패하면 유형 오류라고 하는 셰이더 생성 오류의 특수한 경우가 발생합니다.
유형 검사는 구문 구문에 유형 규칙을 재귀적으로 적용하여 수행할 수 있습니다. 여기서 구문 구문은 표현식 또는 문입니다. 유형 규칙은 구문 구문에 대한 정적 컨텍스트가 해당 구문 안에 포함된 표현식의 정적 유형을 결정하는 방식을 설명합니다. 유형 규칙은 두 부분으로 구성됩니다:
-
결론.
-
전제 조건은 다음으로 구성됩니다:
-
표현식의 경우:
-
하위 표현식이 있는 경우 그 하위 표현식의 유형 단언. 각각은 직접 충족되거나 실현 가능한 자동 변환 (§ 6.1.2 변환 순위에 정의됨)을 통해 충족될 수 있습니다. WGSL은 프로그램의 정적 유형을 결정하는 데 필요한 모든 const 표현식을 평가합니다.
-
표현식이 문에서 사용되는 방식.
-
-
문의 경우:
-
문의 구문 형태, 그리고
-
문 안의 최상위 표현식에 대한 유형 단언.
-
-
있는 경우 기타 도식적 매개변수에 대한 조건.
-
선택적으로 기타 정적 컨텍스트.
-
유형 규칙은 전제 조건과 결론에 유형 매개변수를 가질 수 있습니다. 유형 규칙의 결론이나 전제 조건에 유형 매개변수가 포함되어 있으면 이를 매개변수화됨이라고 합니다. 포함되어 있지 않으면 규칙이 완전히 구체화됨이라고 합니다. 매개변수화된 유형 규칙의 각 유형 매개변수에 유형을 대입하여 완전히 구체화된 유형 규칙을 만들 수 있으며, 규칙에서 동일한 매개변수가 나타날 때마다 동일한 유형을 사용합니다. 규칙의 유형 매개변수에 유형을 할당하는 것을 대입이라고 합니다.
예를 들어 다음은 논리 부정
(!e 형태의 표현식)에 대한 유형 규칙입니다:
| 전제 조건 | 결론 |
|---|---|
| e: T T is bool or vecN<bool> | !e: T
|
이는 유형 매개변수 T를 포함하므로 매개변수화된 규칙이며,
T는 네 유형 중 하나인
bool, vec2<bool>,
vec3<bool>, 또는 vec4<bool>을 나타낼 수 있습니다.
T를 vec3<bool>로 매핑하는 대입을 적용하면
다음과 같은 완전히 구체화된 유형 규칙이 생성됩니다:
| 전제 조건 | 결론 |
|---|---|
e: vec3<bool> | !e: vec3<bool>
|
규칙의 다른 조건을 만족하는 어떤 대입을 적용하여 매개변수화된 규칙에서 생성할 수 있는 각각의 완전히 구체화된 규칙을 매개변수화된 규칙의 오버로드라고 합니다. 예를 들어 불리언 부정 규칙에는 네 개의 오버로드가 있습니다. 이는 유형 매개변수 T에 유형을 할당하는 방법이 네 가지이기 때문입니다.
참고: 즉, 매개변수화된 유형 규칙은 완전히 구체화된 유형 규칙 집합을 위한 패턴을 제공하며, 각각은 매개변수화된 규칙에 서로 다른 대입을 적용하여 생성됩니다.
유형 규칙이 구문 구문에 적용된다고 하는 경우는 다음과 같습니다:
-
규칙의 결론이 구문 구문의 유효한 구문 분석과 일치하고,
-
규칙의 전제 조건이 충족됩니다.
매개변수화된 유형 규칙은 표현식에 적용되는 완전히 구체화된 유형 규칙을 생성하는 대입이 존재하는 경우 그 표현식에 적용됩니다.
표현식 1u+2u를 생각해 보십시오.
여기에는 두 개의 리터럴 하위 표현식인 1u와 2u가 있으며,
둘 다 u32 유형입니다.
최상위
표현식은 덧셈입니다.
§ 8.8 산술 표현식의 규칙을 참조하면, 다음 이유로
덧셈의 유형 규칙이 이 표현식에 적용됩니다:
-
1u+2u는 e1+e2 형태의 구문 분석과 일치하며, e1은1u를, e2는2u를 나타내고, -
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 부동 소수점 평가에 설명된 제한 사항을 전제로 값을 보존합니다.
참고: 자동 변환은 두 종류의 상황에서만 발생합니다. 첫째, const 표현식을 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는 모두 const 표현식이고 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번째 하위 표현식에 대해 다음이 성립합니다:
-
정적 유형이 계산되어 있습니다.
-
표현식의 정적 유형에서 전제 조건의 해당 유형 단언이 요구하는 유형으로의 실행 가능한 자동 변환이 있습니다. 해당 변환의 ConversionRank를 C.R(i)라고 합니다.
-
-
실행 가능한 자동 변환 후 하위 표현식 중 하나가 추상 유형으로 해석되지만 다른 하위 표현식 중 하나가 const 표현식이 아닌 모든 후보를 제거합니다.
참고: 결과적으로 구문의 하위 표현식 중 하나라도 const 표현식이 아니라면, 구문의 모든 하위 표현식은 구체적 유형이어야 합니다.
-
후보의 순위를 매깁니다. 두 오버로드 후보 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 // 접미사가 없는 정수 리터럴은 필요한 경우 부동 소수점으로 변환될 수 있습니다: // AbstractInt를 f32로 자동 변환하며 변환 순위는 5입니다. var f32_promotion : f32= 1 ; // 변수는 f32를 보유합니다. // 유효하지 않음: 부동 소수점에서 정수로의 실행 가능한 변환이 없습니다. var i32_demotion : i32= 1.0 ; // 유효하지 않음 // 표현식에서 추론됩니다. var u32_from_expr = 1 + u32_1 ; // 변수는 u32를 보유합니다. var i32_from_expr = 1 + i32_1 ; // 변수는 i32를 보유합니다. // 값은 표현 가능해야 합니다. let u32_too_large : u32= 1234567890123456890 ; // 유효하지 않음, 오버플로 let i32_too_large : i32= 1234567890123456890 ; // 유효하지 않음, 오버플로 let u32_large : u32= 2147483649 ; // 유효함 let i32_large : i32= 2147483649 ; // 유효하지 않음, 오버플로 let f32_out_of_range1 = 0x1p500 ; // 유효하지 않음, 범위 초과 let f32_hex_lost_bits = 0x1.0000000001p0 ; // 유효하지 않음, f32로 정확히 표현할 수 없음 // 최소 정수: AbstractInt에 단항 부정을 적용한 다음 i32를 추론합니다. // AbstractInt에서 구성 가능한 유형으로 가장 선호되는 변환(가장 낮은 // 변환 순위)은 AbstractInt에서 i32로의 변환입니다. let i32_min = - 2147483648 ; // 유형은 i32입니다. // 유효하지 않음. 위와 같이 AbstractInt에서 i32를 선택하지만 값이 // 범위를 벗어나 셰이더 생성 오류를 발생시킵니다. let i32_too_large_2 = 2147483648 ; // 유효하지 않음. // 하위 표현식은 AbstractInt 및 AbstractFloat로 해석될 수 있습니다. // 다음 예제는 모두 유효하며 변수의 값은 6u입니다. var u32_expr1 = ( 1 + ( 1 + ( 1 + ( 1 + 1 )))) + 1u ; var u32_expr2 = 1u + ( 1 + ( 1 + ( 1 + ( 1 + 1 )))); var u32_expr3 = ( 1 + ( 1 + ( 1 + ( 1u + 1 )))) + 1 ; var u32_expr4 = 1 + ( 1 + ( 1 + ( 1 + ( 1u + 1 )))); // 내장 함수 매개변수를 기반으로 한 추론입니다. // 가장 선호되는 후보는 clamp(i32,i32,i32)->i32입니다. let i32_clamp = clamp ( 1 , - 5 , 5 ); // 가장 선호되는 후보는 clamp(u32,u32,u32)입니다. // 리터럴은 AbstractInt에서 u32로의 자동 변환을 사용합니다. let u32_clamp = clamp ( 5 , 0 , u32_from_expr ); // 가장 선호되는 후보는 clamp(f32,f32,f32)->f32입니다. // 리터럴은 AbstractInt에서 f32로의 자동 변환을 사용합니다. let f32_clamp = clamp ( 0 , f32_1 , 1 ); // 다음 예제는 모두 초기값 10f를 가진 f32로 승격됩니다. let f32_promotion1 = 1.0 + 2 + 3 + 4 ; let f32_promotion2 = 2 + 1.0 + 3 + 4 ; let f32_promotion3 = 1f + (( 2 + 3 ) + 4 ); let f32_promotion4 = (( 2 + ( 3 + 1f )) + 4 ); // 유형 규칙 위반입니다. // 유효하지 않음, 초기화자는 f32로만 해석될 수 있습니다: // AbstractFloat에서 u32로의 실행 가능한 자동 변환이 없습니다. let mismatch : u32= 1.0 ; // 유효하지 않음. 부호가 혼합된 매개변수를 허용하는 clamp 오버로드가 없습니다. let ambiguous_clamp = clamp ( 1u , 0 , 1i ); // 추론은 문 수준에서 완료됩니다. // let 선언의 초기화자는 구성 가능하거나 포인터여야 합니다. // AbstractInt에서 구성 가능한 유형으로 가장 선호되는 자동 변환은 // 변환 순위 2인 AbstractInt에서 i32로의 변환입니다. 따라서 '1'은 i32로 추론됩니다. let some_i32 = 1 ; // let some_i32: i32 = 1i;와 같습니다. let some_f32 : f32= some_i32 ; // 유형 오류: i32를 f32에 대입할 수 없습니다. // 또 다른 오버플로 사례입니다. let overflow_u32 = ( 1 - 2 ) + 1u ; // 유효하지 않음, -1은 u32 범위를 벗어납니다. // 이상적인 값은 32비트 범위를 벗어나지만 다시 범위 안으로 들어옵니다. let out_and_in_again = ( 0x1ffffffff / 8 ); // 비슷하지만 유효하지 않습니다. let out_of_range = ( 0x1ffffffff / 8u ); // 계산을 32비트에서 수행해야 하므로 // 0x1ffffffff가 범위를 벗어납니다.
6.2.2. 불리언 유형
bool 유형은
true 및 false 값을 포함합니다.
| 전제 조건 | 결론 | 설명 |
|---|---|---|
true: bool
| true 값. | |
false: bool
| false 값. |
6.2.3. 정수 유형
u32 유형은 32비트 부호 없는 정수의 집합입니다.
i32 유형은 32비트 부호 있는 정수의 집합입니다. 최상위 비트 위치에 부호 비트가 있는 2의 보수 표현을 사용합니다.
오버플로되는 구체적 정수 유형에 대한 표현식은 2bitwidth를 법으로 한 결과를 생성합니다.
| 유형 | 최솟값 | 최댓값 |
|---|---|---|
| i32 | i32(-2147483648) | 2147483647i |
| i32(-0x80000000) | 0x7fffffffi | |
| u32 | 0u | 4294967295u |
| 0x0u | 0xffffffffu |
참고: AbstractInt도 정수 유형입니다.
6.2.4. 부동 소수점 유형
f32 유형은 IEEE-754 binary32(단정밀도) 형식의 32비트 부동 소수점 값 집합입니다. 자세한 내용은 § 15.7 부동 소수점 평가를 참조하십시오.
f16 유형은
IEEE-754 binary16(반정밀도) 형식의 16비트
부동 소수점 값 집합입니다. 프로그램에
f16 확장을 활성화하는
enable f16; 지시문이 포함되어 있지 않은 상태에서 f16
유형을 사용하면 셰이더 생성
오류입니다. 자세한 내용은 § 15.7 부동 소수점 평가를 참조하십시오.
다음 표에는 부동 소수점 유형의 일부 극값이 나열되어 있습니다. 각각에는 대응하는 음수 값이 있습니다.
| 유형 | 가장 작은 양의 비정규값 | 가장 작은 양의 정규값 | 가장 큰 양의 유한값 | 2의 거듭제곱 중 가장 큰 유한값 |
|---|---|---|---|---|
| f32 | 1.40129846432481707092e-45f | 1.17549435082228750797e-38f | 3.40282346638528859812e+38f | 0x1p+127f |
| 0x1p-149f | 0x1p-126f | 0x1.fffffep+127f | ||
| f16 | 5.9604644775390625e-8h | 0.00006103515625h | 65504.0h | 0x1p+15h |
| 0x1p-24h | 0x1p-14h | 0x1.ffcp+15h |
참고: AbstractFloat도 부동 소수점 유형입니다.
6.2.5. 스칼라 유형
스칼라 유형은 bool, AbstractInt, AbstractFloat, i32, u32, f32, 그리고 f16입니다.
숫자 스칼라 유형은 AbstractInt, AbstractFloat, i32, u32, f32, 그리고 f16입니다.
정수 스칼라 유형은 AbstractInt, i32, 그리고 u32입니다.
스칼라 변환은 한 스칼라 유형의 값을 다른 스칼라 유형의 값으로 매핑합니다. 일반적으로 결과 값은 대상 유형의 제한 범위 내에서 원래 값에 가깝습니다. 스칼라 변환은 다음 중 하나로 발생합니다:
-
값 생성자를 명시적으로 호출하거나,
-
추상 숫자 유형의 const 표현식을 실행 가능한 자동 변환을 통해 다른 유형으로 변환할 때입니다.
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 중 하나여야 합니다. |
| atomic<vec2<u32>> |
vec2<u32> 유형의 원자적 유형입니다.
이 유형의 값은 부호 없는 64비트
정수 유형을 나타내며, 하위 32비트는
벡터
구성 요소 0에, 상위 32비트는 벡터 구성 요소 1에 있습니다.
atomic_vec2u_min_max 확장으로 활성화됩니다. |
표현식은 원자적 유형으로 평가되어서는 안 됩니다.
원자적 유형은 workgroup
주소 공간의 변수 또는 read_write 접근 모드를 가진 스토리지
버퍼 변수에 의해서만 인스턴스화될 수 있습니다.
저장 유형이
atomic<vec2<u32>>이거나 이를 포함하는 경우 변수는 storage 주소 공간에 있어야 합니다.
해당 유형에 대한 연산의 메모리 범위는
유형이 인스턴스화된 주소 공간에 따라 결정됩니다.
workgroup 주소 공간의 원자적 유형은
Workgroup의 메모리 범위를 가지며,
storage
주소 공간의 원자적 유형은 QueueFamily의 메모리 범위를 가집니다.
원자적 수정은 원자적 객체의 내용을 설정하는 해당 객체에 대한 모든 연산입니다. 새 값이 객체의 기존 값과 같더라도 해당 연산은 수정으로 간주됩니다.
WGSL에서 원자적 수정은 각 객체별로 상호 순서가 정해집니다. 즉, 셰이더 스테이지 실행 중 각 원자적 객체 A에 대해 모든 에이전트는 A에 적용되는 수정 연산의 동일한 순서를 관찰합니다. 서로 다른 원자적 객체의 순서는 어떤 방식으로도 연관되지 않을 수 있으며, 인과 관계가 암시되지 않습니다. workgroup 공간의 변수는 워크그룹 내에서 공유되지만 서로 다른 워크그룹 간에는 공유되지 않는다는 점에 유의하십시오.
6.2.9. 배열 유형
배열은 인덱스로 접근할 수 있는 요소 값의 시퀀스입니다.
| 유형 | 설명 |
|---|---|
| array<E,N> | E 유형의 요소 N개를 가진 고정 크기
배열입니다. N을 배열의 요소 수라고 합니다. |
| array<E> | E 유형 요소의 런타임 크기 배열입니다.
이러한 배열은 특정 컨텍스트에서만 나타날 수 있습니다. |
배열의 첫 번째 요소는 인덱스 0에 있으며, 이후의 각 요소는 다음 정수 인덱스에 있습니다. § 8.5.3 배열 접근 표현식을 참조하십시오.
표현식은 런타임 크기 배열 유형으로 평가되어서는 안 됩니다.
고정 크기 배열의 요소 수 표현식 N에는 다음 제약 조건이 적용됩니다:
-
override 표현식이어야 합니다.
-
N이 0보다 크지 않은 경우:
-
그렇지 않으면 파이프라인 생성 오류입니다.
참고: N이 override 선언에 의존하는 경우 요소 수 값은 파이프라인 생성 시점에 완전히 결정되고, 그렇지 않으면 셰이더 모듈 생성 시점에 완전히 결정됩니다.
참고: 유형 동등성을 충족하려면 const 표현식이 아닌 모든 override 표현식은 식별자여야 합니다. 재정의 가능한 상수로 크기가 지정된 워크그룹 변수를 참조하십시오.
런타임 크기 배열의 요소 수는 해당 스토리지 버퍼 변수와 연결된 버퍼 바인딩의 크기에 따라 결정됩니다. § 13.3.4 버퍼 바인딩이 런타임 크기 배열 요소 수를 결정함을 참조하십시오.
배열 요소 유형은 다음 중 하나여야 합니다:
-
스칼라 유형
-
벡터 유형
-
행렬 유형
-
원자적 유형
-
생성 시 고정 풋프린트를 가진 배열 유형
-
생성 시 고정 풋프린트를 가진 구조체 유형.
참고: 배열 요소 유형은 버퍼 유형일 수 없습니다.
참고: 요소 유형은 일반 유형이어야 합니다.
두 배열 유형은 다음 조건이 모두 참인 경우에만 동일합니다:
-
요소 유형이 동일합니다.
-
요소 수 지정이 일치합니다. 즉, 다음 중 하나가 참입니다:
-
둘 다 런타임 크기입니다.
-
둘 다 생성 시 고정 풋프린트를 가진 고정 크기이며 한쪽이 부호 있고 다른 쪽이 부호 없더라도 요소 수의 값이 같습니다. (요소 수는 항상 양수이므로 이 경우 부호 있는 값과 부호 없는 값을 비교할 수 있습니다.)
-
둘 다 요소 수가 동일한 파이프라인 재정의 가능 상수의 선언으로 해석되는 식별자로 지정된 고정 크기입니다.
-
// array<f32,8>과 array<i32,8>은 서로 다른 유형입니다: // 요소 유형이 다릅니다. var < private> a : array< f32, 8 > ; var < private> b : array< i32, 8 > ; var < private> c : array< i32, 8u > ; // array<i32,8>과 array<i32,8u>는 동일한 유형입니다. const width = 8 ; const height = 8 ; // array<i32,8>, array<i32,8u>, array<i32,width>는 동일한 유형입니다. // 요소 수는 8로 평가됩니다. var < private> d : array< i32, width > ; // array<i32,height>와 array<i32,width>는 동일한 유형입니다. var < private> e : array< i32, width > ; var < private> f : array< i32, height > ;
참고: 재정의 가능한 상수로 크기가 지정된 배열 유형의 유일한 유효한 사용은 workgroup 주소 공간의 메모리 뷰입니다. 여기에는 워크그룹 변수의 저장 유형이 포함됩니다. § 7 변수 및 값 선언을 참조하십시오.
override blockSize = 16 ; var < workgroup> odds : array< i32, blockSize > ; var < workgroup> evens : array< i32, blockSize > ; // 동일한 유형 // 다음 중 어느 것도 'odds' 및 'evens'와 동일한 유형이 아닙니다. // 다른 유형: 식별자 'blockSize'가 아닙니다. var < workgroup> evens_0 : array< i32, 16 > ; // 다른 유형: 요소 수를 표현하기 위해 산술을 사용합니다. var < workgroup> evens_1 : array< i32,( blockSize * 2 / 2 ) > ; // 다른 유형: 식별자만이 아니라 괄호를 사용합니다. var < workgroup> evens_2 : array< i32,( blockSize ) > ; // 재정의 가능한 요소 수는 바깥쪽 수준에서만 나타날 수 있으므로 // 유효하지 않은 예입니다. // var<workgroup> both: array<array<i32,blockSize>,2>; // 재정의 가능한 요소 수는 워크그룹 변수에만 유효하므로 // 유효하지 않은 예입니다. // var<private> bad_address_space: array<i32,blockSize>;
6.2.10. 구조체 유형
구조체는 이름이 지정된 멤버 값을 이름으로 묶은 그룹입니다.
| 유형 | 설명 |
|---|---|
struct AStructName {M1 : T1, ... MN : TN, } |
식별자
AStructName으로 이름이 지정되고
N개의 멤버를 가지며,
멤버 i의 이름이 식별자 Mi이고
유형이 Ti인 구조체 유형의 선언입니다.
N은 적어도 1이어야 합니다. 동일한 구조체 유형의 두 멤버는 같은 이름을 가져서는 안 됩니다. |
구조체 유형은 모듈 범위에서 선언됩니다. 프로그램 소스의 다른 곳에서는 구조체 유형을 해당 식별자 이름으로 나타냅니다. § 5 선언 및 범위를 참조하십시오.
두 구조체 유형은 이름이 같은 경우에만 동일합니다.
구조체 멤버 유형은 다음 중 하나여야 합니다:
-
스칼라 유형
-
벡터 유형
-
행렬 유형
-
원자적 유형
-
생성 시 고정 풋프린트를 가진 고정 크기 배열 유형
-
런타임 크기 배열 유형. 단, 구조체의 마지막 멤버인 경우에만 허용됩니다.
-
생성 시 고정 풋프린트를 가진 구조체 유형
참고: 구조체 멤버 유형은 버퍼 유형일 수 없습니다.
참고: 사용자가 선언한 모든 구조체 유형은 구체적입니다.
참고: 각 멤버 유형은 일반 유형이어야 합니다.
구조체 멤버 및 배열 요소 유형에 대한 제한의 결과 중 일부는 다음과 같습니다:
-
포인터, 텍스처 또는 샘플러는 배열이나 구조체 내부의 어떤 중첩 수준에도 나타나서는 안 됩니다.
-
런타임 크기 배열이 더 큰 유형의 일부인 경우 구조체의 마지막 요소로만 나타날 수 있으며, 해당 구조체 자체는 바깥쪽 배열이나 구조체의 일부가 될 수 없습니다.
// 세 개의 멤버가 있는 구조체입니다. struct Data { a : i32, b : vec2< f32> , c : array< i32, 10 > , // 마지막 쉼표는 선택 사항입니다. } // Data 유형의 값을 저장하는 변수를 선언합니다. var < private> some_data : Data ;
'struct' 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. 고정 풋프린트 유형
변수의 메모리 풋프린트는 변수의 내용을 저장하는 데 사용되는 메모리 위치의 수입니다. 변수의 메모리 풋프린트는 저장 유형에 따라 달라지며 셰이더 수명 주기의 어느 시점에 확정됩니다. 대부분의 변수는 매우 이른 셰이더 생성 시점에 크기가 결정됩니다. 일부 변수는 더 늦은 파이프라인 생성 시점에, 또 다른 변수는 셰이더 실행 시작 시점에야 크기가 결정될 수 있습니다.
유형의 구체화 크기가 셰이더 생성 시점에 완전히 결정되면 해당 유형은 생성 시 고정 풋프린트를 가집니다.
유형의 크기가 파이프라인 생성 시점에 완전히 결정되면 해당 유형은 고정 풋프린트를 가집니다.
참고: 모든 구체적 생성 시 고정 풋프린트 및 고정 풋프린트 유형은 저장 가능합니다.
참고: 파이프라인 생성은 셰이더 생성에 의존하므로, 생성 시 고정 풋프린트를 가진 유형은 고정 풋프린트도 가집니다.
생성 시 고정 풋프린트를 가진 유형은 다음과 같습니다:
-
스칼라 유형
-
벡터 유형
-
행렬 유형
-
원자적 유형
-
다음 조건을 만족하는 고정 크기 배열 유형:
-
모든 멤버가 생성 시 고정 풋프린트를 가진 구조체 유형.
-
다음 조건을 만족하는 고정 크기 버퍼 유형:
-
크기가 const 표현식입니다.
-
참고: 구성 가능한 유형은 생성 시 고정 풋프린트를 가집니다.
고정 풋프린트를 가진 유형은 다음 중 하나입니다:
-
생성 시 고정 풋프린트를 가진 유형
-
크기를 추가로 제한하지 않은 고정 크기 버퍼 유형
참고: 요소 수가 const 표현식이 아닌 override 표현식인 고정 크기 배열의 유일한 유효한 사용은 workgroup 주소 공간의 메모리 뷰입니다. 여기에는 워크그룹 변수의 저장 유형이 포함됩니다.
참고: 고정 풋프린트 유형은 원자적 유형을 직접 또는 간접적으로 포함할 수 있지만 구성 가능한 유형은 그럴 수 없습니다.
참고: 고정 풋프린트 유형에는 런타임 크기 배열, 런타임 크기 버퍼 및 런타임 크기 배열을 포함하는 모든 구조체가 제외됩니다.
6.3. 버퍼 유형
이러한 유형에는 buffer_view 언어 기능이 필요합니다.
버퍼 값은 내용이 다른 호스트 공유 가능 유형으로 해석될 수 있는 메모리를 나타냅니다. 그 외에는 버퍼 값은 불투명합니다. 변수의 데이터에 여러 다른 유형으로 접근해야 하거나 셰이더 작성자가 하나의 변수를 여러 논리 변수로 세분화하려는 경우에 유용합니다.
버퍼 유형은 구성 가능하지 않으며, buffer_view 내장 함수를 통해 해당 데이터를 불투명하지 않은 호스트 공유 가능 유형으로 해석한 후에만 접근할 수 있습니다.
| 유형 | 설명 |
|---|---|
| buffer<N> | N바이트의 저장 공간을 가진 고정 크기
버퍼입니다. N은 override 표현식이어야 합니다. |
| buffer | 런타임 크기 버퍼입니다. |
고정 크기 버퍼는 storage, uniform, 그리고 workgroup 주소 공간의 변수로만 인스턴스화할 수 있습니다. storage 및 uniform 주소 공간에서는 크기가 const 표현식이어야 합니다. 런타임 크기 버퍼는 storage 주소 공간의 변수로만 인스턴스화할 수 있습니다.
N이 0보다 크지 않은 경우:
-
그렇지 않으면 파이프라인 생성 오류입니다.
f16 확장이 활성화되어 있고 N이 2로 나누어떨어지지 않는 경우:
-
그렇지 않으면 파이프라인 생성 오류입니다.
f16 확장이 활성화되지 않았고 N이 4로 나누어떨어지지 않는 경우:
-
그렇지 않으면 파이프라인 생성 오류입니다.
두 버퍼 유형은 다음 조건 중 하나가 성립하는 경우에만 동일합니다:
-
둘 다 런타임 크기입니다.
-
둘 다 생성 시 고정 풋프린트를 가진 고정 크기이고 한쪽이 부호 있고 다른 쪽이 부호 없더라도 크기의 값이 같습니다. (크기는 항상 양수이므로 이 경우 부호 있는 값과 부호 없는 값을 비교할 수 있습니다.)
-
둘 다 크기가 동일한 파이프라인 재정의 가능 상수의 동일한 선언으로 해석되는 식별자로 지정된 고정 크기입니다.
6.4. 열거 유형
열거 유형은 이름이 지정된 값의 제한된 집합입니다. 열거는 유효한 텍셀 형식 집합과 같이 특정 개념의 가능성 집합을 서로 구분하는 데 사용됩니다.
열거자는 열거에서 이름이 지정된 값 중 하나입니다. 각 열거자는 다른 모든 열거자와 구별되며 다른 모든 종류의 값과도 구별됩니다.
WGSL 소스에서는 새로운 열거자 또는 새로운 열거 유형을 선언하는 메커니즘이 없습니다.
참고: 열거자는 템플릿 매개변수로 사용됩니다.
6.4.1. 미리 선언된 열거자
다음 표에는 WGSL의 열거 유형, 해당 미리 선언된 열거자, 그리고 해당 열거 유형에 필요한 언어 확장이 나열되어 있습니다. 열거 유형은 존재하지만 WGSL 소스에서 표기할 수 없습니다.
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는 read_write 접근 모드를 가진 vecN<S> 유형 벡터의 포인터입니다.
-
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 선언의 effective-value-type은 구체적인 구성 가능 유형 // 또는 포인터 유형이어야 합니다. 따라서 스위즐 뷰 로드 규칙을 호출하여 // 스위즐 뷰를 자동으로 vec3u로 변환합니다. let u = v . agb ; // 스위즐은 연쇄적으로 사용할 수 있습니다. // 다음과 같습니다: v.zy = vec2(99,100); v . yz . yx = vec2( 99 , 100 ); // 스위즐 뷰에 한 글자를 적용하면 기반 벡터의 // 스칼라 구성 요소에 대한 참조를 산출합니다. // 다음과 같습니다: v.z = 99; v . yz . y = 99 ; // 스위즐 뷰를 인덱싱하면 벡터 구성 요소 중 하나에 대한 참조를 산출합니다. // 한 글자 벡터 접근을 형성하는 것처럼 동작하지만, // 인덱스가 스위즐 이름에서 사용할 글자를 선택합니다. v . zy [ 1 ] = 50 ; // v.y = 50;과 같습니다. }
// 이 예에서는 swizzle_assignment 외에도 pointer_composite_access 지원을 가정합니다. requires pointer_composite_access ; fn swizzle_read_and_write_via_pointer ( p : ptr< function, vec4u> ) { // 다음과 같습니다: (*p).y = 1; (*p).z = 2; p . yz = vec2u( 1 , 2 ); // 다음과 같습니다: let u = vec3((*p).a, (*p).g, (*p).b); let u = p . agb ; // 스위즐은 연쇄적으로 사용할 수 있습니다. // 다음과 같습니다: p.zy = vec2(99,100); p . yz . yx = vec2( 99 , 100 ); // 포인터에서 스위즐 뷰를 생성할 수 있습니다. // 스위즐 뷰에 한 글자를 적용하면 기반 벡터의 // 스칼라 구성 요소에 대한 참조를 산출합니다. // 다음과 같습니다: (*p).z = 99; p . yz . y = 99 ; // 스위즐 뷰를 인덱싱하면 벡터 구성 요소 중 하나에 대한 참조를 산출합니다. // 한 글자 벡터 접근을 형성하는 것처럼 동작하지만, // 인덱스가 스위즐 이름에서 사용할 글자를 선택합니다. p . zy [ 1 ] = 50 ; // (*p).y = 50;과 같습니다. }
fn invalid_swizzle_cases () { var v : vec2u; // 유효하지 않음: 구성 요소를 반복하는 스위즐에는 대입할 수 없습니다. v . xx = vec2u( 1 , 2 ); // 유효하지 않음: 'z'는 대상 벡터의 범위를 벗어납니다. v . xz = vec2u( 1 , 2 ); let u = v . xz ; // 유효하지 않음: xyzw와 rgba 문자 체계를 혼합해서는 안 됩니다. v . xr = vec2u( 1 , 2 ); // 스위즐 뷰의 주소를 가져올 수 없습니다. // 여기서 v.xy는 스위즐 뷰 (&v,`01`)입니다. // & 연산자는 스위즐 뷰에 적용되지 않으므로 유형 검사가 실패합니다. let p = & v . xy ; }
균일성 분석을 위해 스위즐 뷰 쓰기는 갱신되는 구성 요소의 값 균일성에만 영향을 줄 수 있습니다. 이 때문에 전체 스위즐 뷰와 부분 스위즐 뷰를 구분합니다.
그러나 기반 벡터의 모든 구성 요소를 쓰는 것은 메모리 모델에서 중요합니다. 서로 다른 두 호출이 메모리에 있는 동일한 벡터의 서로 다른 구성 요소를 동시에 갱신하면 데이터 경합이 발생합니다.
var < workgroup> w : vec4u; @compute @workgroup_size ( 2 ) fn this_races ( @builtin ( local_invocation_index) gid : u32) { if ( gid == 0 ) { w . xy = vec2u( 0 , 1 ); // 전체 벡터를 쓰므로 다른 호출과 경합합니다. } else { w . zw = vec2u( 2 , 3 ); // 전체 벡터를 쓰므로 다른 호출과 경합합니다. } }
6.5.5. 유효 및 무효 메모리 참조
참조가 형성되는 방법은 § 6.5.9 참조 및 포인터 값 형성에 자세히 설명되어 있습니다. 일반적으로 유효한 참조는 다음 방식으로 형성됩니다:
-
변수의 이름을 지정하거나,
-
기반이 유효한 메모리 뷰인 이름 있는 구성 요소 표현식, 또는
일반적으로 무효 메모리 참조는 다음 방식으로 형성됩니다:
-
무효 포인터에 간접 참조 연산자를 적용하거나,
-
기반이 무효 메모리 참조인 이름 있는 구성 요소 표현식, 또는
무효 포인터는 다음 방식으로 형성됩니다:
-
bufferView 또는 bufferArrayView 내장 함수를 호출했을 때, 그 결과 포인터의 메모리 뷰가 그렇지 않으면 버퍼 포인터 인수의 메모리 뷰 범위를 벗어난 메모리 위치를 포함하게 되는 경우.
유효한 포인터는 유효한 참조에 대응하는 포인터입니다.
유효한 스위즐 뷰는 포인터 값이 유효한 스위즐 뷰입니다. 무효 스위즐 뷰는 포인터 값이 무효인 스위즐 뷰입니다.
6.5.6. 기원 변수
-
R이 변수이면 해당 변수입니다.
-
R이 포인터 값 P에 간접 참조 연산자(단항 *)를 적용한 결과이면 P의 기원 변수입니다.
-
R이 이름 있는 구성 요소 표현식 또는 인덱싱 표현식이면 기반의 기원 변수입니다.
포인터 값의 기원 변수는 대응하는 참조 값의 기원 변수로 정의됩니다.
스위즐 뷰의 기원 변수는 스위즐 뷰 포인터의 기원 변수로 정의됩니다.
참고: 기원 변수는 동적 개념입니다. 함수의 형식 매개변수에 대한 기원 변수는 해당 함수의 호출 위치에 따라 달라집니다. 서로 다른 호출 위치는 서로 다른 기원 변수 내부를 가리키는 포인터를 제공할 수 있습니다.
유효한 참조는 항상 어떤 변수의 메모리 위치 일부 또는 전부에 대한 비어 있지 않은 메모리 뷰에 대응합니다.
유효한 스위즐 뷰는 항상 어떤 변수 내부 벡터의 메모리 위치에 대응합니다.
다음 예에서 참조 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{ // return 문의 표현식 유형은 함수의 선언된 반환 유형과 // 일치해야 하므로 'i32'여야 합니다. // 'age' 표현식의 유형은 ref<private,i32,read_write>입니다. // 참조의 저장 유형이 표현식에 필요한 유형과 일치하고 // 다른 유형 규칙이 적용되지 않으므로 로드 규칙을 적용합니다. // 이 컨텍스트에서 'age'의 평가는 return 문이 실행되는 시점에 // 'age'가 참조하는 메모리 위치에서 로드된 i32 값입니다. return age ; } fn caller () { age = 21 ; // copy_age 상수는 i32 값 21을 얻게 됩니다. let copy_age : i32= get_age (); }
포인터를 이 방식으로 정의하면 두 가지 주요 사용 사례가 가능합니다:
-
포인터 유형의 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 () { // 스토리지 메모리의 특정 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이 산출됩니다. // f32 값 1.0을 uv.x가 참조하는 스토리지 메모리 위치에 저장합니다. uv . x = 1.0 ; // 대입의 왼쪽 피연산자를 평가합니다: // 'uv[1]'을 평가하여 참조를 산출합니다: // 1. 먼저 'uv'를 평가하여 'uv' 변수의 메모리에 대한 // 참조를 산출합니다. 결과 유형은 ref<function,vec2<f32>,read_write>입니다. // 2. 그런 다음 '[1]' 배열 인덱스 구문을 적용하여 이전 단계에서 // 참조된 벡터의 두 번째 구성 요소에 대한 메모리 참조를 산출합니다. // 결과 유형은 ref<function,f32,read_write>입니다. // 대입의 오른쪽 피연산자를 평가하면 f32 값 2.0이 산출됩니다. // f32 값 2.0을 uv[1]이 참조하는 스토리지 메모리 위치에 저장합니다. uv [ 1 ] = 2.0 ; var m : mat3x2< f32> ; // 'm[2]'를 평가할 때: // 1. 먼저 'm'을 평가하여 'm' 변수의 메모리에 대한 // 참조를 산출합니다. 결과 유형은 ref<function,mat3x2<f32>,read_write>입니다. // 2. 그런 다음 '[2]' 배열 인덱스 구문을 적용하여 이전 단계의 참조 // 값이 가리키는 세 번째 열 벡터에 대한 메모리 참조를 // 산출합니다. // 따라서 'm[2]' 표현식의 유형은 ref<function,vec2<f32>,read_write>입니다. // 'let' 선언의 유형은 vec2<f32>이므로 선언문은 // 초기화자가 vec2<f32> 유형이어야 함을 요구합니다. // 다른 유형 규칙이 적용될 수 없으므로 로드 규칙이 적용되며, // 초기화자를 평가하면 선언이 실행되는 시점에 'm[2]'가 참조하는 // 메모리 위치에서 로드된 vec2<f32> 값이 // 산출됩니다. let p_m_col2 : vec2< f32> = m [ 2 ]; var A : array< i32, 5 > ; // 'A[4]'를 평가할 때 // 1. 먼저 'A'를 평가하여 'A' 변수의 메모리에 대한 // 참조를 산출합니다. 결과 유형은 ref<function,array<i32,5>,read_write>입니다. // 2. 그런 다음 '[4]' 배열 인덱스 구문을 적용하여 이전 단계의 // 참조 값이 참조하는 배열의 다섯 번째 요소에 대한 // 메모리 참조를 산출합니다. // 결과 값의 유형은 ref<function,i32,read_write>입니다. // let 선언은 오른쪽 피연산자가 i32 유형이어야 함을 요구합니다. // 다른 유형 규칙이 적용될 수 없으므로 로드 규칙이 적용되며, // 초기화자를 평가하면 선언이 실행되는 시점에 'A[4]'가 참조하는 // 메모리 위치에서 로드된 i32 값이 // 산출됩니다. let A_4_value : i32= A [ 4 ]; // 'person.weight'를 평가할 때 // 1. 먼저 'person'을 평가하여 모듈 범위에 선언된 // 'person' 변수의 메모리에 대한 참조를 산출합니다. // 결과 유형은 ref<private,S,read_write>입니다. // 2. 그런 다음 '.weight' 멤버 접근 구문을 적용하여 이전 단계의 // 참조 값이 참조하는 메모리의 두 번째 멤버에 대한 // 메모리 참조를 산출합니다. // 결과 유형은 ref<private,f32,read_write>입니다. // let 선언은 오른쪽 피연산자가 f32 유형이어야 함을 요구합니다. // 다른 유형 규칙이 적용될 수 없으므로 로드 규칙이 적용되며, // 초기화자를 평가하면 선언이 실행되는 시점에 // 'person.weight'가 참조하는 메모리 위치에서 로드된 f32 값이 // 산출됩니다. let person_weight : f32= person . weight ; // 또는 동일한 구문을 사용하여 포인터에서 참조를 형성할 수도 있습니다. let uv_ptr = & uv ; // 이 함수 본문의 나머지 부분에서 'uv_ptr'은 'uv'의 기반 메모리에 대한 // 포인터를 나타내며 유형은 // ptr<function,vec2<f32>,read_write>입니다. // 대입의 왼쪽 피연산자를 평가합니다: // '*uv_ptr'을 평가하여 참조를 산출합니다: // 1. 먼저 'uv_ptr'을 평가하여 'uv' 변수의 메모리에 대한 // 포인터를 산출합니다. 결과 유형은 ptr<function,vec2<f32>,read_write>입니다. // 2. 그런 다음 간접 참조 표현식 연산자를 적용하여 // 'uv'의 메모리에 대한 참조를 산출합니다. // 대입의 오른쪽 피연산자를 평가하면 vec2<f32> 값 (1.0, 2.0)이 산출됩니다. // 값 (1.0, 2.0)을 uv가 참조하는 스토리지 메모리 위치에 저장합니다. * uv_ptr = vec2f( 1.0 , 2.0 ); // 대입의 왼쪽 피연산자를 평가합니다: // 'uv_ptr.x'를 평가하여 참조를 산출합니다: // 1. 먼저 'uv_ptr'을 평가하여 'uv' 변수의 메모리에 대한 // 포인터를 산출합니다. 결과 유형은 ptr<function,vec2<f32>,read_write>입니다. // 2. 그런 다음 '.x' 벡터 접근 구문을 적용하여 이전 단계의 // 참조 값이 가리키는 벡터의 첫 번째 구성 요소에 대한 // 메모리 참조를 산출합니다. // 결과 유형은 ref<function,f32,read_write>입니다. // 대입의 오른쪽 피연산자를 평가하면 f32 값 1.0이 산출됩니다. // f32 값 1.0을 uv.x가 참조하는 스토리지 메모리 위치에 저장합니다. uv_ptr . x = 1.0 ; // 대입의 왼쪽 피연산자를 평가합니다: // 'uv_ptr[1]'을 평가하여 참조를 산출합니다: // 1. 먼저 'uv_ptr'을 평가하여 'uv' 변수의 메모리에 대한 // 포인터를 산출합니다. 결과 유형은 ptr<function,vec2<f32>,read_write>입니다. // 2. 그런 다음 '[1]' 배열 인덱스 구문을 적용하여 이전 단계에서 // 참조된 벡터의 두 번째 구성 요소에 대한 메모리 참조를 산출합니다. // 결과 유형은 ref<function,f32,read_write>입니다. // 대입의 오른쪽 피연산자를 평가하면 f32 값 2.0이 산출됩니다. // f32 값 2.0을 uv[1]이 참조하는 스토리지 메모리 위치에 저장합니다. uv_ptr [ 1 ] = 2.0 ; let m_ptr = & m ; // 'm_ptr[2]'를 평가할 때: // 1. 먼저 'm_ptr'을 평가하여 'm' 변수의 메모리에 대한 // 포인터를 산출합니다. 결과 유형은 ptr<function,mat3x2<f32>,read_write>입니다. // 2. 그런 다음 '[2]' 배열 인덱스 구문을 적용하여 이전 단계의 참조 // 값이 가리키는 세 번째 열 벡터에 대한 메모리 참조를 // 산출합니다. // 따라서 'm[2]' 표현식의 유형은 ref<function,vec2<f32>,read_write>입니다. // 'let' 선언의 유형은 vec2<f32>이므로 선언문은 // 초기화자가 vec2<f32> 유형이어야 함을 요구합니다. // 다른 유형 규칙이 적용될 수 없으므로 로드 규칙이 적용되며, // 초기화자를 평가하면 선언이 실행되는 시점에 'm[2]'가 참조하는 // 메모리 위치에서 로드된 vec2<f32> 값이 // 산출됩니다. let p_m_col2 : vec2< f32> = m_ptr [ 2 ]; let A_ptr = & A ; // 'A[4]'를 평가할 때 // 1. 먼저 'A'를 평가하여 'A' 변수의 메모리에 대한 // 포인터를 산출합니다. 결과 유형은 ptr<function,array<i32,5>,read_write>입니다. // 2. 그런 다음 '[4]' 배열 인덱스 구문을 적용하여 이전 단계의 // 참조 값이 참조하는 배열의 다섯 번째 요소에 대한 // 메모리 참조를 산출합니다. // 결과 값의 유형은 ref<function,i32,read_write>입니다. // let 선언은 오른쪽 피연산자가 i32 유형이어야 함을 요구합니다. // 다른 유형 규칙이 적용될 수 없으므로 로드 규칙이 적용되며, // 초기화자를 평가하면 선언이 실행되는 시점에 'A[4]'가 참조하는 // 메모리 위치에서 로드된 i32 값이 // 산출됩니다. let A_4_value : i32= A_ptr [ 4 ]; let person_ptr = & person ; // 'person.weight'를 평가할 때 // 1. 먼저 'person_ptr'을 평가하여 모듈 범위에 선언된 // 'person' 변수의 메모리에 대한 포인터를 산출합니다. // 결과 유형은 ptr<private,S,read_write>입니다. // 2. 그런 다음 '.weight' 멤버 접근 구문을 적용하여 이전 단계의 // 참조 값이 참조하는 메모리의 두 번째 멤버에 대한 // 메모리 참조를 산출합니다. // 결과 유형은 ref<private,f32,read_write>입니다. // let 선언은 오른쪽 피연산자가 f32 유형이어야 함을 요구합니다. // 다른 유형 규칙이 적용될 수 없으므로 로드 규칙이 적용되며, // 초기화자를 평가하면 선언이 실행되는 시점에 // 'person.weight'가 참조하는 메모리 위치에서 로드된 f32 값이 // 산출됩니다. let person_weight : f32= person_ptr . weight ; }
포인터 값은 다음 방식 중 하나로 형성됩니다:
-
참조에 주소 가져오기 (단항
&) 연산자를 사용합니다. -
함수 형식 매개변수의 유형이 포인터인 경우, 런타임에 함수가 호출되면 형식 매개변수의 사용은 호출 함수의 호출 위치에서 대응하는 피연산자에 제공된 포인터 값을 나타냅니다.
-
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. 텍스처 및 샘플러 유형
텍셀은 텍스처의 독립적으로 접근 가능한 가장 작은 요소로 사용되는 스칼라 또는 벡터입니다. texel이라는 단어는 texture element의 줄임말입니다.
텍스처는 렌더링에 유용한 특수 연산을 지원하는 텍셀의 집합입니다. WGSL에서는 이러한 연산을 텍스처 내장 함수를 통해 호출합니다. 전체 목록은 § 17.7 텍스처 내장 함수를 참조하십시오.
WGSL 텍스처는 WebGPU GPUTexture에
대응합니다.
텍스처에는 다음 기능이 있습니다:
- 텍셀 형식
-
각 텍셀의 데이터 표현입니다. § 6.6.1 텍셀 형식을 참조하십시오.
- 차원성
-
그리드 좌표의 차원 수와 좌표를 해석하는 방식입니다. 차원 수는 1, 2 또는 3입니다. 대부분의 텍스처는 데카르트 좌표를 사용합니다. 큐브 텍스처에는 정사각형 면이 6개 있으며, 원점에서 원점을 중심으로 하는 큐브를 향하는 방향 벡터로 해석되는 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 | 불변 | 모듈 또는 함수 | 구성 가능 (구체적 또는 추상) | 필수 | const 표현식 | 아니요 |
| override | 불변 | 모듈 | 구체적 스칼라 | 선택 사항3 | const 표현식 또는 override 표현식 | 아니요4 |
| let | 불변 | 함수 | 구체적 구성 가능 또는 포인터 유형. 또한 texture_and_sampler_let 기능이 지원되는 경우 텍스처 또는 샘플러 유형. | 필수 | const 표현식, override 표현식, 또는 런타임 표현식 | 아니요 |
|
var<storage, read> var<storage> | 불변 | 모듈 | 구체적 호스트 공유 가능 | 허용되지 않음 | 예. 스토리지 버퍼 | |
| var<storage, read_write>5,6 | 가변 | 모듈 | 구체적 호스트 공유 가능 | 허용되지 않음 | 예. 스토리지 버퍼 | |
| var<uniform> | 불변 | 모듈 | 구체적 구성 가능 호스트 공유 가능 또는 고정 크기 버퍼 | 허용되지 않음 | 예. 유니폼 버퍼 | |
| var<immediate> | 불변 | 모듈 | 구체적 구성 가능 호스트 공유 가능, 배열 및 배열 멤버를 포함하는 구조체 제외 | 허용되지 않음 | 예. 즉시 데이터 | |
| var5 | 불변7 | 모듈 | 텍스처 | 허용되지 않음 | 예. 텍스처 리소스 | |
| var | 불변 | 모듈 | 샘플러 | 허용되지 않음 | 예. 샘플러 리소스 | |
| var<workgroup>6,8 | 가변 | 모듈 | 구체적 일반 유형으로서 고정 풋프린트를 가지거나 고정 크기 버퍼9 | 허용되지 않음10 | 아니요 | |
| var<private> | 가변 | 모듈 | 구체적 구성 가능 | 선택 사항10 | const 표현식 또는 override 표현식 | 아니요 |
| var<function> var | 가변 | 함수 | 구체적 구성 가능 | 선택 사항10 | const 표현식, override 표현식, 또는 런타임 표현식 | 아니요 |
-
표현식의 유형은 유효 값 유형으로 실행 가능하게 변환될 수 있어야 합니다.
-
초기화자가 지정되지 않은 경우 파이프라인 생성 시점에 값을 제공해야 합니다.
-
override 선언은 셰이더 인터페이스의 일부이지만 바인딩된 리소스는 아닙니다.
-
스토리지 버퍼 및 스토리지 텍스처 중 read 이외의 접근 모드를 가진 것은 버텍스 셰이더 스테이지에서 정적으로 접근할 수 없습니다. WebGPU
createBindGroupLayout()을 참조하십시오. -
원자적 유형은 가변 스토리지 버퍼 또는 워크그룹 변수에만 나타날 수 있습니다.
-
스토리지 텍스처 중 write 또는 read_write 접근 모드를 가진 텍스처의 데이터는 가변이지만 textureStore 내장 함수를 통해서만 수정할 수 있습니다. 변수 자체는 수정할 수 없습니다.
-
workgroup 주소 공간의 변수는 컴퓨트 셰이더 스테이지에서만 정적으로 접근할 수 있습니다.
-
가장 바깥쪽 배열의 요소 수 또는 버퍼의 크기는 override 표현식일 수 있습니다.
-
초기화자가 없으면 변수는 기본 초기화됩니다.
7.1. 변수와 값
변수 선언은 WGSL 모듈에서 유일한 가변 데이터입니다. 값 선언은 항상 불변입니다. 변수에는 연결된 메모리 위치가 있으므로 참조 및 포인터 값의 기반이 될 수 있지만, 값 선언은 포인터나 참조 값의 기반이 될 수 없습니다.
변수 사용은 일반적으로 값 선언 사용보다 비용이 더 큽니다. 변수를 사용하려면 변수와 연결된 메모리 위치를 읽거나 쓰기 위한 추가 연산이 필요하기 때문입니다.
일반적으로 작성자는 다음 순서로 선언 사용을 선호하는 것이 좋으며, 가장 선호되는 옵션을 먼저 나열합니다:
이는 일반적으로 셰이더의 전반적인 성능을 가장 좋게 만듭니다.
7.2. 값 선언
식별자가 값 선언으로 해석되면, 해당 식별자는 그 값을 나타냅니다.
WGSL은 여러 종류의 값 선언을 제공합니다. 각 선언 종류의 값은 셰이더 수명 주기의 서로 다른 시점에 고정됩니다. 값 선언의 종류와 해당 값이 고정되는 시점은 다음과 같습니다:
-
let 선언: 실행될 때
참고: 형식 매개변수는 § 11 함수에 설명되어 있습니다.
7.2.1. const 선언
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 ); // 4개 구성 요소를 가진 AbstractFloat 배열입니다: // (4.0, 2.0, 4.0, 2.0).
7.2.2. override 선언
override 선언은 파이프라인 재정의 가능 상수 값의 이름을 지정합니다. override 선언은 모듈 범위에서만 선언되어야 합니다. 파이프라인 재정의 가능 상수의 값은 파이프라인 생성 시점에 고정됩니다. 값이 지정된 경우 WebGPU 파이프라인 생성 메서드가 제공한 값을 사용하고, 그렇지 않으면 구체화된 초기화 표현식의 값을 사용합니다. override 선언의 유효 값 유형은 구체적 스칼라 유형이어야 합니다.
초기화 표현식은 선택 사항입니다. 존재하는 경우 override 표현식이어야 하며 파이프라인 재정의 가능 상수 기본값을 나타냅니다. 초기화자가 지정되지 않았고 파이프라인 생성 시점에 값도 제공되지 않으면 파이프라인 생성 오류입니다.
선언에 id 속성이 적용된 경우 리터럴 피연산자를 파이프라인 상수 ID라고 하며, 0 이상 65535 이하의 고유한 정수여야 합니다. 즉, 두 override 선언은 동일한 파이프라인 상수 ID를 사용해서는 안 됩니다.
애플리케이션은 파이프라인 생성 시점에 override 선언에 자체 값을 지정할 수 있습니다. 파이프라인 생성 API는 재정의 가능한 상수에서 해당 상수 유형의 값으로의 매핑을 받습니다. 상수는 파이프라인 재정의 가능 상수 식별자 문자열로 식별됩니다. 이는 파이프라인 상수 ID가 지정된 경우 그 값의 10진수 표현이고, 그렇지 않으면 상수의 선언된 이름입니다.
@id ( 0 ) override has_point_light : bool= true ; // 알고리즘 제어 @id ( 1200 ) override specular_param : f32= 2.3 ; // 숫자 제어 @id ( 1300 ) override gain : f32; // 재정의해야 합니다. override width : f32= 0.0 ; // API 수준에서 // 이름 "width"를 사용하여 지정합니다. override depth : f32; // API 수준에서 // 이름 "depth"를 사용하여 지정합니다. // 재정의해야 합니다. override height = 2 * depth ; // 기본값은 // (API 수준에서 설정되지 않은 경우) // 다른 재정의 가능 // 상수에 의존합니다.
7.2.3. let 선언
let 선언은 런타임에 문이 실행될 때마다 고정되는 값의 이름을 지정합니다. let 선언은 함수 범위에서만 선언되어야 하며, 따라서 동적 컨텍스트입니다. let 선언에는 초기화 표현식이 있어야 합니다. 값은 초기화자의 구체화된 값입니다. let 선언의 유효 값 유형은 구체적 구성 가능 유형 또는 포인터 유형 중 하나여야 합니다. texture_and_sampler_let 기능이 지원되는 경우 유효 값 유형은 텍스처 또는 샘플러 유형일 수도 있습니다.
참고: 버퍼 유형은 구성 가능하지 않으므로 버퍼에 대한 포인터만 let 선언이 될 수 있습니다.
// '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 변수의 초기화자가 존재하는 경우 const 표현식 또는 override 표현식이어야 합니다. 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 주소 공간의 변수:
-
그렇지 않으면 구체화된 초기화 표현식을 평가한 결과입니다. 초기화자는 override 표현식이어야 하므로 그 값은 늦어도 파이프라인 생성 시점까지 고정됩니다.
-
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. 표현식
표현식은 값이 계산되는 방식을 지정합니다.
서로 다른 종류의 값 표현식은 평가되는 시점과 표현력 사이에 절충 관계를 제공합니다. 평가 시점이 빠를수록 연산에 더 많은 제약이 있지만, 값을 사용할 수 있는 위치도 더 많아집니다. 이러한 절충 관계로 인해 각 종류의 값 선언마다 서로 다른 유연성을 갖게 됩니다. const 표현식과 override 표현식은 GPU에서 실행되기 전에 평가되므로 최종 GPU 코드에는 표현식 계산 결과만 필요합니다. 또한 const 표현식은 셰이더 생성 시점에 평가되므로 override 표현식보다 더 많은 상황에서 사용할 수 있습니다. 예를 들어 함수 범위 변수의 배열 크기를 지정할 수 있습니다. 런타임 표현식은 const 표현식도 override 표현식도 아닌 표현식입니다. 런타임 표현식은 셰이더 실행 중 GPU에서 계산됩니다. 런타임 표현식은 더 적은 문법 요소에서 사용할 수 있지만, 다른 런타임 값과 같은 더 광범위한 표현식에서 계산될 수 있습니다.
8.1. 조기 평가 표현식
WGSL은 런타임 전에 평가할 수 있는 두 종류의 표현식을 정의합니다:
8.1.1. const 표현식
셰이더 생성 시점에 평가할 수 있는 표현식을 const 표현식이라고 합니다. 표현식의 모든 식별자가 다음으로 해석되면 해당 표현식은 const 표현식입니다:
const 표현식의 유형은 생성 시 고정 풋프린트를 가진 유형으로
해석되어야 합니다.
참고: 추상 유형은 const 표현식의 추론된 유형이 될 수 있습니다.
const 표현식 E는 다음 중 하나인 경우에만 평가됩니다:
-
E가 최상위 표현식인 경우,
-
E가 표현식 OuterE의 하위 표현식이고, OuterE가 평가되며, OuterE를 평가하려면 E를 평가해야 하는 경우,
-
E가 표현식 OuterE의 하위 표현식이고, OuterE의 정적 유형을 결정하려면 E를 평가해야 하는 경우, 또는
-
E가 표현식 OuterE의 하위 표현식이고 OuterE가 셰이더 생성 오류를 발생시키기 위해 E를 평가해야 하는 경우 (예: 정수 나눗셈).
참고: 평가 규칙은
하위 표현식 중 정적 유형을 결정하기 위해 평가해야
하는 것이 없는 한,
단락 평가 연산자 && 및 ||가 오른쪽
피연산자 하위 표현식의 평가를 차단함을 의미합니다.
const 표현식은 WebGPU API 메서드를 구현하는 CPU에서 평가될 수 있습니다. 따라서 AbstractFloat 값에 대한 연산의 정확도 요구 사항은 WebAssembly [WASM-CORE-2] 및 ECMAScript [ECMASCRIPT]와 같은 일반적인 WebGPU 런타임 환경에 요구되는 것보다 더 엄격하지 않습니다. 구체적 부동 소수점 유형(예: f32)의 정확도 요구 사항은 § 15.7.4.1 구체적 부동 소수점 표현식의 정확도에 지정되어 있습니다.
예: (42)는 다음과 같이 분석됩니다:
-
42항은 AbstractInt 값 42입니다. -
이 항을 괄호로 둘러싸면 값이 42인 AbstractInt 유형의 새 표현식
(42)가 생성됩니다.
예: -5는 다음과 같이 분석됩니다:
-
5항은 AbstractInt 값 5입니다. -
이 항 앞에 '
-'를 붙이면 값이 -5인 AbstractInt 유형의 새 표현식-5가 생성됩니다.
예: -2147483648은 다음과 같이 분석됩니다:
-
2147483648항은 AbstractInt 값 2147483648입니다. 이 값은 32비트 부호 있는 정수에 들어가지 않습니다. -
이 항 앞에 '
-'를 붙이면 값이 -2147483648인 AbstractInt 유형의 새 표현식-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))은 다음과 같이 분석됩니다:
-
전체 표현식은 const 표현식입니다.
-
그러나
&&연산자의 단락 평가 규칙이 적용됩니다: 왼쪽 피연산자가false로 평가되므로 오른쪽 피연산자는 평가되지 않습니다. -
i32(5 * 1000 * 1000 * 1000)을 평가하면 셰이더 생성 오류가 발생했을 것입니다. AbstractInt 값 5000000000이 i32 유형을 오버플로하기 때문입니다.
예: false && array<u32, 1 + 2>(0, 1, 2)[0] == 0
-
전체 표현식은 const 표현식입니다.
-
유형 검사는
e1 : bool && e2 : bool을 요구합니다:-
false는 bool 값입니다. -
유형 검사는 오른쪽 피연산자에서 계속 진행되며 결국 배열 요소 수 표현식의
1 + 2를 평가합니다.
-
-
1 + 2는 i32 값3으로 평가됩니다.-
배열의 유형은
array<u32, 3i>입니다.
-
-
배열 접근 표현식과 동등 연산자는 모두 평가되지 않습니다.
8.1.2. override 표현식
파이프라인 생성 시점에 평가할 수 있는 표현식을 override 표현식이라고 합니다. 표현식의 모든 식별자가 다음으로 해석되면 해당 표현식은 override 표현식입니다:
-
override 선언, 또는
-
const 선언, 또는
-
const 함수, 또는
-
유형 별칭, 또는
-
구조체 이름.
참고: 모든 const 표현식은 override 표현식이기도 합니다.
const 표현식이 아닌 override 표현식은 파이프라인 생성 중에만 검증되거나 평가되며, API가 제공한 값이 override 선언에 대입된 후에만 처리됩니다. override 선언의 값이 API를 통해 대입된 경우, 초기화 표현식이 있더라도 평가되지 않습니다. 그렇지 않으면 override 표현식 E는 다음 조건을 만족하는 경우에만 평가됩니다:
-
E가
GPUProgrammableStage에서 지정된 진입점의 셰이더 일부이고: -
다음 중 하나가 참인 경우:
참고: 모든 override 표현식을 override 선언의 초기화자로 사용할 수 있는 것은 아닙니다. 이러한 초기화자는 해석 결과가 구체적 스칼라 유형이어야 하기 때문입니다.
예: override x = 42;는 다음과 같이 분석됩니다:
-
42항은 AbstractInt 값 42입니다. -
override 선언은 구체적 스칼라 유형을 요구합니다.
-
42는 실행 가능한 자동 변환을 통해 i32로 변환됩니다.
예: let y = x + 1;은 다음과 같이 분석됩니다:
-
위에서
x의 유형은 i32입니다. -
표현식
x + 1은 override 선언과 정수 리터럴로 구성되므로 override 표현식입니다. -
표현식의 유형은 i32이며 파이프라인 생성 시점에 평가됩니다. 그 값은 파이프라인 생성 시점에
x가 재정의되는지 여부에 따라 달라집니다.
예: vec3(x,x,x)는 다음과 같이 분석됩니다:
-
위에서
x는 override 선언이며 유형은 i32입니다. -
vec3(x,x,x)의 모든 식별자가 override 선언으로 해석되므로 override 표현식입니다.
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는 const 표현식 | e[i]: T |
벡터의 i번째 구성 요소를 선택합니다. 첫 번째 구성 요소의 인덱스는 i=0입니다. i가 [0,N-1] 범위를 벗어나면 셰이더 생성 오류입니다. 참고: 추상 벡터 값 e를 const 표현식이 아닌 표현식으로 인덱싱하면, 인덱스를 적용하기 전에 벡터가 구체화됩니다. |
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는 const 표현식 | e[i]: vecR<T> |
결과는 e의 i번째 열 벡터입니다.
i가 [0,C-1] 범위를 벗어나면 셰이더 생성 오류입니다. 참고: 추상 행렬 값 e를 const 표현식이 아닌 표현식으로 인덱싱하면, 인덱스를 적용하기 전에 행렬이 구체화됩니다. |
| 전제 조건 | 결론 | 설명 |
|---|---|---|
|
r: ref<AS,matCxR<T>,AM>
또는 ptr<AS,matCxR<T>,AM> i: i32 또는 u32 | r[i] : ref<AS,vecR<T>,AM> |
메모리 뷰 r이
참조하는
행렬의 i번째 열 벡터에 대한 참조를 계산합니다.
i가 [0,C-1] 범위를 벗어나면:
결과 참조의 기원 변수는 r의 기원 변수와 같습니다. |
8.5.3. 배열 접근 표현식
| 전제 조건 | 결론 | 설명 |
|---|---|---|
|
e: array<T,N> i: i32 또는 u32 T는 구체적 | e[i] : T |
결과는 배열 값 e의 i번째 요소 값입니다.
i가 [0,N-1] 범위를 벗어나면:
|
|
e: array<T,N> i: i32 또는 u32 T는 추상 i는 const 표현식 | e[i] : T |
결과는 배열 값 e의 i번째 요소 값입니다.
i가 [0,N-1] 범위를 벗어나면 셰이더 생성 오류입니다. 참고: 추상 배열 값 e를 const 표현식이 아닌 표현식으로 인덱싱하면, 인덱스를 적용하기 전에 배열이 구체화됩니다. |
| 전제 조건 | 결론 | 설명 |
|---|---|---|
|
r: ref<AS,array<T,N>,AM> 또는 ptr<AS,array<T,N>,AM> i: i32 또는 u32 | r[i] : ref<AS,T,AM> |
메모리
뷰 r이 참조하는 배열의 i번째 요소에 대한 참조를 계산합니다.
i가 [0,N-1] 범위를 벗어나면:
결과 참조의 기원 변수는 r의 기원 변수와 같습니다. |
| r: ref<AS,array<T>,AM> 또는 ptr<AS,array<T>,AM> i: i32 또는 u32 | r[i] : ref<AS,T,AM> |
메모리 뷰 r이
참조하는
런타임 크기 배열의 i번째 요소에 대한 참조를 계산합니다.
런타임에 배열이 N개의 요소를 가지고 i가 [0,N-1] 범위를 벗어나면 표현식은 무효 메모리 참조로 평가됩니다. i가 부호 있는 정수이고 i가 0보다 작으면:
결과 참조의 기원 변수는 r의 기원 변수와 같습니다. |
8.5.4. 구조체 접근 표현식
| 전제 조건 | 결론 | 설명 |
|---|---|---|
|
S는 구조체 유형 M은 S의 멤버 식별자 이름이며 유형은 T e: S | e.M: T | 결과는 구조체 값 e에서 이름이 M인 멤버의 값입니다. |
| 전제 조건 | 결론 | 설명 |
|---|---|---|
|
S는 구조체 유형 M은 S의 멤버 식별자 이름이며 유형은 T r: ref<AS,S,AM> 또는 ptr<AS,S,AM> | r.M: ref<AS,T,AM> | 구조체에 대한 메모리 뷰가 주어지면 결과는 식별자 이름이
M인 구조체 멤버에 대한 참조입니다. 결과 참조의 기원 변수는 r의 기원 변수와 같습니다. |
8.6. 스위즐 뷰 표현식
스위즐 뷰 표현식은 swizzle_assignment 언어 확장에 의해 활성화됩니다.
스위즐 뷰는 다음 방식으로 형성됩니다:
-
read_write 접근 모드를 가지며 저장 유형이 벡터인 참조 또는 포인터 값에 여러 글자로 된 스위즐 이름을 적용하거나,
-
스위즐 뷰에 여러 글자로 된 스위즐 이름을 적용합니다.
이 규칙에 따라 스위즐 뷰의 인덱스 목록 부분은 셰이더 생성 시점에 완전히 결정됩니다.
이 절에서는 스위즐 인덱스 함수 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보다 작아야 합니다. |
| 전제 조건 | 결론 | 설명 |
|---|---|---|
|
swizzle_assignment이 지원됨 pointer_composite_access가 지원됨 p: ptr<AS,T,read_write> | p.Z : swizzle<AS,S,N,K> |
결과는 스위즐
뷰 (p, I)입니다.
I의 각 인덱스는 반드시 N보다 작아야 합니다. |
| 전제 조건 | 결론 | 설명 |
|---|---|---|
|
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보다 작아야 합니다. |
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 | 결과는 초기화 표현식에 대해 계산된 값입니다. 표현식은 const 표현식이며 셰이더 생성 시점에 평가됩니다. |
| c는 유형 T의 override 선언으로 해석되는 범위 안의 식별자 | 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. 다음과 같이 update 벡터를 계산합니다. // view_contents + vec2u(55,66) // = vec2u(4,2) + vec2u(55,66) // = vec2u(59,68) // 5. 그런 다음 스위즐 대입은 v[0].x와 v[0].y만 갱신하고, // v[0].z와 v[0].w는 보존합니다. v [ update_and_index ()]. yx += update_and_rhs (); // 이제 v[0]은 vec4u(68,59,100,10)과 같습니다. }
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의 표현식은 const 표현식이어야 합니다.
같은 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 선택자에서 const 표현식을 사용할 수 있습니다. 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 (초기화자;조건;갱신_부분) {본문}
조건 표현식이 존재하는 경우 for 문은 다음 형태의 루프로 디슈거링됩니다:
{조건 표현식이 없는 경우
초기화자 ;
loop {
if !(조건) { break; }
본문
continuing { 갱신_부분 }
}
}
for 문은 다음 형태의 루프로 디슈거링됩니다:
{
초기화자 ;
loop {
본문
continuing { 갱신_부분 }
}
}
또한:
-
initializer가 비어 있지 않으면 첫 번째 반복 전에 추가 범위 안에서 실행됩니다. 초기화자의 선언 범위는 루프 본문의 끝까지 확장됩니다. -
유형 규칙 전제 조건: 조건이 비어 있지 않으면 bool 유형의 표현식이어야 합니다.
-
조건이 존재하면 for 루프 본문을 실행하기 직전에 평가됩니다. 조건이 false이면 § 9.4.6 Break 문이 실행되어 루프 실행을 종료합니다. 이 검사는 각 루프 반복의 시작에서 수행됩니다.
-
-
update_part가 비어 있지 않으면 루프 구성 끝의 continuing 문이 됩니다. -
디슈거링은
body에서 선언된 식별자를 필요에 따라 이름을 바꾸어,update_part의 모든 식별자가 디슈거링 전에 그랬던 것과 동일한 선언으로 계속 해석되도록 합니다.
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 ); // 값을 1로 설정하고 빨간색을 출력하지만 도우미 함수가 // discard 문을 실행하지 않은 경우에만 그렇게 합니다. 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} } } // 동작: {Next}, switch가 Break를 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 어설션.
'const_assert' expression
유형 규칙 전제 조건: 표현식은 bool 유형이어야 합니다.
10.1. 상수 어설션 문
const 어설션 문은 표현식이 false로 평가되면
셰이더 생성 오류를
발생시키는 어설션입니다.
표현식은 const 표현식이어야 합니다.
이 문은 셰이더의 정적 접근
조건을 충족할 수 있지만,
그 밖에는 컴파일된 셰이더에 영향을 주지 않습니다.
const 어설션은
모듈 범위 또는 함수 범위 문으로 나타날 수 있습니다.
const x = 1 ; const y = 2 ; const_assert x < y ; // 모듈 범위에서 유효합니다. const_assert ( y != 0 ); // 괄호는 선택 사항입니다. fn foo () { const z = x + y - 2 ; const_assert z > 0 ; // 함수 안에서 유효합니다. let a = 3 ; const_assert a != 0 ; // 유효하지 않으며 표현식은 const 표현식이어야 합니다. }
11. 함수
함수는 호출될 때 계산 작업을 수행합니다.
함수는 다음 방법 중 하나로 호출됩니다:
-
함수 호출 표현식을 평가합니다. § 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 문법 규칙 인스턴스에서 첫 번째 토큰의 위치입니다. 호출 위치는 동적 컨텍스트입니다. 따라서 같은 텍스트 위치가 여러 호출 위치를 나타낼 수 있습니다.
참고: 쿼드의 모든 호출이 discard된 경우 프래그먼트 셰이더의 함수 호출이 반환되지 않을 수 있습니다. 이러한 경우 제어는 호출 함수로 다시 이동하지 않습니다.
11.3. const 함수
const 속성으로 선언된 함수는 셰이더 생성 시점에 평가할 수 있습니다. 이러한 함수를 const 함수라고 합니다. 이러한 함수 호출은 const 표현식의 일부가 될 수 있습니다.
함수에 const 표현식이 아닌 표현식이나 const 선언이 아닌 선언이 포함되어 있으면 셰이더 생성 오류입니다.
참고: const 속성은 사용자 선언 함수에 적용할 수 없습니다.
const first_one = firstLeadingBit ( 1234 + 4567 ); // 12로 평가됩니다. // firstLeadingBit는 AbstractInt에 대해 // 동작할 수 없으므로 first_one의 유형은 // i32입니다. @id ( 1 ) override x : i32; override y = firstLeadingBit ( x ); // const 표현식은 // override 표현식에서 사용할 수 있습니다. // 이 컨텍스트에서 firstLeadingBit(x)는 // const 표현식이 아닙니다. fn foo () { var a : array< i32, firstLeadingBit ( 257 ) > ; // 모든 매개변수가 const 표현식이면 // const 함수를 const 표현식에서 // 사용할 수 있습니다. }
11.4. 함수 제한
-
-
구성 가능 유형
-
포인터 유형
-
텍스처 유형
-
샘플러 유형
-
-
각 함수 호출 인수는 대응하는 함수 매개변수의 유형으로 평가되어야 합니다.
참고: 모든 종류의 선언 사이에 순환이 허용되지 않으므로 재귀는 허용되지 않습니다.
fn bar ( p : ptr< function, f32> ) { } fn baz ( p : ptr< private, i32> ) { } fn bar2 ( p : ptr< function, f32> ) { let a = &*&* ( p ); bar ( p ); // 유효합니다. bar ( a ); // 유효합니다. } fn baz2 ( p : ptr< storage, f32> ) { } struct S { x : i32} @group ( 0 ) @binding ( 0 ) var < storage> ro_storage : f32; @group ( 0 ) @binding ( 1 ) var < storage, read_write> rw_storage : f32; var usable_priv : i32; var unusable_priv : array< i32, 4 > ; fn foo () { var usable_func : f32; var unusable_func : S ; var i32_func : i32; let a_priv = & usable_priv ; let b_priv = a_priv ; let c_priv = &*& usable_priv ; let d_priv = & ( unusable_priv . x ); let e_priv = d_priv ; let a_func = & usable_func ; let b_func = & unusable_func ; let c_func = & ( * b_func )[ 0 ]; let d_func = c_func ; let e_func = &* a_func ; baz ( & usable_priv ); // 유효합니다. 변수의 주소 가져오기입니다. baz ( a_priv ); // 유효합니다. 실질적으로 변수의 주소 가져오기입니다. baz ( b_priv ); // 유효합니다. 실질적으로 변수의 주소 가져오기입니다. baz ( c_priv ); // 유효합니다. 실질적으로 변수의 주소 가져오기입니다. baz ( d_priv ); // 유효합니다. 메모리 뷰가 변경되었습니다. baz ( e_priv ); // 유효합니다. 메모리 뷰가 변경되었습니다. baz ( & i32_func ); // 유효하지 않습니다. 주소 공간이 일치하지 않습니다. bar ( & usable_func ); // 유효합니다. 변수의 주소 가져오기입니다. bar ( c_func ); // 유효합니다. 메모리 뷰가 변경되었습니다. bar ( d_func ); // 유효합니다. 메모리 뷰가 변경되었습니다. bar ( e_func ); // 유효합니다. 실질적으로 변수의 주소 가져오기입니다. baz2 ( & ro_storage ); // 유효합니다. 변수의 주소 가져오기입니다. baz2 ( & rw_storage ); // 유효하지 않습니다. 접근 모드가 일치하지 않습니다. }
11.4.1. 별칭 분석
11.4.1.1. 루트 식별자
메모리 위치는 함수 실행 중 메모리 뷰 또는 스위즐 뷰를 사용하여 접근할 수 있습니다. 함수 내에서 각 메모리 뷰에는 특정 루트 식별자가 있으며, 이는 해당 함수에서 그 메모리에 처음 접근을 제공하는 변수 또는 형식 매개변수의 이름입니다. 마찬가지로 스위즐 뷰의 루트 식별자는 스위즐 뷰 포인터의 루트 식별자입니다.
참조 또는 포인터 유형의 로컬에서 파생된 표현식은 특정 루트 식별자에 대한 새로운 이름을 도입할 수 있지만, 각 표현식에는 정적으로 결정 가능한 루트 식별자가 있습니다.
포인터 또는 참조 유형의 표현식 E가 주어졌을 때 루트 식별자는 다음과 같이 찾은 기원 변수 또는 포인터 유형의 형식 매개변수입니다:
-
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). 정렬 및 크기 규칙은 상호 재귀적입니다. 그러나 위 제약 조건은 중첩된 유형의 필수 정렬에 의존하고, 유형은 제한된 중첩 깊이를 가지므로 잘 정의됩니다. uniform 또는 storage 버퍼에 바인딩된 메모리의 시작 주소가 속성에 지정된 값보다 낮은 정렬을 가지면, 결과 정렬은 두 값 중 최소값이 됩니다. 구현은 변수의 기준 주소에 상대해서만 속성을 충족합니다. § 14.4 메모리 레이아웃을 참조하십시오. |
| 매개변수 | const
표현식이어야 하며, i32 또는 u32로 해석되어야 합니다. 양수여야 합니다. 2의 거듭제곱이어야 합니다. |
12.2. binding
'@' 'binding' '(' expression ',' ?
')'
| 설명 | 바인드 그룹에서 리소스의 바인딩 번호를 지정합니다. § 13.3.2 리소스 인터페이스를 참조하십시오. |
| 매개변수 | const
표현식이어야 하며, i32 또는 u32로 해석되어야 합니다. 음수가 아니어야 합니다. |
12.3. blend_src
'@' 'blend_src' '(' expression ',' ?
')'
| 설명 |
dual_source_blending 기능이
활성화되었을 때 프래그먼트 출력의 일부를
지정합니다.
§ 13.3.1.3 입출력 위치를 참조하십시오.
location 속성이 있는 구조체 유형의 멤버에만 적용해야 합니다. 숫자 스칼라 또는 숫자 벡터 유형의 객체 선언에만 적용해야 합니다. 셰이더 스테이지 입력에 포함해서는 안 됩니다. 프래그먼트 셰이더 스테이지를 제외하고 셰이더 스테이지 출력에 포함해서는 안 됩니다. |
| 매개변수 | 값이 0 또는 1인 i32 또는 u32로 해석되는 const 표현식이어야 합니다.
|
12.4. builtin
'@' 'builtin' '(' builtin_value_name ',' ? ')'
| 설명 | 연결된 객체가 지정된 토큰으로 표시되는 내장 값임을 지정합니다. § 13.3.1.1 내장 입력 및 출력을 참조하십시오. |
| 매개변수 | 내장 값에 대한 내장 값 이름 토큰이어야 합니다. |
12.5. const
'@' 'const'
| 설명 |
함수가 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 리소스 인터페이스를 참조하십시오. |
| 매개변수 | const
표현식이어야 하며, i32 또는 u32로 해석되어야 합니다. 음수가 아니어야 합니다. |
12.8. id
'@' 'id' '(' expression ',' ?
')'
| 설명 |
파이프라인
재정의 가능 상수의 대체 이름으로
숫자 식별자를 지정합니다.
스칼라 유형의 override 선언에만 적용해야 합니다. |
| 매개변수 | const
표현식이어야 하며, 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 입출력 위치를 참조하십시오.
진입점 함수 매개변수, 진입점 반환 유형 또는 구조체 유형의 멤버에만 적용해야 합니다. 숫자 스칼라 또는 숫자 벡터 유형의 객체 선언에만 적용해야 합니다. 컴퓨트 셰이더 스테이지 입력에 포함해서는 안 됩니다. |
| 매개변수 | const
표현식이어야 하며, i32 또는 u32로 해석되어야 합니다. 음수가 아니어야 합니다. |
12.12. must_use
'@' 'must_use'
| 설명 |
이 함수의 호출은 표현식으로 사용되어야 합니다.
즉, 이 함수 호출은 함수 호출문 전체가 되어서는 안 됩니다.
참고: 많은 함수는 값을 반환하면서
부작용이 없습니다.
이러한 함수를 함수 호출문의 유일한 내용으로 호출하는 것은 흔히 프로그래밍 결함입니다.
이러한 속성을 가진 내장 함수는 참고:
|
| 매개변수 | 없음 |
12.13. size
'@' 'size' '(' expression ',' ?
')'
| 설명 |
구조체 멤버에 예약된 바이트 수를 지정합니다.
§ 14.4 메모리 레이아웃을 참조하십시오. 구조체 유형의 멤버에만 적용해야 합니다. 멤버 유형은 생성 시 고정 풋프린트를 가져야 합니다. |
| 매개변수 | const
표현식이어야 하며, i32 또는 u32로 해석되어야 합니다. 양수여야 합니다. |
12.14. subgroup_size
'@' 'subgroup_size' '(' expression ',' ? ')'
| 설명 | 컴퓨트 셰이더 호출의 서브그룹 크기를 지정합니다. |
| 요구 사항 | subgroup_size_control 확장이 활성화된 경우에만 사용해야 합니다. |
| 매개변수 |
const 표현식
또는 override 표현식이어야 하며, 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로 간주됩니다. |
| 매개변수 |
하나, 둘 또는 세 개의 매개변수를 받습니다.
각 매개변수는 const 표현식 또는 override 표현식이어야 합니다. 모든 매개변수는 i32 또는 u32 중 동일한 유형이어야 합니다. 지정된 매개변수 중 하나라도 양수가 아닌 값으로 평가되는 const 표현식이면 셰이더 생성 오류가 발생합니다. 지정된 매개변수 중 하나라도 양수가 아닌 값으로 평가되거나 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로 해석되는 식별자가 셰이더 스테이지의 함수 중 하나의 선언에 나타납니다.
-
속성, 형식 매개변수, 반환 유형 및 함수 본문을 포함한 함수 선언의 모든 부분.
-
유형 별칭을 따라가는 것을 포함하여 위 항목을 정의하는 데 필요한 모든 유형.
-
유형 정의를 돕는 특별한 경우로, workgroup 주소 공간에 있는 변수의 배열 유형에 대한 요소 수인 override 표현식에서 사용되는 모든 override 선언. 단, 해당 변수 자체가 정적으로 접근되는 경우입니다.
-
위 항목 중 하나에서 override 표현식 평가를 지원하는 데 사용되는 모든 override 선언.
-
위 항목 중 하나에 있는 모든 속성.
이제 셰이더의 인터페이스를 다음으로 구성된 것으로 정확히 정의할 수 있습니다:
-
진입점의 반환 값. 이는 셰이더 스테이지 출력을 나타냅니다.
-
셰이더에 의해 정적으로 접근되는 override 선언입니다.
13.3.1. 스테이지 간 입력 및 출력 인터페이스
셰이더 스테이지 입력은 파이프라인의 상위 단계에서 셰이더 스테이지에 제공되는 데이터입니다. 각 데이터는 내장 입력 값 또는 사용자 정의 입력입니다.
셰이더 스테이지 출력은 셰이더가 파이프라인의 이후 단계에서 추가 처리하도록 제공하는 데이터입니다. 각 데이터는 내장 출력 값 또는 사용자 정의 출력입니다.
IO 속성은 객체를 셰이더 스테이지 입력 또는 셰이더 스테이지 출력으로 설정하거나, 입력 또는 출력의 속성을 추가로 설명하는 데 사용됩니다. IO 속성은 다음과 같습니다:
13.3.1.1. 내장 입력 및 출력
내장 입력 값은 시스템에서 생성된 제어 정보에 대한 접근을 제공합니다. 진입점은 동일한 내장 값 이름을 가진 두 개의 내장 입력을 가져서는 안 됩니다.
이름이 X이고 유형이 TX인 스테이지 S의 내장 입력은 셰이더 스테이지 S의 진입점에 대한 형식 매개변수를 통해 다음 두 방법 중 하나로 접근합니다:
-
매개변수는
builtin(X)속성을 가지며 유형은 TX입니다. -
매개변수는 구조체 유형이고, 구조체 멤버 중 하나가
builtin(X)속성을 가지며 유형은 TX입니다.
반대로 진입점의 매개변수 또는 매개변수 멤버에 builtin 속성이 있으면, 대응하는 builtin은 진입점의 셰이더 스테이지에 대한 입력이어야 합니다.
내장 출력 값은 셰이더가 파이프라인의 이후 처리 단계에 제어 정보를 전달하는 데 사용됩니다. 진입점은 동일한 내장 값 이름을 가진 두 개의 내장 출력을 가져서는 안 됩니다.
이름이 Y이고 유형이 TY인 스테이지 S의 내장 출력은 셰이더 스테이지 S의 진입점에 대한 반환 값을 통해 다음 두 방법 중 하나로 설정합니다:
-
진입점 반환 유형은
builtin(Y)속성을 가지며 유형은 TY입니다. -
진입점 반환 유형은 구조체 유형이고, 구조체 멤버 중 하나가
builtin(Y)속성을 가지며 유형은 TY입니다.
반대로 진입점의 반환 유형 또는 반환 유형의 멤버에 builtin 속성이 있으면, 대응하는 builtin은 진입점의 셰이더 스테이지에 대한 출력이어야 합니다.
참고: position 내장 값은 버텍스 셰이더의 출력이자 프래그먼트 셰이더의 입력입니다.
내장 입력 값과 내장 출력 값을 통틀어 내장 값이라고 합니다.
다음 표는 사용 가능한 내장 값을 요약합니다. 각각은 내장 값에 대한 내장 값 이름 토큰입니다. 각각은 이후 절에서 자세히 설명합니다.
| 이름 | 스테이지 | 방향 | 유형 | 확장 |
|---|---|---|---|---|
| vertex_index | 버텍스 | 입력 | u32 | |
| instance_index | 버텍스 | 입력 | u32 | |
| clip_distances | 버텍스 | 출력 | array<f32, N> (N ≤ 8)
| clip_distances |
| position | 버텍스 | 출력 | vec4<f32> | |
| 프래그먼트 | 입력 | vec4<f32> | ||
| front_facing | 프래그먼트 | 입력 | bool | |
| frag_depth | 프래그먼트 | 출력 | f32 | |
| primitive_index | 프래그먼트 | 입력 | u32 | primitive_index |
| sample_index | 프래그먼트 | 입력 | u32 | |
| sample_mask | 프래그먼트 | 입력 | u32 | |
| 프래그먼트 | 출력 | u32 | ||
| local_invocation_id | 컴퓨트 | 입력 | vec3<u32> | |
| local_invocation_index | 컴퓨트 | 입력 | u32 | |
| global_invocation_id | 컴퓨트 | 입력 | vec3<u32> | |
| global_invocation_index | 컴퓨트 | 입력 | u32 | linear_indexing |
| workgroup_id | 컴퓨트 | 입력 | vec3<u32> | |
| workgroup_index | 컴퓨트 | 입력 | u32 | linear_indexing |
| num_workgroups | 컴퓨트 | 입력 | vec3<u32> | |
| subgroup_invocation_id | 컴퓨트 | 입력 | u32 | subgroups |
| 프래그먼트 | ||||
| subgroup_size | 컴퓨트 | 입력 | u32 | subgroups |
| 프래그먼트 | ||||
| subgroup_id | 컴퓨트 | 입력 | u32 | subgroups 및 subgroup_id |
| num_subgroups | 컴퓨트 | 입력 | u32 | subgroups 및 subgroup_id |
struct VertexOutput { @builtin ( position) my_pos : vec4< f32> , @builtin ( clip_distances ) my_clip_distances : array< f32, 8 > , } @vertex fn vs_main ( @builtin ( vertex_index) my_index : u32, @builtin ( instance_index) my_inst_index : u32, ) -> VertexOutput {} struct FragmentOutput { @builtin ( frag_depth) depth : f32, @builtin ( sample_mask) mask_out : u32} @fragment fn fs_main ( @builtin ( front_facing) is_front : bool, @builtin ( position) coord : vec4< f32> , @builtin ( sample_index) my_sample_index : u32, @builtin ( sample_mask) mask_in : u32, ) -> FragmentOutput {} @compute @workgroup_size ( 64 ) fn cs_main ( @builtin ( local_invocation_id) local_id : vec3< u32> , @builtin ( local_invocation_index) local_index : u32, @builtin ( global_invocation_id) global_id : vec3< u32> , ) {}
13.3.1.1.1. clip_distances
| 이름 | clip_distances |
| 스테이지 | 버텍스 |
| 유형 | array<f32, N> |
| 방향 | 출력 |
| 설명 |
배열의 각 값은 사용자 정의 클립 평면까지의 거리를 나타냅니다. 클립 거리가
0이면 버텍스가 평면 위에 있음을 의미하고, 양의 거리는 버텍스가 클립
반공간 안에 있음을 의미하며, 음의 거리는 버텍스가 클립 반공간 밖에 있음을 의미합니다. clip_distances의 배열
크기는 ≤ 8이어야 합니다.
WebGPU § 23.2.4
프리미티브 클리핑을 참조하십시오.
|
13.3.1.1.2. frag_depth
| 이름 | frag_depth |
| 스테이지 | 프래그먼트 |
| 유형 | f32 |
| 방향 | 출력 |
| 설명 |
뷰포트 깊이 범위에서 갱신된 프래그먼트의 깊이입니다.
WebGPU § 3.3 좌표계를 참조하십시오. fragment_depth 기능이 지원되면 builtin 속성은 선택적 두 번째 매개변수를 가져 깊이 모드를 지정할 수 있습니다:
프래그먼트의 원래 깊이는 프래그먼트의 RasterizationPoint의 깊이 속성입니다. 셰이더가 깊이 모드 약속을 위반하는 깊이 값을 반환하면 대신 불확정 깊이 값이 사용될 수 있습니다.
|
13.3.1.1.3. front_facing
| 이름 | front_facing |
| 스테이지 | 프래그먼트 |
| 유형 | bool |
| 방향 | 입력 |
| 설명 | 현재 프래그먼트가 앞면을 향한 프리미티브에 있으면 True입니다. 그렇지 않으면 False입니다. |
13.3.1.1.4. global_invocation_id
| 이름 | global_invocation_id |
| 스테이지 | 컴퓨트 |
| 유형 | vec3<u32> |
| 방향 | 입력 |
| 설명 | 현재 호출의 전역 호출 ID, 즉 컴퓨트 셰이더 그리드에서의 위치입니다. global_invocation_id의 값은 workgroup_id * workgroup_size + local_invocation_id와 같습니다. |
13.3.1.1.5. global_invocation_index
| 이름 | global_invocation_index |
| 스테이지 | 컴퓨트 |
| 유형 | u32; |
| 방향 | 입력 |
| 설명 |
현재 호출의 전역 호출 인덱스, 즉
컴퓨트 셰이더
그리드에서의 선형 위치입니다. global_invocation_index의 값은
다음과 같습니다:
global_invocation_id.x +
참고: 디스패치된
워크그룹 수로 인해 이 값이 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 렌더링 파이프라인에
지정된 샘플 count입니다.
이 속성이 적용되었을 때 프래그먼트 셰이더의 효과가
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. 리소스 인터페이스
리소스는 셰이더 스테이지 외부의 데이터에 대한 접근을 제공하며, override 선언도 아니고, 즉시 데이터 변수도 아니며, 셰이더 스테이지 입력 또는 출력도 아닌 객체입니다. 리소스는 셰이더의 모든 호출이 공유합니다.
리소스에는 네 종류가 있습니다:
셰이더의 리소스 인터페이스는 셰이더 스테이지의 함수가 정적으로 접근하는 모듈 범위 리소스 변수의 집합입니다.
각 리소스 변수는 group 및 binding 속성을 모두 사용하여 선언되어야 합니다. 셰이더의 스테이지와 함께 이 값들은 셰이더 파이프라인에서 리소스의 바인딩 주소를 식별합니다. WebGPU § 8.3 GPUPipelineLayout을 참조하십시오.
즉시 데이터 변수는 group 또는 binding 속성을 사용하지 않습니다.
셰이더의 서로 다른 두 리소스 변수는 쌍으로 고려했을 때 동일한 group 및 binding 값을 가져서는 안 됩니다.
13.3.3. 리소스 레이아웃 호환성
WebGPU는 셰이더의 리소스 인터페이스가 해당 셰이더를 사용하는 파이프라인 레이아웃과 일치할 것을 요구합니다.
리소스 인터페이스의 WGSL 변수가 호환되지 않는 WebGPU 바인딩 멤버 또는 바인딩 유형에 바인딩되면 파이프라인 생성 오류이며, 호환성은 다음 표에서 정의됩니다.
인터페이스 검증 요구 사항은 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 { // 정렬(16) 크기(32) position: vec3f, // 오프셋(0) 정렬(16) 크기(12) // -- 암시적 멤버 정렬 패딩 -- // 오프셋(12) 크기(4) color : vec3f, // 오프셋(16) 정렬(16) 크기(12) // -- 암시적 구조체 크기 패딩 -- // 오프셋(28) 크기(4) } struct LightStorage { // 정렬(16) pointCount : u32, // 오프셋(0) 정렬(4) 크기(4) // -- 암시적 멤버 정렬 패딩 -- // 오프셋(4) 크기(12) point : array< PointLight > , // 오프셋(16) 정렬(16) 요소크기(32) } @group ( 0 ) @binding ( 1 ) var < storage> lights : LightStorage ;
다음 표는 lights 변수의 point 멤버에 대한
NRuntime 예를 보여줍니다.
| 유효 버퍼 바인딩 크기 | lights 변수의 point 멤버에 대한 NRuntime
| 계산 |
|---|---|---|
| 1024 | 31 | truncate( ( 1024 - 16 ) ÷ 32) ) |
| 1025 | 31 | truncate( ( 1025 - 16 ) ÷ 32) ) |
| 1039 | 31 | truncate( ( 1039 - 16 ) ÷ 32) ) |
| 1040 | 32 | truncate( ( 1040 - 16 ) ÷ 32) ) |
14. 메모리
WGSL에서 저장 가능한 유형의 값은 나중에 가져오기 위해 메모리에 저장할 수 있습니다. 이 절에서는 메모리의 구조와 메모리에 접근하는 연산의 의미론을 설명합니다. 메모리에 배치할 수 있는 값의 유형과 메모리 접근을 수행하는 데 사용되는 유형은 § 6.5 메모리 뷰를 참조하십시오.
14.1. 메모리 위치
메모리는 서로 구별되는 메모리 위치의 집합으로 구성됩니다. 각 메모리 위치의 크기는 8비트입니다. 메모리에 영향을 미치는 연산은 하나 이상의 메모리 위치 집합과 상호 작용합니다. 복합 값에 대한 메모리 연산은 패딩 메모리 위치에 접근하지 않습니다. 따라서 연산이 접근하는 메모리 위치 집합은 연속적이지 않을 수 있습니다.
두 메모리 위치 집합은 메모리 위치 집합의 교집합이 비어 있지 않으면 겹칩니다.
14.2. 메모리 접근 모드
메모리 접근은 메모리 위치에 작용하는 연산입니다.
-
읽기 접근은 메모리 위치의 내용을 관찰합니다.
-
쓰기 접근은 메모리 위치의 내용을 설정합니다.
하나의 연산은 읽기, 쓰기 또는 읽기와 쓰기를 모두 수행할 수 있습니다.
특정 메모리 위치는 특정 종류의 접근만 지원할 수 있으며, 이는 메모리의 접근 모드로 표현됩니다.
| 접근 모드 | 지원되는 접근 |
|---|---|
| read | 읽기 접근을 지원하지만 쓰기는 지원하지 않습니다. |
| write | 쓰기 접근을 지원하지만 읽기는 지원하지 않습니다. |
| read_write | 읽기와 쓰기 접근을 모두 지원합니다. |
WGSL은 열거자 read,
write 및 read_write를 미리 선언합니다.
14.3. 주소 공간
메모리 위치는 주소 공간으로 분할됩니다. 각 주소 공간에는 변경 가능성, 가시성, 포함할 수 있는 값, 그리고 해당 공간의 변수를 사용하는 방법을 결정하는 고유한 특성이 있습니다. 자세한 내용은 § 7 변수 및 값 선언을 참조하십시오.
주어진 메모리 뷰의 접근 모드는 흔히 컨텍스트에 의해 결정됩니다:
storage 주소 공간은 read 및 read_write 접근 모드를 모두 지원합니다. 다른 각 주소 공간은 하나의 접근 모드만 지원합니다. 각 주소 공간의 기본 접근 모드는 다음 표에 설명되어 있습니다.
| 주소 공간 | 호출 간 공유 | 기본 접근 모드 | 참고 |
|---|---|---|---|
| function | 동일한 호출에서만 | read_write | |
| private | 동일한 호출에서만 | read_write | |
| workgroup | 동일한 컴퓨트 셰이더 워크그룹의 호출 | read_write | 가장 바깥쪽 배열의 요소 수는 파이프라인 재정의 가능 상수일 수 있습니다. |
| uniform | 동일한 셰이더 스테이지의 호출 | read | 유니폼 버퍼 변수용 |
| storage | 동일한 셰이더 스테이지의 호출 | read | 스토리지 버퍼 변수용 |
| immediate | 동일한 셰이더 스테이지의 호출 | read | 즉시
데이터 변수용. 각 진입점은 최대 하나의 immediate 변수에 정적으로 접근할 수 있습니다. |
| handle | 동일한 셰이더 스테이지의 호출 | read | 샘플러
및 텍스처
변수용. |
WGSL은 handle 주소 공간을 제외한 각 주소 공간에 대해
열거자를 미리 선언합니다.
workgroup 주소 공간의 변수는 컴퓨트 셰이더 스테이지에서만 정적으로 접근되어야 합니다.
storage 주소
공간의 변수(스토리지 버퍼)는 접근 모드가
read인 경우에만 버텍스 셰이더 스테이지에서 정적으로
접근될 수 있습니다.
저장 유형이
write 또는 read_write 접근 모드의 스토리지 텍스처인
변수는 버텍스 셰이더 스테이지에서
정적으로
접근될 수 없습니다.
WebGPU createBindGroupLayout()을
참조하십시오.
참고: 각 주소 공간은 서로 다른 성능 특성을 가질 수 있습니다.
WGSL 소스에서 변수 선언 또는 포인터 유형을 작성할 때:
14.4. 메모리 레이아웃
WGSL에서 유형의 레이아웃은 주소 공간과 독립적입니다. 엄밀히 말하면 이 레이아웃은 호스트 공유 가능 버퍼에서만 관찰할 수 있습니다. 유니폼 버퍼와 스토리지 버퍼 변수는 메모리의 바이트 시퀀스로 구성된 대량 데이터를 공유하는 데 사용됩니다. 버퍼는 CPU와 GPU 사이, 파이프라인의 서로 다른 셰이더 스테이지 사이, 또는 서로 다른 파이프라인 사이에서 공유됩니다.
버퍼 데이터는 재포맷이나 변환 없이 공유되므로 버퍼 생산자와 소비자가 메모리 레이아웃에 동의하지 않으면 동적 오류이며, 메모리 레이아웃은 버퍼의 바이트가 유형이 지정된 WGSL 값으로 구성되는 방식을 설명합니다. 이러한 바이트는 공통 기준 위치에 상대적인 값의 메모리 위치입니다.
버퍼 변수의 저장 유형은 아래 설명과 같이 완전히 구체화된 메모리 레이아웃을 가진 호스트 공유 가능 유형이어야 합니다.
각 버퍼 변수는 uniform 또는 storage 주소 공간 중 하나에 선언되어야 합니다.
유형의 메모리 레이아웃은 다음을 포함하는 표현식을 평가할 때만 중요합니다:
8비트 바이트는 호스트 공유 가능 메모리의 가장 기본 단위입니다. 이 절에서 정의하는 용어는 8비트 바이트 수를 나타냅니다.
다음 표기법을 사용합니다. 여기서 T는 호스트 공유 가능 또는 고정 풋프린트 유형이고, S는 호스트 공유 가능 또는 고정 풋프린트 구조체 유형이며, A는 호스트 공유 가능 또는 고정 풋프린트 배열이나 런타임 크기 배열입니다:
-
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의
크기
|
참고: buffer 유형은 다른 어떤 유형에도 포함될 수 없으므로 정렬은 중요하지 않습니다.
bool 값이 4바이트 정렬로 4바이트를 차지하도록 지정함으로써
구현은 데이터 경합을 도입하지 않고 메모리에서 인접한 불리언 값을 지원할 수 있습니다.
14.4.2. 구조체 멤버 레이아웃
구조체의 내부 레이아웃은 멤버의 크기와 정렬에서 계산됩니다. 기본적으로 멤버는 멤버 정렬 요구 사항을 충족하면서 겹치지 않도록 순서대로 촘촘하게 배치됩니다.
이 기본 내부 레이아웃은 레이아웃 속성을 사용하여 재정의할 수 있으며, 해당 속성은:
구조체 유형 S의 i번째 멤버에는 각각 SizeOfMember(S, i) 및 AlignOfMember(S, i)로 나타내는 크기와 정렬이 있습니다. 멤버 크기와 정렬은 구조체 시작에서 각 멤버까지의 바이트 오프셋을 계산하는 데 사용되며, § 14.4.4 값의 내부 레이아웃에서 설명합니다.
S의 i번째 멤버에 속성 size(k)가 있으면 SizeOfMember(S, i)는 k입니다. 그렇지 않으면 멤버의 유형이 T일 때 SizeOf(T)입니다.
S의 i번째 멤버에 속성 align(k)가 있으면 AlignOfMember(S, i)는 k입니다. 그렇지 않으면 멤버의 유형이 T일 때 AlignOf(T)입니다.
구조체 멤버에 size 속성이 적용된 경우 값은 멤버 유형의 크기 이상이어야 합니다:
SizeOfMember(S, i) ≥ SizeOf(T)
여기서 T는 S의 i번째 멤버 유형입니다.
첫 번째 구조체 멤버는 항상 구조체 시작으로부터 바이트 오프셋이 0입니다:
OffsetOfMember(S, 1) = 0
이후의 각 멤버는 멤버 유형 정렬을 충족하고 이전 멤버와 겹치지 않는 가장 낮은 오프셋에 배치됩니다. 각 멤버 인덱스 i > 1에 대해:
OffsetOfMember(S, i) = roundUp(AlignOfMember(S, i ), OffsetOfMember(S, i-1) + SizeOfMember(S, i-1))
struct A { // 정렬(8) 크기(24) u : f32, // 오프셋(0) 정렬(4) 크기(4) v : f32, // 오프셋(4) 정렬(4) 크기(4) w : vec2< f32> , // 오프셋(8) 정렬(8) 크기(8) x : f32// 오프셋(16) 정렬(4) 크기(4) // -- 암시적 구조체 크기 패딩 -- // 오프셋(20) 크기(4) } struct B { // 정렬(16) 크기(160) a : vec2< f32> , // 오프셋(0) 정렬(8) 크기(8) // -- 암시적 멤버 정렬 패딩 -- // 오프셋(8) 크기(8) b : vec3< f32> , // 오프셋(16) 정렬(16) 크기(12) c : f32, // 오프셋(28) 정렬(4) 크기(4) d : f32, // 오프셋(32) 정렬(4) 크기(4) // -- 암시적 멤버 정렬 패딩 -- // 오프셋(36) 크기(4) e : A , // 오프셋(40) 정렬(8) 크기(24) f : vec3< f32> , // 오프셋(64) 정렬(16) 크기(12) // -- 암시적 멤버 정렬 패딩 -- // 오프셋(76) 크기(4) g : array< A , 3 > , // 요소 스트라이드 24 오프셋(80) 정렬(8) 크기(72) h : i32// 오프셋(152) 정렬(4) 크기(4) // -- 암시적 구조체 크기 패딩 -- // 오프셋(156) 크기(4) } @group ( 0 ) @binding ( 0 ) var < storage, read_write> storage_buffer : B ;
struct A { // 정렬(8) 크기(32) u : f32, // 오프셋(0) 정렬(4) 크기(4) v : f32, // 오프셋(4) 정렬(4) 크기(4) w : vec2< f32> , // 오프셋(8) 정렬(8) 크기(8) @size ( 16 ) x : f32// 오프셋(16) 정렬(4) 크기(16) } struct B { // 정렬(16) 크기(208) a : vec2< f32> , // 오프셋(0) 정렬(8) 크기(8) // -- 암시적 멤버 정렬 패딩 -- // 오프셋(8) 크기(8) b : vec3< f32> , // 오프셋(16) 정렬(16) 크기(12) c : f32, // 오프셋(28) 정렬(4) 크기(4) d : f32, // 오프셋(32) 정렬(4) 크기(4) // -- 암시적 멤버 정렬 패딩 -- // 오프셋(36) 크기(12) @align ( 16 ) e : A , // 오프셋(48) 정렬(16) 크기(32) f : vec3< f32> , // 오프셋(80) 정렬(16) 크기(12) // -- 암시적 멤버 정렬 패딩 -- // 오프셋(92) 크기(4) g : array< A , 3 > , // 요소 스트라이드 32 오프셋(96) 정렬(8) 크기(96) h : i32// 오프셋(192) 정렬(4) 크기(4) // -- 암시적 구조체 크기 패딩 -- // 오프셋(196) 크기(12) } @group ( 0 ) @binding ( 0 ) var < uniform> uniform_buffer : B ;
14.4.3. 배열 레이아웃 예제
// 다음과 같은 배열: // - 정렬은 4 = AlignOf(f32) // - 요소 스트라이드는 4 = roundUp(AlignOf(f32),SizeOf(f32)) = roundUp(4,4) // - 크기는 32 = 스트라이드 * 요소_수 = 4 * 8 var small_stride : array< f32, 8 > ; // 다음과 같은 배열: // - 정렬은 16 = AlignOf(vec3<f32>) = 16 // - 요소 스트라이드는 16 = roundUp(AlignOf(vec3<f32>), SizeOf(vec3<f32>)) // = roundUp(16,12) // - 크기는 128 = 스트라이드 * 요소_수 = 16 * 8 var bigger_stride : array< vec3< f32> , 8 > ;
// 다음과 같은 배열: // - 정렬은 4 = AlignOf(f32) // - 요소 스트라이드는 4 = roundUp(AlignOf(f32),SizeOf(f32)) = 4 // B가 그리기 또는 디스패치 명령에서 바인딩의 유효 버퍼 바인딩 크기이면 // 요소 수는 다음과 같습니다: // N_runtime = floor(B / 요소 스트라이드) = floor(B / 4) @group ( 0 ) @binding ( 0 ) var < storage> weights : array< f32> ; // 다음과 같은 배열: // - 정렬은 16 = AlignOf(vec3<f32>) = 16 // - 요소 스트라이드는 16 = roundUp(AlignOf(vec3<f32>), SizeOf(vec3<f32>)) // = roundUp(16,12) // B가 그리기 또는 디스패치 명령에서 바인딩의 유효 버퍼 바인딩 크기이면 // 요소 수는 다음과 같습니다: // N_runtime = floor(B / 요소 스트라이드) = floor(B / 16) var < storage> directions : array< vec3< f32>> ;
14.4.4. 값의 내부 레이아웃
이 절에서는 전체 값의 배치가 주어졌다고 가정할 때 호스트 공유 가능 값의 내부가 버퍼의 바이트 위치에 배치되는 방식을 설명합니다. 이러한 레이아웃은 값의 유형과 구조체 멤버의 align 및 size 속성에 따라 달라집니다. 이러한 규칙은 아래 설명과 같이 불투명하지 않은 유형에 적용되며, buffer 유형의 값에는 내부 구조가 없고 이 규칙의 제약을 받지 않습니다.
값이 배치되는 버퍼 바이트 오프셋은 유형 정렬 요구 사항을 충족해야 합니다: 유형 T의 값이 버퍼 오프셋 k에 배치되면 어떤 음이 아닌 정수 c에 대해 k = c × AlignOf(T)입니다.
데이터는 주소 공간과 관계없이 동일하게 나타납니다.
참고: bool 유형은 호스트 공유 가능하지 않습니다. WGSL은 bool 값의 크기와 정렬이 4바이트라고 지정하지만 bool 값의 내부 레이아웃은 지정하지 않습니다.
u32 또는 i32 유형의 값 V가 호스트 공유 버퍼의 바이트 오프셋 k에 배치되면:
-
바이트 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, S가 C에 나타날 수 있다고 가정 | RequiredAlignOf(S, C), uniform_buffer_standard_layout이 지원되거나 C가 uniform이 아님 | RequiredAlignOf(S, C), uniform_buffer_standard_layout이 지원되지 않고 C가 uniform임 |
|---|---|---|
| bool, i32, u32, f32, 또는 f16 | AlignOf(S) | AlignOf(S) |
| atomic<T> | AlignOf(S) | AlignOf(S) |
| vecN<T> | AlignOf(S) | AlignOf(S) |
| matCxR<T> | AlignOf(S) | AlignOf(S) |
| array<T, N> | AlignOf(S) | roundUp(16, AlignOf(S)) |
| array<T> | AlignOf(S) C가 uniform인 경우 buffer_view 내장 함수의 결과인 경우를 제외하고 허용되지 않음 | roundUp(16, AlignOf(S)) buffer_view 내장 함수의 결과인 경우를 제외하고 허용되지 않음 |
| struct S | AlignOf(S) | roundUp(16, AlignOf(S)) |
유형 T의 구조체 멤버는 주소 공간 C에 대한 RequiredAlignOf(T, C)의 배수인 구조체 시작으로부터의 바이트 오프셋을 가져야 합니다:
OffsetOfMember(S, i) = k × RequiredAlignOf(T, C)
여기서 k는 음이 아닌 정수이며 구조체 S의 i번째 멤버는 유형 T입니다.
요소 유형 T의 배열은 주소 공간 C에 대한 RequiredAlignOf(T, C)의 배수인 요소 스트라이드를 가져야 합니다:
StrideOf(array<T, N>) = k × RequiredAlignOf(T, C)
StrideOf(array<T>) = k × RequiredAlignOf(T, C)
여기서 k는 양의 정수입니다.
uniform_buffer_standard_layout이 지원되지 않을 때, uniform 주소 공간은 다음을 요구합니다:
-
배열 요소는 16바이트 경계에 정렬됩니다. 즉, 어떤 양의 정수 k에 대해 StrideOf(array<T,N>) = 16 × k입니다.
-
구조체 멤버 자체가 구조체 유형
S이면 해당 멤버의 시작과 뒤따르는 모든 멤버의 시작 사이의 바이트 수는 roundUp(16, SizeOf(S)) 이상이어야 합니다.
참고: 다음 예제는 uniform 버퍼의 레이아웃 요구 사항을 충족하기 위해 구조체 멤버에서 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 > // 스트라이드 4 } // 유효하지 않음, 스트라이드는 16의 배수여야 합니다. @group ( 0 ) @binding ( 0 ) var < uniform> invalid : small_stride ; struct wrapped_f32 { @size ( 16 ) elem : f32} struct big_stride { a : array< wrapped_f32 , 8 > // 스트라이드 16 } @group ( 0 ) @binding ( 1 ) var < uniform> valid : big_stride ; // 유효함
14.5. 메모리 모델
일반적으로 WGSL은 Vulkan 메모리 모델을 따릅니다. 이 절의 나머지 부분에서는 WGSL 프로그램이 Vulkan 메모리 모델에 매핑되는 방식을 설명합니다.
참고: Vulkan 메모리 모델은 형식적 Alloy 모델의 텍스트 버전입니다.
14.5.1. 메모리 연산
WGSL에서 읽기 접근은 Vulkan 메모리 모델의 메모리 읽기 연산과 같습니다. WGSL에서 쓰기 접근은 Vulkan 메모리 모델의 메모리 쓰기 연산과 같습니다.
호출이 다음 중 하나를 실행하면 읽기 접근이 발생합니다:
-
로드 규칙의 평가
-
스위즐 뷰 로드 규칙의 평가
-
다음을 제외한 모든 텍스처 내장 함수:
-
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. 프라이빗과 비프라이빗
storage 또는
workgroup 주소 공간의 모든 비원자적 읽기 접근은
non-private로 간주되며
Workgroup 범위의 NonPrivatePointer | MakePointerVisible 메모리 피연산자를 가진
읽기 연산에 대응합니다.
storage 또는
workgroup 주소 공간의 모든 비원자적 쓰기 접근은
non-private로 간주되며
Workgroup 범위의 NonPrivatePointer | MakePointerAvailable 메모리 피연산자를 가진
쓰기 연산에 대응합니다.
handle 주소
공간의 모든 비원자적 읽기 접근은 non-private로 간주되며
Workgroup 범위의 NonPrivateTexel | MakeTexelVisible 메모리 피연산자를 가진
읽기 연산에 대응합니다.
handle
주소 공간의 모든 비원자적 쓰기 접근은
non-private로 간주되며
Workgroup 범위의 NonPrivateTexel | MakeTexelAvailable 메모리 피연산자를 가진
쓰기 연산에 대응합니다.
15. 실행
§ 1.1 개요에서는 셰이더가 호출되고 호출로 분할되는 방식을 설명합니다. 이 절에서는 호출이 개별적으로 그리고 집단적으로 실행되는 방식에 대한 추가 제약 조건을 설명합니다.
15.1. 호출 내부의 프로그램 순서
WGSL 모듈의 각 문은 실행 중 0회 이상 실행될 수 있습니다. 주어진 호출에 대해 주어진 문의 각 실행은 고유한 동적 문 인스턴스를 나타냅니다.
문에 표현식이 포함된 경우 문의 의미론은 다음을 결정합니다:
-
표현식이 문 실행의 일부로 평가되는지 여부.
-
문 안의 독립적인 표현식 사이의 상대적인 평가 순서.
표현식 중첩은 평가를 완료하기 위해 충족해야 하는 데이터 의존성을 정의합니다.
즉, 중첩된 표현식은 바깥쪽 표현식을
평가하기 전에 평가되어야 합니다.
WGSL에서 표현식 피연산자의 평가 순서는 왼쪽에서 오른쪽입니다.
예를 들어 foo() + bar()는 bar()보다 먼저 foo()를 평가해야 합니다.
§ 8 표현식을 참조하십시오.
WGSL 모듈의 문은 제어 흐름 순서로 실행됩니다. § 9 문 및 § 11.2 함수 호출을 참조하십시오.
15.2. 균일성
집단 연산 (예: 배리어, 도함수 또는 암시적으로 계산된 도함수에 의존하는 텍스처 연산)은 GPU에서 동시에 실행되는 서로 다른 호출 사이의 조정을 필요로 합니다. 모든 호출이 이를 동시에, 즉 균일한 제어 흐름에서 실행하면 연산이 올바르고 이식 가능하게 실행됩니다.
반대로 호출의 엄격한 부분집합만 연산을 실행하면, 즉 비균일 제어 흐름에서 실행하면 잘못되거나 이식 불가능한 동작이 발생합니다. 비공식적으로는 비균일 제어 의존성으로 인해 일부 호출은 집단 연산에 도달하지만 다른 호출은 도달하지 않거나 같은 시점에 도달하지 않습니다. 비균일 제어 의존성은 동작이 비균일 값에 의존하는 제어 흐름 문에서 발생합니다.
예를 들어 서로 다른 호출이 if, break-if, while, 또는 for의 조건에 대해 서로 다른 값을 계산하거나, switch의 선택자에 대해 서로 다른 값을 계산하거나, 단락 평가 이항 연산자(&&또는||)의 왼쪽 피연산자에 대해 서로 다른 값을 계산하면 비균일 제어 의존성이 발생합니다.
이러한 비균일 값은 정적으로 균일하다고 증명되지 않은 특정 소스로 추적할 수 있는 경우가 많습니다. 이러한 소스에는 다음이 포함되지만 이에 한정되지 않습니다:
올바르고 이식 가능한 동작을 보장하기 위해 WGSL 구현은 정적 균일성 분석을 수행하여 각 집단 연산이 균일한 제어 흐름에서 실행됨을 증명하려고 시도합니다. 이후 하위 절에서 이 분석을 설명합니다.
균일성 실패는 균일성 분석이 특정 집단 연산이 균일한 제어 흐름에서 실행됨을 증명할 수 없을 때 트리거됩니다.
-
도함수를 계산하는 내장 함수에 대해 균일성 실패가 트리거되면 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가 명제
True에 대응한다고 보는 것이며,
따라서 RequiredToBeUniform.error -> X는 X가 true라고 말하는 것과
같습니다.
반대로 어떤 것의 균일성을 보장할 수 없음을 표현하려면(예: 스레드 ID를 보유하는 변수) 해당 노드에서 MayBeNonUniform으로 간선을 추가합니다. 이를 이해하는 한 가지 방법은 MayBeNonUniform이 명제 False에 대응한다고 보는 것이며, 따라서 X -> MayBeNonUniform은 X가 false라고 말하는 것과 같습니다.
이 해석의 결과로 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에 p의 변수를 사용합니다. var x = i ; let x_tmp1 = x ; // x의 값을 캡처합니다. let p2 = & ( p_var [ x_tmp1 ]); // p1의 초기화자를 대입합니다. x = 0 ; * ( & ( p_var [ x_tmp1 ])) = 5 ; // p2의 초기화자를 대입합니다. return ( * ( & p_var ))[ x ]; // p1의 초기화자를 대입합니다. }
15.2.5. 함수 범위 변수 값 분석
특정 문에서 각 함수 범위 변수의 값은 해당 위치에 도달하는 대입과, 경우에 따라, 초기값의 관점에서 분석할 수 있습니다.
대입은 다음과 같은 경우 전체 대입입니다:
그렇지 않으면 대입은 부분 대입입니다.
전체 참조는 다음 중 하나인 참조 유형의 표현식입니다:
전체 포인터는 다음 중 하나인 포인터 유형의 표현식입니다:
참고: 이 분석을 위해서는 포인터 유형의 형식 매개변수가 전체 포인터일 수 있는 경우는 필요하지 않습니다.
전체 참조와 마찬가지로 전체 포인터는 대응하는 기원 변수 x의 모든 메모리 위치에 대한 메모리 뷰입니다.
전체 참조가 아닌 참조는 부분 참조입니다. 따라서 부분 참조는 다음 중 하나입니다:
멤버가 하나인 구조체 유형과 해당 유형을 저장하는 변수를 살펴보십시오:
struct S { member : i32; } fn foo () { var v : S ; }
그러면 v는 전체 참조이고 v.member는 부분 참조입니다.
두 메모리 뷰는 동일한 메모리
위치를 포함하지만 v의 저장 유형은 S이고
v.s의 저장 유형은 i32입니다.
요소가 하나인 배열에서도 비슷한 상황이 발생합니다:
fn foo () { var arr : array< i32, 1 > ; }
그러면 arr는 전체 참조이고 arr[0]은 부분 참조입니다.
두 메모리 뷰는 동일한 메모리
위치를 포함하지만 arr의 저장 유형은 array<i32,1>이고
arr[0]의 저장 유형은 i32입니다.
분석을 단순화하기 위해 어떤 종류의 부분 참조를 통한 대입도 연결된 기원 변수의 모든 메모리 위치를 수정하지 않는 것으로 취급합니다. 이로 인해 분석은 보수적으로 동작하며 엄밀히 필요한 것보다 더 많은 프로그램에서 균일성 실패를 트리거할 수 있습니다.
전체 스위즐 뷰는 스위즐 뷰 sv = (p, IndexList)로 평가되는 표현식이며 다음을 만족합니다:
-
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), s1 안에서 동작이 {Continue}이고 s2로 제어를 이동하는 모든 si에 대해 Vout(si) |
| loop { s1 continuing { s2 } } | Vin(next) | Break가 s1의 동작에 있으면 Vout(s2), s1 안에서 동작이 {Break}이고 next로 제어를 이동하는 모든 si에 대해 Vout(si) |
| switch e { case _: s1 case _: s2 ... case _: s3 } | Vin(si) | Vout(prev) |
| switch e { case _: s1 case _: s2 ... case _: s3 } | Vin(next) | 동작에 Next 또는 Break가 포함되는 모든
si에 대해 Vout(si), 그리고 sj 안에서 동작이 {Break}이고 next로 제어를 이동하는 모든 문에 대해 Vout(sj) |
그 밖의 모든 문(함수 호출 제외)에 대해 Vin(next)는 Vout(prev)와 동등합니다.
참고: 문 동작 분석에서와 동일한 디슈거링이 적용됩니다.
15.2.6. 문의 균일성 규칙
문을 분석하는 규칙은 문 자체와 그 시작에서의 제어 흐름에 대응하는 노드(아래에서는 "CF"로 표기)를 인수로 받고 다음 두 가지를 반환합니다:
-
문을 빠져나갈 때의 제어 흐름에 대응하는 노드
-
그래프에 추가할 새 노드 및 간선 집합
아래 표에서 (CF1, S) => CF2는 "제어 흐름 CF1에서 시작하여 S에 대한 분석을 실행하고,
그래프에 필요한 변경을 적용한 뒤 결과 제어 흐름 노드의 이름을 CF2로 지정한다"는 뜻입니다.
마찬가지로 (CF1, E) => V는 "제어 흐름 CF1에서 시작하여 표현식 E에 대한 분석을 실행하고,
그래프에 필요한 변경을 적용한 뒤 결과 값 노드의 이름을 V로 지정한다"는 뜻입니다
(표현식 분석은 다음 절 참조).
이러한 표현식 평가는 대입의
왼쪽 피연산자 일부가 아닌 모든 표현식에 사용되며
RHSValue라고 합니다.
대입의 왼쪽 피연산자 일부인 표현식에는
유사한 규칙 집합인 LHSValue가 있으며,
이를 LHSValue: (CF, E) => L로 표기합니다. 값의 균일성에 대응하는 노드를
계산하는 대신 대입 대상 변수의 균일성에 대응하는 노드를 계산합니다.
참고: LHSValue에는 증가 및 감소 문의 표현식이 포함됩니다.
참고: RHSValue에는 대입 문의 오른쪽 피연산자 일부인 표현식이나 대입, 증가 또는 감소 문의 일부가 아닌 표현식이 포함됩니다.
여러 간선을 생성해야 하는 경우 X -> Y, X -> Z의 축약형으로
X -> {Y, Z}를 사용합니다.
루프를 분석할 때는 다음 패턴을 사용합니다:
-
노드 CF'는 각 반복 시작 시점의 제어 흐름 균일성을 모델링합니다.
-
노드 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가 지원되지 않거나 균일성 범위가 서브그룹이 아닌 경우, 이름 없는 트리거 규칙으로 구성된 잠재적 트리거 집합을 가진 CallSiteRequiredToBeUniform.error.
-
참고: 트리거 규칙에는 이름이 없으므로 필터링할 수 없습니다.
-
-
그렇지 않으면 CallSiteNoRestriction.
-
-
또한 subgroup_uniformity가 지원되지 않거나 균일성 범위가 서브그룹이 아닌 경우, workgroupUniformLoad 호출에서 매개변수
p는 이름 없는 트리거 규칙으로 구성된 잠재적 트리거 집합을 가진 매개변수 태그 ParameterRequiredToBeUniform.error를 가집니다.
-
-
§ 17.6 도함수 내장 함수, § 17.7.8 textureSample, § 17.7.9 textureSampleBias 및 § 17.7.10 textureSampleCompare의 함수 호출:
-
ReturnValueMayBeNonUniform인 함수 태그를 가집니다.
-
다음과 같은 호출 위치 태그를 가집니다:
-
subgroup_uniformity가 지원되지 않거나 균일성 범위가 서브그룹이 아닌 경우
-
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 쿼드 연산의 함수 호출:
-
다음 중 하나인 함수 태그를 가집니다:
-
DF를 호출 위치와 트리거 규칙 subgroup_uniformity에 대한 가장 가까운 바깥쪽 진단 필터라고 합니다.
-
다음과 같은 호출 위치 태그를 가집니다:
-
subgroup_uniformity가 지원되지 않거나 균일성 범위가 서브그룹이면:
-
DF가 존재하면 S를 DF의 새 심각도 매개변수라고 합니다.
-
S가 심각도 off이면 호출 위치 태그는 CallSiteNoRestriction입니다.
-
그렇지 않으면 호출 위치 태그는 CallSiteRequiredToBeUniform.S이며, subgroup_uniformity 요소로 구성된 잠재적 트리거 집합을 가집니다.
-
-
그러한 DF가 없으면 호출 위치 태그는 CallSiteRequiredToBeUniform.error이며, subgroup_uniformity 요소로 구성된 잠재적 트리거 집합을 가집니다.
-
-
그렇지 않으면 CallSiteNoRestriction.
-
-
또한 subgroupShuffleUp 또는 subgroupShuffleDown 호출의 경우, 매개변수
delta는 다음 중 하나인 매개변수 태그를 가집니다:-
subgroup_uniformity가 지원되지 않거나 균일성 범위가 서브그룹이면:
-
DF가 존재하면 S를 DF의 새 심각도 매개변수라고 합니다.
-
S가 심각도 off이면 매개변수 태그는 NoRestriction입니다.
-
그렇지 않으면 매개변수 태그는 ParameterRequiredToBeUniform.S이며, subgroup_uniformity 요소로 구성된 잠재적 트리거 집합을 가집니다.
-
-
그러한 DF가 없으면 매개변수 태그는 ParameterRequiredToBeUniform.error이며, subgroup_uniformity 요소로 구성된 잠재적 트리거 집합을 가집니다.
-
-
그렇지 않으면 NoRestriction.
-
-
또한 subgroupShuffleXor 호출의 경우 매개변수
mask는 다음 중 하나인 매개변수 태그를 가집니다:-
subgroup_uniformity가 지원되지 않거나 균일성 범위가 서브그룹이면:
-
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. 함수 범위 변수 균일성
이 예제는 함수 범위 변수의 값에 의존하는 유효한
배리어 함수 호출과 유효하지 않은 호출을 모두 보여줍니다.
workgroupBarrier는 x의 값이 변경 가능한 모듈 범위 변수
a에서 파생되므로 유효하지 않습니다.
storageBarrier는 x의 값이 변경 불가능한 모듈 범위 변수
b에서 파생되므로 유효합니다.
이 예제는 함수 범위 변수 수명에서 서로 다른 균일성 기간을 분리하는
값 분석의 능력을 강조합니다.
또한 첫 번째 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:
-
binary32:
-
binary64:
다음 알고리즘은 부동 소수점 값의 비트 표현을 대응하는 확장 실수 값 또는 NaN으로 매핑합니다:
알고리즘: 부동 소수점 비트 해석입력: Bits, 이진 부동 소수점 유형 값의 비트 표현.
출력: F, Bits가 나타내는 부동 소수점 값.
절차:
bias를 유형의 지수 바이어스라고 합니다.
tsw를 유형의 후행 가수 필드의 비트 너비라고 합니다.
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 부동 소수점 변환을 참조하십시오.
-
부동 소수점 예외는 생성되지 않습니다.
-
WGSL의 부동 소수점 연산은 IEEE-754 규칙에 따라 중간 결과를 생성하지만, IEEE-754에서 의무화한 예외는 표현식이 const 표현식, override 표현식 또는 런타임 표현식인지에 따라 서로 다른 동작으로 매핑됩니다.
-
유한 피연산자에 대한 연산을 생각해 보십시오. 연산의 중간 결과는 IEEE-754가 해당 연산에 오버플로, 유효하지 않은 연산 또는 0으로 나누기 예외를 시그널하도록 요구하는 경우에만 오버플로, 무한대 또는 NaN을 생성합니다. 동작은 유한 수학 가정에 의해 추가로 수정됩니다.
-
-
시그널링 NaN은 생성되지 않을 수 있습니다. 중간 계산에서 모든 시그널링 NaN은 조용한 NaN으로 변환될 수 있습니다.
-
유한 수학 가정:
-
셰이더 실행 전에 생성된 오버플로, 무한대 및 NaN은 오류를 생성합니다.
-
유한 값에 대한 const 표현식 및 override 표현식은 IEEE-754 규칙에 따라 오버플로, 무한대 및 NaN을 중간 결과 값으로 생성합니다.
-
참고: 이 규칙은 구현이 이러한 종류의 표현식에 대해 정확도 한계 내에서 오버플로, 무한대 및 NaN을 신뢰성 있게 감지하여 오류를 일관되게 생성하도록 요구합니다.
-
-
부동 소수점 유형의 const 표현식이 오버플로되거나 NaN 또는 무한대로 평가되면 셰이더 생성 오류가 발생합니다.
-
부동 소수점 유형의 override 표현식이 오버플로되거나 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이면 유한 수학 가정에 따라:
-
표현식이 override 표현식이면 파이프라인 생성 오류를 생성합니다.
-
그렇지 않으면 X'' = X'입니다.
15.7.4. 부동 소수점 정확도
-
x가 T에 있으면 x,
-
그렇지 않으면:
-
x보다 큰 T의 가장 작은 값, 또는
-
x보다 작은 T의 가장 큰 값.
-
즉, 결과는 위 또는 아래로 반올림될 수 있습니다: WGSL은 반올림 모드를 지정하지 않습니다.
참고: 부동 소수점 유형에는 양의 무한대와 음의 무한대가 포함되므로 올바르게 반올림된 결과는 유한하거나 무한할 수 있습니다.
참고: 무제한 정밀도로 계산한 연산 결과에는
double의 정밀도를 초과하는 정밀도가 필요할 수 있습니다.
이러한 경우의 예는 x - y에서 x=1.0 이고 y=1.17e-38인 경우입니다
(가장 작은 양의 정규 단정밀도 부동 소수점 수).
이 숫자들의 지수는 126만큼 차이가 납니다. IEEE-754 binary64(배정밀도)
형식은 가수에 52비트만 있으므로
뺄셈을 수행하면 y의 모든 유효 비트가 손실됩니다.
반올림 모드에 따라, 이 경우와 y가 작지만 0이 아닌 많은 다른 경우에서
WGSL 표현식 x - y는 x와 같은 값을 산출할 수 있습니다.
[ECMASCRIPT]는 IEEE-754
roundTiesToEven 반올림 모드와 동등한 방식을
사용한다는 점에 유의하십시오.
마지막 자리 단위인 ULP는
부동 소수점 수 x에 대해 다음과 같이 정의됩니다 [Muller2005]:
-
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는 부동 소수점 연산을 사용하며, GPU의 determinant 구현은 오버플로와 오차에 대한 견고성보다 속도와 단순성을 우선합니다. 예를 들어 단순한 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의 표현식이 override 표현식이면 파이프라인 생성 오류가 발생합니다.
그렇지 않으면 변환은 다음과 같이 진행됩니다:
X'를 원래 값 X로 설정합니다.
소스 유형 S가 대상 유형 T보다 더 많은 가수 비트를 가진 부동 소수점 유형이면 소스 값 X의 추가 가수 비트는 버릴 수 있습니다 (즉, 0인 것처럼 취급할 수 있습니다). 이에 따라 X'를 갱신합니다.
X'가 대상 유형 T의 가장 큰 양의 유한 값 또는 가장 작은 음의 유한 값이면 XOut = X'로 설정합니다.
그렇지 않으면 XOut을 대상 유형 T에서 X'와 같은 부호를 가진 무한대 값으로 설정합니다.
참고: 정수 값은 표현 가능한 인접한 두 부동 소수점 값 사이에 있을 수 있습니다. 특히 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>입니다I는 T가 벡터인 경우에만 벡터입니다T는 I도 추상인 경우에만 추상일 수 있으며 그 반대도 마찬가지입니다
참고: 어느 한 매개변수가 구체적이면 다른 매개변수는 자동 변환을 거쳐 구체적 유형(해당하는 경우)이 되며 결과도 구체적 유형이 됩니다. |
| 설명 |
다음을 제외하고 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>입니다
|
| 설명 | e1과 e2의 구성 요소별 선형 혼합을 반환하며,
각 구성 요소에 스칼라 혼합 계수 e3를 사용합니다.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와 같은 방향의 단위 벡터를 반환합니다.
정의역은 0 벡터를 제외한 모든 벡터입니다. |
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 도함수를 참조하십시오.
이러한 함수 호출은:
-
균일성 분석 이 호출이 균일한 제어 흐름에 있음을 증명할 수 없으면 derivative_uniformity 진단을 트리거합니다.
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의 편미분을 반환합니다.
현재 호출과 동일한 쿼드에서 제공되며
쿼드 호출
ID가 i인 호출의 결과는 다음과 같습니다.
|
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의 편미분을 반환합니다.
현재 호출과 동일한 쿼드에서 제공되며
쿼드 호출
ID가 i인 호출의 결과는 다음과 같습니다.
|
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구성 요소 벡터를 계산합니다:
-
선형 필터링을 사용하는 샘플링 연산에서 사용될 4개의 텍셀을 밉 레벨 0에서 찾습니다:
-
지정된 좌표, 배열 인덱스(있는 경우) 및 오프셋(있는 경우)을 사용합니다.
-
텍스처 공간 좌표 (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)
-
네 텍셀은 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 표현식은 반드시 const 표현식(예:
1)이어야 합니다.값은 최소 0, 최대 3이어야 합니다. 이 범위를 벗어난 값은 셰이더 생성 오류를 발생시킵니다. |
t
| 읽을 샘플링된 또는 깊이 텍스처입니다. |
s
| 샘플러 유형입니다. |
coords
| 텍스처 좌표입니다. |
array_index
|
0 기반 텍스처 배열 인덱스입니다. 이 값은 [0, textureNumLayers(t) - 1] 범위로 제한됩니다. |
offset
|
텍스처를 샘플링하기 전에 정규화되지 않은 텍스처 좌표에 적용되는 선택적 텍셀 오프셋입니다.
이 오프셋은 텍스처 래핑 모드를 적용하기 전에 적용됩니다.offset 표현식은 반드시 const 표현식(예:
vec2<i32>(1, 2))이어야 합니다.각 offset 구성 요소는 반드시 최소 -8, 최대
7이어야 합니다. 이 범위를 벗어난 값은 셰이더 생성 오류를 발생시킵니다.
|
반환:
위에서 설명한 대로 선택된 텍셀의 지정된 채널에서 추출한 구성 요소로 이루어진 4구성 요소 벡터입니다.
@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
텍스처 개더 비교 연산은 깊이 텍스처의 네 텍셀에 대해 깊이 비교를 수행하고 결과를 다음과 같이 하나의 벡터로 수집합니다:
-
선형 필터링을 사용하는 깊이 샘플링 연산에서 사용될 네 텍셀을 밉 레벨 0에서 찾습니다:
-
지정된 좌표, 배열 인덱스(있는 경우) 및 오프셋(있는 경우)을 사용합니다.
-
텍스처 공간 좌표 (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 표현식은 반드시 const 표현식(예:
vec2<i32>(1, 2))이어야 합니다.각 offset 구성 요소는 반드시 최소 -8, 최대
7이어야 합니다. 이 범위를 벗어난 값은 셰이더 생성 오류를 발생시킵니다.
|
반환:
위에서 설명한 대로 선택된 텍셀에 대한 비교 결과로 구성된 4구성 요소 벡터입니다.
@group ( 0 ) @binding ( 0 ) var dt : texture_depth_2d; @group ( 0 ) @binding ( 1 ) var s : sampler; fn gather_depth_compare ( c : vec2< f32> , depth_ref : f32) -> vec4< f32> { return textureGatherCompare ( dt , s , c , depth_ref ); }
17.7.4. textureLoad
샘플링이나 필터링 없이 텍스처에서 단일 텍셀을 읽습니다.
| 매개변수화 | 오버로드 |
|---|---|
| C는 i32 또는 u32입니다 L은 i32 또는 u32입니다 ST는 i32, u32 또는 f32입니다 |
|
| 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 표현식은 반드시 const 표현식(예:
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 표현식은 반드시 const 표현식(예:
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 표현식은 반드시 const 표현식(예:
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 표현식은 반드시 const 표현식(예:
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 표현식은 반드시 const 표현식(예:
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 표현식은 반드시 const 표현식(예:
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이어야 합니다.
달리 명시되지 않는 한, T는 반드시 u32 또는 i32여야 합니다.
17.8.1. atomicLoad
fn atomicLoad ( atomic_ptr : ptr< AS , atomic< T > , read_write> ) -> T
atomic_ptr이 가리키는 값을 원자적으로 로드하여 반환합니다.
객체를 수정하지
않습니다.
17.8.2. atomicStore
fn atomicStore ( atomic_ptr : ptr< AS , atomic< T > , read_write> , v : T )
atomic_ptr이 가리키는 원자적 객체에 값 v를 원자적으로 저장합니다.
17.8.3. 원자적 읽기-수정-쓰기 산술 및 논리 함수
각 함수는 다음 단계를 원자적으로 수행합니다:
-
atomic_ptr이 가리키는 원래 값을 로드합니다. -
함수 이름의 연산(예: max)을 값 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인 경우에only if값v를 저장합니다.
두 멤버를 가진 구조체를 반환하며, 첫 번째 멤버 old_value는
연산 전 원자적 객체의 원래 값이고 두 번째 멤버 exchanged는
비교가 성공했는지 여부입니다.
// 모든 연산은 원자적으로 수행됩니다 fn atomicCompareExchangeWeak ( atomic_ptr : ptr< AS , atomic< T > , read_write> , cmp : T , v : T ) -> _atomic_compare_exchange_result < T > { let old = * atomic_ptr ; // 이 비교는 허위로 실패할 수 있습니다. let comparison = old == cmp ; if comparison { * atomic_ptr = v ; } return __atomic_compare_exchange_result < T > ( old , comparison ); }
참고: 동등 비교는 일부 구현에서 허위로 실패할 수 있습니다. 즉,
결과 구조체의 exchanged 멤버는
old_value 멤버가 cmp와 같더라도 false일 수 있습니다.
17.8.6. 원자적 저장 최솟값 및 최댓값 함수
이 함수들은 모두 atomic_vec2u_min_max 언어 기능을 필요로 합니다.
이 함수들은 값을 반환하지 않습니다.
17.8.6.1.
atomicStoreMin
fn atomicStoreMin ( atomic_ptr : ptr< storage, atomic< vec2< u32>> , read_write> , v : vec2< u32> )
atomic_ptr이 가리키는 원자적 객체에 대해
v 값을 사용해 64비트 부호 없는 정수 최솟값 연산을 원자적으로 수행합니다.
다음 단계를 원자적으로 수행합니다:
-
atomic_ptr이 참조하는 메모리에서 원래 vec2u 값 old를 로드합니다.
-
64비트 부호 없는 정수 값을 계산합니다:
-
old64 = 232 × old[1] + old[0]
-
v64 = 232 × v[1] + v[0]
-
-
old64와 v64의 최솟값으로 값 new64를 계산합니다.
-
다음과 같은 vec2<u32> 유형의 값 new를 계산합니다:
-
new[0]에는 new64의 최하위 32비트가 포함되고,
-
new[1]에는 new64의 최상위 32비트가 포함됩니다.
-
-
new를 atomic_ptr이 참조하는 메모리에 저장합니다.
17.8.6.2.
atomicStoreMax
fn atomicStoreMax ( atomic_ptr : ptr< storage, atomic< vec2< u32>> , read_write> , v : vec2< u32> )
atomic_ptr이 가리키는 원자적 객체에 대해
v 값을 사용해 64비트 부호 없는 정수 최댓값 연산을 원자적으로 수행합니다.
다음 단계를 원자적으로 수행합니다:
-
atomic_ptr이 참조하는 메모리에서 원래 vec2u 값 old를 로드합니다.
-
64비트 부호 없는 정수 값을 계산합니다:
-
old64 = 232 × old[1] + old[0]
-
v64 = 232 × v[1] + v[0]
-
-
old64와 v64의 최댓값으로 값 new64를 계산합니다.
-
다음과 같은 vec2<u32> 유형의 값 new를 계산합니다:
-
new[0]에는 new64의 최하위 32비트가 포함되고,
-
new[1]에는 new64의 최상위 32비트가 포함됩니다.
-
-
new를 atomic_ptr이 참조하는 메모리에 저장합니다.
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. 동기화 내장 함수
모든 동기화 함수는 Acquire/Release 메모리 순서를 사용하는 제어 배리어를 실행합니다. 즉, 모든 동기화 함수와 영향을 받는 메모리 및 원자적 연산은 동기화 함수에 대해 프로그램 순서로 정렬됩니다. 또한 동기화 함수보다 프로그램 순서상 앞선 영향을 받는 메모리 및 원자적 연산은 워크그룹의 어떤 멤버가 동기화 함수보다 프로그램 순서상 뒤에 있는 영향을 받는 메모리 또는 원자적 연산을 실행하기 전에 워크그룹의 다른 모든 스레드에서 볼 수 있어야 합니다.
모든 동기화 함수는 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는 구체적 숫자 스칼라 또는 구체적 숫자 벡터입니다
|
| 설명 |
현재 호출에 대해 subgroup_invocation_id + delta와 일치하는 서브그룹 호출
ID를 가진 호출에서 e를 반환합니다.
|
17.12.12.2. subgroupShuffleUp
| 오버로드 |
|
| 전제 조건 | T는 구체적 숫자 스칼라 또는 구체적 숫자 벡터입니다
|
| 설명 |
현재 호출에 대해 subgroup_invocation_id - delta와 일치하는 서브그룹 호출
ID를 가진 호출에서 e를 반환합니다.
|
17.12.12.3. subgroupShuffleXor
| 오버로드 |
|
| 전제 조건 | T는 구체적 숫자 스칼라 또는 구체적 숫자 벡터입니다
|
| 설명 |
현재 호출에 대해 subgroup_invocation_id ^ mask와 일치하는 서브그룹 호출
ID를 가진 호출에서 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 미디어 유형
Internet Assigned Numbers Authority(IANA)는 [IANA-MEDIA-TYPES]에서 미디어 유형 레지스트리를 유지합니다.
다음은 WGSL 모듈을 위한 text/wgsl 미디어 유형의 정의입니다.
IANA에 등록되어 있으며,
https://www.iana.org/assignments/media-types/text/wgsl에
나와 있습니다.
- 유형 이름
-
text
- 하위 유형 이름
-
wgsl
- 필수 매개변수
-
해당 없음
- 선택적 매개변수
-
없음
- 인코딩 고려 사항
-
binary
WGSL은 바이트 순서 표시(BOM) 없이 UTF-8 인코딩을 사용하는 유니코드 텍스트입니다. § 3 텍스트 구조를 참조하십시오.
- 보안 고려 사항:
-
WebGPU 셰이딩 언어(WGSL)는 WebGPU API의 컨텍스트에서 실행될 GPU 코드를 위한 프로그래밍 언어입니다. 보안 고려 사항은 [WebGPU] 2.1절 보안 고려 사항을 참조하십시오. 개인정보 보호 고려 사항은 [WebGPU] 2.2절 개인정보 보호 고려 사항을 참조하십시오.
- 상호 운용성 고려 사항:
-
WebGPU 구현은 서로 다른 기능을 가질 수 있으며, 이러한 차이는 WGSL 프로그램에서 사용할 수 있는 기능에 영향을 줄 수 있습니다. [WebGPU] 3.6절 선택적 기능과 § 4.1.2 언어 확장을 참조하십시오.
구현은 이 등록이 WGSL의 이후 판에도 적용되는 것처럼 동작할 것으로 예상되며, 공개된 명세 참조도 그에 따라 때때로 업데이트될 수 있습니다. 이러한 기대는 미디어 유형 등록에서는 이례적이지만, 업계에 널리 퍼진 관례와 일치합니다.
- 공개된 명세:
-
WebGPU 셰이딩 언어
- 이 미디어 유형을 사용하는 애플리케이션:
-
WebGPU 구현입니다. 웹 브라우저가 포함될 것으로 예상됩니다.
- 프래그먼트 식별자 고려 사항
-
없음
- 추가 정보:
-
매직 넘버: 없음
파일 확장자:
.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