vulakn教程--Drawing a Triangle--Set up--Logical Device
2016-09-05 22:53
387 查看
原文链接 : Vulakn-tutorial
声明 :
我们不打算使例子太复杂,特性(fetures)采用默认值Vk_FALSE,当我们想做一些更有趣的事情的时候,可以再回过头来修改。
首先,我们来看一个和队列有关的,一个很重要的结构体
说明 : flags 保留未来使用(reserved for future use),后面3个参数表示,创建queueCount个queueFamilyIndex类型的队列,每个队列的优先级用pQueuePriorities数组表示。优先级的值为0.0~1.0 , 值越大优先级越高。
填充 :
像创建其他Vulkan对象一样,必不可少的是Vk_XXX_CreateInfo结构体,这次我们需要
说明: 该结构除了对队列(queue)和特性(features)支持的限定外,还有对Validation layers 和 Extensions的限定,例如一个很重要的extension :
这里enableValidationLayers和validationLayers直接取自创建VkInstances时已有的定义。
我们在VkDeviceCreateInfo 里定义的队列(queue 类型为VkQueue)将会随着logical device 一同被创建。那么我们怎么获得这个队列的句柄(handle)呢 ?
参数说明 :
源码:
Logical Device
只有Physical Device 还不行,我们还需要创建Logical Device 来与它相联。Logical Device的创建和VkInstance的创建过程差不多,需要明确我们所需的特性(features)、extensions、Validation layers 、queue等。
声明 :
VDeleter<VkDevice> device{vkDestroyDevice};
我们不打算使例子太复杂,特性(fetures)采用默认值Vk_FALSE,当我们想做一些更有趣的事情的时候,可以再回过头来修改。
VkPhysicalDeviceFeatures deviceFeatures = {};
首先,我们来看一个和队列有关的,一个很重要的结构体
VkDeviceQueueCreateInfo:
typedef struct VkDeviceQueueCreateInfo { VkStructureType sType; const void* pNext; VkDeviceQueueCreateFlags flags; uint32_t queueFamilyIndex; uint32_t queueCount; const float* pQueuePriorities; } VkDeviceQueueCreateInfo;
说明 : flags 保留未来使用(reserved for future use),后面3个参数表示,创建queueCount个queueFamilyIndex类型的队列,每个队列的优先级用pQueuePriorities数组表示。优先级的值为0.0~1.0 , 值越大优先级越高。
填充 :
QueueFamilyIndices indices = findQueueFamilies(physicalDevice); VkDeviceQueueCreateInfo queueCreateInfo = {}; queueCreateInfo.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO; queueCreateInfo.queueFamilyIndex = indices.graphicsFamily; queueCreateInfo.queueCount = 1; //创建一个队列 float queuePriority = 1.0f; queueCreateInfo.pQueuePriorities = &queuePriority;
像创建其他Vulkan对象一样,必不可少的是Vk_XXX_CreateInfo结构体,这次我们需要
VkDeviceCreateInfo:
typedef struct VkDeviceCreateInfo { VkStructureType sType; const void* pNext; VkDeviceCreateFlags flags;//(future use) uint32_t queueCreateInfoCount; const VkDeviceQueueCreateInfo* pQueueCreateInfos; uint32_t enabledLayerCount; const char* const* ppEnabledLayerNames; uint32_t enabledExtensionCount; const char* const* ppEnabledExtensionNames; const VkPhysicalDeviceFeatures* pEnabledFeatures; } VkDeviceCreateInfo;
说明: 该结构除了对队列(queue)和特性(features)支持的限定外,还有对Validation layers 和 Extensions的限定,例如一个很重要的extension :
VK_KHR_swapchain支持,同样,我们不想把问题复杂化,正如在创建
VkInstance时定义的那样,我们直接将那时定义的layers 和 extensions应用到这里,所不同的是现在是创建VkDevice阶段。
VkDeviceCreateInfo createInfo = {}; createInfo.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO; createInfo.pQueueCreateInfos = &queueCreateInfo; createInfo.queueCreateInfoCount = 1; createInfo.pEnabledFeatures = &deviceFeatures; createInfo.enabledExtensionCount = 0; //暂时不使用扩展 if (enableValidationLayers) { createInfo.enabledLayerCount = validationLayers.size(); createInfo.ppEnabledLayerNames = validationLayers.data(); } else { createInfo.enabledLayerCount = 0; } //创建logical device if (vkCreateDevice(physicalDevice, &createInfo, nullptr, &device) != VK_SUCCESS) { throw std::runtime_error("failed to create logical device!"); }
这里enableValidationLayers和validationLayers直接取自创建VkInstances时已有的定义。
我们在VkDeviceCreateInfo 里定义的队列(queue 类型为VkQueue)将会随着logical device 一同被创建。那么我们怎么获得这个队列的句柄(handle)呢 ?
VkQueue graphicsQueue; vkGetDeviceQueue(device, indices.graphicsFamily, 0, &graphicsQueue);
参数说明 :
device: logical device.
indices.graphicsFamily: 队列种类。
queueIndex: 这里是 0 ,因为我们只创建了一个队列,所以这里索引为0.
VkQueue *:
&graphicsQueue。
源码:
#define GLFW_INCLUDE_VULKAN #include <GLFW/glfw3.h> #include <iostream> #include <stdexcept> #include <functional> #include <vector> #include <cstring> const int WIDTH = 800; const int HEIGHT = 600; const std::vector<const char*> validationLayers = { "VK_LAYER_LUNARG_standard_validation" }; #ifdef NDEBUG const bool enableValidationLayers = false; #else const bool enableValidationLayers = true; #endif 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); } } template <typename T> class VDeleter { public: VDeleter() : VDeleter([](T, VkAllocationCallbacks*) {}) {} VDeleter(std::function<void(T, VkAllocationCallbacks*)> deletef) { this->deleter = [=](T obj) { deletef(obj, nullptr); }; } VDeleter(const VDeleter<VkInstance>& instance, std::function<void(VkInstance, T, VkAllocationCallbacks*)> deletef) { this->deleter = [&instance, deletef](T obj) { deletef(instance, obj, nullptr); }; } VDeleter(const VDeleter<VkDevice>& device, std::function<void(VkDevice, T, VkAllocationCallbacks*)> deletef) { this->deleter = [&device, deletef](T obj) { deletef(device, obj, nullptr); }; } ~VDeleter() { cleanup(); } T* operator &() { cleanup(); return &object; } operator T() const { return object; } private: T object{VK_NULL_HANDLE}; std::function<void(T)> deleter; void cleanup() { if (object != VK_NULL_HANDLE) { deleter(object); } object = VK_NULL_HANDLE; } }; struct QueueFamilyIndices { int graphicsFamily = -1; bool isComplete() { return graphicsFamily >= 0; } }; class HelloTriangleApplication { public: void run() { initWindow(); initVulkan(); mainLoop(); } private: GLFWwindow* window; VDeleter<VkInstance> instance{vkDestroyInstance}; VDeleter<VkDebugReportCallbackEXT> callback{instance, DestroyDebugReportCallbackEXT}; VDeleter<VkSurfaceKHR> surface{instance, vkDestroySurfaceKHR}; VkPhysicalDevice physicalDevice = VK_NULL_HANDLE; VDeleter<VkDevice> device{vkDestroyDevice}; VkQueue graphicsQueue; void initWindow() { glfwInit(); glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API); glfwWindowHint(GLFW_RESIZABLE, GLFW_FALSE); window = glfwCreateWindow(WIDTH, HEIGHT, "Vulkan", nullptr, nullptr); } void initVulkan() { createInstance(); setupDebugCallback(); pickPhysicalDevice(); createLogicalDevice(); } void mainLoop() { while (!glfwWindowShouldClose(window)) { glfwPollEvents(); } } void createInstance() { if (enableValidationLayers && !checkValidationLayerSupport()) { throw std::runtime_error("validation layers requested, but not available!"); } VkApplicationInfo appInfo = {}; appInfo.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO; appInfo.pApplicationName = "Hello Triangle"; 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; VkInstanceCreateInfo createInfo = {}; createInfo.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO; createInfo.pApplicationInfo = &appInfo; auto extensions = getRequiredExtensions(); createInfo.enabledExtensionCount = extensions.size(); createInfo.ppEnabledExtensionNames = extensions.data(); 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 instance!"); } } 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 set up debug callback!"); } } void pickPhysicalDevice() { uint32_t deviceCount = 0; vkEnumeratePhysicalDevices(instance, &deviceCount, nullptr); if (deviceCount == 0) { throw std::runtime_error("failed to find GPUs 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 GPU!"); } } void createLogicalDevice() { QueueFamilyIndices indices = findQueueFamilies(physicalDevice); VkDeviceQueueCreateInfo queueCreateInfo = {}; queueCreateInfo.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO; queueCreateInfo.queueFamilyIndex = indices.graphicsFamily; queueCreateInfo.queueCount = 1; float queuePriority = 1.0f; queueCreateInfo.pQueuePriorities = &queuePriority; VkPhysicalDeviceFeatures deviceFeatures = {}; VkDeviceCreateInfo createInfo = {}; createInfo.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO; createInfo.pQueueCreateInfos = &queueCreateInfo; createInfo.queueCreateInfoCount = 1; createInfo.pEnabledFeatures = &deviceFeatures; createInfo.enabledExtensionCount = 0; if (enableValidationLayers) { createInfo.enabledLayerCount = validationLayers.size(); createInfo.ppEnabledLayerNames = validationLayers.data(); } else { createInfo.enabledLayerCount = 0; } if (vkCreateDevice(physicalDevice, &createInfo, nullptr, &device) != VK_SUCCESS) { throw std::runtime_error("failed to create logical device!"); } vkGetDeviceQueue(device, indices.graphicsFamily, 0, &graphicsQueue); } bool isDeviceSuitable(VkPhysicalDevice device) { QueueFamilyIndices indices = findQueueFamilies(device); return indices.isComplete(); } QueueFamilyIndices findQueueFamilies(VkPhysicalDevice device) { QueueFamilyIndices indices; uint32_t queueFamilyCount = 0; vkGetPhysicalDeviceQueueFamilyProperties(device, &queueFamilyCount, nullptr); std::vector<VkQueueFamilyProperties> queueFamilies(queueFamilyCount); vkGetPhysicalDeviceQueueFamilyProperties(device, &queueFamilyCount, queueFamilies.data()); int i = 0; for (const auto& queueFamily : queueFamilies) { if (queueFamily.queueCount > 0 && queueFamily.queueFlags & VK_QUEUE_GRAPHICS_BIT) { indices.graphicsFamily = i; } if (indices.isComplete()) { break; } i++; } return indices; } std::vector<const char*> getRequiredExtensions() { std::vector<const char*> extensions; unsigned int glfwExtensionCount = 0; const char** glfwExtensions; glfwExtensions = glfwGetRequiredInstanceExtensions(&glfwExtensionCount); for (unsigned int i = 0; i < glfwExtensionCount; i++) { extensions.push_back(glfwExtensions[i]); } if (enableValidationLayers) { extensions.push_back(VK_EXT_DEBUG_REPORT_EXTENSION_NAME); } return extensions; } 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; } 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; } }; int main() { HelloTriangleApplication app; try { app.run(); } catch (const std::runtime_error& e) { std::cerr << e.what() << std::endl; return EXIT_FAILURE; } return EXIT_SUCCESS; }
相关文章推荐
- vulakn教程--Drawing a Triangle--Set up--Physical Device and Queue Family
- vulakn教程--Drawing a Triangle--Set up--Instance
- vulakn教程--Drawing a Triangle--Set up--Validation layers
- vulakn教程--Drawing a Triangle--Pipeline--Introduction
- vulakn教程--Drawing a Triangle--Presentation--Window surface
- vulakn教程--Drawing a Triangle--Set up--Base code
- vulakn教程--Drawing a Triangle--Presentation--SwapChain
- vulakn教程--Drawing a Triangle--Pipeline--Render passes
- vulakn教程--Drawing a Triangle--Draw--Render and presentation
- vulakn教程--Drawing a Triangle--Pipeline--Fixed function
- vulakn教程--Drawing a Triangle--Presentation-- Image views
- vulakn教程--Drawing a Triangle--Pipeline--Shader Module
- vulakn教程--Drawing a Triangle--Draw--CommandBuffer
- vulakn教程--Drawing a Triangle--Draw--Framebuffer
- DirectX 教程: DirectX Tutorial - Direct3D: Drawing a Triangle
- CIRCOS教程翻译 3.9——Drawing on top of data
- "https://open.gl/"教程之Drawing Polygons源码(freeglut版)
- Android OpenGL ES 开发教程(11):绘制三角形Triangle
- Drawing a triangle - Instance
- NPOI 1.2.3教程 -22 画图Drawing