메모내용
Nav
CreateCommittedResource 에 사용되는 자원 설명 관련 구조체 를 다른 하나의 페이지로 만들것

리소스 공간 할당

                        
struct Vec4{
    float r;
    float g;
    float b;
    float a;
}

Vec4 data = {0.1f, 0.2f, 0.3f, 0.4f};


// Buffer GPU 에 할당하고 포인터 받기
ComPtr<ID3D12Resource> buffer;
D3D12_HEAP_PROPERTIES resourceProp = CD3DX12_HEAP_PROPERTIES(D3D12_HEAP_TYPE_UPLOAD) ; 
D3D12_RESOURCE_DESC resourceDesc = CD3DX12_RESOURCE_DESC :: buffer(sizeof(Vec4));// 업로드 타입으로 설정


// 리소스 공간 할당
DEVICE->CreateCommittedResource(
    &resourceProp,
    D3D12_HEAP_FLAG_NONE,
    &resourceDesc,
    D3D12_RESOURCE_STATE_GENERIC_READ,
    nullptr,
    IID_PPV_ARGS(&buffer)
)


// 데이터 매핑하기BYTE* ToBuffer;

buffer->Map(0, nullptr, reinterpret_cast<void**>(ToBuffer));
memcpy(ToBuffer, &data, sizeof(data));
buffer->Unmap(0, nullptr);
                        
                    

Committed Resource

Committed Resource 는 ID3D12Device 의 CreateCommittedResource() 를 통해 생성가능하다. DirectX12 에서 모든 리소스는 ID3D12Resource COM 객체에 만들어진다. 반환되는 인터페이스 포인터주소는 물리적인 주소가 아니라, 가상메모리(VirtualAddress) 주소이다. (Committed, Placed, Reserved Resource 모두 가상메모리 주소를 반환한다.) 그런데, CreateCommittedResource() 를 통해서 리소스를 생성하면, 가상메모리에다가 리소스를 만들어 반환하는것과 더불어서 물리적인 메모리에다가 리소스 메모리가 메핑(Mapping)될 메모리를 미리 할당한다. 즉, CommittedResource 는 가상메모리+물리적메모리 둘다 생성하는 리소스이다. (1:1 로 대응하다) ( 나중에 리소스 가 많아지게 되면 그래픽 카드 물리적 메모리가 부족할 수 있다 ) CommittedResource 를 사용하면 물리적인 메모리, 즉 HEAP 공간이 자동으로 할당된다.

                        
virtual HRESULT CreateCommittedResource(
    const D3D12_HEAP_PROPERTIES* pHeapProperties,
    D3D12_HEAP_FLAGS HeapFlags,
    const D3D12_RESOURCE_DESC* pDesc,
    D3D12_RESOURCE_STATES InitialResourceState,
    const D3D12_CLEAR_VALUE* pOptimizedClearValue,
    REFIID riidResource,
    void** ppvResource
) = 0;
                        
                    

D3D12_HEAP_PROPERTY

