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 는 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;
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 사용
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;
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;
enum D3D12_MEMORY_POOL{
D3D12_MEMORY_POOL_UNKNWON = 0,
D3D12_MEMORY_POOL_L0 = 1,
D3D12_MEMORY_POOL_L1 = 2
} D3D12_MEMORY_POOL
특별한 플래그가 없다면 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 텍스쳐만 포함하도록 허용
생성하려는 리소스를 설명하는 구조체 이다. 리소스는 텍스쳐 또는 버퍼 이다.
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;
리소스의 속성을 설정하는 구조체 주로 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;
모든 그래픽적인 이미지, 혹은 버퍼를 GPU 가 사용할 때 편하게 사용할 수 있도록 리소스의 메모리 취치들이 정렬되어서 만들어질 수 있도록 해주는 기준 4KB, 64KB, 4MB 등등 그래픽카드마다 다르다. 0 을 쓰면 Default 로 알아서 Alignment 를 정해준다 (64KB)
리소스의 형식 MSDN - DXGI_FORMAT 원하는 값을 찾아서 사용하거나, DXGI_FORMAT_UNKNOWN 을 설정
다중 샘플링 설정하는 값 다중 표본화의 개수와 품질 수준. 깊이∙스텐실 버퍼에 적용하는 다중표본화 설정들은 렌더 대상에 쓰인 설정들과 부합해야 한다. 4X MSAA 에서는 픽셀당 네 개의 부분픽셀에 대한 색상과 깊이∙스텐실 정보를 저장해야 하므로 후면 버퍼와 깊이 버퍼가 화면 해상도의 4배 이어야 함
리소스의 연속적인 메모리 형태를 어떤 방식으로 할지 결정하는 값 1차원 배열의 메모리를 사용하기 위해서는 D3D12_TEXTURE_LAYOUT_ROW_MAJOR 를 설정해준다 기본적인 경우 D3D12_TEXTURE_LAYOUT_UNKNOWN 지정
... |
기타 지원 플래그들. 리소스의 상태 특별한 기능이 없다면 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;
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) 이다.
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 는 Resource 를 어떤 값으로 초기화 할 것인지 설정하는 값이다. 주로 RenderTarget 과 Depth / Stencil Buffer Resource 에 대해 이 값을 설정해 준다. 따로 설정하지 않을 것이면 nullptr 을 설정한다.
설정한 값으로 Resource 가 생성되고 나면, 반환되는 인터페이스 포인터 값이다.