diff --git a/src/DeviceLibrary.cpp b/src/DeviceLibrary.cpp index 13c72f5..8243cd2 100644 --- a/src/DeviceLibrary.cpp +++ b/src/DeviceLibrary.cpp @@ -1,16 +1,25 @@ #include "DeviceLibrary.h" +#include "debug/VulkanDebugLibs.h" +#include "global.h" + #include -#include #include #include #include -#include #include using namespace AgnosiaEngine; VkPhysicalDevice physicalDevice = VK_NULL_HANDLE; VkPhysicalDeviceProperties deviceProperties; VkPhysicalDeviceFeatures deviceFeatures; +VulkanDebugLibs debug; +VkQueue graphicsQueue; + +#ifdef DEBUG + const bool enableValidationLayers = true; +#else + const bool enableValidationLayers = false; +#endif struct QueueFamilyIndices { std::optional graphicsFamily; @@ -56,6 +65,7 @@ bool isDeviceSuitable(VkPhysicalDevice device) { // We need to find a device that supports graphical operations, or else we cant do much with it! This function just runs over all the queueFamilies and sees if there // is a queue family with the VK_QUEUE_GRAPHICS_BIT flipped! QueueFamilyIndices indices = findQueueFamilies(device); + return deviceProperties.deviceType == VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU && deviceFeatures.multiViewport && deviceFeatures.geometryShader && indices.isComplete(); } @@ -84,4 +94,34 @@ void DeviceLibrary::pickPhysicalDevice(VkInstance& instance) { } } +void DeviceLibrary::createLogicalDevice(VkDevice& device) { + // Describe how many queues we want for a single family (1) here, right now we are solely interested in graphics capabilites, + // but Compute Shaders, transfer ops, decode and encode operations can also queued with setup! We also assign each queue a priority. + QueueFamilyIndices indices = findQueueFamilies(physicalDevice); + VkDeviceQueueCreateInfo queueCreateInfo{}; + queueCreateInfo.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO; + queueCreateInfo.queueFamilyIndex = indices.graphicsFamily.value(); + queueCreateInfo.queueCount = 1; + + float queuePriority = 1.0f; + queueCreateInfo.pQueuePriorities = &queuePriority; + + 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 = static_cast(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.value(), 0, &graphicsQueue); +} diff --git a/src/DeviceLibrary.h b/src/DeviceLibrary.h index 6364294..1992923 100644 --- a/src/DeviceLibrary.h +++ b/src/DeviceLibrary.h @@ -1,7 +1,9 @@ +#pragma once #include namespace AgnosiaEngine { class DeviceLibrary { public: void pickPhysicalDevice(VkInstance& instance); + void createLogicalDevice(VkDevice& devicvee); }; } diff --git a/src/debug/VulkanDebugLibs.cpp b/src/debug/VulkanDebugLibs.cpp index b092d56..243512f 100644 --- a/src/debug/VulkanDebugLibs.cpp +++ b/src/debug/VulkanDebugLibs.cpp @@ -1,14 +1,13 @@ #include -#include #include #include #define GLFW_INCLUDE_VULKAN #include +#include "../global.h" #include "VulkanDebugLibs.h" using namespace AgnosiaEngine; -#include #include #include @@ -21,9 +20,6 @@ using namespace AgnosiaEngine; // This is our messenger object! It handles passing along debug messages to the debug callback we will also set. VkDebugUtilsMessengerEXT debugMessenger; // This is the set of "layers" to hook into. Basically, layers are used to tell the messenger what data we want, its a filter. *validation* is the general blanket layer to cover incorrect usage. -const std::vector validationLayers = { - "VK_LAYER_KHRONOS_validation" -}; std::vector getRequiredExtensions() { // This gets a little weird, Vulkan is platform agnostic, so you need to figure out what extensions to interface with the current system are needed @@ -50,6 +46,7 @@ static VKAPI_ATTR VkBool32 VKAPI_CALL debugCallback( // The VKAPI_CALL and VKAPI_ATTR ensure that the function has the right signature for vulkan to call it. The callback message can be anything from a diagnostic to error! // You can even sort by those diagnostics with their flags, since they are just integers, maybe TODO? std::cerr << "Validation layer: " << pCallbackData->pMessage << std::endl; + std::cout << "\n"; return VK_FALSE; } diff --git a/src/debug/VulkanDebugLibs.h b/src/debug/VulkanDebugLibs.h index 8cc7a34..195b5b0 100644 --- a/src/debug/VulkanDebugLibs.h +++ b/src/debug/VulkanDebugLibs.h @@ -1,3 +1,5 @@ +#pragma once +#include #include namespace AgnosiaEngine { diff --git a/src/global.cpp b/src/global.cpp new file mode 100644 index 0000000..b830e75 --- /dev/null +++ b/src/global.cpp @@ -0,0 +1,5 @@ +#include "global.h" + +const std::vector validationLayers = { + "VK_LAYER_KHRONOS_validation" +}; diff --git a/src/global.h b/src/global.h new file mode 100644 index 0000000..bee9eea --- /dev/null +++ b/src/global.h @@ -0,0 +1,5 @@ +#pragma once +#include +#include + +extern const std::vector validationLayers; diff --git a/src/main.cpp b/src/main.cpp index 16745b6..67025f4 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1,5 +1,6 @@ #include +#include #define GLFW_INCLUDE_VULKAN #include @@ -37,7 +38,8 @@ private: GLFWwindow* window; VkInstance instance; VulkanDebugLibs debug; - DeviceLibrary device; + DeviceLibrary deviceLibs; + VkDevice device; // Initialize GLFW Window. First, Initialize GLFW lib, disable resizing for // now, and create window. void initWindow() { @@ -52,7 +54,8 @@ private: void initVulkan() { createInstance(); debug.setupDebugMessenger(instance); // The debug messenger is out holy grail, it gives us Vulkan related debug info when built with the -DNDEBUG flag (as per the makefile) - device.pickPhysicalDevice(instance); + deviceLibs.pickPhysicalDevice(instance); + deviceLibs.createLogicalDevice(device); } void createInstance() { @@ -82,6 +85,7 @@ private: } void cleanup() { // Similar to the last handoff, destroy the debug util in a safe manner in the library! + vkDestroyDevice(device, nullptr); if(enableValidationLayers) { debug.DestroyDebugUtilsMessengerEXT(instance, nullptr); }