⭐ Vulkan & CMake/Vulkan

[Vulkan] Vulkan Instance

Designerd 2024. 8. 2. 11:47

 

 

 

목차

     

     



    인프런 삼각형님의 '삼각형의 실전! Vulkan 중급' 강의를 참고하였습니다. 

    😎 [삼각형의 실전! Vulkan 중급] 강의 들으러 가기!

     

     

    Vulkan Instance


     

     

    Vulkan Instance란?

     

    Vulkan Instance는 Vulkan API를 사용하기 위해 필요한 객체다. (OpenGL의 컨텍스트와 같은 레벨으로 봐도 된다)

     

    • 어플리케이션Vulkan 드라이버 간의 연결초기화하고 관리한다.
    • 사용할 Instance Layer를 정의한다.
    • 사용할 Instance Extension을 정의한다.
    • 어플리케이션 정보를 Vulkan 드라이버에 제공한다.  

     

    Vulkan Instance를 통해 Vulkan Loader를 설정한다!


     

     

    Vulkan Instance 생성

     

     

     

    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;

     

    멤버 변수  설명 
      sType   구조체의 타입
      pNext  NULL 또는 확장 기능 구조체의 포인터

    < sType이 필요한 이유 >
     -  const void* 형이기 때문에 Vulkan Driver는 주소가 가지고 있는 구조체가 어떤 구조체인지 알지 못한다. 어떤 구조체인지는 sType을 통해 알 수 있다.
      flags  지금은 사용X
      pApplicationInfo  (어플리케이션의 정보를 정의한) VkApplicationInfo 변수의 주소
    -  Vulkan Driver에게 어플리케이션 정보를 보내고 싶지 않으면 Null 값을 넣으면 된다. 
      enabledLayerCount  활성화할 Layer의 개수
      ppEnabledLayerNames   활성화할 Layer 이름 배열의 포인터
      enabledExtensionCount  활성화할 Extension의 개수
      ppEnabledExtensionNames  활성화할 Extension 이름 배열의 포인터

     

    enabledLayerNames와 ppEnabledLayerNames를 통해 사용하려는 Layer를 정의한다. 

    enabledExtensionCount와 ppEnabledExtensionNames를 통해 사용하려는 Extension을 정의한다. 


     

     

    어플리케이션 정보 넘기기

     

    typedef struct VkApplicationInfo {
         VkStructureType sType;
         const void* pNext;
         const char* pApplicationName;
         uint32_t applicationVersion;
         const char* pEngineName;
         uint32_t engineVersion;
         uint32_t apiVersion;
    } VkApplicationInfo;

     

    멤버 변수  설명 
      sType   구조체의 타입
      pNext  NULL 또는 확장 기능 구조체의 포인터
      pApplicationName  어플리케이션 이름 변수의 포인터
      applicationVerion  어플리케이션 버전
      pEngineName   엔진 이름 변수의 포인터
      engineVersion  엔진의 버전
      apiVersion  사용하는 Vulkan 버전

     

    Vulkan Driver는 pApplicationName, applicationVersion 정보를 사용해서 원하는 어플리케이션에만 적용되는 패치를 적용할 수 있다.  (ex. 드라이버 릴리즈 노트에 특정 게임의 성능을 향상했다는 글이 대표적인 예다. 일반적으로 성능 향상 패치는 모두에게 적용하기 어렵다. )

     

    Vulkan Driver는 pEngineName, engineVersion 정보를 사용해서 특정 엔진에만 적용되는 패치를 적용할 수 있다. 

     


     

     

    사용할 Instance Layer 설정

     

    이 벡터가 VkInstanceCreateInfo에 사용된다.

     


     

     

    Vulkan Instance 생성

     

    VkResult vkCreateInstance(
         const VkInstanceCreateInfo* pCreateInfo,
         const VkAllocationCallbacks* pAllocator,
         VkInstance* pInstance);

     

    매개 변수  설명 
     pCreateInfo   VkInstanceCreateInfo 변수의 포인터
     pAllocator  일단 NULL을 사용. (나중에 다루는 방법을 찾아보자)
     pInstance  VkInstance 변수의 포인터 (생성된 Vulkan Instance가 pInstance에 쓰여진다)

     

    Vulkan Instance는 vkCreateInstance로 생성할 수 있다.

     


     

     

    Vulkan Instance 파괴

     

    void vkDestroyInstance(
         VkInstance instance,
         const VkAllocationCallbacks* pAllocator);

     

    매개 변수  설명 
     instance  VkInstance
     pAllocator  일단 NULL을 사용. (나중에 다루는 방법을 찾아보자)

     


     

     

    코드

     

    // MIT License
    //
    // Copyright (c) 2024 Daemyung Jang
    //
    // Permission is hereby granted, free of charge, to any person obtaining a copy
    // of this software and associated documentation files (the "Software"), to deal
    // in the Software without restriction, including without limitation the rights
    // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
    // copies of the Software, and to permit persons to whom the Software is
    // furnished to do so, subject to the following conditions:
    //
    // The above copyright notice and this permission notice shall be included in all
    // copies or substantial portions of the Software.
    //
    // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
    // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
    // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
    // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
    // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
    // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
    // SOFTWARE.
    
    #include <cassert>
    #include <array>
    #include <vector>
    
    #include "VkRenderer.h"
    #include "VkUtil.h"
    #include "AndroidOut.h"
    using namespace std;
    
    VkRenderer::VkRenderer() {
    
        // VkApplicationInfo 구조체 정의
        VkApplicationInfo applicationInfo{
            .sType = VK_STRUCTURE_TYPE_APPLICATION_INFO,
            .pApplicationName = "Practice Vulkan",
            .applicationVersion = VK_MAKE_API_VERSION(0, 0, 1, 0),
            .apiVersion = VK_MAKE_API_VERSION(0, 1, 3, 0)
        };
    
        // 사용할 수 있는 레이어를 얻어온다.
        uint32_t instanceLayerCount;
        VK_CHECK_ERROR(vkEnumerateInstanceLayerProperties(&instanceLayerCount, nullptr));
    
        vector<VkLayerProperties> instanceLayerProperties(instanceLayerCount);
        VK_CHECK_ERROR(vkEnumerateInstanceLayerProperties(&instanceLayerCount,
                                                          instanceLayerProperties.data()));
    
        // 활성화할 레이어의 이름을 배열로 만든다.
        vector<const char*> instanceLayerNames;
        for (const auto &layerProperty : instanceLayerProperties) {
            instanceLayerNames.push_back(layerProperty.layerName);
        }
    
        // sType: 구조체의 타입, pApplicationInfo: 어플리케이션의 이름
        // enabledLayerCount, ppEnableLayerNames: 사용할 레이어의 정보를 정의
        VkInstanceCreateInfo instanceCreateInfo{
            .sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO,
            .pApplicationInfo = &applicationInfo,
            .enabledLayerCount = static_cast<uint32_t>(instanceLayerNames.size()),
            .ppEnabledLayerNames = instanceLayerNames.data()
        };
    
        // vkCreateInstance로 인스턴스 생성. 생성된 인스턴스가 mInstance에 쓰여진다.
        VK_CHECK_ERROR(vkCreateInstance(&instanceCreateInfo, nullptr, &mInstance));
    }
    
    VkRenderer::~VkRenderer() {
        vkDestroyInstance(mInstance, nullptr);
    }