[Shader] ComputeShader 기초 스터디 노트
3개 버퍼 생성.
input, output, result
이 때,
input buffer를 shader에 알려주기 위한 ShaderResourceView 필요, 생성.
outout buffer를 shader에 알려주기 위한 UnordedAddressView 필요,생성.
처리 결과를 받아올 때
result buffer에 output buffer의 리소스를 복사.
Map() -> target pointer 로 result buffer 값 복사 -> Unmap()
이렇게 처리하는 이유는, output buffer와 result buffer의 BUFFER_DESC 가 다르기 때문.
D3D11_BUFFER_DESC
https://learn.microsoft.com/ko-kr/windows/win32/api/d3d11/ns-d3d11-d3d11_buffer_desc
D3D11Buffer의 BUFFER_DESC를 생성할 때 가장 중요한 옵션 Usage
buffer별 Usage 선언
input buffer : DYNAMIC
output buffer : DEFAULT
result buffer : STAGING
https://learn.microsoft.com/ko-kr/windows/win32/api/d3d11/ne-d3d11-d3d11_usage
BindFlags 선언
input buffer : SHADER_RESOURCE
output buffer : UNORDERED_READ
result buffer : 0
결과값은 gpu에서 output buffer에 저장되고, output buffer의 값은 DeviceContext->CopyResource() 함수를 이용해서 output buffer에서 result buffer로 복사. result buffer의 값은 DC->Map/Unmap 함수 내에서 memcpy로 CPU복사 처리.
Conpute Shader에서는 ComputeInput 구조체를 정해진 셰이더 시맨틱으로 선언해서 사용.
struct ComputeInput
{
uint3 groupID : SV_GroupID;
uint3 groupThreadID : SV_GroupThreadID;
uint3 dispatchThreadID : SV_DispatchThreadID;
uint groupIndex : SV_GroupIndex;
};
void CS(ComputeInput input)
{
// ...
}
https://learn.microsoft.com/ko-kr/windows/win32/direct3dhlsl/sv-groupindex
각각의 값의 의미는 아래 이미지를 참고.
uint3 groupID 는 스레드 그룹 좌표 ID를 의미. (Dispatch 인자로 전달하는 ThreadGroupCountX,Y,Z 값)
uint3 groupoThreadID 는 스레드 그룹에서 스레드 자체 좌표 ID. 다른 그룹에서 겹칠 수 있음. (셰이더의 [numthreads(10, 8, 3)] 값)
uint3 dispatchThreadID 는 전체 그룹에서 스레드의 고유한 좌표 ID. 겹치지 않는 좌표값.
uint groupIndex 는 현재 스레드 그룹 내에서 현재 스레드의 index값. 다른 그룹에서 겹칠 수 있음.
https://learn.microsoft.com/ko-kr/windows/win32/api/d3d11/nf-d3d11-id3d11devicecontext-dispatch
Input 값은 셰이더의 Input.Load() 함수 시리즈로 얻어오고,
Output 값은 셰이더의 Output.Store() 함수 시리즈로 내보낸다.
float value = (float)Input.Load(inAddress);
Output.Store(outAddress, (uint)value);
SRV(Shader Resource View), UAV(Unordered Access View) 모두 설정하고 GPU연산 콜은 DeviceContext->Dispatch() 메소드를 호출.
아래는 UnrealEngine 5의 D3D11 RHI 인터페이스 RHIDispatchComputeShaderI() 메소드. ThreadGroupCountX,Y,Z 를 인자로 전달한다.
void FD3D11DynamicRHI::RHIDispatchComputeShader(uint32 ThreadGroupCountX, uint32 ThreadGroupCountY, uint32 ThreadGroupCountZ)
{
FRHIComputeShader* ComputeShaderRHI = GetCurrentComputeShader();
FD3D11ComputeShader* ComputeShader = ResourceCast(ComputeShaderRHI);
StateCache.SetComputeShader(ComputeShader->Resource);
GPUProfilingData.RegisterGPUDispatch(FIntVector(ThreadGroupCountX, ThreadGroupCountY, ThreadGroupCountZ));
if (ComputeShader->bShaderNeedsGlobalConstantBuffer)
{
CommitComputeShaderConstants();
}
CommitComputeResourceTables(ComputeShader);
Direct3DDeviceIMContext->Dispatch(ThreadGroupCountX, ThreadGroupCountY, ThreadGroupCountZ);
StateCache.SetComputeShader(nullptr);
EnableUAVOverlap();
}
게임 개발에 필수적인 내용을 담는 명서들을 소개합니다.
<유니티 교과서 개정6판>(유니티 최신 버전) 구입 링크
https://link.coupang.com/a/be3P0t
<리얼-타임 렌더링(REAL-TIME RENDERING) 4/e> 구입 링크
https://link.coupang.com/a/8VWas
<이득우의 게임 수학:39가지 예제로 배운다! 메타버스를 구성하는 게임 수학의 모든 것> 구입 링크
https://link.coupang.com/a/9BqLd
유니티 에셋 스토어 링크
https://assetstore.unity.com?aid=1011lvz7h
(링크를 통해 도서/에셋 구입시 일정액의 수수료를 지급받습니다.)