• Home
  • About
    • 게임 개발자 유정룡 photo

      게임 개발자 유정룡

      포트폴리오

    • Learn More
    • Email
    • Github
    • Bitbucket
  • Projects
    • All Projects
    • All Tags

Direct3D11 공부 28일차(ComputeShader - ThreadGroup)

06 Jul 2021

Reading time ~2 minutes

ThreadGroup

이 전에는 스레드 그룹이 1개로 진행했다 이젠 이 스레드 그룹을 2개 이상으로 만들어보자 그리고 Input 값도 받아오자

RawBufferDemo

void RawBufferDemo::Initialize()
{
	Shader* shader = new Shader(L"60_RawBuffer.fx");

	// 스레드 그룹 내에서 운영할 스레드 갯수
	UINT count = 2 * 10 * 8 * 3;

	struct Output
	{
		UINT GroupID[3];
		UINT GroupThreadID[3];
		UINT DispatchThreadID[3];
		UINT GroupIndex;

		float RetValue;
	};
	//RawBuffer* rawBuffer = new RawBuffer(NULL, 0, sizeof(Output) * count);

	struct Input
	{
		float value = 0.0f;
	};
	Input* input = new Input[count];

	for (UINT i = 0; i < count; i++)
	{
		input[i].value = Math::Random(0.0f, 10000.0f);
	}
	RawBuffer* rawBuffer = new RawBuffer(input, sizeof(Input) * count, sizeof(Output) * count);

	shader->AsSRV("Input")->SetResource(rawBuffer->SRV());
	shader->AsUAV("Output")->SetUnorderedAccessView(rawBuffer->UAV());
	shader->Dispatch(0, 0, 2, 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,%f\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, temp.RetValue
		);
	}
	fclose(file);
}

이번에는 Input도 받아오고 그룹을 하나 더 만들어야 하기 때문에

shader->Dispatch(0, 0, 2, 1, 1); 

에서 그룹 하나를 늘려준다.

Shader

ByteAddressBuffer Input; // SRV
RWByteAddressBuffer Output; // UAV

struct Group
{
    uint3 GroupID;
    uint3 GroupThreadID;
    uint3 DispatchThreadID;
    uint GroupIndex;
    
    float RetValue;
};

Input의 주석을 삭제하고 Input을 받아올 변수를 하나 만든다.

[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.GroupID.x * 10 * 8 * 3 + input.GroupIndex;
    
    // 4바이트인 uint 가 3개, 3개, 3개, 1개 그래서 10 * 4
    uint outAddress = index * 11 * 4;
    
    uint inAddress = index * 4;
    float temp = asfloat(Input.Load(inAddress));
    group.RetValue = temp;
    
    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)); // 40
    Output.Store(outAddress + 40, asuint(group.RetValue));
}

그룹에 따라 index값을 변경해주고 값을 받아온다. 그리고 outAddress의 10을 그룹이 하나 늘었기 때문에 11로 하나 증가시켜준다.

이러면

0,0,0,0,0,0,0,0,0,0,0,12.512589
1,0,0,0,1,0,0,1,0,0,1,5635.853516
2,0,0,0,2,0,0,2,0,0,2,1933.042358
3,0,0,0,3,0,0,3,0,0,3,8087.404785
4,0,0,0,4,0,0,4,0,0,4,5850.093262
5,0,0,0,5,0,0,5,0,0,5,4798.730469
6,0,0,0,6,0,0,6,0,0,6,3502.914551
7,0,0,0,7,0,0,7,0,0,7,8959.624023
8,0,0,0,8,0,0,8,0,0,8,8228.400391
9,0,0,0,9,0,0,9,0,0,9,7466.047852
10,0,0,0,0,1,0,0,1,0,10,1741.081055
11,0,0,0,1,1,0,1,1,0,11,8589.434570
12,0,0,0,2,1,0,2,1,0,12,7105.014160
.
.
.

이게 왜 이렇게 계산이 되냐하면

출처

GroupID는 현재 그룹 GroupThreadID는 현재 그룹의 스레드의 ID 그리고 DspatchThreadID는 작동하고 있는 스레드의 아이디 그리고 GroupIndex는 몇번째 인덱스인지이다. 계산식을 보면 이해가 좀 더 빠르다.



DirectX Share Tweet +1