Added Logical Device setup, currently there are a few errors thrown because we don't enable any extensions, but DO enable optional features, which rely on those extensions. It seems like vulkan can deal with these errors without crashing, but this will be addressed shortly regardless

This commit is contained in:
Lillian Salehi 2024-10-05 19:59:15 -05:00
parent f161504410
commit 9a6a351e23
7 changed files with 64 additions and 9 deletions

View File

@ -1,16 +1,25 @@
#include "DeviceLibrary.h" #include "DeviceLibrary.h"
#include "debug/VulkanDebugLibs.h"
#include "global.h"
#include <cstdint> #include <cstdint>
#include <iostream>
#include <optional> #include <optional>
#include <ostream> #include <ostream>
#include <stdexcept> #include <stdexcept>
#include <vector>
#include <vulkan/vulkan_core.h> #include <vulkan/vulkan_core.h>
using namespace AgnosiaEngine; using namespace AgnosiaEngine;
VkPhysicalDevice physicalDevice = VK_NULL_HANDLE; VkPhysicalDevice physicalDevice = VK_NULL_HANDLE;
VkPhysicalDeviceProperties deviceProperties; VkPhysicalDeviceProperties deviceProperties;
VkPhysicalDeviceFeatures deviceFeatures; VkPhysicalDeviceFeatures deviceFeatures;
VulkanDebugLibs debug;
VkQueue graphicsQueue;
#ifdef DEBUG
const bool enableValidationLayers = true;
#else
const bool enableValidationLayers = false;
#endif
struct QueueFamilyIndices { struct QueueFamilyIndices {
std::optional<uint32_t> graphicsFamily; std::optional<uint32_t> 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 // 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! // is a queue family with the VK_QUEUE_GRAPHICS_BIT flipped!
QueueFamilyIndices indices = findQueueFamilies(device); QueueFamilyIndices indices = findQueueFamilies(device);
return deviceProperties.deviceType == VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU && deviceFeatures.multiViewport && deviceFeatures.geometryShader && indices.isComplete(); 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<uint32_t>(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);
}

View File

@ -1,7 +1,9 @@
#pragma once
#include <vulkan/vulkan_core.h> #include <vulkan/vulkan_core.h>
namespace AgnosiaEngine { namespace AgnosiaEngine {
class DeviceLibrary { class DeviceLibrary {
public: public:
void pickPhysicalDevice(VkInstance& instance); void pickPhysicalDevice(VkInstance& instance);
void createLogicalDevice(VkDevice& devicvee);
}; };
} }

View File

@ -1,14 +1,13 @@
#include <cstdint> #include <cstdint>
#include <iostream>
#include <stdexcept> #include <stdexcept>
#include <vulkan/vk_platform.h> #include <vulkan/vk_platform.h>
#define GLFW_INCLUDE_VULKAN #define GLFW_INCLUDE_VULKAN
#include <GLFW/glfw3.h> #include <GLFW/glfw3.h>
#include "../global.h"
#include "VulkanDebugLibs.h" #include "VulkanDebugLibs.h"
using namespace AgnosiaEngine; using namespace AgnosiaEngine;
#include <vector>
#include <cstring> #include <cstring>
#include <vulkan/vulkan_core.h> #include <vulkan/vulkan_core.h>
@ -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. // This is our messenger object! It handles passing along debug messages to the debug callback we will also set.
VkDebugUtilsMessengerEXT debugMessenger; 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. // 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<const char*> validationLayers = {
"VK_LAYER_KHRONOS_validation"
};
std::vector<const char*> getRequiredExtensions() { std::vector<const char*> 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 // 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! // 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? // 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::cerr << "Validation layer: " << pCallbackData->pMessage << std::endl;
std::cout << "\n";
return VK_FALSE; return VK_FALSE;
} }

View File

@ -1,3 +1,5 @@
#pragma once
#include <vector>
#include <vulkan/vulkan_core.h> #include <vulkan/vulkan_core.h>
namespace AgnosiaEngine { namespace AgnosiaEngine {

5
src/global.cpp Normal file
View File

@ -0,0 +1,5 @@
#include "global.h"
const std::vector<const char*> validationLayers = {
"VK_LAYER_KHRONOS_validation"
};

5
src/global.h Normal file
View File

@ -0,0 +1,5 @@
#pragma once
#include <iostream>
#include <vector>
extern const std::vector<const char*> validationLayers;

View File

@ -1,5 +1,6 @@
#include <vector> #include <vector>
#include <vulkan/vulkan_core.h>
#define GLFW_INCLUDE_VULKAN #define GLFW_INCLUDE_VULKAN
#include <GLFW/glfw3.h> #include <GLFW/glfw3.h>
@ -37,7 +38,8 @@ private:
GLFWwindow* window; GLFWwindow* window;
VkInstance instance; VkInstance instance;
VulkanDebugLibs debug; VulkanDebugLibs debug;
DeviceLibrary device; DeviceLibrary deviceLibs;
VkDevice device;
// Initialize GLFW Window. First, Initialize GLFW lib, disable resizing for // Initialize GLFW Window. First, Initialize GLFW lib, disable resizing for
// now, and create window. // now, and create window.
void initWindow() { void initWindow() {
@ -52,7 +54,8 @@ private:
void initVulkan() { void initVulkan() {
createInstance(); 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) 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() { 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! void cleanup() { // Similar to the last handoff, destroy the debug util in a safe manner in the library!
vkDestroyDevice(device, nullptr);
if(enableValidationLayers) { if(enableValidationLayers) {
debug.DestroyDebugUtilsMessengerEXT(instance, nullptr); debug.DestroyDebugUtilsMessengerEXT(instance, nullptr);
} }