numthreads
: 한 그룹당 인스턴스화될 스레드들의 개수를 지정한다
ex) [numthreads(10, 10, 2)]
x, y가 1 이상이어야 하고 z는 반드시 [1,64]이어야 한다. 그룹의 전체 스레드 개수(x*y*z)가 1024를 넘으면 안된다
dispatch 호출에서 인스턴스화되는 스레드들의 배치 구조는 다수의 스레드가 일렬로 배치되어 있는 형태가 아니다.
스레드 그룹 index를 일차적인 좌표로 삼고, 개별 스레드에 접근할 수 있는 입체적인 형태이다
SV_GroupID : dispatch 호출의 스레드 그룹들 중 현재 스레드가 속한 그룹의 3차원 식별자(uint3)
SV_GroupThreadID : 그 스레드 그룹 안에서의 현재 스레드의 3차원 식별자(uint3)
SV_DispatchThreadID : 전체 dispatch 안에서의 현재 스레드의 3차원 식별자(uint3)
SV_GroupIndex : 현재 스레드가 속한 스레드 그룹의 3차원 식별자를 1차원으로 직렬화한 인덱스(uint)
Buffer<float> 형식의 리소스에 있는 모든 원소의 값을 두배로 만드는 계산셰이더
스레드 그룹의 크기를 numthreads 함수로 선언했다
버퍼가 1차원 형태이므로 SV_DispatchThreadID의 x성분을 사용했다
주 함수는 SV_DispatchThreadID의 x 성분을 버퍼 리소스의 한 원소에 대한 인덱스로 직접 사용한다
버퍼의 원소에 접근할 때 Load를 사용했지만, 대괄호 표기를 사용할 수도 있다.
SV_DispatchThreadID 특성을 이용하면 리소스의 원소에 간단하게 접근이 가능하다
GPU는 스레드 그룹의 한 부분집합을 동기화 지점까지 실행한 후 다른 부분 집합을 동기화 지점까지 실행하는 과정을 반복해서 스레드 그룹의 모든 스레드가 동기화 지점에 도달한 다음에 다음 스레드 그룹으로 넘어간다
메모리 모형
1. Register-Based Memory
Input Attribute Register(v#), Texture Register(t#), 상수버퍼 Register(c#), 순서없는 접근 Register(u#), 임시 Register(r#, x#)을 지원한다
임시 레지스터들은 셰이더 프로그램의 실행 도중 중간 계산 결과를 담는데 주로 쓰인다
최대 개수는 4096개 이다
임시 레지스터는 접근 속도가 빠르기 때문에, 셰이더 프로그램 안에 넣을 자료를 담을 저장소를 결정할 때 가장 먼저 선택되는 후보이다. 선택과 할당은 컴파일러가 자동으로 처리한다
아주 빠르지만 용량이 크지 않다.
사용할 자료를 먼저 셰이더 코어에 적재한 후에야 레지스터들을 사용할 수 있고, 스레드의 셰이더의 실행이 끝나면 레지스터 내용이 초기화된다.
2. Device Memory
셰이더 프로그램의 실행들 사이에서 계속 유지되는 자원이 필요할 때 사용한다
계산 셰이더는 SRV와 UAV를 이용해서 Device 메모리 자원에 접근할 수 있다.
SRV : 자원에 대한 읽기 전용 접근을 제공
UAV : 읽기, 쓰기 접근을 제공
상수버퍼에 저장된 자료에는 읽기 전용으로만 접근이 가능하다
현재 셰이더 프로그램을 실행하는 모든 스레드가 자원에 접근할 수 있다.
메모리에 어떤 값을 요청한 시점과 그 값이 실제로 반환되는 시점 사이에는 상대적으로 높은 잠복지연(Latency)이 존재한다. 따라서 Register-Based Memory 자원보다 훨씬 느리다
3. Group Shared Memory
한 스레드 그룹의 모든 스레드는 동일한 메모리 영역에 접근할 수 있다.
GSM의 크기는 스레드 그룹당 최대 32KB이다. GPU 처리기와 같은 곳에 상주하고 있다. 따라서 Device 메모리 자원보다 접근이 빠르다
groupthread 키워드를 이용해서 전역 변수로 선언한다.
스레드 그룹이 인스턴스화되면 그룹의 모든 스레드가 GSM에 접근할 수 있게 된다.
스레드들이 메모리를 사용하고 상호작용하는 방식을 계산 셰이더 프로그램에서 결정해야하고, 메모리 접근들을 반드시 동기화해야 한다.
그룹당 크기가 32KB를 넘지 못하기 때문에 그보다 많은 양의 자료를 공유하는 경우에는 다른 수단이 필요하다. 정보 공유가 하나의 스레드 그룹의 경계를 넘지 못한다.
Register-Based Memory는 접근이 가장 빠른 대신 용량이 가장 작다
Device Memory는 가용 메모리 크기가 아주 크지만 접근은 가장 느리다
GSM은 Register-Based와 Device의 균형점에 해당한다.
GSM의 존재는 계산 셰이더의 유연성을 크게 높여준다. 여러 개의 스레드가 동시에 접근할 수 있는 메모리 영역이 있다는 것은 스레드들이 서로 정보를 공유할 수 있다는 뜻이다. 그러므로 스레드 그룹 전체의 효율성을 높여주는 요인이 될 수 있다.
ex) 여러 스레드가 텍스처의 자료를 사용해야 하는 경우, 스레드 그룹의 전체적인 텍스처 접근 횟수가 줄어들어서 알고리즘의 전반적인 효율성이 높아진다.