Getting Started with Vulkan
The latest design of my OpenGL renderer using bindless textures has some problems, and although these can be resolved, I think I have hit the limit on how useful an initial OpenGL implementation will be for the new engine. I decided it was time to dive into the Vulkan API. This is sort of scary, because I feel like it sets me back quite a lot, but at the same time the work I do with this will carry forward much better. A Vulkan-based renderer can run on Windows, Linux, Mac, iOS, Android, PS4, and Nintendo Switch.
So far my impressions of the API are pretty good. Although it is very verbose, it gives you a lot of control over things that were previously undefined or vendor-specific hacks. Below is code that initializes Vulkan and chooses a rendering device, with a preference for discrete GPUs over integrated graphics.
VkInstance inst; VkResult res; VkDevice device; VkApplicationInfo appInfo = {}; appInfo.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO; appInfo.pApplicationName = "MyGame"; appInfo.applicationVersion = VK_MAKE_VERSION(1, 0, 0); appInfo.pEngineName = "TurboEngine"; appInfo.engineVersion = VK_MAKE_VERSION(1, 0, 0); appInfo.apiVersion = VK_API_VERSION_1_0; // Get extensions uint32_t extensionCount = 0; vkEnumerateInstanceExtensionProperties(nullptr, &extensionCount, nullptr); std::vector<VkExtensionProperties> availableExtensions(extensionCount); vkEnumerateInstanceExtensionProperties(nullptr, &extensionCount, availableExtensions.data()); std::vector<const char*> extensions; VkInstanceCreateInfo createInfo = {}; createInfo.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO; createInfo.pApplicationInfo = &appInfo; createInfo.enabledExtensionCount = (uint32_t)extensions.size(); createInfo.ppEnabledExtensionNames = extensions.data(); #ifdef DEBUG createInfo.enabledLayerCount = 1; const char* DEBUG_LAYER = "VK_LAYER_LUNARG_standard_validation"; createInfo.ppEnabledLayerNames = &DEBUG_LAYER; #endif res = vkCreateInstance(&createInfo, NULL, &inst); if (res == VK_ERROR_INCOMPATIBLE_DRIVER) { std::cout << "cannot find a compatible Vulkan ICD\n"; exit(-1); } else if (res) { std::cout << "unknown error\n"; exit(-1); } //Enumerate devices uint32_t gpu_count = 1; std::vector<VkPhysicalDevice> devices; res = vkEnumeratePhysicalDevices(inst, &gpu_count, NULL); if (gpu_count > 0) { devices.resize(gpu_count); res = vkEnumeratePhysicalDevices(inst, &gpu_count, &devices[0]); assert(!res && gpu_count >= 1); } //Sort list with discrete GPUs at the beginning std::vector<VkPhysicalDevice> sorteddevices; for (int n = 0; n < devices.size(); n++) { VkPhysicalDeviceProperties deviceprops = VkPhysicalDeviceProperties{}; vkGetPhysicalDeviceProperties(devices[n], &deviceprops); if (deviceprops.deviceType == VkPhysicalDeviceType::VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU) { sorteddevices.insert(sorteddevices.begin(),devices[n]); } else { sorteddevices.push_back(devices[n]); } } devices = sorteddevices; VkDeviceQueueCreateInfo queue_info = {}; unsigned int queue_family_count; for (int n = 0; n < devices.size(); ++n) { vkGetPhysicalDeviceQueueFamilyProperties(devices[n], &queue_family_count, NULL); if (queue_family_count >= 1) { std::vector<VkQueueFamilyProperties> queue_props; queue_props.resize(queue_family_count); vkGetPhysicalDeviceQueueFamilyProperties(devices[n], &queue_family_count, queue_props.data()); if (queue_family_count >= 1) { bool found = false; for (int i = 0; i < queue_family_count; i++) { if (queue_props[i].queueFlags & VK_QUEUE_GRAPHICS_BIT) { queue_info.queueFamilyIndex = i; found = true; break; } } if (!found) continue; float queue_priorities[1] = { 0.0 }; queue_info.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO; queue_info.pNext = NULL; queue_info.queueCount = 1; queue_info.pQueuePriorities = queue_priorities; VkDeviceCreateInfo device_info = {}; device_info.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO; device_info.pNext = NULL; device_info.queueCreateInfoCount = 1; device_info.pQueueCreateInfos = &queue_info; device_info.enabledExtensionCount = 0; device_info.ppEnabledExtensionNames = NULL; device_info.enabledLayerCount = 0; device_info.ppEnabledLayerNames = NULL; device_info.pEnabledFeatures = NULL; res = vkCreateDevice(devices[n], &device_info, NULL, &device); if (res == VK_SUCCESS) { VkPhysicalDeviceProperties deviceprops = VkPhysicalDeviceProperties{}; vkGetPhysicalDeviceProperties(devices[n], &deviceprops); std::cout << deviceprops.deviceName; vkDestroyDevice(device, NULL); break; } } } } vkDestroyInstance(inst, NULL);
- 3
- 1
9 Comments
Recommended Comments