일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | 5 | 6 | 7 |
8 | 9 | 10 | 11 | 12 | 13 | 14 |
15 | 16 | 17 | 18 | 19 | 20 | 21 |
22 | 23 | 24 | 25 | 26 | 27 | 28 |
29 | 30 | 31 |
- C++
- 혼공머신
- OpenGL
- 책리뷰
- 한빛미디어
- 혼공스
- 자바스크립트
- 벌칸
- 머신러닝
- 딥러닝
- 컴퓨터그래픽스
- vulkan
- 혼공단5기
- 혼자공부하는C언어
- 혼공학습단
- tutorial
- 혼공단
- 데이터분석
- 혼공
- 파이썬
- 혼공S
- 제이펍
- 혼공네트
- 네트워크
- 불칸
- 혼공컴운
- 혼자공부하는네트워크
- 리뷰리뷰
- 혼공C
- 나는리뷰어다
- Today
- Total
Scientia Conditorium
[Vulkan005][번역] Vulkan Tutorial - 삼각형 그리기 인스턴스(Drawing a triangle - Instance) 본문
[Vulkan005][번역] Vulkan Tutorial - 삼각형 그리기 인스턴스(Drawing a triangle - Instance)
크썸 2023. 11. 19. 20:19원문 : https://vulkan-tutorial.com/Drawing_a_triangle/Setup/Instance
[Vulkan005][번역] Vulkan Tutorial - 삼각형 그리기 인스턴스(Drawing a triangle - Instance)
인스턴스 만들기(Creating an instance)
가장 먼저 해야할 일은 인스턴스를 생성하여 Vulkan 라이브러리를 초기화하는 것입니다. 인스턴스는 응용 프로그램과 Vulkan 라이브러리간의 연결이며, 인스턴스를 생성하려면 드라이버에 응용 프로그램에 대한 몇 가지 세부 정보를 지정해야 합니다.
먼저 CreateInstance 함수를 추가하고 initVulkan 함수에서 호출합니다.
void initVulkan() {
createInstance();
}
인스턴스에 핸들을 보유할 데이터 멤버를 추가합니다.
private:
VkInstance instance;
이제 인스턴스를 생성하려면 먼저 응용 프로그램에 대한 몇 가지 정보로 구조체를 채워야 합니다. 이 데이터는 기술적으로 선택 사항이지만 특정 애플리케이션을 최적화하기 위해 드라이버에 유용한 정보를 제공할 수 있습니다. 예를 들어 특정 특수 동작이 있는 잘 알려진 그래픽 엔진을 사용하기 위해서). 이 구조체를 VkApplicationInfo 라고 합니다.
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;
}
앞서 언근했듯이, Vulkan의 많은 구조체에서는 sType 멤버 유형을 명시적으로 지정해야 합니다. 이 구조체도 나중에 확장 정보를 가리킬 수 있는 pNext 멤버가 있는 많은 구조체 중 하나입니다. 여기서는 초기값을 nullptr 로 남겨두겠습니다.(구조체 생성시 {} 해주면 포인터의 경우 nullptr로 초기화됩니다)
Vulkan의 많은 정보는 함수 매개변수 대신 구조체를 통해 전달되며 인스턴스 생성을 위한 충분한 정보를 제공하기 위해 구조체를 하나 더 채워야 합니다. 이 다음 구조체는 선택 사항이 아니며 Vulkan 드라이버에 사용할 전역 확장 및 유효성 검사 레이어를 알려줍니다. 여기서 전역이란 특정 장치가 아닌 프로그램 전체에 적용된다는 의미이며, 이는 다음 몇 챕터에서 명확해질 것입니다.
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!");
}
이제 프로그램을 실행하여 인스턴스가 성공적으로 생성되었는지 확인합니다.
VK_ERROR_INCOMPATIBLE_DRIVER가 발생했을 때
최신 MoltenVK sdk와 함께 MacOS를 사용하는 경우, vkCreateInstance 에서 VK_ERROR_INCOMPATIBLE_DRIVER 가 반환될 수 있습니다. lunarg 홈페이지의 macOS에서 Vulkan SDK 시작하기 페이지를 참고하면, 1.3.216 Vulkan SDK부터 VK_KHR_PORTABILITY_subset 확장은 필수입니다.
이 오류를 해결하려면 먼저 VkInstanceCreateInfo 구조체의 플래그에 VK_INSTANCE_CREATE_ENUMERATE_PORTABILITY_BIT_KHR 비트를 추가한 다음 인스턴스 활성화 확장자 목록에 VK_KHR_PORTABILITY_ENUMERATION_EXTENSION_NAME 을 추가합니다.
일반적인 코드는 다음과 같습니다.
...
std::vector<const char*> requiredExtensions;
for(uint32_t i = 0; i < glfwExtensionCount; i++) {
requiredExtensions.emplace_back(glfwExtensions[i]);
}
requiredExtensions.emplace_back(VK_KHR_PORTABILITY_ENUMERATION_EXTENSION_NAME);
createInfo.flags |= VK_INSTANCE_CREATE_ENUMERATE_PORTABILITY_BIT_KHR;
createInfo.enabledExtensionCount = (uint32_t) requiredExtensions.size();
createInfo.ppEnabledExtensionNames = requiredExtensions.data();
if (vkCreateInstance(&createInfo, nullptr, &instance) != VK_SUCCESS) {
throw std::runtime_error("failed to create instance!");
}
확장판 지원 확인(Checking for extension support)
vkCreateInstance 문서를 보면 가능한 오류 코드 중 하나가 VK_ERROR_EXTENSION_NOT_PRESENT 라는 것을 알 수 있습니다. 필요한 확장을 지정하고 해당 오류 코드가 다시 발생했을 때 종료하면 됩니다. 이 방법은 창 시스템 인터페이스와 같은 필수 확장 기능에는 적합하지만, 선택적 기능을 확인하려면 어떻게 해야 할까요?
인스턴스를 생성하기 전에 지원되는 확장 목록을 검색하려면 vkEnumerateInstanceExtensionProperties 함수가 있습니다. 이 함수는 확장 기능의 수를 저장하는 변수에 대한 포인터와 확장 기능의 세부 정보를 저정하는 VkExtensionProperties 배열을 받습니다. 또한 특정 유효성 검사 계층을 기준으로 확장을 필터링할 수 있는 선택적 첫 번째 매개변수가 필요하지만 지금은 무시하겠습니다.
확장자 세부 정보를 저장할 배열을 할당하려면 먼저 확장자 수가 몇 개인지 알아야 합니다. 후자의 매개변수를 비워두면 확장자 수만 요청할 수 있습니다.
uint32_t extensionCount = 0;
vkEnumerateInstanceExtensionProperties(nullptr, &extensionCount, nullptr);
이제 확장자 세부 정보를 담을 배열을 할당합니다.(#include <vector>)
std::vector<VkExtensionProperties> extensions(extensionCount);
마지막으로 확장자 세부 정보를 쿼리할 수 있습니다.(쿼리한다라는 말이 자주 나오는데, 쉽게 생각해서 어떤 데이터베이스에 또는 데이터 저장소에 정보를 요청하여 받아온다라고 생각하시면 됩니다.)
vkEnumerateInstanceExtensionProperties(nullptr, &extensionCount, extensions.data());
각 VkExtensionProperties 구조체에는 확장의 이름과 버전이 포함되어 있습니다. 간단한 for문(\t는 들여쓰기를 위한 탭)로 나열할 수 있습니다.
std::cout << "available extensions:\n";
for (const auto& extension : extensions) {
std::cout << '\t' << extension.extensionName << '\n';
}
Vulkan 지원에 대한 세부 정보를 제공하려는 경우 이 코드를 createInstance 함수에 추가할 수 있습니다. 도전 과제로 glfwGetRequiredInstanceExtensions 가 반환한 모든 확장이 지원되는 확장 목록에 포함되는지 확인하는 함수를 만들어 보세요.
정리(Cleaning up)
프로그램이 종료되기 직전에만 VkInstance 를 삭제해야 합니다. vkDestoryInstance 함수를 사용하여 cleanup 에서 삭제할 수 있습니다.
void cleanup() {
vkDestroyInstance(instance, nullptr);
glfwDestroyWindow(window);
glfwTerminate();
}
vkDestroyInstance 함수의 매개변수는 간단합니다. 이전 장에서 언급했듯이 Vulkan의 할당 및 해제 함수에는 선택적 할당자 콜백이 있는데, 이 콜백에 nullptr을 전달하면 무시할 수 있습니다. 다음 장에서 생성할 다른 모든 Vulkan 리소스는 인스턴스가 소멸되기 전에 정리해야 합니다.
인스턴스 생성 후 더 복잡한 단계를 계속하기 전에 유효성 검사 계층을 확인하여 디버깅 옵션을 평가할 차례입니다.
이번 장의 전체 코드는 아래 페이지에서 확인할 수 있습니다.
주인장 코드
작성 중
'프로그래밍 > 컴퓨터 그래픽스' 카테고리의 다른 글
[Vulkan][오류] VUID-vkGetDeviceQueue-queueFamilyIndex 오류 (1) | 2023.12.02 |
---|---|
[Vulkan][오류] Validation Error : VUIT-vkDestroyInstance 오류 (0) | 2023.11.29 |
[Vulkan004][번역] Vulkan Tutorial - 삼각형 그리기 기본 코드(Drawing a triangle - Base code) (0) | 2023.11.18 |
[Vulkan003][번역] Vulkan Tutorial - 개발 환경(Development environment) (0) | 2023.11.14 |
[Vulkan002][번역] Vulkan Tutorial - 개요(Overview) (0) | 2023.11.12 |