blegh
This commit is contained in:
parent
32a3d21488
commit
e72e9bd51f
|
@ -14,6 +14,7 @@ common_cpp_args = [
|
||||||
'-Wno-c++98-compat-pedantic',
|
'-Wno-c++98-compat-pedantic',
|
||||||
'-Wno-pre-c++20-compat-pedantic',
|
'-Wno-pre-c++20-compat-pedantic',
|
||||||
'-Wno-padded',
|
'-Wno-padded',
|
||||||
|
'-Wno-switch-default',
|
||||||
'-mavx2',
|
'-mavx2',
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
|
@ -1,32 +1,97 @@
|
||||||
|
#include <fmt/color.h>
|
||||||
#include <fmt/format.h>
|
#include <fmt/format.h>
|
||||||
|
|
||||||
#include "debug_messenger.hpp"
|
#include "debug_messenger.hpp"
|
||||||
|
|
||||||
fn DebugMessenger::create(const vk::Instance& instance) -> vk::UniqueDebugUtilsMessengerEXT {
|
fn DebugMessenger::create(const vk::Instance& instance, Config config)
|
||||||
|
-> std::expected<vk::UniqueDebugUtilsMessengerEXT, std::string> {
|
||||||
#ifdef NDEBUG
|
#ifdef NDEBUG
|
||||||
return nullptr;
|
return nullptr;
|
||||||
#else
|
#else
|
||||||
vk::DebugUtilsMessengerCreateInfoEXT createInfo {
|
try {
|
||||||
.messageSeverity = vk::DebugUtilsMessageSeverityFlagBitsEXT::eVerbose |
|
vk::DebugUtilsMessengerCreateInfoEXT createInfo {
|
||||||
vk::DebugUtilsMessageSeverityFlagBitsEXT::eWarning |
|
.messageSeverity = config.severity_flags,
|
||||||
vk::DebugUtilsMessageSeverityFlagBitsEXT::eError,
|
.messageType = config.type_flags,
|
||||||
.messageType = vk::DebugUtilsMessageTypeFlagBitsEXT::eGeneral |
|
.pfnUserCallback = debugCallback,
|
||||||
vk::DebugUtilsMessageTypeFlagBitsEXT::eValidation |
|
.pUserData = &config,
|
||||||
vk::DebugUtilsMessageTypeFlagBitsEXT::ePerformance,
|
};
|
||||||
.pfnUserCallback = debugCallback,
|
|
||||||
.pUserData = nullptr,
|
|
||||||
};
|
|
||||||
|
|
||||||
return instance.createDebugUtilsMessengerEXTUnique(createInfo);
|
return instance.createDebugUtilsMessengerEXTUnique(createInfo);
|
||||||
|
} catch (const vk::SystemError& e) {
|
||||||
|
return std::unexpected(fmt::format("Failed to create debug messenger: {}", e.what()));
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
VKAPI_ATTR VkBool32 VKAPI_CALL DebugMessenger::debugCallback(
|
VKAPI_ATTR VkBool32 VKAPI_CALL DebugMessenger::debugCallback(
|
||||||
VkDebugUtilsMessageSeverityFlagBitsEXT /*messageSeverity*/,
|
VkDebugUtilsMessageSeverityFlagBitsEXT messageSeverity,
|
||||||
VkDebugUtilsMessageTypeFlagsEXT /*messageType*/,
|
VkDebugUtilsMessageTypeFlagsEXT messageType,
|
||||||
const VkDebugUtilsMessengerCallbackDataEXT* pCallbackData,
|
const VkDebugUtilsMessengerCallbackDataEXT* pCallbackData,
|
||||||
void* /*pUserData*/
|
void* pUserData
|
||||||
) {
|
) {
|
||||||
fmt::println("validation layer: {}", pCallbackData->pMessage);
|
const auto* config = static_cast<const Config*>(pUserData);
|
||||||
|
|
||||||
|
Message msg { .message = pCallbackData->pMessage,
|
||||||
|
.severity = static_cast<vk::DebugUtilsMessageSeverityFlagBitsEXT>(messageSeverity),
|
||||||
|
.type = static_cast<vk::DebugUtilsMessageTypeFlagsEXT>(messageType),
|
||||||
|
.function_name = pCallbackData->pMessageIdName
|
||||||
|
? std::optional<std::string_view>(pCallbackData->pMessageIdName)
|
||||||
|
: std::nullopt,
|
||||||
|
.id = pCallbackData->messageIdNumber };
|
||||||
|
|
||||||
|
const auto formattedMessage = formatMessage(msg);
|
||||||
|
|
||||||
|
if (config && config->use_stderr_for_errors &&
|
||||||
|
(messageSeverity & VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT)) {
|
||||||
|
fmt::println(stderr, "{}", formattedMessage);
|
||||||
|
} else {
|
||||||
|
fmt::println("{}", formattedMessage);
|
||||||
|
}
|
||||||
|
|
||||||
return VK_FALSE;
|
return VK_FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn DebugMessenger::formatMessage(const Message& msg) -> std::string {
|
||||||
|
// Color based on severity
|
||||||
|
fmt::color textColor = fmt::color::white;
|
||||||
|
std::string_view severityText;
|
||||||
|
|
||||||
|
switch (msg.severity) {
|
||||||
|
case vk::DebugUtilsMessageSeverityFlagBitsEXT::eVerbose:
|
||||||
|
textColor = fmt::color::light_blue;
|
||||||
|
severityText = "VERBOSE";
|
||||||
|
break;
|
||||||
|
case vk::DebugUtilsMessageSeverityFlagBitsEXT::eInfo:
|
||||||
|
textColor = fmt::color::white;
|
||||||
|
severityText = "INFO";
|
||||||
|
break;
|
||||||
|
case vk::DebugUtilsMessageSeverityFlagBitsEXT::eWarning:
|
||||||
|
textColor = fmt::color::yellow;
|
||||||
|
severityText = "WARNING";
|
||||||
|
break;
|
||||||
|
case vk::DebugUtilsMessageSeverityFlagBitsEXT::eError:
|
||||||
|
textColor = fmt::color::red;
|
||||||
|
severityText = "ERROR";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Build message type string
|
||||||
|
std::string typeStr;
|
||||||
|
if (msg.type & vk::DebugUtilsMessageTypeFlagBitsEXT::eGeneral)
|
||||||
|
typeStr += "GENERAL ";
|
||||||
|
if (msg.type & vk::DebugUtilsMessageTypeFlagBitsEXT::eValidation)
|
||||||
|
typeStr += "VALIDATION ";
|
||||||
|
if (msg.type & vk::DebugUtilsMessageTypeFlagBitsEXT::ePerformance)
|
||||||
|
typeStr += "PERFORMANCE ";
|
||||||
|
|
||||||
|
// Format the message with color and structure
|
||||||
|
return fmt::format(
|
||||||
|
fmt::emphasis::bold | fg(textColor),
|
||||||
|
"[{}] {} {}{}: {}",
|
||||||
|
severityText,
|
||||||
|
typeStr,
|
||||||
|
msg.function_name.has_value() ? fmt::format("in {} ", *msg.function_name) : "",
|
||||||
|
msg.id,
|
||||||
|
msg.message
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
|
@ -2,12 +2,35 @@
|
||||||
|
|
||||||
#define VULKAN_HPP_DISPATCH_LOADER_DYNAMIC 1 // Use dynamic dispatch for Vulkan functions
|
#define VULKAN_HPP_DISPATCH_LOADER_DYNAMIC 1 // Use dynamic dispatch for Vulkan functions
|
||||||
#define VULKAN_HPP_NO_CONSTRUCTORS
|
#define VULKAN_HPP_NO_CONSTRUCTORS
|
||||||
|
#include <expected>
|
||||||
|
#include <string>
|
||||||
|
#include <string_view>
|
||||||
#include <vulkan/vulkan.hpp>
|
#include <vulkan/vulkan.hpp>
|
||||||
|
|
||||||
#include "../util/types.hpp"
|
#include "../util/types.hpp"
|
||||||
|
|
||||||
class DebugMessenger {
|
class DebugMessenger {
|
||||||
public:
|
public:
|
||||||
|
/**
|
||||||
|
* @brief Configuration for debug messenger
|
||||||
|
*/
|
||||||
|
struct Config {
|
||||||
|
vk::DebugUtilsMessageSeverityFlagsEXT severity_flags;
|
||||||
|
vk::DebugUtilsMessageTypeFlagsEXT type_flags;
|
||||||
|
bool use_stderr_for_errors;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Debug message information
|
||||||
|
*/
|
||||||
|
struct Message {
|
||||||
|
std::string_view message;
|
||||||
|
vk::DebugUtilsMessageSeverityFlagBitsEXT severity;
|
||||||
|
vk::DebugUtilsMessageTypeFlagsEXT type;
|
||||||
|
std::optional<std::string_view> function_name;
|
||||||
|
i32 id;
|
||||||
|
};
|
||||||
|
|
||||||
DebugMessenger() = default;
|
DebugMessenger() = default;
|
||||||
DebugMessenger(const DebugMessenger&) = default;
|
DebugMessenger(const DebugMessenger&) = default;
|
||||||
DebugMessenger(DebugMessenger&&) = delete;
|
DebugMessenger(DebugMessenger&&) = delete;
|
||||||
|
@ -15,7 +38,22 @@ class DebugMessenger {
|
||||||
fn operator=(DebugMessenger&&)->DebugMessenger& = delete;
|
fn operator=(DebugMessenger&&)->DebugMessenger& = delete;
|
||||||
~DebugMessenger() = default;
|
~DebugMessenger() = default;
|
||||||
|
|
||||||
static fn create(const vk::Instance& instance) -> vk::UniqueDebugUtilsMessengerEXT;
|
/**
|
||||||
|
* @brief Creates a debug messenger with the specified configuration
|
||||||
|
* @param instance Vulkan instance
|
||||||
|
* @param config Debug messenger configuration
|
||||||
|
* @return Expected containing the debug messenger or an error message
|
||||||
|
*/
|
||||||
|
static fn create(
|
||||||
|
const vk::Instance& instance,
|
||||||
|
Config config = { .severity_flags = vk::DebugUtilsMessageSeverityFlagBitsEXT::eVerbose |
|
||||||
|
vk::DebugUtilsMessageSeverityFlagBitsEXT::eWarning |
|
||||||
|
vk::DebugUtilsMessageSeverityFlagBitsEXT::eError,
|
||||||
|
.type_flags = vk::DebugUtilsMessageTypeFlagBitsEXT::eGeneral |
|
||||||
|
vk::DebugUtilsMessageTypeFlagBitsEXT::eValidation |
|
||||||
|
vk::DebugUtilsMessageTypeFlagBitsEXT::ePerformance,
|
||||||
|
.use_stderr_for_errors = true }
|
||||||
|
) -> std::expected<vk::UniqueDebugUtilsMessengerEXT, std::string>;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static VKAPI_ATTR VkBool32 VKAPI_CALL debugCallback(
|
static VKAPI_ATTR VkBool32 VKAPI_CALL debugCallback(
|
||||||
|
@ -24,4 +62,11 @@ class DebugMessenger {
|
||||||
const VkDebugUtilsMessengerCallbackDataEXT* pCallbackData,
|
const VkDebugUtilsMessengerCallbackDataEXT* pCallbackData,
|
||||||
void* pUserData
|
void* pUserData
|
||||||
);
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Formats a debug message for output
|
||||||
|
* @param msg Message information
|
||||||
|
* @return Formatted message string
|
||||||
|
*/
|
||||||
|
static fn formatMessage(const Message& msg) -> std::string;
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,118 +1,118 @@
|
||||||
|
#include <expected>
|
||||||
#include <fmt/format.h>
|
#include <fmt/format.h>
|
||||||
#include <set>
|
#include <set>
|
||||||
#include <tuple>
|
#include <span>
|
||||||
|
|
||||||
#include "device_manager.hpp"
|
#include "device_manager.hpp"
|
||||||
|
|
||||||
#include "../structs/swap_chain_support_details.hpp"
|
#include "../structs/swap_chain_support_details.hpp"
|
||||||
|
|
||||||
|
struct PhysicalDeviceInfo {
|
||||||
|
vk::PhysicalDevice physical_device;
|
||||||
|
vk::SampleCountFlagBits msaa_samples;
|
||||||
|
f32 max_line_width;
|
||||||
|
bool wide_line_support;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct LogicalDeviceInfo {
|
||||||
|
vk::UniqueDevice device;
|
||||||
|
vk::Queue graphics_queue;
|
||||||
|
vk::Queue present_queue;
|
||||||
|
};
|
||||||
|
|
||||||
fn DeviceManager::pickPhysicalDevice(
|
fn DeviceManager::pickPhysicalDevice(
|
||||||
const vk::Instance& instance,
|
const vk::Instance& instance,
|
||||||
const vk::SurfaceKHR& surface,
|
const vk::SurfaceKHR& surface,
|
||||||
const std::vector<const char*>& requiredExtensions
|
std::span<const char* const> requiredExtensions
|
||||||
) -> std::tuple<vk::PhysicalDevice, vk::SampleCountFlagBits, f32, bool> {
|
) -> std::expected<PhysicalDeviceInfo, std::string> {
|
||||||
// Get all available physical devices
|
// Get all available physical devices
|
||||||
std::vector<vk::PhysicalDevice> devices = instance.enumeratePhysicalDevices();
|
auto devices = instance.enumeratePhysicalDevices();
|
||||||
|
|
||||||
if (devices.empty())
|
if (devices.empty())
|
||||||
throw std::runtime_error("Failed to find GPUs with Vulkan support!");
|
return std::unexpected("Failed to find GPUs with Vulkan support!");
|
||||||
|
|
||||||
#ifndef NDEBUG
|
#ifndef NDEBUG
|
||||||
fmt::println("Available devices:");
|
fmt::println("Available devices:");
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
vk::PhysicalDevice physicalDevice;
|
// Find the first suitable device using ranges
|
||||||
vk::SampleCountFlagBits msaaSamples = vk::SampleCountFlagBits::e1;
|
auto suitableDevice = std::ranges::find_if(devices, [&](const auto& device) {
|
||||||
f32 maxLineWidth = 1.0F;
|
return isDeviceSuitable(device, surface, requiredExtensions);
|
||||||
bool wideLineSupport = false;
|
});
|
||||||
|
|
||||||
// For each device,
|
if (suitableDevice == devices.end())
|
||||||
for (const vk::PhysicalDevice& device : devices) {
|
return std::unexpected("Failed to find a suitable GPU!");
|
||||||
#ifndef NDEBUG
|
|
||||||
vk::PhysicalDeviceProperties properties = device.getProperties();
|
|
||||||
fmt::println("\t{}", properties.deviceName.data());
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// Set the first suitable device as the physical device
|
vk::PhysicalDeviceProperties deviceProperties = suitableDevice->getProperties();
|
||||||
if (isDeviceSuitable(device, surface, requiredExtensions)) {
|
|
||||||
physicalDevice = device;
|
|
||||||
msaaSamples = getMaxUsableSampleCount(physicalDevice);
|
|
||||||
|
|
||||||
// Get the device properties for line width limits
|
|
||||||
vk::PhysicalDeviceProperties deviceProperties = device.getProperties();
|
|
||||||
maxLineWidth = deviceProperties.limits.lineWidthRange[1];
|
|
||||||
wideLineSupport = deviceProperties.limits.lineWidthRange[1] > 1.0F;
|
|
||||||
|
|
||||||
#ifndef NDEBUG
|
#ifndef NDEBUG
|
||||||
fmt::println("Maximum supported line width: {}", maxLineWidth);
|
fmt::println("\t{}", deviceProperties.deviceName.data());
|
||||||
fmt::println("Wide lines supported: {}", wideLineSupport ? "yes" : "no");
|
fmt::println("Maximum supported line width: {}", deviceProperties.limits.lineWidthRange[1]);
|
||||||
|
fmt::println("Wide lines supported: {}", deviceProperties.limits.lineWidthRange[1] > 1.0F ? "yes" : "no");
|
||||||
#endif
|
#endif
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// If no suitable device was found, throw an error
|
return PhysicalDeviceInfo {
|
||||||
if (!physicalDevice)
|
.physical_device = *suitableDevice,
|
||||||
throw std::runtime_error("Failed to find a suitable GPU!");
|
.msaa_samples = getMaxUsableSampleCount(*suitableDevice),
|
||||||
|
.max_line_width = deviceProperties.limits.lineWidthRange[1],
|
||||||
return std::make_tuple(physicalDevice, msaaSamples, maxLineWidth, wideLineSupport);
|
.wide_line_support = deviceProperties.limits.lineWidthRange[1] > 1.0F,
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
fn DeviceManager::createLogicalDevice(
|
fn DeviceManager::createLogicalDevice(
|
||||||
const vk::PhysicalDevice& physicalDevice,
|
const vk::PhysicalDevice& physicalDevice,
|
||||||
const vk::SurfaceKHR& surface,
|
const vk::SurfaceKHR& surface,
|
||||||
const std::vector<const char*>& requiredExtensions,
|
std::span<const char* const> requiredExtensions,
|
||||||
const bool enableValidationLayers,
|
bool enableValidationLayers,
|
||||||
const std::vector<const char*>& validationLayers
|
std::span<const char* const> validationLayers
|
||||||
) -> std::tuple<vk::UniqueDevice, vk::Queue, vk::Queue> {
|
) -> std::expected<LogicalDeviceInfo, std::string> {
|
||||||
QueueFamilyIndices indices = findQueueFamilies(physicalDevice, surface);
|
try {
|
||||||
|
QueueFamilyIndices indices = findQueueFamilies(physicalDevice, surface);
|
||||||
|
|
||||||
// Create a set of unique queue families needed
|
std::set<u32> uniqueQueueFamilies = { indices.graphics_family.value(), indices.present_family.value() };
|
||||||
std::set<u32> uniqueQueueFamilies = { indices.graphics_family.value(), indices.present_family.value() };
|
|
||||||
|
|
||||||
// Create queue create infos for each unique queue family
|
std::vector<vk::DeviceQueueCreateInfo> queueCreateInfos;
|
||||||
std::vector<vk::DeviceQueueCreateInfo> queueCreateInfos;
|
f32 queuePriority = 1.0F;
|
||||||
f32 queuePriority = 1.0F;
|
|
||||||
|
|
||||||
for (u32 queueFamily : uniqueQueueFamilies) {
|
// Use ranges to transform unique queue families into create infos
|
||||||
vk::DeviceQueueCreateInfo queueCreateInfo {
|
std::ranges::transform(uniqueQueueFamilies, std::back_inserter(queueCreateInfos), [&](u32 queueFamily) {
|
||||||
.queueFamilyIndex = queueFamily,
|
return vk::DeviceQueueCreateInfo {
|
||||||
.queueCount = 1,
|
.queueFamilyIndex = queueFamily,
|
||||||
.pQueuePriorities = &queuePriority,
|
.queueCount = 1,
|
||||||
|
.pQueuePriorities = &queuePriority,
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
vk::PhysicalDeviceFeatures deviceFeatures {
|
||||||
|
.wideLines = vk::True,
|
||||||
|
.samplerAnisotropy = vk::True,
|
||||||
};
|
};
|
||||||
queueCreateInfos.push_back(queueCreateInfo);
|
|
||||||
|
vk::DeviceCreateInfo createInfo {
|
||||||
|
.queueCreateInfoCount = static_cast<u32>(queueCreateInfos.size()),
|
||||||
|
.pQueueCreateInfos = queueCreateInfos.data(),
|
||||||
|
.enabledExtensionCount = static_cast<u32>(requiredExtensions.size()),
|
||||||
|
.ppEnabledExtensionNames = requiredExtensions.data(),
|
||||||
|
.pEnabledFeatures = &deviceFeatures,
|
||||||
|
};
|
||||||
|
|
||||||
|
if (enableValidationLayers) {
|
||||||
|
createInfo.enabledLayerCount = static_cast<u32>(validationLayers.size());
|
||||||
|
createInfo.ppEnabledLayerNames = validationLayers.data();
|
||||||
|
}
|
||||||
|
|
||||||
|
auto device = physicalDevice.createDeviceUnique(createInfo);
|
||||||
|
auto graphicsQueue = device->getQueue(indices.graphics_family.value(), 0);
|
||||||
|
auto presentQueue = device->getQueue(indices.present_family.value(), 0);
|
||||||
|
|
||||||
|
return LogicalDeviceInfo {
|
||||||
|
.device = std::move(device),
|
||||||
|
.graphics_queue = graphicsQueue,
|
||||||
|
.present_queue = presentQueue,
|
||||||
|
};
|
||||||
|
} catch (const vk::SystemError& e) {
|
||||||
|
return std::unexpected(fmt::format("Failed to create logical device: {}", e.what()));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Specify device features
|
|
||||||
vk::PhysicalDeviceFeatures deviceFeatures {
|
|
||||||
.fillModeNonSolid = true,
|
|
||||||
.wideLines = true,
|
|
||||||
.samplerAnisotropy = true,
|
|
||||||
};
|
|
||||||
|
|
||||||
// Create the logical device
|
|
||||||
vk::DeviceCreateInfo createInfo {
|
|
||||||
.queueCreateInfoCount = static_cast<u32>(queueCreateInfos.size()),
|
|
||||||
.pQueueCreateInfos = queueCreateInfos.data(),
|
|
||||||
.enabledExtensionCount = static_cast<u32>(requiredExtensions.size()),
|
|
||||||
.ppEnabledExtensionNames = requiredExtensions.data(),
|
|
||||||
.pEnabledFeatures = &deviceFeatures,
|
|
||||||
};
|
|
||||||
|
|
||||||
// Only enable validation layers if requested
|
|
||||||
if (enableValidationLayers) {
|
|
||||||
createInfo.enabledLayerCount = static_cast<u32>(validationLayers.size());
|
|
||||||
createInfo.ppEnabledLayerNames = validationLayers.data();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create the logical device
|
|
||||||
vk::UniqueDevice device = physicalDevice.createDeviceUnique(createInfo);
|
|
||||||
|
|
||||||
// Get queue handles
|
|
||||||
vk::Queue graphicsQueue = device->getQueue(indices.graphics_family.value(), 0);
|
|
||||||
vk::Queue presentQueue = device->getQueue(indices.present_family.value(), 0);
|
|
||||||
|
|
||||||
return std::make_tuple(std::move(device), graphicsQueue, presentQueue);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn DeviceManager::getMaxUsableSampleCount(const vk::PhysicalDevice& physicalDevice
|
fn DeviceManager::getMaxUsableSampleCount(const vk::PhysicalDevice& physicalDevice
|
||||||
|
@ -162,9 +162,9 @@ fn DeviceManager::findQueueFamilies(const vk::PhysicalDevice& device, const vk::
|
||||||
}
|
}
|
||||||
|
|
||||||
fn DeviceManager::isDeviceSuitable(
|
fn DeviceManager::isDeviceSuitable(
|
||||||
const vk::PhysicalDevice& device,
|
const vk::PhysicalDevice& device,
|
||||||
const vk::SurfaceKHR& surface,
|
const vk::SurfaceKHR& surface,
|
||||||
const std::vector<const char*>& requiredExtensions
|
std::span<const char* const> requiredExtensions
|
||||||
) -> bool {
|
) -> bool {
|
||||||
// Check queue family support
|
// Check queue family support
|
||||||
QueueFamilyIndices indices = findQueueFamilies(device, surface);
|
QueueFamilyIndices indices = findQueueFamilies(device, surface);
|
||||||
|
@ -190,20 +190,15 @@ fn DeviceManager::isDeviceSuitable(
|
||||||
}
|
}
|
||||||
|
|
||||||
fn DeviceManager::checkDeviceExtensionSupport(
|
fn DeviceManager::checkDeviceExtensionSupport(
|
||||||
const vk::PhysicalDevice& device,
|
const vk::PhysicalDevice& device,
|
||||||
const std::vector<const char*>& requiredExtensions
|
std::span<const char* const> requiredExtensions
|
||||||
) -> bool {
|
) -> bool {
|
||||||
// Get available extensions
|
|
||||||
std::vector<vk::ExtensionProperties> availableExtensions = device.enumerateDeviceExtensionProperties();
|
std::vector<vk::ExtensionProperties> availableExtensions = device.enumerateDeviceExtensionProperties();
|
||||||
|
|
||||||
// Convert available extensions to a set of strings for easier lookup
|
// Use ranges to check if all required extensions are available
|
||||||
std::set<std::string> availableExtensionNames;
|
|
||||||
for (const auto& extension : availableExtensions) {
|
|
||||||
availableExtensionNames.insert(extension.extensionName);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check if all required extensions are available
|
|
||||||
return std::ranges::all_of(requiredExtensions, [&](const char* required) {
|
return std::ranges::all_of(requiredExtensions, [&](const char* required) {
|
||||||
return availableExtensionNames.contains(required);
|
return std::ranges::any_of(availableExtensions, [&](const vk::ExtensionProperties& available) {
|
||||||
|
return strcmp(required, available.extensionName) == 0;
|
||||||
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,6 +2,8 @@
|
||||||
|
|
||||||
#define VULKAN_HPP_DISPATCH_LOADER_DYNAMIC 1
|
#define VULKAN_HPP_DISPATCH_LOADER_DYNAMIC 1
|
||||||
#define VULKAN_HPP_NO_CONSTRUCTORS
|
#define VULKAN_HPP_NO_CONSTRUCTORS
|
||||||
|
#include <expected>
|
||||||
|
#include <span>
|
||||||
#include <vulkan/vulkan.hpp>
|
#include <vulkan/vulkan.hpp>
|
||||||
|
|
||||||
#include "../structs/queue_family_indices.hpp"
|
#include "../structs/queue_family_indices.hpp"
|
||||||
|
@ -11,20 +13,38 @@ class DeviceManager {
|
||||||
public:
|
public:
|
||||||
DeviceManager() = default;
|
DeviceManager() = default;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Result type for physical device selection
|
||||||
|
*/
|
||||||
|
struct PhysicalDeviceInfo {
|
||||||
|
vk::PhysicalDevice physical_device;
|
||||||
|
vk::SampleCountFlagBits msaa_samples;
|
||||||
|
f32 max_line_width;
|
||||||
|
bool wide_line_support;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Result type for logical device creation
|
||||||
|
*/
|
||||||
|
struct LogicalDeviceInfo {
|
||||||
|
vk::UniqueDevice device;
|
||||||
|
vk::Queue graphics_queue;
|
||||||
|
vk::Queue present_queue;
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Picks a suitable physical device (GPU) for the application.
|
* @brief Picks a suitable physical device (GPU) for the application.
|
||||||
*
|
*
|
||||||
* @param instance Vulkan instance to use for device selection
|
* @param instance Vulkan instance to use for device selection
|
||||||
* @param surface Surface to check for compatibility
|
* @param surface Surface to check for compatibility
|
||||||
* @param requiredExtensions List of required device extensions
|
* @param requiredExtensions List of required device extensions
|
||||||
* @return std::tuple<vk::PhysicalDevice, vk::SampleCountFlagBits, f32, bool> Physical device, MSAA samples,
|
* @return std::expected<PhysicalDeviceInfo, std::string> Physical device info or error message
|
||||||
* max line width, wide line support
|
|
||||||
*/
|
*/
|
||||||
static fn pickPhysicalDevice(
|
static fn pickPhysicalDevice(
|
||||||
const vk::Instance& instance,
|
const vk::Instance& instance,
|
||||||
const vk::SurfaceKHR& surface,
|
const vk::SurfaceKHR& surface,
|
||||||
const std::vector<const char*>& requiredExtensions
|
std::span<const char* const> requiredExtensions
|
||||||
) -> std::tuple<vk::PhysicalDevice, vk::SampleCountFlagBits, f32, bool>;
|
) -> std::expected<PhysicalDeviceInfo, std::string>;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Creates a logical device with the specified features.
|
* @brief Creates a logical device with the specified features.
|
||||||
|
@ -34,15 +54,15 @@ class DeviceManager {
|
||||||
* @param requiredExtensions Device extensions to enable
|
* @param requiredExtensions Device extensions to enable
|
||||||
* @param enableValidationLayers Whether to enable validation layers
|
* @param enableValidationLayers Whether to enable validation layers
|
||||||
* @param validationLayers Validation layers to enable if enabled
|
* @param validationLayers Validation layers to enable if enabled
|
||||||
* @return std::tuple<vk::UniqueDevice, vk::Queue, vk::Queue> Logical device and queues
|
* @return std::expected<LogicalDeviceInfo, std::string> Logical device info or error message
|
||||||
*/
|
*/
|
||||||
static fn createLogicalDevice(
|
static fn createLogicalDevice(
|
||||||
const vk::PhysicalDevice& physicalDevice,
|
const vk::PhysicalDevice& physicalDevice,
|
||||||
const vk::SurfaceKHR& surface,
|
const vk::SurfaceKHR& surface,
|
||||||
const std::vector<const char*>& requiredExtensions,
|
std::span<const char* const> requiredExtensions,
|
||||||
bool enableValidationLayers,
|
bool enableValidationLayers,
|
||||||
const std::vector<const char*>& validationLayers
|
std::span<const char* const> validationLayers
|
||||||
) -> std::tuple<vk::UniqueDevice, vk::Queue, vk::Queue>;
|
) -> std::expected<LogicalDeviceInfo, std::string>;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Gets the maximum supported MSAA sample count.
|
* @brief Gets the maximum supported MSAA sample count.
|
||||||
|
@ -71,20 +91,16 @@ class DeviceManager {
|
||||||
* @return bool True if device is suitable
|
* @return bool True if device is suitable
|
||||||
*/
|
*/
|
||||||
static fn isDeviceSuitable(
|
static fn isDeviceSuitable(
|
||||||
const vk::PhysicalDevice& device,
|
const vk::PhysicalDevice& device,
|
||||||
const vk::SurfaceKHR& surface,
|
const vk::SurfaceKHR& surface,
|
||||||
const std::vector<const char*>& requiredExtensions
|
std::span<const char* const> requiredExtensions
|
||||||
) -> bool;
|
) -> bool;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Checks if a physical device supports required extensions.
|
* @brief Checks if the device supports the required extensions.
|
||||||
*
|
|
||||||
* @param device Physical device to check
|
|
||||||
* @param requiredExtensions Required device extensions
|
|
||||||
* @return bool True if device supports all required extensions
|
|
||||||
*/
|
*/
|
||||||
static fn checkDeviceExtensionSupport(
|
static fn checkDeviceExtensionSupport(
|
||||||
const vk::PhysicalDevice& device,
|
const vk::PhysicalDevice& device,
|
||||||
const std::vector<const char*>& requiredExtensions
|
std::span<const char* const> requiredExtensions
|
||||||
) -> bool;
|
) -> bool;
|
||||||
};
|
};
|
||||||
|
|
57
src/main.cpp
57
src/main.cpp
|
@ -161,10 +161,12 @@ class VulkanApp {
|
||||||
Camera mCamera; ///< Camera object
|
Camera mCamera; ///< Camera object
|
||||||
|
|
||||||
// Light settings
|
// Light settings
|
||||||
LightInfo mLightSettings { .position = glm::vec3(2.0F, 2.0F, 2.0F),
|
LightInfo mLightSettings {
|
||||||
.color = glm::vec3(1.0F, 1.0F, 1.0F),
|
.position = glm::vec3(2.0F, 2.0F, 2.0F),
|
||||||
.ambient_strength = 0.1F,
|
.color = glm::vec3(1.0F, 1.0F, 1.0F),
|
||||||
.specular_strength = 0.5F };
|
.ambient_strength = 0.1F,
|
||||||
|
.specular_strength = 0.5F,
|
||||||
|
};
|
||||||
|
|
||||||
// Mouse input tracking
|
// Mouse input tracking
|
||||||
bool mFirstMouse = true; ///< Flag for first mouse movement
|
bool mFirstMouse = true; ///< Flag for first mouse movement
|
||||||
|
@ -641,7 +643,21 @@ class VulkanApp {
|
||||||
return;
|
return;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
mDebugMessenger = DebugMessenger::create(mInstance.get());
|
DebugMessenger::Config config {
|
||||||
|
.severity_flags = vk::DebugUtilsMessageSeverityFlagBitsEXT::eVerbose |
|
||||||
|
vk::DebugUtilsMessageSeverityFlagBitsEXT::eWarning |
|
||||||
|
vk::DebugUtilsMessageSeverityFlagBitsEXT::eError,
|
||||||
|
.type_flags = vk::DebugUtilsMessageTypeFlagBitsEXT::eGeneral |
|
||||||
|
vk::DebugUtilsMessageTypeFlagBitsEXT::eValidation |
|
||||||
|
vk::DebugUtilsMessageTypeFlagBitsEXT::ePerformance,
|
||||||
|
.use_stderr_for_errors = true,
|
||||||
|
};
|
||||||
|
|
||||||
|
auto result = DebugMessenger::create(mInstance.get(), config);
|
||||||
|
if (!result) {
|
||||||
|
throw std::runtime_error(result.error());
|
||||||
|
}
|
||||||
|
mDebugMessenger = std::move(*result);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -658,10 +674,18 @@ class VulkanApp {
|
||||||
* the application's requirements.
|
* the application's requirements.
|
||||||
*/
|
*/
|
||||||
fn pickPhysicalDevice() -> void {
|
fn pickPhysicalDevice() -> void {
|
||||||
std::tie(mPhysicalDevice, mMsaaSamples, mMaxLineWidth, mWideLineSupport) =
|
auto result =
|
||||||
DeviceManager::pickPhysicalDevice(
|
DeviceManager::pickPhysicalDevice(mInstance.get(), mSurface.get(), std::span(deviceExtensions));
|
||||||
mInstance.get(), mSurface.get(), std::vector(deviceExtensions.begin(), deviceExtensions.end())
|
|
||||||
);
|
if (!result) {
|
||||||
|
throw std::runtime_error(result.error());
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto& info = *result;
|
||||||
|
mPhysicalDevice = info.physical_device;
|
||||||
|
mMsaaSamples = info.msaa_samples;
|
||||||
|
mMaxLineWidth = info.max_line_width;
|
||||||
|
mWideLineSupport = info.wide_line_support;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -671,13 +695,22 @@ class VulkanApp {
|
||||||
* features and retrieving handles to the graphics and presentation queues.
|
* features and retrieving handles to the graphics and presentation queues.
|
||||||
*/
|
*/
|
||||||
fn createLogicalDevice() -> void {
|
fn createLogicalDevice() -> void {
|
||||||
std::tie(mDevice, mGraphicsQueue, mPresentQueue) = DeviceManager::createLogicalDevice(
|
auto result = DeviceManager::createLogicalDevice(
|
||||||
mPhysicalDevice,
|
mPhysicalDevice,
|
||||||
mSurface.get(),
|
mSurface.get(),
|
||||||
std::vector(deviceExtensions.begin(), deviceExtensions.end()),
|
std::span(deviceExtensions),
|
||||||
enableValidationLayers,
|
enableValidationLayers,
|
||||||
std::vector(validationLayers.begin(), validationLayers.end())
|
std::span(validationLayers)
|
||||||
);
|
);
|
||||||
|
|
||||||
|
if (!result) {
|
||||||
|
throw std::runtime_error(result.error());
|
||||||
|
}
|
||||||
|
|
||||||
|
auto info = std::move(*result);
|
||||||
|
mDevice = std::move(info.device);
|
||||||
|
mGraphicsQueue = info.graphics_queue;
|
||||||
|
mPresentQueue = info.present_queue;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
Loading…
Reference in a new issue