Root signature

ㅋㅋ·2022년 7월 15일
0

DirectX12강의

목록 보기
6/39

root signature의 슬롯 메모리 한계로 인하여 테이블을 사용해야할 경우

table은 포인터처럼 사용되어 마치 사용할 레지스터 배열의 시작점을 알려주는 것과 비슷함

Constant buffer들을 가리키는 Decriptor heap(CBV)를 만들고 이를

복사하여 GPU에게 요청하면 GPU는 레지스터에 해당 값들을 로드함

CBV를 복사하는 destination 메모리는 이전과 마찬가지로 복사는 즉시되지만

실제 사용은 command 요청 후이다.

그렇기 때문에 버퍼를 만들어 사용해야함

SetDescriptorHeaps 함수로 메모리 버퍼를 가리키고,

SetGraphicsRootDescriptorTable 함수로 버퍼 내의 몇번째 데이터를 사용할지 알려줌

SetDescriptorHeaps는 매우 느리니 남발하면 안되고 프레임당 한번만 불릴 수 있게 구현

=>

SetDescriptorHeaps를 여러번 불러야 하는 경우, table 설계 자체를 다시해야 함


CD3DX12_DESCRIPTOR_RANGE ranges[] =
{
	CD3DX12_DESCRIPTOR_RANGE(D3D12_DESCRIPTOR_RANGE_TYPE_CBV, 5, 0),
};

CD3DX12_ROOT_PARAMETER param[1];
param[0].InitAsDescriptorTable(_countof(ranges), ranges);

root signature 파라미터 설정 시에

CD3DX12_DESCRIPTOR_RANGE 데이터에 b0부터 5개를 사용한다고 입력

InitAsDescriptorTable 함수로 사용할 뷰가 몇개인지 입력하여 초기화


ComPtr<ID3D12DescriptorHeap>		_cbvHeap;
D3D12_CPU_DESCRIPTOR_HANDLE			_cpuHandleBegin = {};
uint32								_handleIncrementSize = 0;

CBV는 위와 같은 데이터들이 필요

_cpuHandleBegin는 heap의 시작 지점을 가리키는 핸들

_handleIncrementSize는 데이터 하나의 크기를 말함

void ConstantBuffer::CreateView()
{
	D3D12_DESCRIPTOR_HEAP_DESC cbvDesc = {};
	cbvDesc.NumDescriptors = _elementCount;
	cbvDesc.Flags = D3D12_DESCRIPTOR_HEAP_FLAG_NONE;
	cbvDesc.Type = D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV;
	DEVICE->CreateDescriptorHeap(&cbvDesc, IID_PPV_ARGS(&_cbvHeap));

	...
}

constant buffer를 view로 만들어 저장할 view 버퍼를 만드는 함수

프로그램에서 사용하는 view 버퍼 플래그는 D3D12_DESCRIPTOR_HEAP_FLAG_NONE

GPU가 실제 사용할 view 버퍼 플래그는 D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE 이어야 함


	_cpuHandleBegin = _cbvHeap->GetCPUDescriptorHandleForHeapStart();
	_handleIncrementSize = DEVICE->GetDescriptorHandleIncrementSize(D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV);

	for (uint32 i = 0; i < _elementCount; ++i)
	{
		D3D12_CPU_DESCRIPTOR_HANDLE cbvHandle = GetCpuHandle(i);

		D3D12_CONSTANT_BUFFER_VIEW_DESC cbvDesc = {};
		cbvDesc.BufferLocation = _cbvBuffer->GetGPUVirtualAddress() + static_cast<uint64>(_elementSize) * i;
		cbvDesc.SizeInBytes = _elementSize;   // CB size is required to be 256-byte aligned.

		DEVICE->CreateConstantBufferView(&cbvDesc, cbvHandle);
	}

_handleIncrementSize는 그래픽카드마다 다르기 때문에 장치에서 가지고 와야 한다

그리고 constant buffer의 정보들을 가지고 view들을 생성


table descriptor heap => GPU에서 사용할 descriptor heap 구현

class TableDescriptorHeap
{
	...
    
private:

	ComPtr<ID3D12DescriptorHeap> _descHeap;
	uint64					_handleSize = 0;
	uint64					_groupSize = 0;
	uint64					_groupCount = 0;

	uint32					_currentGroupIndex = 0;
};

_groupSize 버퍼의사이즈 (_handleSize * 데이터 개수)

_groupCount 버퍼의 개수


void TableDescriptorHeap::Init(uint32 count)
{
	...
    
	D3D12_DESCRIPTOR_HEAP_DESC desc = {};
	desc.NumDescriptors = count * REGISTER_COUNT;
	desc.Flags = D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE;
	desc.Type = D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV;

	DEVICE->CreateDescriptorHeap(&desc, IID_PPV_ARGS(&_descHeap));

	...
}

앞에서 말한 바와 같이 플래그는 D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE

해당 플래그가 있어야 GPU 메모리에 상주 한다고 함


void TableDescriptorHeap::SetCBV(D3D12_CPU_DESCRIPTOR_HANDLE srcHandle, CBV_REGISTER reg)
{
	D3D12_CPU_DESCRIPTOR_HANDLE destHandle = GetCPUHandle(reg);

	uint32 destRange = 1;
	uint32 srcRange = 1;
	DEVICE->CopyDescriptors(1, &destHandle, &destRange, 1, &srcHandle, &srcRange, D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV);
}

constant buffer를 가지고 만들어둔 descriptor heap를

CopyDescriptors 함수를 통해 GPU가 사용할 descriptor heap에 복사한다.


void TableDescriptorHeap::CommitTable()
{
	D3D12_GPU_DESCRIPTOR_HANDLE handle = _descHeap->GetGPUDescriptorHandleForHeapStart();
	handle.ptr += _currentGroupIndex * _groupSize;
	CMD_LIST->SetGraphicsRootDescriptorTable(0, handle);

	_currentGroupIndex++;
}

command list에 사용할 테이블 주소를 SetGraphicsRootDescriptorTable 함수로 등록한다.


GEngine->GetTableDescHeap()->Clear();

ID3D12DescriptorHeap* descHeap = GEngine->GetTableDescHeap()->GetDescriptorHeap().Get();
_cmdList->SetDescriptorHeaps(1, &descHeap);

렌더링 시작 함수에서 SetDescriptorHeaps 함수를 통해 사용하는 heap을 지정해야 함


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

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

	D3D12_CPU_DESCRIPTOR_HANDLE cpuHandle = GetCpuHandle(_currentIndex);

	_currentIndex++;

	return cpuHandle;
}

constant buffer에 데이터를 넣는 함수는 넣은 메모리 주소를 반환하게 하여

view를 만들 때 쓸 수 있도록 수정


{
	D3D12_CPU_DESCRIPTOR_HANDLE handle = GEngine->GetCB()->PushData(0, &_transform, sizeof(_transform));
	GEngine->GetTableDescHeap()->SetCBV(handle, CBV_REGISTER::b0);
    
    GEngine->GetTableDescHeap()->CommitTable();
}

메쉬 렌더 시에 handle의 데이터는 b0 레지스터에 로드해 달라고 설정

이후 commit 하여 SetGraphicsRootDescriptorTable 함수가 요청할 수 있도록 함

0개의 댓글