i ❤️ segfaulting
This commit is contained in:
parent
0f4d0d72d9
commit
bca2a4e999
|
@ -42,6 +42,7 @@ executable(
|
||||||
'src/camera/camera.cpp',
|
'src/camera/camera.cpp',
|
||||||
'src/init/vulkan_instance.cpp',
|
'src/init/vulkan_instance.cpp',
|
||||||
'src/init/debug_messenger.cpp',
|
'src/init/debug_messenger.cpp',
|
||||||
|
'src/init/device_manager.cpp',
|
||||||
'src/window/window_manager.cpp',
|
'src/window/window_manager.cpp',
|
||||||
],
|
],
|
||||||
include_directories: include_directories('include', is_system: true),
|
include_directories: include_directories('include', is_system: true),
|
||||||
|
|
209
src/init/device_manager.cpp
Normal file
209
src/init/device_manager.cpp
Normal file
|
@ -0,0 +1,209 @@
|
||||||
|
#include <fmt/format.h>
|
||||||
|
#include <set>
|
||||||
|
#include <tuple>
|
||||||
|
|
||||||
|
#include "device_manager.hpp"
|
||||||
|
|
||||||
|
#include "../structs/swap_chain_support_details.hpp"
|
||||||
|
|
||||||
|
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> {
|
||||||
|
// Get all available physical devices
|
||||||
|
std::vector<vk::PhysicalDevice> devices = instance.enumeratePhysicalDevices();
|
||||||
|
|
||||||
|
if (devices.empty())
|
||||||
|
throw std::runtime_error("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;
|
||||||
|
|
||||||
|
// For each device,
|
||||||
|
for (const vk::PhysicalDevice& device : devices) {
|
||||||
|
#ifndef NDEBUG
|
||||||
|
vk::PhysicalDeviceProperties properties = device.getProperties();
|
||||||
|
fmt::println("\t{}", properties.deviceName.data());
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// 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;
|
||||||
|
|
||||||
|
#ifndef NDEBUG
|
||||||
|
fmt::println("Maximum supported line width: {}", maxLineWidth);
|
||||||
|
fmt::println("Wide lines supported: {}", wideLineSupport ? "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);
|
||||||
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
|
||||||
|
// Create a set of unique queue families needed
|
||||||
|
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;
|
||||||
|
|
||||||
|
for (u32 queueFamily : uniqueQueueFamilies) {
|
||||||
|
vk::DeviceQueueCreateInfo queueCreateInfo {
|
||||||
|
.queueFamilyIndex = queueFamily,
|
||||||
|
.queueCount = 1,
|
||||||
|
.pQueuePriorities = &queuePriority,
|
||||||
|
};
|
||||||
|
queueCreateInfos.push_back(queueCreateInfo);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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
|
||||||
|
) -> vk::SampleCountFlagBits {
|
||||||
|
vk::PhysicalDeviceProperties physicalDeviceProperties = physicalDevice.getProperties();
|
||||||
|
|
||||||
|
vk::SampleCountFlags counts = physicalDeviceProperties.limits.framebufferColorSampleCounts &
|
||||||
|
physicalDeviceProperties.limits.framebufferDepthSampleCounts;
|
||||||
|
|
||||||
|
if (counts & vk::SampleCountFlagBits::e64)
|
||||||
|
return vk::SampleCountFlagBits::e64;
|
||||||
|
if (counts & vk::SampleCountFlagBits::e32)
|
||||||
|
return vk::SampleCountFlagBits::e32;
|
||||||
|
if (counts & vk::SampleCountFlagBits::e16)
|
||||||
|
return vk::SampleCountFlagBits::e16;
|
||||||
|
if (counts & vk::SampleCountFlagBits::e8)
|
||||||
|
return vk::SampleCountFlagBits::e8;
|
||||||
|
if (counts & vk::SampleCountFlagBits::e4)
|
||||||
|
return vk::SampleCountFlagBits::e4;
|
||||||
|
if (counts & vk::SampleCountFlagBits::e2)
|
||||||
|
return vk::SampleCountFlagBits::e2;
|
||||||
|
|
||||||
|
return vk::SampleCountFlagBits::e1;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn DeviceManager::findQueueFamilies(const vk::PhysicalDevice& device, const vk::SurfaceKHR& surface)
|
||||||
|
-> QueueFamilyIndices {
|
||||||
|
QueueFamilyIndices indices;
|
||||||
|
|
||||||
|
// Get queue family properties
|
||||||
|
std::vector<vk::QueueFamilyProperties> queueFamilies = device.getQueueFamilyProperties();
|
||||||
|
|
||||||
|
// Find queue family with graphics support
|
||||||
|
for (size_t i = 0; i < queueFamilies.size(); i++) {
|
||||||
|
if (queueFamilies[i].queueFlags & vk::QueueFlagBits::eGraphics)
|
||||||
|
indices.graphics_family = static_cast<u32>(i);
|
||||||
|
|
||||||
|
// Check for presentation support
|
||||||
|
if (device.getSurfaceSupportKHR(static_cast<u32>(i), surface))
|
||||||
|
indices.present_family = static_cast<u32>(i);
|
||||||
|
|
||||||
|
if (indices.isComplete())
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return indices;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn DeviceManager::isDeviceSuitable(
|
||||||
|
const vk::PhysicalDevice& device,
|
||||||
|
const vk::SurfaceKHR& surface,
|
||||||
|
const std::vector<const char*>& requiredExtensions
|
||||||
|
) -> bool {
|
||||||
|
// Check queue family support
|
||||||
|
QueueFamilyIndices indices = findQueueFamilies(device, surface);
|
||||||
|
|
||||||
|
// Check extension support
|
||||||
|
bool extensionsSupported = checkDeviceExtensionSupport(device, requiredExtensions);
|
||||||
|
|
||||||
|
// Check swap chain support
|
||||||
|
bool swapChainAdequate = false;
|
||||||
|
if (extensionsSupported) {
|
||||||
|
SwapChainSupportDetails swapChainSupport;
|
||||||
|
swapChainSupport.capabilities = device.getSurfaceCapabilitiesKHR(surface);
|
||||||
|
swapChainSupport.formats = device.getSurfaceFormatsKHR(surface);
|
||||||
|
swapChainSupport.present_modes = device.getSurfacePresentModesKHR(surface);
|
||||||
|
swapChainAdequate = !swapChainSupport.formats.empty() && !swapChainSupport.present_modes.empty();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check device features
|
||||||
|
vk::PhysicalDeviceFeatures supportedFeatures = device.getFeatures();
|
||||||
|
|
||||||
|
return indices.isComplete() && extensionsSupported && swapChainAdequate &&
|
||||||
|
supportedFeatures.samplerAnisotropy;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn DeviceManager::checkDeviceExtensionSupport(
|
||||||
|
const vk::PhysicalDevice& device,
|
||||||
|
const std::vector<const char*>& 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
|
||||||
|
return std::ranges::all_of(requiredExtensions, [&](const char* required) {
|
||||||
|
return availableExtensionNames.contains(required);
|
||||||
|
});
|
||||||
|
}
|
89
src/init/device_manager.hpp
Normal file
89
src/init/device_manager.hpp
Normal file
|
@ -0,0 +1,89 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#define VULKAN_HPP_NO_CONSTRUCTORS
|
||||||
|
#include <vulkan/vulkan.hpp>
|
||||||
|
|
||||||
|
#include "../structs/queue_family_indices.hpp"
|
||||||
|
#include "../util/types.hpp"
|
||||||
|
|
||||||
|
class DeviceManager {
|
||||||
|
public:
|
||||||
|
DeviceManager() = default;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @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
|
||||||
|
*/
|
||||||
|
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>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Creates a logical device with the specified features.
|
||||||
|
*
|
||||||
|
* @param physicalDevice Physical device to create logical device from
|
||||||
|
* @param surface Surface to create device with
|
||||||
|
* @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
|
||||||
|
*/
|
||||||
|
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>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Gets the maximum supported MSAA sample count.
|
||||||
|
*
|
||||||
|
* @param physicalDevice Physical device to check
|
||||||
|
* @return vk::SampleCountFlagBits Maximum supported sample count
|
||||||
|
*/
|
||||||
|
static fn getMaxUsableSampleCount(const vk::PhysicalDevice& physicalDevice) -> vk::SampleCountFlagBits;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Finds queue families that support required operations.
|
||||||
|
*
|
||||||
|
* @param device Physical device to check
|
||||||
|
* @param surface Surface to check presentation support
|
||||||
|
* @return QueueFamilyIndices Indices of suitable queue families
|
||||||
|
*/
|
||||||
|
static fn findQueueFamilies(const vk::PhysicalDevice& device, const vk::SurfaceKHR& surface)
|
||||||
|
-> QueueFamilyIndices;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Checks if a physical device is suitable for the application.
|
||||||
|
*
|
||||||
|
* @param device Physical device to check
|
||||||
|
* @param surface Surface to check compatibility with
|
||||||
|
* @param requiredExtensions Required device extensions
|
||||||
|
* @return bool True if device is suitable
|
||||||
|
*/
|
||||||
|
static fn isDeviceSuitable(
|
||||||
|
const vk::PhysicalDevice& device,
|
||||||
|
const vk::SurfaceKHR& surface,
|
||||||
|
const std::vector<const char*>& 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
|
||||||
|
*/
|
||||||
|
static fn checkDeviceExtensionSupport(
|
||||||
|
const vk::PhysicalDevice& device,
|
||||||
|
const std::vector<const char*>& requiredExtensions
|
||||||
|
) -> bool;
|
||||||
|
};
|
203
src/main.cpp
203
src/main.cpp
|
@ -3,6 +3,7 @@
|
||||||
#include <fmt/format.h> // For string formatting
|
#include <fmt/format.h> // For string formatting
|
||||||
#include <shaderc/shaderc.hpp> // For shader compilation
|
#include <shaderc/shaderc.hpp> // For shader compilation
|
||||||
#include <unordered_set> // For unordered_set container
|
#include <unordered_set> // For unordered_set container
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
// GLM (OpenGL Mathematics) configuration
|
// GLM (OpenGL Mathematics) configuration
|
||||||
#define GLM_FORCE_DEPTH_ZERO_TO_ONE // Use Vulkan's depth range (0 to 1) instead of OpenGL's (-1 to 1)
|
#define GLM_FORCE_DEPTH_ZERO_TO_ONE // Use Vulkan's depth range (0 to 1) instead of OpenGL's (-1 to 1)
|
||||||
|
@ -22,6 +23,7 @@
|
||||||
// Include custom utility headers
|
// Include custom utility headers
|
||||||
#include "camera/camera.hpp" // Camera class
|
#include "camera/camera.hpp" // Camera class
|
||||||
#include "init/debug_messenger.hpp"
|
#include "init/debug_messenger.hpp"
|
||||||
|
#include "init/device_manager.hpp"
|
||||||
#include "init/vulkan_instance.hpp"
|
#include "init/vulkan_instance.hpp"
|
||||||
#include "structs/camera_info.hpp"
|
#include "structs/camera_info.hpp"
|
||||||
#include "structs/light_info.hpp"
|
#include "structs/light_info.hpp"
|
||||||
|
@ -378,10 +380,11 @@ class VulkanApp {
|
||||||
mImGuiDescriptorPool = mDevice->createDescriptorPoolUnique(poolInfo);
|
mImGuiDescriptorPool = mDevice->createDescriptorPoolUnique(poolInfo);
|
||||||
|
|
||||||
ImGui_ImplVulkan_InitInfo initInfo = {
|
ImGui_ImplVulkan_InitInfo initInfo = {
|
||||||
.Instance = mInstance.get(),
|
.Instance = mInstance.get(),
|
||||||
.PhysicalDevice = mPhysicalDevice,
|
.PhysicalDevice = mPhysicalDevice,
|
||||||
.Device = mDevice.get(),
|
.Device = mDevice.get(),
|
||||||
.QueueFamily = findQueueFamilies(mPhysicalDevice).graphics_family.value(),
|
.QueueFamily =
|
||||||
|
DeviceManager::findQueueFamilies(mPhysicalDevice, mSurface.get()).graphics_family.value(),
|
||||||
.Queue = mGraphicsQueue,
|
.Queue = mGraphicsQueue,
|
||||||
.DescriptorPool = mImGuiDescriptorPool.get(),
|
.DescriptorPool = mImGuiDescriptorPool.get(),
|
||||||
.RenderPass = mRenderPass.get(),
|
.RenderPass = mRenderPass.get(),
|
||||||
|
@ -653,45 +656,10 @@ class VulkanApp {
|
||||||
* the application's requirements.
|
* the application's requirements.
|
||||||
*/
|
*/
|
||||||
fn pickPhysicalDevice() -> void {
|
fn pickPhysicalDevice() -> void {
|
||||||
// Get all physical devices
|
std::tie(mPhysicalDevice, mMsaaSamples, mMaxLineWidth, mWideLineSupport) =
|
||||||
std::vector<vk::PhysicalDevice> devices = mInstance->enumeratePhysicalDevices();
|
DeviceManager::pickPhysicalDevice(
|
||||||
|
mInstance.get(), mSurface.get(), std::vector(deviceExtensions.begin(), deviceExtensions.end())
|
||||||
// Make sure there are supported devices
|
);
|
||||||
if (devices.empty())
|
|
||||||
throw std::runtime_error("Failed to find GPUs with Vulkan support!");
|
|
||||||
|
|
||||||
#ifndef NDEBUG
|
|
||||||
fmt::println("Available devices:");
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// For each device,
|
|
||||||
for (const vk::PhysicalDevice& device : devices) {
|
|
||||||
#ifndef NDEBUG
|
|
||||||
vk::PhysicalDeviceProperties properties = device.getProperties();
|
|
||||||
fmt::println("\t{}", properties.deviceName.data());
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// Set the first suitable device as the physical device
|
|
||||||
if (isDeviceSuitable(device)) {
|
|
||||||
mPhysicalDevice = device;
|
|
||||||
mMsaaSamples = getMaxUsableSampleCount();
|
|
||||||
|
|
||||||
// Get the device properties for line width limits
|
|
||||||
vk::PhysicalDeviceProperties deviceProperties = device.getProperties();
|
|
||||||
mMaxLineWidth = deviceProperties.limits.lineWidthRange[1];
|
|
||||||
mWideLineSupport = deviceProperties.limits.lineWidthRange[1] > 1.0F;
|
|
||||||
|
|
||||||
#ifndef NDEBUG
|
|
||||||
fmt::println("Maximum supported line width: {}", mMaxLineWidth);
|
|
||||||
fmt::println("Wide lines supported: {}", mWideLineSupport ? "yes" : "no");
|
|
||||||
#endif
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// If no suitable device was found, throw an error
|
|
||||||
if (!mPhysicalDevice)
|
|
||||||
throw std::runtime_error("Failed to find a suitable GPU!");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -701,50 +669,13 @@ 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 {
|
||||||
// Get the queue families
|
std::tie(mDevice, mGraphicsQueue, mPresentQueue) = DeviceManager::createLogicalDevice(
|
||||||
QueueFamilyIndices qfIndices = findQueueFamilies(mPhysicalDevice);
|
mPhysicalDevice,
|
||||||
|
mSurface.get(),
|
||||||
std::vector<vk::DeviceQueueCreateInfo> queueCreateInfos;
|
std::vector(deviceExtensions.begin(), deviceExtensions.end()),
|
||||||
|
enableValidationLayers,
|
||||||
std::set<u32> uniqueQueueFamilies = {
|
std::vector(validationLayers.begin(), validationLayers.end())
|
||||||
qfIndices.graphics_family.value(),
|
);
|
||||||
qfIndices.present_family.value(),
|
|
||||||
};
|
|
||||||
|
|
||||||
// Set the queue priority
|
|
||||||
f32 queuePriority = 1.0F;
|
|
||||||
|
|
||||||
// For each unique queue family, create a queue create info
|
|
||||||
queueCreateInfos.reserve(uniqueQueueFamilies.size());
|
|
||||||
|
|
||||||
for (u32 queueFamily : uniqueQueueFamilies)
|
|
||||||
queueCreateInfos.push_back({
|
|
||||||
.queueFamilyIndex = queueFamily,
|
|
||||||
.queueCount = 1,
|
|
||||||
.pQueuePriorities = &queuePriority,
|
|
||||||
});
|
|
||||||
|
|
||||||
// Enable required features
|
|
||||||
vk::PhysicalDeviceFeatures deviceFeatures {
|
|
||||||
.fillModeNonSolid = vk::True, // Required for wireframe rendering
|
|
||||||
.wideLines = vk::True, // Required for line width > 1.0
|
|
||||||
.samplerAnisotropy = vk::True,
|
|
||||||
};
|
|
||||||
|
|
||||||
// Create the logical device
|
|
||||||
vk::DeviceCreateInfo createInfo {
|
|
||||||
.queueCreateInfoCount = static_cast<u32>(queueCreateInfos.size()),
|
|
||||||
.pQueueCreateInfos = queueCreateInfos.data(),
|
|
||||||
.enabledExtensionCount = static_cast<u32>(deviceExtensions.size()),
|
|
||||||
.ppEnabledExtensionNames = deviceExtensions.data(),
|
|
||||||
.pEnabledFeatures = &deviceFeatures,
|
|
||||||
};
|
|
||||||
|
|
||||||
mDevice = mPhysicalDevice.createDeviceUnique(createInfo);
|
|
||||||
|
|
||||||
// Get the graphics and present queues
|
|
||||||
mGraphicsQueue = mDevice->getQueue(qfIndices.graphics_family.value(), 0);
|
|
||||||
mPresentQueue = mDevice->getQueue(qfIndices.present_family.value(), 0);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -766,7 +697,7 @@ class VulkanApp {
|
||||||
imageCount > swapChainSupport.capabilities.maxImageCount)
|
imageCount > swapChainSupport.capabilities.maxImageCount)
|
||||||
imageCount = swapChainSupport.capabilities.maxImageCount;
|
imageCount = swapChainSupport.capabilities.maxImageCount;
|
||||||
|
|
||||||
QueueFamilyIndices qfIndices = findQueueFamilies(mPhysicalDevice);
|
QueueFamilyIndices qfIndices = DeviceManager::findQueueFamilies(mPhysicalDevice, mSurface.get());
|
||||||
std::array<u32, 2> queueFamilyIndices = {
|
std::array<u32, 2> queueFamilyIndices = {
|
||||||
qfIndices.graphics_family.value(),
|
qfIndices.graphics_family.value(),
|
||||||
qfIndices.present_family.value(),
|
qfIndices.present_family.value(),
|
||||||
|
@ -1272,7 +1203,7 @@ class VulkanApp {
|
||||||
* the buffers from which command buffer memory is allocated.
|
* the buffers from which command buffer memory is allocated.
|
||||||
*/
|
*/
|
||||||
fn createCommandPool() -> void {
|
fn createCommandPool() -> void {
|
||||||
QueueFamilyIndices queueFamilyIndices = findQueueFamilies(mPhysicalDevice);
|
QueueFamilyIndices queueFamilyIndices = DeviceManager::findQueueFamilies(mPhysicalDevice, mSurface.get());
|
||||||
|
|
||||||
vk::CommandPoolCreateInfo poolInfo { .flags = vk::CommandPoolCreateFlagBits::eResetCommandBuffer,
|
vk::CommandPoolCreateInfo poolInfo { .flags = vk::CommandPoolCreateFlagBits::eResetCommandBuffer,
|
||||||
.queueFamilyIndex = queueFamilyIndices.graphics_family.value() };
|
.queueFamilyIndex = queueFamilyIndices.graphics_family.value() };
|
||||||
|
@ -2690,100 +2621,6 @@ class VulkanApp {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Checks if a physical device is suitable for the application.
|
|
||||||
*
|
|
||||||
* @param device The physical device to check.
|
|
||||||
* @return True if the device is suitable, false otherwise.
|
|
||||||
*
|
|
||||||
* This function checks if a physical device meets all the requirements
|
|
||||||
* of the application, including queue families, extensions, and features.
|
|
||||||
*/
|
|
||||||
fn isDeviceSuitable(const vk::PhysicalDevice& device) -> bool {
|
|
||||||
// Get the queue families that support the required operations
|
|
||||||
QueueFamilyIndices qfIndices = findQueueFamilies(device);
|
|
||||||
|
|
||||||
// Check if the device supports the required extensions
|
|
||||||
bool extensionsSupported = checkDeviceExtensionSupport(device);
|
|
||||||
|
|
||||||
bool swapChainAdequate = false;
|
|
||||||
|
|
||||||
if (extensionsSupported) {
|
|
||||||
SwapChainSupportDetails swapChainSupport = querySwapChainSupport(device);
|
|
||||||
// Check if the swap chain is adequate (make sure it has
|
|
||||||
// at least one supported format and presentation mode)
|
|
||||||
swapChainAdequate = !swapChainSupport.formats.empty() && !swapChainSupport.present_modes.empty();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check if the device supports the required features
|
|
||||||
vk::PhysicalDeviceFeatures supportedFeatures = device.getFeatures();
|
|
||||||
|
|
||||||
// If the device supports everything required, return true
|
|
||||||
return qfIndices.isComplete() && extensionsSupported && swapChainAdequate &&
|
|
||||||
supportedFeatures.samplerAnisotropy;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Checks if a device supports all required extensions.
|
|
||||||
*
|
|
||||||
* @param device The physical device to check.
|
|
||||||
* @return True if all required extensions are supported, false otherwise.
|
|
||||||
*
|
|
||||||
* This function verifies that a physical device supports all the
|
|
||||||
* extensions required by the application.
|
|
||||||
*/
|
|
||||||
static fn checkDeviceExtensionSupport(const vk::PhysicalDevice& device) -> bool {
|
|
||||||
// Get the available extensions
|
|
||||||
std::vector<vk::ExtensionProperties> availableExtensions = device.enumerateDeviceExtensionProperties();
|
|
||||||
|
|
||||||
// Create a set of required extension names
|
|
||||||
std::set<string> requiredExtensions(deviceExtensions.begin(), deviceExtensions.end());
|
|
||||||
|
|
||||||
// Remove each required extension from the set of available extensions
|
|
||||||
for (const vk::ExtensionProperties& extension : availableExtensions)
|
|
||||||
requiredExtensions.erase(extension.extensionName);
|
|
||||||
|
|
||||||
// If the set is empty, all required extensions are supported
|
|
||||||
return requiredExtensions.empty();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Finds queue families that support required operations.
|
|
||||||
*
|
|
||||||
* @param device The physical device to check.
|
|
||||||
* @return A QueueFamilyIndices struct with the found queue family indices.
|
|
||||||
*
|
|
||||||
* This function finds queue families that support graphics operations
|
|
||||||
* and presentation to the window surface.
|
|
||||||
*/
|
|
||||||
fn findQueueFamilies(const vk::PhysicalDevice& device) -> QueueFamilyIndices {
|
|
||||||
// Create a struct to store the queue family indices
|
|
||||||
QueueFamilyIndices qfIndices;
|
|
||||||
|
|
||||||
// Get the queue family properties
|
|
||||||
std::vector<vk::QueueFamilyProperties> queueFamilies = device.getQueueFamilyProperties();
|
|
||||||
|
|
||||||
// For every queue family,
|
|
||||||
for (u32 i = 0; i < queueFamilies.size(); i++) {
|
|
||||||
// Check if the queue family supports the required operations
|
|
||||||
if (queueFamilies[i].queueFlags & vk::QueueFlagBits::eGraphics)
|
|
||||||
qfIndices.graphics_family = i;
|
|
||||||
|
|
||||||
// Check if the queue family supports presentation
|
|
||||||
vk::Bool32 queuePresentSupport = device.getSurfaceSupportKHR(i, mSurface.get());
|
|
||||||
|
|
||||||
// If the queue family supports presentation, set the present family index
|
|
||||||
if (queuePresentSupport)
|
|
||||||
qfIndices.present_family = i;
|
|
||||||
|
|
||||||
// If the queue family supports both operations, we're done
|
|
||||||
if (qfIndices.isComplete())
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
return qfIndices;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Checks if all requested validation layers are available.
|
* @brief Checks if all requested validation layers are available.
|
||||||
*
|
*
|
||||||
|
|
|
@ -24,7 +24,10 @@ namespace constants {
|
||||||
|
|
||||||
// Validation layers
|
// Validation layers
|
||||||
#ifndef NDEBUG
|
#ifndef NDEBUG
|
||||||
constexpr std::array<const char*, 1> validationLayers = { "VK_LAYER_KHRONOS_validation" };
|
constexpr bool enableValidationLayers = true;
|
||||||
|
constexpr std::array<const char*, 1> validationLayers = { "VK_LAYER_KHRONOS_validation" };
|
||||||
|
#else
|
||||||
|
constexpr bool enableValidationLayers = false;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Device extensions
|
// Device extensions
|
||||||
|
|
Loading…
Reference in a new issue