본문 바로가기

Vulkan

Setup - Creating an instance

이전 글 : Drawing Triangle - Base code

다음 글 : Validation layers


Drawing Triangle - Creating an instance

인스턴스를 생성하기

가장 먼저 해야 할 일은 인스턴스를 생성하여 Vulkan 라이브러리를 초기화 하는 것입니다. 인스턴스는 응용 프로그램과 Vulkan 라이브러리 간의 연결이며 이를 작성하려면 응용 프로그램에 대한 세부 정보를 드라이버에 지정해야 합니다.


먼저 createInstace() 함수를 추가하고 initVulkan 함수에서 이 함수에 대한 호출을 추가 하십시오.

void initVulkan() {
   createInstance();
}


이전 장의 리소스 관리 섹션에서 작성한 클래스 멤버를 추가하여 인스턴스에 대한 핸들을 관리합니다.

private:
VkInstance instance;


vkDestroyInstance 함수는 잠시 후에 만들 인스턴스를 정리 합니다. 두 번째 매개 변수는 선택적이며 사용자 정의 할당자에 콜백을 지정할 수 있습니다. 대부분의 생성 및 소멸 함수에는 콜백 매개변수가 있으며 VDeleter 정의에서 볼 수 있듯이 항상 nullptr을 인수로 전달합니다.


이제 인스턴스를 만들려면 먼저 응용 프로그램에 대한 정보가 담긴 구조체를 작성해야 합니다. 이 데이터는 선택 사항이지만 그래픽 엔진이 어떤 특수 행동을 하는지 알려 드라이버에 특정 정보를 최적화 하는 데 유용한 정보를 제공 할 수 있습니다.

이 구조체는 VkApplicationinfo 라고 불립니다.

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;



앞서 언급했듯이 Vulkan의 많은 구조체는 sType멤버에 타입을 명시적으로 지정해야 합니다. 이는추가 확장 정보를 가리킬수 있는 pNext 멤버 또한 Vulkan의 많은 구조체에 존재합니다. 여기서는 nullptr로 남겨 둡니다.


Vulkan은 많은 정보는 함수 매개 변수 대신 구조체를 통해 전달되며 인스턴스를 만드는 데 필요한 충분한 정보를 제공하기 위해 하나 이상의 구조체를 채워야 합니다.

다음 구조체는 명시적으로 표현해야 하며, Vulkan 드라이버에게 사용할 전역 확장 및 유효성 계층을 알려줍니다. 여기서 global은 특정 프로그램이 아니며 전체 프로그램에 적용된다는 것을 의미 합니다.다음 챕터에서 다시 살펴 보겠습니다.

VkInstanceCreateInfo createInfo = {};
createInfo.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO;
createInfo.pApplicationInfo = &appInfo;


첫 번째 두 매개 변수는 간단합니다. 다음 두 개의 계층은 원하는 전역 확장을 정합니다. 개요 장에서 언급했듯이 Vulkan은 플랫폼에 무관 한 API로, 윈도우 시스템과 인터페이스 하기 위한 확장이 필요합니다. GLFW 구조체에 전달할 수 있는 확장 기능을 반환하는 편리한 기본 제공 함수가 있습니다


uint32_t glfwExtensionCount = 0;
const char** glfwExtensions;

glfwExtensions = glfwGetRequiredInstanceExtensions(&glfwExtensionCount);

createInfo.enabledExtensionCount = glfwExtensionCount;
createInfo.ppEnabledExtensionNames = glfwExtensions;


구조체의 마지막 두 멤버가 활성화 할 전역 유효성 검사 레이어를 결정합니다. 우리는 다음 장에서 이것들에 관해 더 자세히 이야기 할 것입니다, 그래서 그냥 비워 두십시오.


createInfo.enabledLayerCount = 0;


이제 Vulkan이 인스턴스를 생성하는 데 필요한 모든 것을 지정했으며 vkCreateInstance 호출을 최종적으로 실행할 수 있습니다.

VkResult result = vkCreateInstance(&createInfo, nullptr, &instance);


다음과 같이 Vulkan의 객체 생성 함수 매개변수가 따르는 일반적인 패턴은 다음과 같습니다.

• 생성 정보가 있는 구조체에 대한 포인터.

• 항상 사용자 정의 할당자 콜백에 대한 포인터, 이 튜토리얼 에서는 항상 nullptr입니다.

• 새 객체에 대한 핸들을 저장하는 변수의 포인터

모든 것이 잘 되면 인스턴스에 대한 핸들이 래핑된 VkInstance 클래스 멤버에 저장 됩니다. 거의 모든 Vulkan함수는 VK_SUCCESS또는 오류 코드인 VkResult 유형의 값을 반환합니다. 인스턴스가 성공적으로 작성되었는지 확인하려면 반환 값이 성공인지 확인 하십시오.

if (vkCreateInstance(&createInfo, nullptr, &instance) != VK_SUCCESS) {
   throw std::runtime_error("failed to create instance!");
}


이제 프로그램을 실행하여 인스턴스가 성공적으로 생성 되었는지 확인 하십시오.

Checking for extension support

확장 기능 지원 확인

만약 당신이 vkCreateInstance 문서를 봤다면 오류 코드 중 하나가 VK_ERROR_EXTIONSION_NOT_PRESENT 임을 알 수 있습니다. 오류 코드가 발생하면 필요한 특정 확장 기능을 요청하고 종료 할 수 있습니다.

