2019-10-16 14:02:00 -07:00
|
|
|
#include <iostream>
|
|
|
|
#include <vector>
|
|
|
|
|
|
|
|
#include <vulkan/vulkan.hpp>
|
|
|
|
|
|
|
|
const std::vector<const char*> validationLayers = {
|
2025-02-06 04:02:13 -08:00
|
|
|
"VK_LAYER_KHRONOS_validation"
|
2019-10-16 14:02:00 -07:00
|
|
|
};
|
|
|
|
#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<VkLayerProperties> 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;
|
|
|
|
}
|
|
|
|
|
2019-10-20 14:55:58 -07:00
|
|
|
// 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;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2019-10-16 14:02:00 -07:00
|
|
|
// 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<VkExtensionProperties> 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<VkPhysicalDevice> 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!");
|
|
|
|
}
|
|
|
|
}
|
2019-10-20 14:55:58 -07:00
|
|
|
|
|
|
|
void createLogicalDevice() {
|
|
|
|
uint32_t queueFamilyPropertiesCount = 0;
|
|
|
|
vkGetPhysicalDeviceQueueFamilyProperties(physicalDevice, &queueFamilyPropertiesCount, nullptr);
|
|
|
|
|
|
|
|
std::vector<VkQueueFamilyProperties> 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;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2019-10-16 14:02:00 -07:00
|
|
|
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();
|
2019-10-20 14:55:58 -07:00
|
|
|
createLogicalDevice();
|
2019-10-16 14:02:00 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
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;
|
2025-02-06 04:02:13 -08:00
|
|
|
}
|