DirectX

7.6 루트 서명 추가 설명

Awesome Red Tomato 2022. 1. 8. 23:10

1. 루트 매개변수

루트 서명이 루트 매개변수의 배열로 정의된 점을 기억할 것이다. 

 

ShapeApp의 루트 매개변수

 

지금까지는 서술자 테이블에 해당하는 루트 매개변수 하나로만 이루어졌다. 그러나 꼭 서술자 테이블이어야 하는 것은 아니다.

 

루트 매개변수는 세 종류이다.

 

  • 서술자 테이블: 힙 안에 있는 일련의 서술자들의 구간을 지정한다.
  • 루트 서술자: 묶을 자원을 직접 식별하는 하나의 서술자로 힙에 둘 필요가 없다. 상수 버퍼에 대한 CBV나 기타 자원에 대한 SRV/UAV만 묶을 수 있다. 특히, 텍스처에 대한 SRV는 루트 서술자로 묶을 수 없다.
  • 루트 상수: 직접 묶을 32비트 상수 값들의 목록이다.

 

성능상 이유로 매개변수의 비용은 다음과 같다.

 

  • 서술자 테이블: DWORD 하나
  • 루트 서술자: DWORD 두 개
  • 루트 상수: 32비트 상수당 DWORD 하나

 

2. 서술자 테이블

 

https://docs.microsoft.com/en-us/windows/win32/api/d3d12/ns-d3d12-d3d12_root_descriptor_table

 

D3D12_ROOT_DESCRIPTOR_TABLE (d3d12.h) - Win32 apps

Describes the root signature 1.0 layout of a descriptor table as a collection of descriptor ranges that are all relative to a single base descriptor handle.

docs.microsoft.com

 

 

3. 루트 서술자

 

루트 상수를 정의하려면 D3D12_ROOT_PARAMETER의 Descriptor멤버를 채워 루트 상수에 대해 좀 더 구체적인 정보를 제공해야 한다.

 

https://docs.microsoft.com/en-us/windows/win32/api/d3d12/ns-d3d12-d3d12_root_constants

 

D3D12_ROOT_CONSTANTS (d3d12.h) - Win32 apps

Describes constants inline in the root signature that appear in shaders as one constant buffer.

docs.microsoft.com

 

 

4. 루트 상수

루트 상수를 정의하려면 D3D12_ROOT_PARAMETER의 Constants멤버를 채워 루트 상수에 대해 좀 더 구체적인 정보를 제공해야 한다.

 

https://docs.microsoft.com/en-us/windows/win32/api/d3d12/ns-d3d12-d3d12_root_constants

 

D3D12_ROOT_CONSTANTS (d3d12.h) - Win32 apps

Describes constants inline in the root signature that appear in shaders as one constant buffer.

docs.microsoft.com

 

셰이더의 관점에서 루트 상수는 그냥 상수 버퍼의 한 자료와 다를 바 없다. 루트 서술자처럼, 서술자 힙이 필요하지 않다.

 

 

5. 좀 더 복잡한 루트 서명 예제

다음과 같은 셰이더가 있다고 하자.

Texture2D gDiffuseMap : register(t0);

cbuffer cbPerObject : register(b0)
{
	float4x4 gWorld;
	float4x4 gTexTransform;
};

cbuffer cbPass : register(b1)
{
    float4x4 gView;
    float4x4 gInvView;
    float4x4 gProj;
    float4x4 gInvProj;
    float4x4 gViewProj;
    float4x4 gInvViewProj;

    float3 gEyePosW;

    float cbPerObjectPad1;

    float2 gRenderTargetSize;
    float2 gInvRenderTargetSize;

    float gNearZ;
    float gFarZ;

    float gTotalTime;
    float gDeltaTime;

	float4 gAmbientLight;
	Light gLights[MaxLights];
};

cbuffer cbMaterial : register(b2)
{
	float4 gDiffuseAlbedo;
    float3 gFresnelR0;
    float  gRoughness;
	float4x4 gMatTransform;
};

 

이 셰이더를 위한 루트 서명은 다음과 같을 것이다.

 

CD3DX12_DESCRIPTOR_RANGE texTable;
texTable.Init(
	D3D12_DESCRIPTOR_RANGE_TYPE_SRV,
	1,		// 서술자 개수
	0);		// 레지스터(t0)

CD3DX12_ROOT_PARAMETER slotRootParam[4];
slotRootParam[0].InitAsDescriptorTable(1, &texTable, D3D12_SHADER_VISIBILITY_PIXEL);
slotRootParam[1].InitAsConstantBufferView(0);
slotRootParam[2].InitAsConstantBufferView(1);
slotRootParam[3].InitAsConstantBufferView(2);

CD3DX12_ROOT_SIGNATURE_DESC rootSignature(4, slotRootParam, 0, nullptr);

 

 

6. 루트 인수의 버전 적용

응용 프로그램이 루트 매개변수에 실제로 전달하는 값을 루트 인수(root argument)라고 한다. 다음은 그리기 호출에서 루트 인수들을 변경하는 예시이다.

for(size_t i = 0; i < mRitem.size(); ++i)
{
	...
	...

	// 현 프레임 자원과 렌더 항목을 위한 CBV 오프셋
	int cbvOffset = mCurrFrameResourceIndex*(int)mRitem.size();
	cbvOffset += ri.Cbindex;
	CbvHandle.Offset(cbvOffset, mCbvSrvDecriptorSize);

	// 이 그리기 호출에서 사용할 서술자 지정
	cmdList->SetGraphicsRootDescriptorTable(0, cbvTable);

	cmdList->DrawIndexedInstanced(
		ri->IndexCount, 
		1, 
		ri->StartIndexLocation, 
		ri->BaseVertexLocation, 
		0);
}

 

각 명령은 해당 그리기 호출 시점에서 설정되어 있던 루트 인수들로 실행된다. 이는 하드웨어가 각 그리기 호출 시점에서의 루트 인수들의 상태('스냅숏')를 자동으로 저장하기 때문이다. 다른 말로, 그리기 호출마다 루트 인수들의 고유한 버전이 만들어 진다.