DirectX12의 Descriptor Heap, RootSignature 등 주변 필기

개인적으로 DirectX12는 얼토당토않게 이해하기 쉬우며 Descriptor Heap에 대한 정리도 잘하지 못한다.완전히 이해한 것은 아니기 때문에 잘못된 부분이 있을 수 있지만, 초보자가 이해에 더 가까워질 수 있도록 읽는 가치도 있을 수 있다.

말하자면 Descriptor


'Descriptor Heap'이란'Descriptor'를 정리한 무더기를 말하는데, 이름에서 알 수 있듯이'Descriptor'가 무엇을 위해 준비했는지는 머리의 한 구석에 넣어야 한다.
우선, 메모리에 일부 계열 원본(예를 들어 무늬와 상수 버퍼)이 존재하고 농담급에서 메모리를 참고할 때 GPU 측은 이 자원이 무엇을 가리키는지 모르는 것 같다(예를 들어 어떤 유형, 형식 같은 정보).따라서 Descriptor를 사용하면 이것이 무늬인지 상수 버퍼인지 식별할 수 있습니다.

Descriptor의 종류입니다. Descriptor Heap입니다.


Descriptor는 다음과 같은 5가지가 있는데 같은 무더기에 다른 종류의Descriptor를 저장할 수 없습니다.
(참조: https://docs.microsoft.com/ja-jp/windows/win32/direct3d12/creating-descriptor-heaps
typedef enum D3D12_DESCRIPTOR_HEAP_TYPE
{
    D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV,    // Constant buffer/Shader resource/Unordered access views
    D3D12_DESCRIPTOR_HEAP_TYPE_SAMPLER,        // Samplers
    D3D12_DESCRIPTOR_HEAP_TYPE_RTV,            // Render target view
    D3D12_DESCRIPTOR_HEAP_TYPE_DSV,            // Depth stencil view
    D3D12_DESCRIPTOR_HEAP_TYPE_NUM_TYPES       // Simply the number of descriptor heap types
} D3D12_DESCRIPTOR_HEAP_TYPE;

예를 들어 렌더링 목표에 사용되는 두 개의 무늬 자원이 존재한다고 가정하고 type을RTV, DescriptorHeap 크기 2를 만듭니다.
그런 다음 ID3D 12 CreateRenderTargetView 함수를 사용하여 리소스 및 D3D 12 활용RENDER_TARGET_VIEW_DESC 및 Descriptor Heap에서 분리된 스토리지 위치에서 Descriptor(렌더링 TargetView)를 만들어 복사합니다.
RTV가 아닌 경우 ID 3D 12 Create Constant BufferView 등 다양한 유형의 함수는 D3D Device에 있어야 합니다.

DescriptorTable


Descriptor Heap 리소스만 설정하면 면도기 어디에 바인딩되는지 정보가 부족합니다.저것을 지정하는 것은Descriptor Table입니다.각각Descriptor Heap의 바인딩을 지정할 수 있습니다.Descriptor Table에는 Range라는 객체가 있습니다. 첫 번째 Range는 b0과 Descriptor Heap의 시작을 Descriptor 바인딩을, 두 번째 Range는 Descriptor Heap의 다른 Descriptor를 바인딩으로 지정합니다.

RootSignature


제작된 Descriptor Heap은 RootSignature의 RootParameter 중 하나로 지정해야 합니다.RootPromeeter로 지정할 수 있는 것도 있기 때문에 다른 32비트 상수, CBV, SRV, UAV를 지정할 수 있다.Sampler도 StaticSampler로 RootSignature로 설정할 수 있지만 이 부분은 생략됩니다.
지금까지의 참조: DirectX면 145회.

구체적 예


위의 설명은 자기도 이해할 수 없을 것 같아서 구체적인 예를 들어 다시 한 번 자세히 보려고 합니다.
자원이 적어 설명에 적합한 예는 아니지만 직접 새 샘플을 쓰는 것도 번거롭다. DirectX Graphic Example의 HelloTexture를 예로 들자.
주로 다음 코드에 사용된 DescriptorHeap 주변을 판독합니다.
https://github.com/microsoft/DirectX-Graphics-Samples/blob/v10.0.19041.0/Samples/Desktop/D3D12HelloWorld/src/HelloTexture/D3D12HelloTexture.cpp
한 마디로 하면 내가 하고 싶은 일은 아래의 대략적인 그림처럼 무늬와 음영의 레지스터 b0을 연결하는 것이다.
그렇기 때문에 Descriptor, Descriptor Heap, Descriptor Table, Root Signature 등이 필요하다.

설명 모음 만들기
109행 견본에서 나온 다음 코드를 사용하여 렌더링 대상의 설명 더미와 자원을 숨기는 설명 더미를 만듭니다.
// Create descriptor heaps.
{
    // Describe and create a render target view (RTV) descriptor heap.
    D3D12_DESCRIPTOR_HEAP_DESC rtvHeapDesc = {};
    rtvHeapDesc.NumDescriptors = FrameCount;
    rtvHeapDesc.Type = D3D12_DESCRIPTOR_HEAP_TYPE_RTV;
    rtvHeapDesc.Flags = D3D12_DESCRIPTOR_HEAP_FLAG_NONE;
    ThrowIfFailed(m_device->CreateDescriptorHeap(&rtvHeapDesc, IID_PPV_ARGS(&m_rtvHeap)));

    // Describe and create a shader resource view (SRV) heap for the texture.
    D3D12_DESCRIPTOR_HEAP_DESC srvHeapDesc = {};
    srvHeapDesc.NumDescriptors = 1;
    srvHeapDesc.Type = D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV;
    srvHeapDesc.Flags = D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE;
    ThrowIfFailed(m_device->CreateDescriptorHeap(&srvHeapDesc, IID_PPV_ARGS(&m_srvHeap)));

    m_rtvDescriptorSize = m_device->GetDescriptorHandleIncrementSize(D3D12_DESCRIPTOR_HEAP_TYPE_RTV);
}

설명자 더미에 저장된 설명자의 수량(.NumDescriptors)과 설명자의 종류(.Type)와 표지(.Flags)를 설정합니다.
RenderTarget에 대한 설명 모음과 CBV, SRV, UAV에 대한 설명 모음을 만듭니다.
텍스쳐 생성 및 설명자
우선, 중요한 무늬 자체는 메모리에 확보해야 한다.275~350줄은 무늬 자원을 확보하고 데이터를 복제하는 코드입니다.
320줄의 다음 코드를 알았을 때, 설명자를 만들고 설명자표의 제어점과 연결되는 것을 발견할 수 있습니다.자신이 설명자=XXX뷰(Shader ResourceView 등)라는 인식이 있지만 엄밀히 말하면 다를 수 있다.
// Describe and create a SRV for the texture.
D3D12_SHADER_RESOURCE_VIEW_DESC srvDesc = {};
srvDesc.Shader4ComponentMapping = D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING;
srvDesc.Format = textureDesc.Format;
srvDesc.ViewDimension = D3D12_SRV_DIMENSION_TEXTURE2D;
srvDesc.Texture2D.MipLevels = 1;
m_device->CreateShaderResourceView(m_texture.Get(), &srvDesc, m_srvHeap->GetCPUDescriptorHandleForHeapStart());


그림은 이런 상태이다.

명령 목록에 설명 더미 설정하기
생성된 설명자 더미는 명령 목록에 설정됩니다. 예를 들어 견본의 435 줄입니다.SetDescriptorHeaps는 등록 명령 목록에 사용되는 무더기라고 생각하지만 Set G r aphicsRootDescriptorTable는 무엇입니까? 이 점은 앞으로 설명자 무더기를 설정하고 등록하는 것일 뿐 당초 목표 b0과 관련이 있을 수 없습니다.
어쨌든 RootParameter Index(첫 번째 파라미터)에 0과 설명자 더미의 손잡이를 설정하고 머릿속에서 다음 RootSignature 주위를 보세요.
ID3D12DescriptorHeap* ppHeaps[] = { m_srvHeap.Get() };
m_commandList->SetDescriptorHeaps(_countof(ppHeaps), ppHeaps);

m_commandList->SetGraphicsRootDescriptorTable(0, m_srvHeap->GetGPUDescriptorHandleForHeapStart());

RootSignature, RootParameter 등
여기 부분에서 샘플의 159행을 주목합니다.
CD3DX12는 설명자 모음의 설명자와 설명자의 설명자를 연결하기 위해DESCRIPTOR_RANGE1이라는 구조체가 존재합니다.앞으로 제작될 RootSignature를 위해 먼저 설명자의 유형/수량과 레지스터의 번호 정보를 가진 구조체입니다.
때로는 묘사자 탁자라고도 불린다.
CD3DX12_DESCRIPTOR_RANGE1 ranges[1];
        ranges[0].Init(D3D12_DESCRIPTOR_RANGE_TYPE_SRV, 1, 0, 0, D3D12_DESCRIPTOR_RANGE_FLAG_DATA_STATIC);

CD3DX12_DESCRIPTOR_RANGE1(
    D3D12_DESCRIPTOR_RANGE_TYPE rangeType,
    UINT numDescriptors,
    UINT baseShaderRegister,
    UINT registerSpace = 0,
    D3D12_DESCRIPTOR_RANGE_FLAGS flags = D3D12_DESCRIPTOR_RANGE_FLAG_NONE,
    UINT offsetInDescriptorsFromTableStart =
    D3D12_DESCRIPTOR_RANGE_OFFSET_APPEND)
{
    Init(rangeType, numDescriptors, baseShaderRegister, registerSpace, flags, offsetInDescriptorsFromTableStart);
}
그런 다음 Range를 사용하여 RootParameter라는 구조체를 만듭니다.이번 RootParameter의 색인 0은Descriptor Table(방금 만든 Range)로 지정되었습니다.
InitAs Descriptor Table 외에도 InitAs Constans는 설명자를 지정하지 않고 리소스 스토리지에 직접 연결하는 역할을 하지만 이번에는 설명을 생략합니다.
어쨌든 RootParameter의 배열 안에 몇 개의Descriptor Table를 지정했습니다.
CD3DX12_ROOT_PARAMETER1 rootParameters[1];
rootParameters[0].InitAsDescriptorTable(1, &ranges[0], D3D12_SHADER_VISIBILITY_PIXEL);

inline void InitAsDescriptorTable(
UINT numDescriptorRanges,
_In_reads_(numDescriptorRanges) const D3D12_DESCRIPTOR_RANGE1* pDescriptorRanges,
D3D12_SHADER_VISIBILITY visibility = D3D12_SHADER_VISIBILITY_ALL)
{
InitAsDescriptorTable(*this, numDescriptorRanges, pDescriptorRanges, visibility);
}
여기서 생각나는 것은 이전 부분에서 S e t G r aphics RootDescriptor Table에서 RootParameter Index의 0에 지정된 설명자 더미의 명령을 불러왔다는 것입니다.
현재 만들어진 RootParameter의 Index0은 농담 레지스터 0에 설명자가 있는 정보를 가진Descriptor Table로 레지스터와 자원의 연결을 해결합니다.
이후 RootParameter를 사용하여 RootSignature를 제작하고 RootSignature를 통해 RootParameter와 RootParameter Index가 설정한 정보에 따라 그림자가 b0에 사용하는 자원을 찾아낸다.
길어졌기 때문에 전체적인 절차는 다음과 같다
  • 설명자 표에 설명자의 수량과 명암 레지스터에 대한 정보를 저장한다
  • 이를 바탕으로 루트 매개변수 생성하기
  • 루트 매개 변수의 인덱스 0에 설명표를 설정
  • 나중에 명령 목록에서 색인과 설명 부적을 연결
  • 이 매개 변수를 사용하여 루트 서명 만들기
  • 생성된 루트 서명도 파이프라인 상태에 설정되고 명령 목록에 지정됨
  • 설명자 테이블, 루트 매개변수 다이어그램

    구체적인 예를 총결하다.
    이로써 우리는 각양각색의 대상을 제작한 후에 그것을 사용하여 서로 다른 대상을 만들고 다시 사용한 후에 마침내 b0에 무늬를 기록하였다.나는 이전에 도표한 물건을 모두 조합하는 것이 바로 이런 관계라고 생각한다.

    더 복잡한 예를 만들 때 자기가 쓰는 노트.


    이 기사의 근원이 되기 전에 자신이 너무 난잡하게 쓴 노트의 사진과 내용의 노트
  • Descriptor Table에 설명자 설정
  • 그래서 두 개가 쌓인 상태에서 테이블이 두 개
  • 두 표는 RootParameter Index의 0으로 설정해야 하며, 첫 번째는 두 번째
  • 좋은 웹페이지 즐겨찾기