2021. 8. 5. 02:02ㆍ그래픽스/vk
1. Creating an instance
- instance 는 소프트웨어 구조체, 응용프로그램의 상태를 다른 앱이나 현재앱의 문맥에서 수행되는 라이브러리부터 논리적으로 분리시킴
- 시스템의 물리 장치는 인스턴스의 구성원으로 표현, 각각 특정 능력을 가지고, 가용한 큐의 선택을 포함
- vulkan은 앱의 하위시스템, vulkan라이브러리에 한번 연결하고 초기화하면 일부 상태를 추적
-> 추적하기 위해서는 객체들을 저장해야함. 이를 인스턴스 장치, Vkinstance 객체로 표현.
- 인스턴스를 생성, vulkan 라이브러리를 초기화해야함
- 인스턴스는 응용프로그램과 vk 라이브러리간의 연결
- 이를 작성하려면 응용 프로그램에 대한 세부정보를 드라이버에 지정해야함
2. vkCreateInstance - 인스턴스 생성 함수
VkResult vkCreateInstance(
const VkInstanceCreateInfo* pCreateInfo,
const VkAllocationCallbacks* pAllocator,
VkInstance* pInstance);
- 초기화할 VkInstance 타입과, 전달해야할 두가지 포인터를 볼 수 있다.
- 여기서 pAllocator는 사용자 정의 할당자 콜백에 대한포인터로 튜토리얼에선 nullptr을 사용한다
(사용자 정의 메모리 할당)
- 생성 정보가 있는 구조체는 VKInstanceCreateInfo 타입으로 필수적인 정보가 담겨있다.
- 그리고 마지막 파라미터는 실제 생성한 인스턴스를 다룰 VkInstance 타입이다.
vulkan은 많은정보를 함수대신 구조체를 통해 전달
- 인스턴스를 만드는데 필요한 충분한 정보를 제공하기위해 하나이상의 구조체를 채워야함.
VkResult타입의 값을 반환하며 이를 통해 오류코드를 확인할 수 있음.
결과는 VkInstance멤버 구조체 변수에 저장됨.
if (vkCreateInstance(&createInfo, nullptr, &instance) != VK_SUCCESS) {
throw std::runtime_error("failed to create instance!");
}
3. VkInstanceCreateInfo
- vkInstanceCreateInfo의 구조체 의 멤버는 다음과 같다.
typedef struct VkInstanceCreateInfo {
VkStructureType sType;
const void* pNext;
VkInstanceCreateFlags flags;
const VkApplicationInfo* pApplicationInfo;
uint32_t enabledLayerCount;
const char* const* ppEnabledLayerNames;
uint32_t enabledExtensionCount;
const char* const* ppEnabledExtensionNames;
} VkInstanceCreateInfo;
아래 구조체는 옵션이 이아니라 무조건 vulkan 드라이버에게 알려야할 정보
- global extensions 과 사용할 validation layers를 알려주는 구조체
- global : 전체 프로그램에 적용됨 (not specific decive)
- vulkan의 많은 구조체는sType멤버에 타입을 명시적으로 지정해야함.
- pNext 또한 확장을 위해 많은 구조체에 존재하지만 지금은 nullptr로 초기화.
- flag는 향후 사용을 위해 예약되어 있음. 0으로 설정
- pApplicationInfo는 응용프로그램에 대한 추가정보를 전달하는 선택적인 구조체포인터
(nullptr로 설정 가능)
- enabledLayerCount와 ppEnabledLayerNames : 각각 활성화하고 싶은 인스턴스 레이어의 수와 이름.
(현재는 count는 0, 이름은 nullptr로 설정하여 유효성 검사 레이어를 안할 수 있음)
- enabledExtensionCount , ppEnabledExtensionNames : 전역 확장을 정함
vulkan은 플랫폼에 무관한 API -> 윈도우 시스템과 인터페이스 하기 위한 확장이필요. -> GLFW 에 필요한 확장기능을 가진 구조체를 리턴하는 편리한 내장함수가 있음. -> glfwGetRequiredInstanceExtension 으로 필요한 구조체 정보를 얻어 설정해주면 됨. |
Vulkan이 인스턴스를 생성하는데 모든것을 지정햇으면, vkCreateInstance호출을 최종적으로 실행할 수 있음
3. 1 VkApplicationInfo
typedef struct VkApplicationInfo{
VkStructureType sType;
const void* pNext;
const char* pApplicationName;
uint32_t applicationVersion;
const char* pEngineName;
uint32_t engineVersion;
uint32_t apiVersion;
} VkApplicationInfo;
인스턴스 를 만들려면 어플리케이션에대한 몇몇 정보를 알려줄 구조체를 작성해야함
- 해당 구조체의 데이터는 선택사항
- 하지만 그래픽 엔진이 특수 행동을 하는지 알려 드라이버에 특정 정보를 최적화하는데 유용한 정보를 제공할 수 있음
(e.g. because it uses a well-known graphics engine with certain special behavior).
VkApplicationInfo appInfo{};
appInfo.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO; // 해당 구조체 타입을 명시
appInfo.pApplicationName = "Hello Triangle"; // '\0' 으로 끝나는 문자열
appInfo.applicationVersion = VK_MAKE_VERSION(1, 0, 0); // 어플리케이션의 버전
appInfo.pEngineName = "No Engine"; //응용프로그램이 기반으로하는 엔진, 미들웨어
appInfo.engineVersion = VK_MAKE_VERSION(1, 0, 0); // 엔진, 미들웨어의 버전
appInfo.apiVersion = VK_API_VERSION_1_0; // vulkan api 버전. 절대적인 최소버전으로 설정
3.2 CreateInstance 전체 코드
void createInstance() {
/*
ApplicationInfo 구조체 초기화
*/
VkApplicationInfo appInfo{};
appInfo.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO;
appInfo.pApplicationName = "Hello Triangle";
appInfo.applicationVersion = VK_MAKE_VERSION(1, 0, 0);
appInfo.pEngineName = "No Engine";
appInfo.engineVersion = VK_MAKE_VERSION(1, 0, 0);
appInfo.apiVersion = VK_API_VERSION_1_0;
/*
createInfo 구조체의 초기화
*/
VkInstanceCreateInfo createInfo{};
createInfo.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO; // 타입을 명시
createInfo.pApplicationInfo = &appInfo; // 위에서 정의한 appinfo 구조체 포인터로 전달
/*
glfw에서 확장자 정보를 가져옴
*/
uint32_t glfwExtensionCount = 0;
const char** glfwExtensions;
glfwExtensions = glfwGetRequiredInstanceExtensions(&glfwExtensionCount);
createInfo.enabledExtensionCount = glfwExtensionCount;
createInfo.ppEnabledExtensionNames = glfwExtensions;
/*
레이어 설정 -> 지금은 0, name은 기본값이 nullptr인것같다.
*/
createInfo.enabledLayerCount = 0;
/*
모든것이 잘 되면 instance 에 대한 핸들이 VkInstance클래스 멤버에 저장됨.
거의 모든 Vulkan 함수는 VK_SUCCESS 또는 오류 코드인 VkResult유형의 값을 반환함.
인스턴스가 성공적으로 작성되었는지 확인하려면 반환 값이 성공인지 확인해야함.
*/
if (vkCreateInstance(&createInfo, nullptr, &instance) != VK_SUCCESS) {
throw std::runtime_error("failed to create instance!");
}
}
4. Checking for extension support -> ?>?
확장 기능은 플랫폼 독립적인 API인 경우 많이 쓰이는 것.
- 확장 기능을 활성화시키려면 명시적으로 알려줘야함.
- 오류 코드중 하나 VK_ERROR_EXTENSION_NOT_PRESENT
- 이 오류코드가 발생하면, 특정 확장 기능을 수정해서 오류를 없애야함.
vkEnumerateInstanceExtensionProperties
VkResult vkEnumerateInstanceExtensionProperties (
const char* pLayerName,
uint32_t* pPropertyCount,
VkExtensionProperties* pProperties);
- 지원되는 확장 목록을 검색하기 위한 함수
- 확장 기능의 수를 저장하는 변수에 대한 포인터와
- 확장 기능의 세부사항을 저장하는 VkExtensionProperties의 배열을 인수로 받음
- 특정 유효성 검사 레이어를 통해 확장을 필터링 할 수 있는 선택적인 첫 번째 매개변수가 있음
(여기선 무시하며 nullptr)
- 확장 기능 정보를 저장하기위해 배열을 할당하려면 먼저 얼마나 많은 배열이 있는지 알아야함.(최대치)
- 마지막 매개변수를 nullptr로 넘김으로써, 확장기능의 최대개수를 요청할 수 있음.
uint32_t extensionCount = 0;
vkEnumerateInstanceExtensionProperties(nullptr, &extensionCount, nullptr);
std::vector 를 사용해 VkExtensionProperties를 확장 기능의 개수만큼 배열을 생성.
std::vector<VkExtensionProperties> extensions(extensionCount);
확장 기능 세부정보에 대해 물어볼 수 있음
vkEnumerateInstanceExtensionProperties(nullptr, &extensionCount, extensions.data());
각 VkExtensionProperties 구조체에는 확장 기능의 이름과 버전이 들어있음.
- 간단히 for 루프를 통해 이들을 나열할 수 있음.
std::cout << "available extensions:\n";
for (const auto& extension : extensions) {
std::cout << '\t' << extension.extensionName << '\n';
}
vulkan 지원에 대한 몇가지 세부 정보를 제공하려는 경우 createInstance 함수(위에서 만든 멤버함수)에 추가할 수 있음.
As a challenge, try to create a function that checks if all of the extensions returned by glfwGetRequiredInstanceExtensions are included in the supported extensions list. (glfw에서 반환된 모든 확장 기능이, 지원되는 확장목록에 포함되어있는 함수인지 확인하는함수를 만들어봐라) |
glfw만 이용한 확장 방법
std::vector<const char*> getRequiredExtensions() {
uint32_t glfwExtensionCount = 0;
const char** glfwExtensions;
glfwExtensions = glfwGetRequiredInstanceExtensions(&glfwExtensionCount);
std::vector<const char*> extensions(glfwExtensions, glfwExtensions + glfwExtensionCount);
if (enableValidationLayers) {
extensions.push_back(VK_EXT_DEBUG_UTILS_EXTENSION_NAME);
}
return extensions;
}
createInstance 함수에서 createInfo를 설정할때 값을 넘겨주면된다.
auto extensions = getRequiredExtensions();
createInfo.enabledExtensionCount = static_cast<uint32_t>(extensions.size());
createInfo.ppEnabledExtensionNames = extensions.data()
5. Cleaning up
- VkInstance 는 오직 프로그램이 종료되기전에 제거해야함
- vkDestroyInstance 함수를 사용
- 매개변수는 간단, allocation and deallocation functions 은 추가적인 allcator callback 을 파라미터로 가짐
-> nullptr로 무시할 수 있다.
- 모든 Vk 리소스는 모두 인스턴스가 삭제되기전에 정리해야함.
- 이제 인스턴스 생성 후 보다 복잡한 단계를 계속하기 전에
-유효성 검사 레이어를 확인하여 디버깅 옵션을 평가해야함
it's time to evaluate our debugging options by checking out validation layers.
https://vulkan-tutorial.com/en/Drawing_a_triangle/Setup/Instance
https://openmynotepad.tistory.com/86?category=1020021
'그래픽스 > vk' 카테고리의 다른 글
[vk] Drawing triangle - setup - Logical device and queue (0) | 2021.08.06 |
---|---|
[vk] Drawing triangle - setup - Physical devices and queue (0) | 2021.08.06 |
[vk] Drawing triangle - setup - Validation layers (0) | 2021.08.05 |
[vk] Drawing triangle - setup - base code (0) | 2021.08.04 |
[vk] Vulkan Tutorial: 삼각형을 그리기 위한 단계 (0) | 2021.08.04 |