ComputeShader
이 전에 말했던 GPU를 CPU 처럼 쓰는 방법을 이용하려면 Shader를 사용해야 한다.(지금까지 늘 GPU에 정보를 넘겨줄때 마다 Shader를 사용했으니 눈치 챌 만 하다.) 어? 그러면 지금까지 파이프라인에는 이 ComputeShader는 없었는데 언제 들어갈까?
IA - VS - (GS - CS - RS) - PS - OM
이 단계로 진행된다.
이번엔 10 * 8 * 3 = 240개의 스레드를 사용한다.
ComputeShader
//ByteAddressBuffer input; // SRV
RWByteAddressBuffer Output; // UAV
struct Group
{
uint3 GroupID;
uint3 GroupThreadID;
uint3 DispatchThreadID;
uint GroupIndex;
};
일단 Ouput만 받기 위해 Output만 받고 각각 받아온다.
struct ComputeInput
{
uint3 GroupID : SV_GroupID;
uint3 GroupThreadID : SV_GroupThreadID;
uint3 DispatchThreadID : SV_DispatchThreadID;
uint GroupIndex : SV_GroupIndex;
};
ComputeInput을 만들어 준다.
[numthreads(10, 8, 3)]
void CS(ComputeInput input)
{
Group group;
group.GroupID = asuint(input.GroupID);
group.GroupThreadID = asuint(input.GroupThreadID);
group.DispatchThreadID = asuint(input.DispatchThreadID);
group.GroupIndex = asuint(input.GroupIndex);
uint index = input.GroupIndex;
// 4바이트인 uint 가 3개, 3개, 3개, 1개 그래서 10 * 4
uint outAddress = index * 10 * 4;
Output.Store3(outAddress + 0, asuint(group.GroupID)); // 12 바이트
Output.Store3(outAddress + 12, asuint(group.GroupThreadID)); // 24
Output.Store3(outAddress + 24, asuint(group.DispatchThreadID)); // 36
Output.Store(outAddress + 36, asuint(group.GroupIndex)); // 36
}
각각 받아오는데 asuint를 활용해서 형 변환을 안전하게 한다.
그런 뒤, CPU로 전달할 때 메모리를 각각 크기만큼 띄어서 전달해 준다.
RawBufferDemo
void RawBufferDemo::Initialize()
{
Shader* shader = new Shader(L"60_RawBuffer.fx");
// 스레드 그룹 내에서 운영할 스레드 갯수
UINT count = 10 * 8 * 3;
struct Output
{
UINT GroupID[3];
UINT GroupThreadID[3];
UINT DispatchThreadID[3];
UINT GroupIndex;
};
RawBuffer* rawBuffer = new RawBuffer(NULL, 0, sizeof(Output) * count);
shader->AsUAV("Output")->SetUnorderedAccessView(rawBuffer->UAV());
shader->Dispatch(0, 0, 1, 1, 1);
Output* output = new Output[count];
rawBuffer->CopyFromOutput(output);
FILE* file;
fopen_s(&file, "../Raw.csv", "w");
for (UINT i = 0; i < count; i++)
{
Output temp = output[i];
fprintf
(
file,
"%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d\n",
i,
temp.GroupID[0], temp.GroupID[1], temp.GroupID[2],
temp.GroupThreadID[0], temp.GroupThreadID[1], temp.GroupThreadID[2],
temp.DispatchThreadID[0], temp.DispatchThreadID[1], temp.DispatchThreadID[2],
temp.GroupIndex
);
}
fclose(file);
}
Output을 받아오고 이것들을 파일로 출력해준다.
0,0,0,0,0,0,0,0,0,0,0
1,0,0,0,1,0,0,1,0,0,1
2,0,0,0,2,0,0,2,0,0,2
3,0,0,0,3,0,0,3,0,0,3
4,0,0,0,4,0,0,4,0,0,4
5,0,0,0,5,0,0,5,0,0,5
6,0,0,0,6,0,0,6,0,0,6
7,0,0,0,7,0,0,7,0,0,7
8,0,0,0,8,0,0,8,0,0,8
9,0,0,0,9,0,0,9,0,0,9
10,0,0,0,0,1,0,0,1,0,10
11,0,0,0,1,1,0,1,1,0,11
12,0,0,0,2,1,0,2,1,0,12
13,0,0,0,3,1,0,3,1,0,13
14,0,0,0,4,1,0,4,1,0,14
15,0,0,0,5,1,0,5,1,0,15
16,0,0,0,6,1,0,6,1,0,16
17,0,0,0,7,1,0,7,1,0,17
18,0,0,0,8,1,0,8,1,0,18
.
.
.
각 ID 만큼 갖고오고 ID를 부여해서 출력한ㄷ.