CommittedResource 는 가상 메모리와 물리적메모리(HEAP) 을 동시에 만들어 주기 때문에 HEAP 영역의 속성을 설정해주어야 한다.

                        
typedef struct D3D12_HEAP_PROPERTIES
{
    D3D12_HEAP_TYPE Type; 
    D3D12_CPU_PAGE_PROPERT// 물리적메모리 HEAP 의 타입. GPU 메모리에 데이터를 전송하는 방법Y CPUPageProperty;
    D3D12_MEMORY_POOL MemoryPoolPreference;
    UINT CreateNodeMask;                        
    UINT VisibleNodeMask;                       // 단일 GPU 어댑터에 대해서는 1 사용
} D3D12_HEAP_PROPERTIES;// 다중 어댑터에서 리소스를 볼 수 있는 토드의 집합을 나타내는 비트, 단일 GPU 어댑터에대해서는 1 사용
                        
                    
  • 3D12_HEAP_PROPERTIES
    • D3D12_HEAP_TYPE : HEAP 의 유형 (GPU 메모리에 데이터를 전송하는 방법)
      •                                                 
        enum D3D12_HEAP_TYPE{
            D3D12_HEAP_TYPE_DEFAULT = 1,
            D3D12_HEAP_TYPE_UPLOAD = 2,
            D3D12_HEAP_TYPE_READBACK = 3,
            D3D12_HEQP_TYPE_CUSTOM = 4,
        } D3D12_HEAP_TYPE;
                                                        
                                                    
      • DEFAULT
        • GPU 전용 메모리
        • GPU 는 읽고 쓰기 가능, CPU 는 접근할 수 없는 타입 ( 대부분의 리소스를 DEFAULT 타입으로 만든다. )
        • CPU 와 GPU 가 데이터를 공유하지 않기 때문에 성능이 개선될 수 있다.
        • DEFAULT Resource 를 사용하려면 CPU 에서 GPU 로 데이터를 복사해야한다. 이를 위해 UPLOAD Resource 를 사용할 수 있습니다.
        • DEFAULT Resource 를 사용하려면 GPU 자원을 할당해야 합니다.
          • D3D12Device :: CreateCommittedResource 메서드를 사용하여 할당할수 있습니다.
        • 나무같이 정적인, 변하지 않는 물체의 정점 데이터를 저장할 때는 DEFAULT Resource 를 사용하는 것이 성능상 좋다.
      • UPLOAD
        • UPLOAD Resource 는 CPU 와 GPU 가 공유하는 메모리
        • CPU 의 그림이나 행렬등의 데이터를 GPU 가 WRITE 할 수 있는 타입. ( GPU 에 업로드를 위한 CPU 접근에 최적화된 타입
        • UPLOAD Resource 를 사용하면, CPU 에서 데이터를 채우고, GPU 가 해당 데이터를 읽어들일 수 있다.
        • UPLOAD Resource 를 사용하면, 매프레임마다 CPU 에서 GPU 로 데이터를 복사해야하기 때문에 성능이 저하될 수 있다.
        • 실시간으로 데이터를 전송해야 할때 유용하다
      • READBACK : CPU 가 읽어가기 위한 HEAP
      • CUSTOM : 잘 사용하지 않는다.
    • D3D12_CPU_PAGE_PROPERTY
      • HEAP 에 대한 CPU-PAGE 속성을 나타낸다
      •                                                 
        enum D3D12_CPU_PAGE_PROPERTY{
            D3D12_CPU_PAGE_PROPERTY_UNKOWN = 0,
            D3D12_CPU_PAGE_PROPERTY_NOT_AVAILABLE = 1,
            D3D12_CPU_PAGE_PROPERTY_WRITE_COMBINE = 2,
            D3D12_CPU_PAGE_PROPERTY_WRITE_BACK = 3,
        } D3D12_CPU_PAGE_PROPERTY;
                                                        
                                                    
      • 별 다른 속성없이 D3D12_CPU_PAGE_PROPERTY_UNKOWN 을 사용한다.
    • D3D12_MEMORY_POOL
      • HEAP에 대한 메모리 풀(Pool) 을 나타낸다
      •                                                 
        enum D3D12_MEMORY_POOL{
            D3D12_MEMORY_POOL_UNKNWON = 0,
            D3D12_MEMORY_POOL_L0 = 1,
            D3D12_MEMORY_POOL_L1 = 2
        } D3D12_MEMORY_POOL
                                                        
                                                    
      • 별 다른 속성없이 D3D12_MEMORY_POOL_UNKNWON 을 사용한다.

D3D12_HEAP_FLAGS

특별한 플래그가 없다면 D3D12_HEAP_FLAG_NONE 을 주로 사용한다.

                        

// HEAP 이 텍스쳐를 포함할 수 있는가 또는 리소스가 어댑터들 사이에서 공유될 수 있는가를 나타낸다.
typedef enum D3D12_HEAP_FLAGS{
    D3D12_HEAP_FLAG_NONE,
    D3D12_HEAP_FLAG_SHARED, 
    D3D12_HEAP_FLAG_BUFFERS,// 다중 프로세서에서 힙을 공유 (CPU 마샬링(Marshaling) 이 필요없음) 
    D3D12_HEAP_FLAG_ALLOW_DIS// 버퍼를 포함하도록 허용되지 않음PLAY,  
    D3D12_HEAP_FLAG_SHARED_CROSS_ADA// 스왑체인 표면을 포함하도록 허용PTER,   
    D3D12_HEAP_FLAG_DENY_RT_DS_TEXTURES,    // 다중 어댑터에서 힙을 공유
    D3D12_HEAP_FLAG_DENY_NON_RT_DS_TEXTURES,// RT/DS 텍스쳐를 포함하도록 허용되지 않음    
    D3D12_HEAP_FLAG_ALLOW_ALL_BUFFERS_AND_TEXTUR// RT/DS 가 아닌 텍스쳐를 포함하도록 허용되지 않음ES, 
    D3D12_HEAP_FLAG_ALLOW_ONLY_BUFFERS, // 모든 유형의 버퍼와 텍스쳐를 포함하도록 허용
    D3D12_HEAP_FLAG_ALLOW_ONLY_NON_RT_DS// 버퍼만 포함하도록 허용_TEXTURES, 
    D3D12_HEAP_FLAG__ALLOW_ONLY_RT_DS_TEXTURES // RT/DS 가 아닌 텍스쳐를 포함하도록 허용
}D3D12_HEAP_FALGS;// RT/DS 텍스쳐만 포함하도록 허용
                        
                    

D3D12_RESOURCE_DESC

생성하려는 리소스를 설명하는 구조체 이다. 리소스는 텍스쳐 또는 버퍼 이다.

                        
typedef struct D3D12_RESOURCE_DESC {
    D3D12_RESOURCE_DIMENSION Dimension;             // 리소스의 속성을 설정
    UINT64                   Alignment;             // 모든 그래픽적인 이미지 혹은 버퍼를 GPU 가 사용할 때 편하게 사용할 수 있도록, 리소스의 메모리 위치들이 정렬되어서 만들어질 수있도록 해주는 기준
    UINT64                   Width;                 // 가로 크기. 텍스처의 너비(텍셀단위), 버퍼자원의 경우에는 버퍼 바이트 개수를 지정한다.
    UINT                     Height;                // 세로 크기. 텍스처의 높이(텍셀단위)
    UINT16                   DepthOrArraySize;      // 3차원 텍스처의 깊이(Z) 혹은, 1&2차원 배열이라면 배열의 크기를 설정해주는값. 3차원 텍스처들의 배열은 지원하지 않음 주의
    UINT16                   MipLevels;             // 밉맵 수준을 설정하는 값이다. 0 을 설정하면 자동으로 계산해준다.
    DXGI_FORMAT              Format;                // 리소스의 형식을 설정하는 값이다. (주로 DXGI_FORMAT_UNKNOWN 설정)            
    DXGI_SAMPLE_DESC         SampleDesc;
    D3D12_TEXTURE_LAYOUT     Layout;
    D3D12_RESOURCE_FLAGS     Flags;
} D3D12_RESOURCE_DESC;
                        
                    

D3D12_RESOURCE_DIMENSION

리소스의 속성을 설정하는 구조체 주로 BUFFER 나 TEXTURE2D 를 사용한다.

                            
enum D3D12_RESOURCE_DIMENSION{
    D3D12_RESOURCE_DIMENSION_UNKNOWN = 0,
    D3D12_RESOURCE_DIMENSION_BUFFER = 1,
    D3D12_RESOURCE_DIMENSION_TEXTURE1D = 2,
    D3D12_RESOURCE_DIMENSION_TEXTURE2D = 3,
    D3D12_RESOURCE_DIMENSION_TEXTURE3D = 4
} D3D12_RESOURCE_DIMENSION;
                            
                        

UINT64 Alignment

모든 그래픽적인 이미지, 혹은 버퍼를 GPU 가 사용할 때 편하게 사용할 수 있도록 리소스의 메모리 취치들이 정렬되어서 만들어질 수 있도록 해주는 기준 4KB, 64KB, 4MB 등등 그래픽카드마다 다르다. 0 을 쓰면 Default 로 알아서 Alignment 를 정해준다 (64KB)

DXGI_FORMAT format

리소스의 형식 MSDN - DXGI_FORMAT 원하는 값을 찾아서 사용하거나, DXGI_FORMAT_UNKNOWN 을 설정

DXGI_SAMPLE_DESC SampleDesc

다중 샘플링 설정하는 값 다중 표본화의 개수와 품질 수준. 깊이∙스텐실 버퍼에 적용하는 다중표본화 설정들은 렌더 대상에 쓰인 설정들과 부합해야 한다. 4X MSAA 에서는 픽셀당 네 개의 부분픽셀에 대한 색상과 깊이∙스텐실 정보를 저장해야 하므로 후면 버퍼와 깊이 버퍼가 화면 해상도의 4배 이어야 함

D3D12_TEXTURE_LAYOUT layout

리소스의 연속적인 메모리 형태를 어떤 방식으로 할지 결정하는 값 1차원 배열의 메모리를 사용하기 위해서는 D3D12_TEXTURE_LAYOUT_ROW_MAJOR 를 설정해준다 기본적인 경우 D3D12_TEXTURE_LAYOUT_UNKNOWN 지정

...

D3D12_RESOURCE_FLAGS miscFlags

기타 지원 플래그들. 리소스의 상태 특별한 기능이 없다면 D3D12_RESOURCE_FLAGS_NONE 으로 설정 깊이∙스텐실 버퍼 자원의 경우에는 D3D12_RESOURCE_MISC_DEPTH_STENCIL 을 지정한다.

                            
    enum D3D12_RESOURCE_FLAGS{
    D3D12_RESOURCE_FLAG_NONE = 0,
    D3D12_RESOURCE_FALG_ALLOW_RENDER_TARGET = 0X1,
    D3D12_RESOURCE_FALG_ALLOW_DEPTH_STENCIL = 0X2,
    D3D12_RESOURCE_FALG_ALLOW_UNORDERED_ACCESS = 0X4,
    D3D12_RESOURCE_FLAG_DENY_SHADER_RESOURCE = 0X8,
    D3D12_RESOURCE_FALG_ALLOW_CROSS_ADAPTER = 0X10,
    D3D12_RESOURCE_FALG_ALLOW_SIMULANEOUS_ACCESS = 0X20,
    D3D12_RESOURCE_FALG_ALLOW_DECODE_REFERENCE_ONLY = 0X40,
    }   D3D12_RESOURCE_FLAGS;
                            
                        

CD3DX12_RESOURCE_DESC

D3D12_RESOURCE_DESC 를 상속해서 편의용 생성자들과 메서드들을 추가한 C++ 래퍼 클래스. 이 클래스의 Buffer 매서드를 이용하면, 버퍼를 서술하는 D3D12_RESOURCE_DESC 구조체 인스턴스를 간단히 생성할 수 있다. 또한 CD3DX12_RESOURCE_DESC 클래스는 또한 텍스처 자원을 서술하는 D3D12_RESOURCE_DESC 의 생성을 돕는 편의용 메서드들과 자원에 관한 정보를 조회하는 편의 메서드들도 제공한다.

                        

/* 버퍼를 서술하는 D3D12_RESOURCE_DESC 구조체를 간단히 생성하는 메서드 */
struct CD3DX12_RESOURCE_DESC : public D3D12_RESOURCE_DESC
{
    static inline CD3DX12_RESOURCE_DESC Buffer(
        UINT64 width,
        D3D12_RESOURCE_FLAGS flags = D3D12_RESOURCE_FLAG_NONE,
        UINT64 alignment = 0
    )
    {
        return CD3DX12_RESOURCE_DESC(
            D3D12_RESOURCE_DIMENSION_BUFFER,
            alignment, width, 1, 1, ,1,
            DXGI_FORMAT_UNKNOWN, 1, 0,
            D3D12_REXTURE_LAYOUT_ROW_MAJOR, flags
        );
    }

    static inline CD3DX12_RESOURCE_DESC Tex1D(...);

    static inline CD3DX12_RESOURCE_DESC Tex2D(...);

    static inline CD3DX12_RESOURCE_DESC Tex3D(...);
}
                            
                        
                    

범용 GPU 자원으로서 버퍼에서 너비(width) 는 가로길이가 아니라 버퍼의 바이트 개수를 뜻한다. 예를 들어 float 64 개를 담는 버퍼의 너비는 64*sizeof(float) 이다.

D3D12_RESOURCE_STATES

Resource 가 사용되는 방법에 따른 Resource 의 초기 상태를 나타내는 값 Resource 가 가질 수 있는 상태들은 여러 종류들이 있다. Resource 에 대해 어떤 명령을 수행하기 위해서는 특정항 상태에 있을 때 가능하다. 모든 Resource 는 어느 한순간에 하나의 STATE 를 꼭 가지도록 되어 있다.

하나의 Resource 에 두개이상의 Process 가 사용하고 있으면 동기화 문제가 생긴다. Resource 라는 단어 자체는 기본적으로 READ_ONLY 의 의미를 내포하고 있다. GPU 의 입장에서는 기본적으로 Resource 의 내용이 바뀌지 않는다. CPU 의 입장에서는 Resource 는 WRITE 의 대상이다. ( Mesh, Texture 등... ) Resource 를 관리하기 위해 만든 개념이 RESOURCE_STATE 이다. DirectX 11 에서는 그래픽카드 드라이버에서 알아서 내부적인 상태를 관리해줬다. 따라서 프로그래머가 건들 수 없어서 드라이버 성능에 따라 성능차이가 났다. DirectX 12 에서는 프로그래머가 직접 관리해줘야 한다. 따라서 모든 Resource 들은 어떤 상태들을 유지하도록 만들어야 한다. Vertex / Index 버퍼에 대해서는 주로 D3D12_RESOURCE_STATE_COMMON 을 사용한다. Depth / Stencil 버퍼를 만들 것이라면 D3D12_RESOURCE_STATE_WRITE 를 설정한다.

D3D12_CLEAR_VALUE

D3D12_CLEAR_VALUE 는 Resource 를 어떤 값으로 초기화 할 것인지 설정하는 값이다. 주로 RenderTarget 과 Depth / Stencil Buffer Resource 에 대해 이 값을 설정해 준다. 따로 설정하지 않을 것이면 nullptr 을 설정한다.

REFIID riidResource, _COM_Outptr_opt_ void** ppvResource

설정한 값으로 Resource 가 생성되고 나면, 반환되는 인터페이스 포인터 값이다.

..