Constant buffer

ㅋㅋ·2022년 7월 15일
0

DirectX12강의

목록 보기
5/39

쉐이더에서 함수에 매개변수를 넣고 다양한 행동을 하기 위해서

인자를 GPU의 레지스터가 특정 값을 로드하도록 요청하여

해당 레지스터를 변수처럼 사용

cbuffer TEST_B0 : register(b0)
{
    float4 offset0;
};

=>

root signature를 통하여 레지스터 사용을 예약해야 함

API bind slot은 API의 번호이며 순서대로 매겨진다

HLSL bind slot은 사용될 레지스터 이름이다.

상수 버퍼로 사용하는 레지스터들은 b로 시작함

root constant 자리에는 레지스터에 어떤 데이터를 입력할지 정해 놓는 공간이다.

상수 데이터나 포인터(Constant buffer view), 테이블이 입력된다.

테이블은 c++의 union과 같이 1번이 사용되면 2번은 꺼지는 식으로 토글 됨

root signature의 슬롯 크기는 하나당 DWORD이고 CBV는 2 슬롯이다.

해당 슬롯의 크기는 제한이 있고 많이 사용하면 성능이 떨어질 수 있음

하지만 테이블을 많이 사용하면 구현이 어려워지기 때문에 트레이드오프가 있음

CD3DX12_ROOT_PARAMETER param[2];
param[0].InitAsConstantBufferView(0);
param[1].InitAsConstantBufferView(1);

해당 내용은 아래와 같음

0 / CBV / b0
1 / CBV / b1

InitAsConstantBufferView 함수에서 쉐이더 visibility를 설정할 수 있는데

이를 통하여 랜더링 파이프라인에서 특정 단계에서만 사용하도록 할 수 있음

기본은 D3D12_SHADER_VISIBILITY_ALL

_cmdList->SetGraphicsRootSignature(ROOT_SIGNATURE.Get());

root signature를 command queue가 렌더를 시작할 때 넣어준다

데이터를 레지스터에 쓰기 위해서는 우선 GPU 메모리를 할당하여

해당 메모리에 데이터를 업로드하고,

이후 Command list를 통하여 레지스터가 해당 값을 읽어가도록 해야함

=>

메모리 할당 및 데이터 업로드는 즉각적으로 실행되지만 레지스터가 실제로 값을 읽는 순간은

command가 실행되는 시점이기 때문에 메모리에 올라간 값이 덮어 써질 수 있음

=>

사용할 메모리를 하나만 만들어 두는게 아닌

버퍼들을 만들어두어 덮어쓰지 않고 다른 메모리를 쓰도록


Constant buffer

_elementSize = (size + 255) & ~255;

constant buffer는 메모리를 할당할 때 256 바이트 배수로 만들어야 함

void ConstantBuffer::CreateBuffer()
{
	uint32 bufferSize = _elementSize * _elementCount;
	D3D12_HEAP_PROPERTIES heapProperty = CD3DX12_HEAP_PROPERTIES(D3D12_HEAP_TYPE_UPLOAD);
	D3D12_RESOURCE_DESC desc = CD3DX12_RESOURCE_DESC::Buffer(bufferSize);

	DEVICE->CreateCommittedResource(
		&heapProperty,
		D3D12_HEAP_FLAG_NONE,
		&desc,
		D3D12_RESOURCE_STATE_GENERIC_READ,
		nullptr,
		IID_PPV_ARGS(&_cbvBuffer));

	_cbvBuffer->Map(0, nullptr, reinterpret_cast<void**>(&_mappedBuffer));
}

위와 같이 업로드 용으로 메모리 버퍼를 할당

매핑된 버퍼는 추후 사용되지 않을 때 해제해준다.

해당 메모리를 GPU가 사용할 때 덮어 쓰는 일이 없어야 함 (동기화 필요)

void ConstantBuffer::PushData(int32 rootParamIndex, void* buffer, uint32 size)
{
	...

	::memcpy(&_mappedBuffer[_currentIndex * _elementSize], buffer, size);

	D3D12_GPU_VIRTUAL_ADDRESS address = GetGpuVirtualAddress(_currentIndex);
	CMD_LIST->SetGraphicsRootConstantBufferView(rootParamIndex, address);
	_currentIndex++;
}

memcpy하여 메모리에 데이터를 복사한 후 SetGraphicsRootConstantBufferView 함수를 통해

레지스터가 해당 메모리를 읽어가도록 요청을 등록해둠

rootParamIndex는 api bind slot의 번호

0개의 댓글