#include #include #include const std::vector validationLayers = { "VK_LAYER_KHRONOS_validation" }; #ifdef NDEBUG const bool enableValidationLayers = false; #else const bool enableValidationLayers = true; #endif // Wrappers for extension functions that must be located using vkGetInstanceProcAddr VkResult CreateDebugReportCallbackEXT(VkInstance instance, const VkDebugReportCallbackCreateInfoEXT* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkDebugReportCallbackEXT* pCallback) { auto func = (PFN_vkCreateDebugReportCallbackEXT) vkGetInstanceProcAddr(instance, "vkCreateDebugReportCallbackEXT"); if(func != nullptr) { return func(instance, pCreateInfo, pAllocator, pCallback); } else { return VK_ERROR_EXTENSION_NOT_PRESENT; } } void DestroyDebugReportCallbackEXT(VkInstance instance, VkDebugReportCallbackEXT callback, const VkAllocationCallbacks* pAllocator) { auto func = (PFN_vkDestroyDebugReportCallbackEXT) vkGetInstanceProcAddr(instance, "vkDestroyDebugReportCallbackEXT"); if(func != nullptr) { func(instance, callback, pAllocator); } } class HelloVkCompute { private: /* data */ VkInstance instance; VkDebugReportCallbackEXT callback; VkPhysicalDevice physicalDevice; // Check if the validation layers are supported. bool checkValidationLayerSupport() { uint32_t layerCount; vkEnumerateInstanceLayerProperties(&layerCount, nullptr); std::vector availableLayers(layerCount); vkEnumerateInstanceLayerProperties(&layerCount, availableLayers.data()); for(const char* layerName : validationLayers) { bool layerFound = false; for(const auto& layerProperties : availableLayers) { if(strcmp(layerName, layerProperties.layerName) == 0) { layerFound = true; break; } } if(!layerFound) { return false; } } return true; } // Determine if the chosen physical device is suitable for our application. bool isDeviceSuitable(VkPhysicalDevice device) { VkPhysicalDeviceProperties deviceProperties; VkPhysicalDeviceFeatures deviceFeatures; vkGetPhysicalDeviceProperties(device, &deviceProperties); vkGetPhysicalDeviceFeatures(device, &deviceFeatures); std::cout << "Checking if device: " << deviceProperties.deviceName << " (id " << deviceProperties.deviceID << ") is suitable" << std::endl; return deviceFeatures.geometryShader; } // Set up our debug report callback to get information back from the validation layers. void setupDebugCallback() { if (!enableValidationLayers) return; VkDebugReportCallbackCreateInfoEXT createInfo = {}; createInfo.sType = VK_STRUCTURE_TYPE_DEBUG_REPORT_CALLBACK_CREATE_INFO_EXT; createInfo.flags = VK_DEBUG_REPORT_ERROR_BIT_EXT | VK_DEBUG_REPORT_WARNING_BIT_EXT; createInfo.pfnCallback = debugCallback; if(CreateDebugReportCallbackEXT(instance, &createInfo, nullptr, &callback) != VK_SUCCESS) { throw std::runtime_error("failed to setup debug callback!"); } } void cleanupDebugCallback() { if (!enableValidationLayers) return; DestroyDebugReportCallbackEXT(instance, callback, nullptr); } void initVulkan() { if(enableValidationLayers && !checkValidationLayerSupport()) { throw std::runtime_error("validation layers requested, but not supported"); } // Create VkApplicationInfo VkApplicationInfo appInfo = {}; appInfo.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO; appInfo.pApplicationName = "Hello Vk Compute"; 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; // Create VkInstanceCreateInfo and have it point to VkApplicationInfo VkInstanceCreateInfo createInfo = {}; createInfo.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO; createInfo.pApplicationInfo = &appInfo; // Enable the validation layers if they are requested if(enableValidationLayers) { createInfo.enabledLayerCount = validationLayers.size(); createInfo.ppEnabledLayerNames = validationLayers.data(); } else { createInfo.enabledLayerCount = 0; } if(vkCreateInstance(&createInfo, nullptr, &instance) != VK_SUCCESS) { throw std::runtime_error("failed to create Vulkan instance!"); } uint32_t extensionCount = 0; vkEnumerateInstanceExtensionProperties(nullptr, &extensionCount, nullptr); std::vector extensions(extensionCount); vkEnumerateInstanceExtensionProperties(nullptr, &extensionCount, extensions.data()); std::cout << "available extensions:" << std::endl; for(const auto& extension : extensions) { std::cout << "\t" << extension.extensionName << std::endl; } } void pickDevice() { uint32_t deviceCount = 0; vkEnumeratePhysicalDevices(instance, &deviceCount, nullptr); if(deviceCount == 0) { throw std::runtime_error("Failed to find a device with Vulkan support!"); } std::vector devices(deviceCount); vkEnumeratePhysicalDevices(instance, &deviceCount, devices.data()); for(const auto& device : devices) { if(isDeviceSuitable(device)) { physicalDevice = device; break; } } if(physicalDevice == VK_NULL_HANDLE) { throw std::runtime_error("Failed to find a suitable device!"); } } void createLogicalDevice() { uint32_t queueFamilyPropertiesCount = 0; vkGetPhysicalDeviceQueueFamilyProperties(physicalDevice, &queueFamilyPropertiesCount, nullptr); std::vector queueFamilyProperties(queueFamilyPropertiesCount); vkGetPhysicalDeviceQueueFamilyProperties(physicalDevice, &queueFamilyPropertiesCount, queueFamilyProperties.data()); for(auto queueFamProp : queueFamilyProperties) { if(queueFamProp.queueFlags & (VK_QUEUE_COMPUTE_BIT)) { std::cout << "Found queue with compute flag" << std::endl; } } } public: // our debug callback function, just prints the message from the Validation layer to stderr static VKAPI_ATTR VkBool32 VKAPI_CALL debugCallback( VkDebugReportFlagsEXT flags, VkDebugReportObjectTypeEXT objType, uint64_t obj, size_t location, int32_t code, const char* layerPrefix, const char* msg, void* userData) { std::cerr << "[Validation Layer]: " << msg << std::endl; return VK_FALSE; } void run() { initVulkan(); pickDevice(); createLogicalDevice(); } }; int main() { HelloVkCompute app; try { app.run(); } catch (const std::runtime_error& e) { std::cerr << e.what() << std::endl; return EXIT_FAILURE; } return EXIT_SUCCESS; }