자원의 개요
자원은 앞에서 말햇듯이 크게 두 가지의 종류로 나뉘는데, 버퍼(Buffer)와 텍스처(Texture)이다.
위의 그림은 자원 클래스들이 모두 ID3DResource라는 단일 공통 기반 클래스로부터 파생된 것임을 보여준다.
이러한 구조는 자원이라는 것이 결국은 파이프라인에 부착(연결)할 수 있고, 입력 또는 출력에 쓰이는 메모리 블록이라는 점을 생각하면 당연한 것이다. 다른 말로 하면 자원은 GPU가 사용하고 조작하도록 마련된 메모리 블록일 뿐이라는 것이다.
자원의 생성
모든 메모리 자원의 생성은 ID3D11Device 인터페이스가 책임진다. 생성된 자원을 파이프라인에 직접 연결할 수도 있고 자원 뷰를 통해서 부착할 수도 있다. 일단 연결이되면 이후 파이프라인 실행 과정 안에서 자원이 실제로 사용된다.
자원의 생성에 쓰이는 ID3D11Device의 메서드는 자원의 종류마다 다르지만, 모두 동일한 일반 패턴을 따른다.
모든 자원 생성 메서드는 세 개의 매개변수를 받는다.
첫 매개변수는 자원 생성에 관한 모든 옵션을 지정하는 구조체이다. 이를 자원 서술(Resource Description)이라고 부른다. 자원 종류마다 자원 서술 구조체가 다르다. 그러나 이 구조체들은 모두 동일한 목적(생성된 자원의 원하는 특성들을 정의)으로 사용된다.
둘째 매개변수는 D3D11_SUBRESOURCE_DATA 구조체를 가리키는 포인터인데, 이 구조체는 자원에 적재할 초기 자료를 제공하는 데 쓰인다. 예를 들어 정적 정점 자료를 담을 버퍼 자원을 만드는 경우 이 구조체를 이용해서 모형의 정점 자료를 버퍼 자원에 채워 넣을 수 있다.
세번째 매개변수는 자원 종류에 맞는 자원 인터페이스를 가리키는 포인터의 포인터로, 자원 생성이 성공하면 해당 자원을 가리키는 포인터가 이 매개변수에 설정된다.
자원 용도 플래그
자원이 존재하는 '메모리'는 비디오 카드일 수도 있고, 시스템의 주 메모리일 수도 있다. 또한 Direct3D 실행 모듈이 자원을 비디오 카드 메모리에서 시스템 메모리로 또는 그 반대 방향으로 이동할 수도 있다. 때문에 응용 프로그램은 반드시 자원의 사용 방식에 대한 자신의 '의도'를 용도 명세 필드를 통해서 명시적으로 밝혀야 한다.
enum D3D11_USAGE
{
D3D11_USAGE_DEFAULT,
D3D11_USAGE_IMMUTABLE,
D3D11_USAGE_DYNAMIC,
D3D11_USAGE_STAGING
}
자원 용도 | DEFAULT | DYNAMIC | IMMUTABLE | STAGING |
GPU 읽기 | YES | YES | YES | YES |
GPU 쓰기 | YES | | | YES |
CPU 쓰기 | | | | YES |
CPU 읽기 | | YES | | YSE |
D3D11_USAGE_DEFAULT(기본 용도) : 표에서 보듯이 기본 용도 자원은 GPU의 읽기 쓰기만 가능하고 CPU의 접근은 모두 거부한다. 이 용도는 렌더 타겟 텍스처나 스트림 출력 정점 버퍼가 있다.
D3D11_USAGE_IMMUTABLE(불변 용도) : 가장 간단한 사용 패턴으로 오직 GPU가 읽을 수만 있다. GPU와 CPU의 쓰기를 모두 거부한다. 이 용도는 정적인 상수나, 정점, 색인 버퍼를 들 수 있다.
D3D11_USAGE_DYNAMIC(동적 용도) : CPU의 쓰기가 가능한 두 가지 용도 중 하나이다. GPU는 읽기만 가능하다. 이 사용 용도는 CPU가 자원의 내용을 생산하고 GPU가 자원을 소비한다.
이 용도는 상수 버퍼에서 사용하면 좋다.
D3D11_USAGE_STAGING(예비 용도) : 이 예비 용도는 특별한 종류의 사용 패턴을 제공한다. 앞에서 말한 세 가지 용도는 렌더링 수행을 위한 전형적인 자원 사용 시나리오들에 해당하는 것이다. 그러나 GPU에서 자료를 계산, 조작하고 그것을 저장이나 추가 조사를 위해 CPU로 읽어 들어야 하는 경우도 있다. 그런 목적의 응용 프로그램에서는 다른 사용 패턴들에 CPU의 읽기 접근을 강제로 허용하는 대신 이 예비 용도의 자원을 중간 계산을 위한 장소로 활용하면 된다.
CPU 접근 플래그
자원의 용도를 지정했다면, 다음으로는 자원에 대한 CPU의 접근 방식을 지정해야 한다. 이 플래그는 CPU에만 국한 된다. 이 열거형의 두 값을 비트 단위 OR로 결합해서 사용하면 읽기와 쓰기를 모두 허용 할 수도 있다. 하지만 자원 용도 플래그에 맞추어서 설정해야만 한다.
enum D3D11_CPU_ACCESS_FLAG
{
D3D11_CPU_ACCESS_WRITE,
D3D11_CPU_ACCESS_READ
}
연결 플래그
자원 서술 구조체의 또 다른 공통 필드로 연결 플래그(Bind Flag)가 있다. 이 필드는 자원을 파이프라인의 어디에 연결할 것인지를 나타낸다. 이 값들을 비트 단위 OR로 결합함으로써 연결 가능 장소를 여러개 지정하는 것도 가능하다. 이 플래그를 제대로 지정하지 않고 자원을 생성하면 나중에 응용 프로그램이 자원을 파이프라인에 연결하려 할 때 오류가 발생한다.
enum D3D11_BIND_FLAG
{
D3D11_BIND_VERTEX_BUFFER,
D3D11_BIND_INDEX_BUFFER,
D3D11_BIND_CONSTANT_BUFFER,
D3D11_BIND_SHADER_RESOURCE,
D3D11_BIND_STREAM_OUTPUT,
D3D11_BIND_RENDER_TARGET,
D3D11_BIND_DEPTH_STENCIL,
D3D11_BIND_UNORDERED_ACCESS,
}
자원을 파이프라인에 연결할 수 있는 지점은 총 여덟 가지이다. 처음 둘은 정점 버퍼와 색인 버퍼에 해당하는 것으로, 파이프라인의 기하구조 자료를 공급하기 위한 입력 조립기 단계에 부착할 자원에 쓰인다. 반면 여섯 번째와 일곱번째의 렌더 타겟 플래그와 깊이/스탠실 버퍼 플래그는 파이프라인의 렌더링 결과를 받는 출력 병합기 단계에 연결할 자원을 위한 것이다. 다섯 번째의 스트림 출력 플래그 역시 파이프라인으로부터의 출력을 위한 것이나, 래스터화된 이미지 자료가 아니라 기하구조 자료를 받는다는 점이 다르다. 반면 D3D11_BIND_CONSTANT_BUFFER, D3D11_BIND_SHADER_RESOURCE,
D3D11_BIND_UNORDERED_ACCESS는 셰이더 프로그램 안에서 사용한다.
위의 그림에서 연결 플래그가 연결되는 부분을 확인 할 수 있다.
자원 해제
자원들은 모두 COM 인터페이스를 구현하는 객체의 형태이며, 따라서 해당객체의 계통 구조 안에는 IUnknown 인터페이스가 존재한다. 이는 자원들이 참조 계수 방식으로 관리된다는 뜻이며, 따라서 응용 프로그램이 자원을 다 사용하고 난 후에는 반드시 참조를 해제해 주어야 한다.