blegh
This commit is contained in:
parent
32a3d21488
commit
e72e9bd51f
|
@ -14,6 +14,7 @@ common_cpp_args = [
|
|||
'-Wno-c++98-compat-pedantic',
|
||||
'-Wno-pre-c++20-compat-pedantic',
|
||||
'-Wno-padded',
|
||||
'-Wno-switch-default',
|
||||
'-mavx2',
|
||||
]
|
||||
|
||||
|
|
|
@ -1,32 +1,97 @@
|
|||
#include <fmt/color.h>
|
||||
#include <fmt/format.h>
|
||||
|
||||
#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
|
||||
return nullptr;
|
||||
#else
|
||||
vk::DebugUtilsMessengerCreateInfoEXT createInfo {
|
||||
.messageSeverity = vk::DebugUtilsMessageSeverityFlagBitsEXT::eVerbose |
|
||||
vk::DebugUtilsMessageSeverityFlagBitsEXT::eWarning |
|
||||
vk::DebugUtilsMessageSeverityFlagBitsEXT::eError,
|
||||
.messageType = vk::DebugUtilsMessageTypeFlagBitsEXT::eGeneral |
|
||||
vk::DebugUtilsMessageTypeFlagBitsEXT::eValidation |
|
||||
vk::DebugUtilsMessageTypeFlagBitsEXT::ePerformance,
|
||||
.pfnUserCallback = debugCallback,
|
||||
.pUserData = nullptr,
|
||||
};
|
||||
try {
|
||||
vk::DebugUtilsMessengerCreateInfoEXT createInfo {
|
||||
.messageSeverity = config.severity_flags,
|
||||
.messageType = config.type_flags,
|
||||
.pfnUserCallback = debugCallback,
|
||||
.pUserData = &config,
|
||||
};
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
VKAPI_ATTR VkBool32 VKAPI_CALL DebugMessenger::debugCallback(
|
||||
VkDebugUtilsMessageSeverityFlagBitsEXT /*messageSeverity*/,
|
||||
VkDebugUtilsMessageTypeFlagsEXT /*messageType*/,
|
||||
VkDebugUtilsMessageSeverityFlagBitsEXT messageSeverity,
|
||||
VkDebugUtilsMessageTypeFlagsEXT messageType,
|
||||
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;
|
||||
}
|
||||
|
||||
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_NO_CONSTRUCTORS
|
||||
#include <expected>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
#include <vulkan/vulkan.hpp>
|
||||
|
||||
#include "../util/types.hpp"
|
||||
|
||||
class DebugMessenger {
|
||||
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(const DebugMessenger&) = default;
|
||||
DebugMessenger(DebugMessenger&&) = delete;
|
||||
|
@ -15,7 +38,22 @@ class DebugMessenger {
|
|||
fn operator=(DebugMessenger&&)->DebugMessenger& = delete;
|
||||
~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:
|
||||
static VKAPI_ATTR VkBool32 VKAPI_CALL debugCallback(
|
||||
|
@ -24,4 +62,11 @@ class DebugMessenger {
|
|||
const VkDebugUtilsMessengerCallbackDataEXT* pCallbackData,
|
||||
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 <set>
|
||||
#include <tuple>
|
||||
#include <span>
|
||||
|
||||
#include "device_manager.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(
|
||||
const vk::Instance& instance,
|
||||
const vk::SurfaceKHR& surface,
|
||||
const std::vector<const char*>& requiredExtensions
|
||||
) -> std::tuple<vk::PhysicalDevice, vk::SampleCountFlagBits, f32, bool> {
|
||||
const vk::Instance& instance,
|
||||
const vk::SurfaceKHR& surface,
|
||||
std::span<const char* const> requiredExtensions
|
||||
) -> std::expected<PhysicalDeviceInfo, std::string> {
|
||||
// Get all available physical devices
|
||||
std::vector<vk::PhysicalDevice> devices = instance.enumeratePhysicalDevices();
|
||||
auto devices = instance.enumeratePhysicalDevices();
|
||||
|
||||
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
|
||||
fmt::println("Available devices:");
|
||||
#endif
|
||||
|
||||
vk::PhysicalDevice physicalDevice;
|
||||
vk::SampleCountFlagBits msaaSamples = vk::SampleCountFlagBits::e1;
|
||||
f32 maxLineWidth = 1.0F;
|
||||
bool wideLineSupport = false;
|
||||
// Find the first suitable device using ranges
|
||||
auto suitableDevice = std::ranges::find_if(devices, [&](const auto& device) {
|
||||
return isDeviceSuitable(device, surface, requiredExtensions);
|
||||
});
|
||||
|
||||
// For each device,
|
||||
for (const vk::PhysicalDevice& device : devices) {
|
||||
#ifndef NDEBUG
|
||||
vk::PhysicalDeviceProperties properties = device.getProperties();
|
||||
fmt::println("\t{}", properties.deviceName.data());
|
||||
#endif
|
||||
if (suitableDevice == devices.end())
|
||||
return std::unexpected("Failed to find a suitable GPU!");
|
||||
|
||||
// Set the first suitable device as the physical device
|
||||
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;
|
||||
vk::PhysicalDeviceProperties deviceProperties = suitableDevice->getProperties();
|
||||
|
||||
#ifndef NDEBUG
|
||||
fmt::println("Maximum supported line width: {}", maxLineWidth);
|
||||
fmt::println("Wide lines supported: {}", wideLineSupport ? "yes" : "no");
|
||||
fmt::println("\t{}", deviceProperties.deviceName.data());
|
||||
fmt::println("Maximum supported line width: {}", deviceProperties.limits.lineWidthRange[1]);
|
||||
fmt::println("Wide lines supported: {}", deviceProperties.limits.lineWidthRange[1] > 1.0F ? "yes" : "no");
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// If no suitable device was found, throw an error
|
||||
if (!physicalDevice)
|
||||
throw std::runtime_error("Failed to find a suitable GPU!");
|
||||
|
||||
return std::make_tuple(physicalDevice, msaaSamples, maxLineWidth, wideLineSupport);
|
||||
return PhysicalDeviceInfo {
|
||||
.physical_device = *suitableDevice,
|
||||
.msaa_samples = getMaxUsableSampleCount(*suitableDevice),
|
||||
.max_line_width = deviceProperties.limits.lineWidthRange[1],
|
||||
.wide_line_support = deviceProperties.limits.lineWidthRange[1] > 1.0F,
|
||||
};
|
||||
}
|
||||
|
||||
fn DeviceManager::createLogicalDevice(
|
||||
const vk::PhysicalDevice& physicalDevice,
|
||||
const vk::SurfaceKHR& surface,
|
||||
const std::vector<const char*>& requiredExtensions,
|
||||
const bool enableValidationLayers,
|
||||
const std::vector<const char*>& validationLayers
|
||||
) -> std::tuple<vk::UniqueDevice, vk::Queue, vk::Queue> {
|
||||
QueueFamilyIndices indices = findQueueFamilies(physicalDevice, surface);
|
||||
const vk::PhysicalDevice& physicalDevice,
|
||||
const vk::SurfaceKHR& surface,
|
||||
std::span<const char* const> requiredExtensions,
|
||||
bool enableValidationLayers,
|
||||
std::span<const char* const> validationLayers
|
||||
) -> std::expected<LogicalDeviceInfo, std::string> {
|
||||
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;
|
||||
f32 queuePriority = 1.0F;
|
||||
std::vector<vk::DeviceQueueCreateInfo> queueCreateInfos;
|
||||
f32 queuePriority = 1.0F;
|
||||
|
||||
for (u32 queueFamily : uniqueQueueFamilies) {
|
||||
vk::DeviceQueueCreateInfo queueCreateInfo {
|
||||
.queueFamilyIndex = queueFamily,
|
||||
.queueCount = 1,
|
||||
.pQueuePriorities = &queuePriority,
|
||||
// Use ranges to transform unique queue families into create infos
|
||||
std::ranges::transform(uniqueQueueFamilies, std::back_inserter(queueCreateInfos), [&](u32 queueFamily) {
|
||||
return vk::DeviceQueueCreateInfo {
|
||||
.queueFamilyIndex = queueFamily,
|
||||
.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
|
||||
|
@ -162,9 +162,9 @@ fn DeviceManager::findQueueFamilies(const vk::PhysicalDevice& device, const vk::
|
|||
}
|
||||
|
||||
fn DeviceManager::isDeviceSuitable(
|
||||
const vk::PhysicalDevice& device,
|
||||
const vk::SurfaceKHR& surface,
|
||||
const std::vector<const char*>& requiredExtensions
|
||||
const vk::PhysicalDevice& device,
|
||||
const vk::SurfaceKHR& surface,
|
||||
std::span<const char* const> requiredExtensions
|
||||
) -> bool {
|
||||
// Check queue family support
|
||||
QueueFamilyIndices indices = findQueueFamilies(device, surface);
|
||||
|
@ -190,20 +190,15 @@ fn DeviceManager::isDeviceSuitable(
|
|||
}
|
||||
|
||||
fn DeviceManager::checkDeviceExtensionSupport(
|
||||
const vk::PhysicalDevice& device,
|
||||
const std::vector<const char*>& requiredExtensions
|
||||
const vk::PhysicalDevice& device,
|
||||
std::span<const char* const> requiredExtensions
|
||||
) -> bool {
|
||||
// Get available extensions
|
||||
std::vector<vk::ExtensionProperties> availableExtensions = device.enumerateDeviceExtensionProperties();
|
||||
|
||||
// Convert available extensions to a set of strings for easier lookup
|
||||
std::set<std::string> availableExtensionNames;
|
||||
for (const auto& extension : availableExtensions) {
|
||||
availableExtensionNames.insert(extension.extensionName);
|
||||
}
|
||||
|
||||
// Check if all required extensions are available
|
||||
// Use ranges to check if all required extensions are available
|
||||
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_NO_CONSTRUCTORS
|
||||
#include <expected>
|
||||
#include <span>
|
||||
#include <vulkan/vulkan.hpp>
|
||||
|
||||
#include "../structs/queue_family_indices.hpp"
|
||||
|
@ -11,20 +13,38 @@ class DeviceManager {
|
|||
public:
|
||||
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.
|
||||
*
|
||||
* @param instance Vulkan instance to use for device selection
|
||||
* @param surface Surface to check for compatibility
|
||||
* @param requiredExtensions List of required device extensions
|
||||
* @return std::tuple<vk::PhysicalDevice, vk::SampleCountFlagBits, f32, bool> Physical device, MSAA samples,
|
||||
* max line width, wide line support
|
||||
* @return std::expected<PhysicalDeviceInfo, std::string> Physical device info or error message
|
||||
*/
|
||||
static fn pickPhysicalDevice(
|
||||
const vk::Instance& instance,
|
||||
const vk::SurfaceKHR& surface,
|
||||
const std::vector<const char*>& requiredExtensions
|
||||
) -> std::tuple<vk::PhysicalDevice, vk::SampleCountFlagBits, f32, bool>;
|
||||
const vk::Instance& instance,
|
||||
const vk::SurfaceKHR& surface,
|
||||
std::span<const char* const> requiredExtensions
|
||||
) -> std::expected<PhysicalDeviceInfo, std::string>;
|
||||
|
||||
/**
|
||||
* @brief Creates a logical device with the specified features.
|
||||
|
@ -34,15 +54,15 @@ class DeviceManager {
|
|||
* @param requiredExtensions Device extensions to enable
|
||||
* @param enableValidationLayers Whether to enable validation layers
|
||||
* @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(
|
||||
const vk::PhysicalDevice& physicalDevice,
|
||||
const vk::SurfaceKHR& surface,
|
||||
const std::vector<const char*>& requiredExtensions,
|
||||
bool enableValidationLayers,
|
||||
const std::vector<const char*>& validationLayers
|
||||
) -> std::tuple<vk::UniqueDevice, vk::Queue, vk::Queue>;
|
||||
const vk::PhysicalDevice& physicalDevice,
|
||||
const vk::SurfaceKHR& surface,
|
||||
std::span<const char* const> requiredExtensions,
|
||||
bool enableValidationLayers,
|
||||
std::span<const char* const> validationLayers
|
||||
) -> std::expected<LogicalDeviceInfo, std::string>;
|
||||
|
||||
/**
|
||||
* @brief Gets the maximum supported MSAA sample count.
|
||||
|
@ -71,20 +91,16 @@ class DeviceManager {
|
|||
* @return bool True if device is suitable
|
||||
*/
|
||||
static fn isDeviceSuitable(
|
||||
const vk::PhysicalDevice& device,
|
||||
const vk::SurfaceKHR& surface,
|
||||
const std::vector<const char*>& requiredExtensions
|
||||
const vk::PhysicalDevice& device,
|
||||
const vk::SurfaceKHR& surface,
|
||||
std::span<const char* const> requiredExtensions
|
||||
) -> bool;
|
||||
|
||||
/**
|
||||
* @brief Checks if a physical device supports required extensions.
|
||||
*
|
||||
* @param device Physical device to check
|
||||
* @param requiredExtensions Required device extensions
|
||||
* @return bool True if device supports all required extensions
|
||||
* @brief Checks if the device supports the required extensions.
|
||||
*/
|
||||
static fn checkDeviceExtensionSupport(
|
||||
const vk::PhysicalDevice& device,
|
||||
const std::vector<const char*>& requiredExtensions
|
||||
const vk::PhysicalDevice& device,
|
||||
std::span<const char* const> requiredExtensions
|
||||
) -> bool;
|
||||
};
|
||||
|
|
57
src/main.cpp
57
src/main.cpp
|
@ -161,10 +161,12 @@ class VulkanApp {
|
|||
Camera mCamera; ///< Camera object
|
||||
|
||||
// Light settings
|
||||
LightInfo mLightSettings { .position = glm::vec3(2.0F, 2.0F, 2.0F),
|
||||
.color = glm::vec3(1.0F, 1.0F, 1.0F),
|
||||
.ambient_strength = 0.1F,
|
||||
.specular_strength = 0.5F };
|
||||
LightInfo mLightSettings {
|
||||
.position = glm::vec3(2.0F, 2.0F, 2.0F),
|
||||
.color = glm::vec3(1.0F, 1.0F, 1.0F),
|
||||
.ambient_strength = 0.1F,
|
||||
.specular_strength = 0.5F,
|
||||
};
|
||||
|
||||
// Mouse input tracking
|
||||
bool mFirstMouse = true; ///< Flag for first mouse movement
|
||||
|
@ -641,7 +643,21 @@ class VulkanApp {
|
|||
return;
|
||||
#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.
|
||||
*/
|
||||
fn pickPhysicalDevice() -> void {
|
||||
std::tie(mPhysicalDevice, mMsaaSamples, mMaxLineWidth, mWideLineSupport) =
|
||||
DeviceManager::pickPhysicalDevice(
|
||||
mInstance.get(), mSurface.get(), std::vector(deviceExtensions.begin(), deviceExtensions.end())
|
||||
);
|
||||
auto result =
|
||||
DeviceManager::pickPhysicalDevice(mInstance.get(), mSurface.get(), std::span(deviceExtensions));
|
||||
|
||||
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.
|
||||
*/
|
||||
fn createLogicalDevice() -> void {
|
||||
std::tie(mDevice, mGraphicsQueue, mPresentQueue) = DeviceManager::createLogicalDevice(
|
||||
auto result = DeviceManager::createLogicalDevice(
|
||||
mPhysicalDevice,
|
||||
mSurface.get(),
|
||||
std::vector(deviceExtensions.begin(), deviceExtensions.end()),
|
||||
std::span(deviceExtensions),
|
||||
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