1. Direct3D Compute Shader
1.1 Compute Shader
1.1.1 I/O Resource - Input Texture
- 계산 셰이더에 묶을 수 있는 좌원은 두 종류, Buffer & Texture
- 이전 글에서 두 Texture를 계산할 때 입력된 Texture를 계산 셰이더에 실제로 입력
- 응용 프로그램에서 Texture에 대한 SRV를 생성하고 Effect File로 전달하는 변수를 통해 설정
- 보통 Texture Resource를 셰이더 자원 뷰를 통해 픽셀 셰이더에 묶는 것과 마찬 가지 방식
- Input Texture들의 경우 해당 셰이더 자원 뷰가 읽기 전용
StructuredBuffer<Data> gInputA; StructuredBuffer<Data> gInputB;
1.1.2 I/O Resource - Output Texture
- 출력 자원은 특별하게 취급, 자원 형식 이름에 읽기-쓰기를 뜻하는 RW가 붙음
- 계산 셰이더는 이 자원의 원소들을 읽거나 쓸 수 있음
RWStructuredBuffer<Data> gOutput;
- 출력 자원을 계산 셰이더에 묶는 방법은 입력 자원의 경우와 다름
- 순서 없는 접근 뷰를 사용하여 생성
D3D11_BUFFER_DESC outputDesc; /* 나머지 생략 */
outputDesc.BindFlags = D3D11_BIND_SHADER_RESOURCE | D3D11_BIND_UNORDERED_ACCESS;
- 계산 셰이더를 그래픽 작업에 활용할 때 계산 셰이더로 Texture로 일정한 방식으로 변경한 후
- Texture를 어떤 기하구조에 입히는 경우가 많음, 이 처럼 두 플래그를 결합해서 Texture를 지정하는 것은 흔함
ID3DX11EffectUnorderedAccessViewVariable* Output;
Output = mFX->GetVariableByName("gOutput")->AsUnorderedAccessView();
Output->SetUnorderedAccessView(_outputUAV);
1.1.3 Index Texture
- Dispatch Thread ID에 기초해 Texture Index를 결정, 각 스레드는 고유한 배분 ID가 부여
- 계산 셰이더는 GPU에서 실행되므로 통상적인 GPU 도구를 사용 가능, Texture Filtering을 통해 표본 추출
- 기존 필터링을 사용하되 매개변수가 추가되는데, Texture의 밉맵 수준이 추가됨
- 선형 밉맵 필터링이 활성화된 경우 분수를 지정함으로써 두 밉맵 수준을 보간할 수 있음
- Texture를 추출할 때 정수 Index가 아닌 0부터 1까지 구간으로 저규화된 Texture 좌표를 사용
- 정수 Index를 사용하는 계산 셰이더
[numthreads(16, 16, 1)]
void CS(int3 dispatchThreadID : SV_DispatchThreadlD)
{
int x = dispatchThreadID.x; int y = dispatchThreadID.y;
gNextSolOutput[int2(x,y)] = gWaveConstants [0] * gPrevSolInput[int2(x, y)].r;
}
- 정규화된 Texture 좌표와 Sample Level 사용하는 계산 셰이더
[numthreads(16, 16, 1)]
void CS(int3 dispatchThreadID : SV_DispatchThreadID)
{
int x = dispatchThreadID.x; int y = dispatchThreadID.y;
float2 c = float2(x, y) / 512.0f;
gNextSoloutput[int2(x,y)] = gWaveConstants[0] * gPrevSolInput.SampleLevel(SamplerState, c, 0.0f).r;
}
1.1.4 Structured Buffer
- 같은 형식의 원소들을 담는 버퍼, 구조적 버퍼임을 알려 주는 플래그를 지정, 저장할 원소의 바이트 단위 크기를 지정
D3D11_BUFFER_DESC inputDesc; /* 나머지 생략 */
inputDesc.ByteWidth = sizeof(Data) * _numElements;
inputDesc.MiscFlags = D3D11_RESOURCE_MISC_BUFFER_STRUCTURED;
- 구조적 버퍼를 계산 셰이더에 입력 자원으로 묶기 위해 구조적 버퍼에 대한 셰이더 자원 뷰를 생성
- 구조적 버퍼를 읽기-쓰기 자원으로 묶기 위해 순서 없는 뷰를 생성하고 계산 셰이더에 설정
D3D11_SHADER_RESOURCE_VIEW_DESC srvDesc; D3D11_UNORDERED_ACCESS_VIEW_DESC uavDesc;
_device->CreateShaderResourceView(bufferA.Get(), &srvDesc, _inputASRV.GetAddressOf());
_device->CreateShaderResourceView(bufferB.Get(), &srvDesc, _inputBSRV.GetAddressOf());
_device->CreateUnorderedAccessView(_outputBuffer.Get(), &uavDesc, _outputUAV.GetAddressOf());
- 구조적 버퍼에 대한 셰이더 자원 뷰나 순서 없는 자원 뷰를 생성할 때 Format 속성에 밑의 코드를 설정
- 일반적으로 구조적 버퍼는 한 멤버에 해당하지 않는 사용자 정의 형식을 사용
srvDesc.Format = DXGI_FORMAT_UNKNOWN; uavDesc.Format = DXGI_FORMAT_UNKNOWN;
1.1.5 Result Compute Shader
- 계산 셰이더로 Texture를 처리하는 경우 일반적으로 처리를 마친 Texture를 기하구조에 입혀 화면에 표시
- 계산 셰이더가 제대로 작업을 수행했는지 시각적으로 확인 가능
- 구조적 버퍼를 사용할 때, GPGPU 프로그래밍에서 계산 셰이더의 결과를 표시X
- 계산 결과를 확인하려면 GPU 메모리에 담긴 자료를 시스템 메모리로 복사해 올 수 있어야 함
- 예비 용도 & CPU 접근 가능 플래그를 지정하여 시스템 메모리 버퍼를 생성
outputDesc.Usage = D3D11_USAGE_STAGING; outputDesc.BindFlags = 0;
outputDesc.CPUAccessFlags = D3D11_CPU_ACCESS_READ;
HR(_device->CreateBuffer(&outputDesc, 0, _outputDebugBuffer.GetAddressOf()));
- 밑의 함수를 통해 GPU 자원을 시스템 메모리 자원으로 복사
md3dImmediateContext->CopyResource(mOutputDebugBuffer, mOutputBuffer);
- 위의 작업을 통해 자료를 매핑하여 읽음
std::ofstream fout("results.txt");
D3D11_MAPPED_SUBRESOURCE mappedData;
_deviceContext->Map(_outputDebugBuffer.Get(), 0, D3D11_MAP_READ, 0, &mappedData);
/* 읽어 드리는 작업 */
_deviceContext->Unmap(_outputDebugBuffer.Get(), 0);
fout.close();
'C++ Algorithm & Study > Game Math & DirectX 11' 카테고리의 다른 글
[Direct11] 29. EX App Program - Blur System (0) | 2023.06.21 |
---|---|
[Direct11] 28. Direct3D Compute Shader - Blur System (0) | 2023.06.21 |
[Direct11] 26. Direct3D Compute Shader (0) | 2023.06.21 |
[Direct11] 25. EX App Program - Billboard (0) | 2023.06.20 |
[Direct11] 24. Direct3D Geometry Shader (0) | 2023.06.20 |