⭐ Vulkan & CMake/Vulkan

[Vulkan] Vulkan Physical device

Designerd 2024. 8. 2. 12:45

 

 

목차

     

     


     

     

    Vulkan Physical device


     

     

    Vulkan Physical device란?

     

    Vulkan Physical device는 보통 GPU를 말한다.

     

    개발자는 Vulkan Physical device를 통해서 어떤 GPU로 Vulkan을 실행시킬지 결정할 수 있다.  OpenGL과 달리 Vulkan은 개발자가 어플리케이션에 더 적합한 GPU를 선택할 수 있다.

     


     

     

    GPU가 2개 이상인 경우

     

    컴퓨터에 Intel GPU와 NVIDIA GPU가 탑재되어 있는 경우가 많다.

    성능이 중요하다면 NVIDIA GPU를 사용하고 전력 소비량이 중요하면 Intel GPU를 사용하게 된다. 상황에 따라 둘 다 사용하게 설정할 수도 있다.   

     

    데스크탑이나 워크스테이션의 경우 여러개의 GPU를 장착할 수 있다. 이 때, 어플리케이션이 어떤 GPU에서 동작할지 결정할 수 있다. 또한, 개발자가 몇 개의 GPU를 사용할지 결정할 수 있다.


     

     

    Vulkan Physical device 얻기

     

    VkResult vkEnumeratePhysicalDevices(
         VkInstance instance,
         uint32_t* pPhysicalDeviceCount,
         VkPhysicalDevice* pPhysicalDevices);

     

    매개 변수  설명 
     instance VkInstance
     pPhysicalDeviceCount 사용할 수 있는 VkPhysicalDevice의 개수를 얻는데 사용되거나, 얻으려는 VkPhysicalDevice의 개수를 정의한 변수의 포인터
     pPhysicalDevices  사용할 수 있는 VkPhysicalDevice의 개수를 얻기 위해서는 NULL 포인터이어야 하고,
    VkPhysicalDevice를 얻기 위해선 VkPhysicalDevice 배열의 포인터이어야 한다.

     

     

     

     

    void vkGetPhysicalDeviceProperties(
         VkPhysicalDevice physicalDevice,
         VkPhysicalDeviceProperties* pProperties);

     

    매개 변수  설명 
     physicalDevice    VkPhysicalDevice
     pProperties   VkPhysicalDeviceProperties 변수의 포인터

     


     

     

    VkPhysicalDeviceProperties 구조체

     

    typedef struct VkPhysicalDeviceProperties {
         uint32_t apiVersion;
         uint32_t driverVersion;
         uint32_t vendorID;
         uint32_t deviceID;
         VkPhysicalDeviceType deviceType;
         char deviceName[VK_MAX_PHYSICAL_DEVICE_NAME_SIZE];
         uint8_t pipelineCacheUUID[VK_UUID_SIZE];
         VkPhysicalDeviceLimits limits;
         VkPhysicalDeviceSparseProperties sparseProperties;
    } VkPhysicalDeviceProperties;

     

    매개 변수  설명 
     apiVersion  VkPhysicalDevice가 지원하는 벌칸 API의 버전
     driverVersion  Vulkan 드라이버 버전
     venderID  벤더 아이디 (=제조사 아이디)
     deviceID  Vulkan Physical device의 아이디
     deviceType  Vulkan Physical device의 타입
     deviceName  Vulkan Physical device의 이름
     pipelineCacheUUID  
     limits  Vulkan Physical device의 사양이 담김 (GPU의 메모리, 코어의 개수, Hz 등)
     sparseProperties  

     


     

     

    코드

     

    #include <cassert>
    #include <array>
    #include <vector>
    #include <iomanip>
    
    #include "VkRenderer.h"
    #include "VkUtil.h"
    #include "AndroidOut.h"
    
    using namespace std;
    
    VkRenderer::VkRenderer() {
        // ================================================================================
        // 1. VkInstance 생성
        // ================================================================================
        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);
        }
    
        VkInstanceCreateInfo instanceCreateInfo{
                .sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO,
                .pApplicationInfo = &applicationInfo,
                .enabledLayerCount = static_cast<uint32_t>(instanceLayerNames.size()),
                .ppEnabledLayerNames = instanceLayerNames.data()
        };
    
        VK_CHECK_ERROR(vkCreateInstance(&instanceCreateInfo, nullptr, &mInstance));
    
        // ================================================================================
        // 2. VkPhysicalDevice 선택
        // ================================================================================
        uint32_t physicalDeviceCount;
        VK_CHECK_ERROR(vkEnumeratePhysicalDevices(mInstance, &physicalDeviceCount, nullptr));
    
        vector<VkPhysicalDevice> physicalDevices(physicalDeviceCount);
        VK_CHECK_ERROR(vkEnumeratePhysicalDevices(
                mInstance, &physicalDeviceCount, physicalDevices.data()));
    
        // 간단한 예제를 위해 첫 번째 VkPhysicalDevice를 사용
        mPhysicalDevice = physicalDevices[0];
    
        VkPhysicalDeviceProperties physicalDeviceProperties; // 이 구조체 안에 GPU에 필요한 모든 정보가 있다.
        vkGetPhysicalDeviceProperties(mPhysicalDevice, &physicalDeviceProperties);
    
        aout << "Selected Physical Device Information ↓" << endl;
        aout << setw(16) << left << " - Device Name: "
             << string_view(physicalDeviceProperties.deviceName) << endl;
        aout << setw(16) << left << " - Device Type: "
             << vkToString(physicalDeviceProperties.deviceType) << endl;
        aout << std::hex;
        aout << setw(16) << left << " - Device ID: " << physicalDeviceProperties.deviceID << endl;
        aout << setw(16) << left << " - Vendor ID: " << physicalDeviceProperties.vendorID << endl;
        aout << std::dec;
        aout << setw(16) << left << " - API Version: "
             << VK_API_VERSION_MAJOR(physicalDeviceProperties.apiVersion) << "."
             << VK_API_VERSION_MINOR(physicalDeviceProperties.apiVersion);
        aout << setw(16) << left << " - Driver Version: "
             << VK_API_VERSION_MAJOR(physicalDeviceProperties.driverVersion) << "."
             << VK_API_VERSION_MINOR(physicalDeviceProperties.driverVersion);
    }
    
    VkRenderer::~VkRenderer() {
        vkDestroyInstance(mInstance, nullptr);
    }