윈도우 시스템 인터페이스와 같은 필수 확장 기능에 대해서는 의미가 있지만 옵션 기능을 확인하려면 어떻게 해야 할까요?

인스턴스를 만들기 전에 지원되는 확장 목록을 검색하려면 vkEnumerateInstanceExtensionProperties 함수가 있어야합니다. 확장 기능의 수를 저장하는 변수에 대한 포인터와 확장 기능의 세부 사항을 저장하는 VkExtentionProperties 의 배열을 인수로 받습니다.

또한 여기 에서는 특정 유효성 검사 레이어를 통해 확장을 필터링 할 수 있는 선택적인 첫 번째 매개 변수가 있습니다 그러나 여기에서는 무시 할 것 입니다. 확장 기능 정보를 저장하기 위해 배열을 할당하려면 먼저 얼마나 많은 배열이 있는지 알아야합니다. 후자의 매개 변수를 공백으로 남김으로써 확장 기능의 개수를 요청 할 수 있습니다.


uint32_t extensionCount = 0;
vkEnumerateInstanceExtensionProperties(nullptr, &extensionCount, nullptr);



이제 include<vector> 를 이용해 확장 기능의 개수만큼 배열을 생성합니다.

std::vector<VkExtensionProperties> extensions(extensionCount);


그리고 확장 기능 세부 정보에 대해 질의 할 수 있습니다

vkEnumerateInstanceExtensionProperties(nullptr, &extensionCount, extensions.data());



VkExtensionProperties 구조체 에는 확장 기능의 이름과 버전이 들어 있습니다. 간단히 for 루프를 통해 이들을 나열 할 수 있습니다.

std::cout << "available extensions:" << std::endl;

for (const auto& extension : extensions) {
   std::cout << "\t" << extension.extensionName << std::endl;
}


Vulkan 지원에 대한 몇 가지 세부 정보를 제공하려는 경우 createInstance 함수에 추가 할 수 있습니다. 문제는 glfwGetRequiredInstanceExtensions에 의해 반환 된 모든 확장이 지원되는 확장 목록에 포함 되어 있는지 확인하는 함수를 만들어 보십시오.


Cleaning up

정리하기

VkInstance는 프로그램이 종료되기 직전에 제거 되어야 합니다. 이는 vkDestroyInstance 함수로 제거 될 수 있습니다 :


void cleanup() {
   vkDestroyInstance(instance, nullptr);

   glfwDestroyWindow(window);

   glfwTerminate();
}


vkDestroyInstance 함수의 매개 변수는 간단 합니다. 이전 장에서 언급 했듯이 Vulkan의 할당 및 할당 해제 함수에는 nullptr을 전달하여 무시할 수 있습니다.

다음 장에서 작성할 다른 Vulkan 리소스는 모두 인스턴스가 삭제 되기 전에 정리 해야합니다.


이제 인스턴스 생성 후보다 복잡한 단계를 계속하기 전에 유효성 검사 레이어를 확인하여 디버깅 옵션을 평가할 차례입니다.




다음은 cpp 내용 입니다.


#define GLFW_INCLUDE_VULKAN
#include <GLFW/glfw3.h>

#include <iostream>
#include <stdexcept>

const int WIDTH = 800;
const int HEIGHT = 600;

class HelloTriangleApplication {
public:
   void run() {
       initWindow();
       initVulkan();
       mainLoop();
       cleanup();
   }

private:
   GLFWwindow* window;

   VkInstance instance;

   void initWindow() {
       glfwInit();

       glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API);
       glfwWindowHint(GLFW_RESIZABLE, GLFW_FALSE);

       window = glfwCreateWindow(WIDTH, HEIGHT, "Vulkan", nullptr, nullptr);
   }

   void initVulkan() {
       createInstance();
   }

   void mainLoop() {
       while (!glfwWindowShouldClose(window)) {
           glfwPollEvents();
       }
   }

   void cleanup() {
       vkDestroyInstance(instance, nullptr);

       glfwDestroyWindow(window);

       glfwTerminate();
   }

   void createInstance() {
       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;

       VkInstanceCreateInfo createInfo = {};
       createInfo.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO;
       createInfo.pApplicationInfo = &appInfo;

       uint32_t glfwExtensionCount = 0;
       const char** glfwExtensions;
       glfwExtensions = glfwGetRequiredInstanceExtensions(&glfwExtensionCount);

       createInfo.enabledExtensionCount = glfwExtensionCount;
       createInfo.ppEnabledExtensionNames = glfwExtensions;

       createInfo.enabledLayerCount = 0;

       if (vkCreateInstance(&createInfo, nullptr, &instance) != VK_SUCCESS) {
           throw std::runtime_error("failed to create instance!");
       }
   }
};

int main() {
   HelloTriangleApplication app;

   try {
       app.run();
   } catch (const std::runtime_error& e) {
       std::cerr << e.what() << std::endl;
       return EXIT_FAILURE;
   }

   return EXIT_SUCCESS;
}



이전 글 : Drawing Triangle - Base code

다음 글 : Validation layers


'Vulkan' 카테고리의 다른 글

Setup - Physical devices and queue families  (0) 2018.01.21
Setup - Validation layers  (0) 2018.01.21
Setup - Base code  (0) 2018.01.20
Development environment  (0) 2018.01.19
Overview  (0) 2018.01.19