- More Documentation

- Vulkan Configuration Implementations
 - Fixed build errors on GCC and Clang
This commit is contained in:
2026-07-18 23:48:00 -04:00
parent ed381c4178
commit cf909624df
164 changed files with 19857 additions and 5872 deletions

View File

@@ -32,7 +32,7 @@
#ifndef FENNEC_RENDERERS_VULKAN_LIB_APP_INFO_H
#define FENNEC_RENDERERS_VULKAN_LIB_APP_INFO_H
#include <volk.h>
#include <fennec/renderers/vulkan/lib/forward.h>
#include <fennec/core/version.h>
#include <fennec/string/cstring.h>
@@ -44,6 +44,12 @@ namespace fennec::vk
/// \brief Wrapper class for VkApplicationInfo
struct app_info : private VkApplicationInfo {
// Definitions =========================================================================================================
private:
// Constructors & Destructor ===========================================================================================
public:
@@ -52,30 +58,36 @@ public:
///
/// \brief Create a Vulkan application information structure
/// \param app_name the name of the application, this cstring must exist for the lifetime of this object
/// until a structure of type fennec::vk::instance is constructed
/// \param app_name the name of the application.
/// \param app_version the internal version of the application
/// \param engine_name the name of the engine, this cstring must exist for the lifetime of this object
/// until a structure of type fennec::vk::instance is constructed
/// \param engine_name the name of the engine.
/// \param engine_version the internal version of the engine
/// \param api_version the Vulkan API version to use, version::patch and version::str are ignored
/// \param ext a pointer to an extension structure, the object next points to must exist for the lifetime of this
/// object until a structure of type fennec::vk::instance is constructed
/// TODO: DEFINE EXTENSION STRUCTURE WRAPPERS
app_info(
const cstring& app_name = {}, const version& app_version = {},
const cstring& engine_name = {}, const version& engine_version = {},
const version& api_version = {},
void* ext = nullptr
const cstring& engine_name = {}, const version& engine_version = {}
) noexcept : VkApplicationInfo {
.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO,
.pNext = ext,
.pApplicationName = app_name,
.pNext = nullptr,
.pApplicationName = nullptr,
.applicationVersion = VK_MAKE_VERSION(app_version.major, app_version.minor, app_version.patch),
.pEngineName = engine_name,
.pEngineName = nullptr,
.engineVersion = VK_MAKE_VERSION(engine_version.major, engine_version.minor, engine_version.patch),
.apiVersion = VK_MAKE_API_VERSION(0, api_version.major, api_version.minor, 0),
} {
.apiVersion = VK_MAKE_API_VERSION(0, 1, 0, 0), // Default to 1.0
}, _app_name(app_name)
, _engine_name(engine_name) {
pApplicationName = _app_name.data();
pEngineName = _engine_name.data();
// Attempt to acquire version supported by the driver
if (vkEnumerateInstanceVersion) {
uint32_t api_version;
vkEnumerateInstanceVersion(&api_version);
apiVersion = VK_MAKE_API_VERSION(0, VK_API_VERSION_MAJOR(api_version), VK_API_VERSION_MINOR(api_version), 0);
}
}
///
@@ -102,13 +114,13 @@ public:
///
/// \brief Copy Assignment
/// \param info The app_info object to move
/// \returns A reference to self
/// \returns A reference to \emph{this}
app_info& operator=(const app_info& info) noexcept = default;
///
/// \brief Move Assignment
/// \param info The app_info object to move
/// \returns A reference to self
/// \returns A reference to \emph{this}
app_info& operator=(app_info&& info) noexcept = default;
/// @}
@@ -121,14 +133,14 @@ public:
/// @{
///
/// \returns \f$this\f$ as if it were a pointer to the underlying type, \f$VkApplicationInfo\f$.
/// \returns \emph{this} as if it were a pointer to the underlying type, \emph{VkApplicationInfo}.
operator VkApplicationInfo*() noexcept {
return this;
}
///
/// \brief Implicit Pointer Conversion
/// \returns \f$this\f$ as if it were a pointer to the underlying type, \f$VkApplicationInfo\f$.
/// \returns \emph{this} as if it were a pointer to the underlying type, \emph{VkApplicationInfo}.
operator const VkApplicationInfo*() const noexcept {
return this;
}
@@ -168,18 +180,22 @@ public:
///
/// \brief Set the engine version
/// \param ver A version struct containing the new version
void set_engine_version(const version& ver) {
engineVersion = VK_MAKE_VERSION(ver.major, ver.minor, ver.patch);
void set_app_version(const version& ver) {
applicationVersion = VK_MAKE_VERSION(ver.major, ver.minor, ver.patch);
}
///
/// \returns A cstring containing the engine name
cstring get_engine_name() const { return cstring(pEngineName, strlen(pEngineName)); }
cstring get_engine_name() const {
return { pEngineName, strlen(pEngineName) };
}
///
/// \brief Set the engine name
/// \param str A cstring containing the new name
void set_engine_name(const cstring& str) { pEngineName = str; }
void set_engine_name(const cstring& str) {
pEngineName = str;
}
///
/// \returns A version struct containing the engine version
@@ -203,7 +219,9 @@ public:
version get_api_version() const {
return version {
.major = VK_API_VERSION_MAJOR(apiVersion),
.minor = VK_API_VERSION_MINOR(apiVersion)
.minor = VK_API_VERSION_MINOR(apiVersion),
.patch = VK_API_VERSION_PATCH(apiVersion),
.meta = VK_API_VERSION_VARIANT(apiVersion),
};
}
@@ -222,7 +240,7 @@ public:
}
///
/// \brief Clear the extension structure with \f$nullptr\f$
/// \brief Clear the extension structure with \emph{nullptr}
void set_extension(nullptr_t) {
pNext = nullptr;
}
@@ -232,6 +250,8 @@ public:
// Private Member Variables ============================================================================================
private:
string _app_name;
string _engine_name;
};
}

View File

@@ -0,0 +1,145 @@
// =====================================================================================================================
// fennec, a free and open source game engine
// Copyright © 2025 Medusa Slockbower
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
// =====================================================================================================================
///
/// \file debug.h
/// \brief
///
///
/// \details
/// \author Medusa Slockbower
///
/// \copyright Copyright © 2025 - 2026 Medusa Slockbower ([GPLv3](https://www.gnu.org/licenses/gpl-3.0.en.html))
///
///
#ifndef FENNEC_RENDERERS_VULKAN_LIB_DEBUG_H
#define FENNEC_RENDERERS_VULKAN_LIB_DEBUG_H
#include <fennec/containers/dynarray.h>
#include <fennec/format/format.h>
#include <fennec/lang/ranges.h>
#include <fennec/renderers/vulkan/lib/forward.h>
#include <fennec/renderers/vulkan/lib/enum.h>
#include <fennec/string/string.h>
namespace fennec::vk
{
///
/// \brief Vulkan Debugger Interface
class debugger {
// Definitions =========================================================================================================
public:
///
/// \brief Info for attaching a debugger to an instance.
struct info
: private VkDebugUtilsMessengerCreateInfoEXT
{
explicit info(const debugger& dbg)
: VkDebugUtilsMessengerCreateInfoEXT {
.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT,
.pNext = nullptr,
.flags = 0,
.messageSeverity = debug_message_severity_all,
.messageType = debug_message_type_all,
.pfnUserCallback = _debug_message,
.pUserData = const_cast<debugger*>(&dbg),
} {
}
operator const VkDebugUtilsMessengerCreateInfoEXT*() const {
return this;
}
};
// Properties ==========================================================================================================
public:
///
/// \brief Instance Creation Info
/// \returns An info object for attaching this debugger to an instance.
info get_info() const {
return info(*this);
}
// Debug Callbacks =====================================================================================================
public:
///
/// \brief
/// \param severity The message severity
/// \param type The message type
/// \param id The message id
/// \param message The message string
/// \param queue The labels in the queue
/// \param commands The labels in the command buffer
/// \param objects The related objects
virtual void message(uint32_t severity,
uint32_t type,
const cstring& id,
const cstring& message,
const dynarray<cstring>& queue,
const dynarray<cstring>& commands,
const dynarray<string>& objects) = 0;
// Private Helper Functions ============================================================================================
private:
static VkBool32 _debug_message(
VkDebugUtilsMessageSeverityFlagBitsEXT messageSeverity,
VkDebugUtilsMessageTypeFlagsEXT messageType,
const VkDebugUtilsMessengerCallbackDataEXT* pCallbackData,
void* pUserData
) {
const cstring id = cstring(pCallbackData->pMessageIdName, strlen(pCallbackData->pMessageIdName));
const cstring message = cstring(pCallbackData->pMessage, strlen(pCallbackData->pMessage));
dynarray<cstring> queue;
dynarray<cstring> commands;
dynarray<string> objects;
debugger* dbg = static_cast<debugger*>(pUserData);
for (const auto& label : range(pCallbackData->pQueueLabels, pCallbackData->pQueueLabels + pCallbackData->queueLabelCount)) {
queue.emplace_back(label.pLabelName, strlen(label.pLabelName));
}
for (const auto& label : range(pCallbackData->pCmdBufLabels, pCallbackData->pCmdBufLabels + pCallbackData->cmdBufLabelCount)) {
commands.emplace_back(label.pLabelName, strlen(label.pLabelName));
}
for (const auto& obj : range(pCallbackData->pObjects, pCallbackData->pObjects + pCallbackData->objectCount)) {
objects.push_back(format("{:#016x} ({})", obj.objectHandle, object_string(obj.objectType)));
}
dbg->message(messageSeverity, messageType, id, message, queue, commands, objects);
return VK_FALSE;
}
};
}
#endif // FENNEC_RENDERERS_VULKAN_LIB_DEBUG_H

View File

@@ -0,0 +1,359 @@
// =====================================================================================================================
// fennec, a free and open source game engine
// Copyright © 2025 Medusa Slockbower
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
// =====================================================================================================================
///
/// \file enum.h
/// \brief
///
///
/// \details
/// \author Medusa Slockbower
///
/// \copyright Copyright © 2025 - 2026 Medusa Slockbower ([GPLv3](https://www.gnu.org/licenses/gpl-3.0.en.html))
///
///
#ifndef FENNEC_RENDERERS_VULKAN_LIB_ENUM_H
#define FENNEC_RENDERERS_VULKAN_LIB_ENUM_H
#include <fennec/renderers/vulkan/lib/forward.h>
namespace fennec::vk
{
// Objects =============================================================================================================
///
/// \brief An enum representing the Vulkan object types
enum object_ : uint32_t {
object_unknown = VK_OBJECT_TYPE_UNKNOWN, //!< Unknown type
object_instance = VK_OBJECT_TYPE_INSTANCE, //!< Vulkan Instance
object_physical_device = VK_OBJECT_TYPE_PHYSICAL_DEVICE, //!< Physical Device
object_logical_device = VK_OBJECT_TYPE_DEVICE, //!< Logical Device
object_queue = VK_OBJECT_TYPE_QUEUE, //!< Queue
object_semaphore = VK_OBJECT_TYPE_SEMAPHORE, //!< Semaphore
object_command_buffer = VK_OBJECT_TYPE_COMMAND_BUFFER, //!< Command Buffer
object_fence = VK_OBJECT_TYPE_FENCE, //!< Fence
object_device_memory = VK_OBJECT_TYPE_DEVICE_MEMORY, //!< Device Memory
object_buffer = VK_OBJECT_TYPE_BUFFER, //!< Buffer
object_image = VK_OBJECT_TYPE_IMAGE, //!< Image
object_event = VK_OBJECT_TYPE_EVENT, //!< Event
object_query_pool = VK_OBJECT_TYPE_QUERY_POOL, //!< Query Pool
object_buffer_view = VK_OBJECT_TYPE_BUFFER_VIEW, //!< Buffer View
object_image_view = VK_OBJECT_TYPE_IMAGE_VIEW, //!< Image View
object_shader_module = VK_OBJECT_TYPE_SHADER_MODULE, //!< Shader Module
object_pipeline_cache = VK_OBJECT_TYPE_PIPELINE_CACHE, //!< Pipeline Cache
object_pipeline_layout = VK_OBJECT_TYPE_PIPELINE_LAYOUT, //!< Pipeline Layout
object_render_pass = VK_OBJECT_TYPE_RENDER_PASS, //!< Render Pass
object_pipeline = VK_OBJECT_TYPE_PIPELINE, //!< Pipeline
object_descriptor_set_layout = VK_OBJECT_TYPE_DESCRIPTOR_SET_LAYOUT, //!< Descriptor Set
object_sampler = VK_OBJECT_TYPE_SAMPLER, //!< Sampler
object_descriptor_pool = VK_OBJECT_TYPE_DESCRIPTOR_POOL, //!< Descriptor Pool
object_descriptor_set = VK_OBJECT_TYPE_DESCRIPTOR_SET, //!< Descriptor Set
object_framebuffer = VK_OBJECT_TYPE_FRAMEBUFFER, //!< Framebuffer
object_command_pool = VK_OBJECT_TYPE_COMMAND_POOL, //!< Command Pool
object_sampler_ycbcr_conversion = VK_OBJECT_TYPE_SAMPLER_YCBCR_CONVERSION, //!< YCBCR Conversion Sampler
object_descriptor_update_template = VK_OBJECT_TYPE_DESCRIPTOR_UPDATE_TEMPLATE, //!< Descriptor Update Template
object_private_data_slot = VK_OBJECT_TYPE_PRIVATE_DATA_SLOT, //!< Private Data Slot
object_debug_report_callback_ext = VK_OBJECT_TYPE_DEBUG_REPORT_CALLBACK_EXT, //!< Debug Report Callback
object_debug_utils_messenger_ext = VK_OBJECT_TYPE_DEBUG_UTILS_MESSENGER_EXT, //!< Debug Utility Messenger
object_validation_cache_ext = VK_OBJECT_TYPE_VALIDATION_CACHE_EXT, //!< Validation Cache
object_micromap_ext = VK_OBJECT_TYPE_MICROMAP_EXT, //!< Micro-Map
object_shader_ext = VK_OBJECT_TYPE_SHADER_EXT, //!< Shader
object_indirect_commands_layout_ext = VK_OBJECT_TYPE_INDIRECT_COMMANDS_LAYOUT_EXT, //!< Indirect Commands Layout
object_indirect_execution_set_ext = VK_OBJECT_TYPE_INDIRECT_EXECUTION_SET_EXT, //!< Indirect Execution Set
object_surface = VK_OBJECT_TYPE_SURFACE_KHR, //!< Surface
object_swapchain = VK_OBJECT_TYPE_SWAPCHAIN_KHR, //!< Swap-chain
object_display = VK_OBJECT_TYPE_DISPLAY_KHR, //!< Display
object_display_mode = VK_OBJECT_TYPE_DISPLAY_MODE_KHR, //!< Display Mode
object_video_session = VK_OBJECT_TYPE_VIDEO_SESSION_KHR, //!< Video Session
object_video_session_parameters = VK_OBJECT_TYPE_VIDEO_SESSION_PARAMETERS_KHR, //!< Video Session Parameters
object_acceleration_structure = VK_OBJECT_TYPE_ACCELERATION_STRUCTURE_KHR, //!< Acceleration Structure
object_deferred_operation = VK_OBJECT_TYPE_DEFERRED_OPERATION_KHR, //!< Deferred Operation
object_pipeline_binary = VK_OBJECT_TYPE_PIPELINE_BINARY_KHR, //!< Pipeline Binary
object_acceleration_structure_NV = VK_OBJECT_TYPE_ACCELERATION_STRUCTURE_NV, //!< NV Acceleration Structure
object_indirect_commands_layout_NV = VK_OBJECT_TYPE_INDIRECT_COMMANDS_LAYOUT_NV, //!< NV Indirect Commands Layout
object_optical_flow_session_NV = VK_OBJECT_TYPE_OPTICAL_FLOW_SESSION_NV, //!< NV Optical Flow Session
object_external_compute_queue_NV = VK_OBJECT_TYPE_EXTERNAL_COMPUTE_QUEUE_NV, //!< NV External Compute Queue
object_cu_module_NVX = VK_OBJECT_TYPE_CU_MODULE_NVX, //!< NVX CU Module
object_cu_function_NVX = VK_OBJECT_TYPE_CU_FUNCTION_NVX, //!< NVX CU Function
object_performance_configuration_INTEL = VK_OBJECT_TYPE_PERFORMANCE_CONFIGURATION_INTEL, //!< Intel Performance Configuration
object_buffer_collection_FUCHSIA = VK_OBJECT_TYPE_BUFFER_COLLECTION_FUCHSIA, //!< Fuchsia Buffer Collection
object_tensor_ARM = VK_OBJECT_TYPE_TENSOR_ARM, //!< ARM Tensor
object_tensor_view_ARM = VK_OBJECT_TYPE_TENSOR_VIEW_ARM, //!< ARM Tensor View
object_data_graph_pipeline_session_ARM = VK_OBJECT_TYPE_DATA_GRAPH_PIPELINE_SESSION_ARM, //!< ARM Data Graph Pipeline Session
// Beta Extensions
#ifdef VK_ENABLE_BETA_EXTENSIONS
object_cuda_module_NV = VK_OBJECT_TYPE_CUDA_MODULE_NV, //!< NV Cuda Module
object_cuda_function_NV = VK_OBJECT_TYPE_CUDA_FUNCTION_NV, //!< NV Cuda Function
#endif
};
inline cstring object_string(uint32_t flag) {
switch (flag) {
default:
case object_unknown: return "Unknown";
case object_instance: return "Instance";
case object_physical_device: return "Physical Device";
case object_logical_device: return "Logical Device";
case object_queue: return "Queue";
case object_semaphore: return "Semaphore";
case object_command_buffer: return "Command Buffer";
case object_fence: return "Fence";
case object_device_memory: return "Device Memory";
case object_buffer: return "Buffer";
case object_image: return "Image";
case object_event: return "Event";
case object_query_pool: return "Query Pool";
case object_buffer_view: return "Buffer View";
case object_image_view: return "Image View";
case object_shader_module: return "Shader Module";
case object_pipeline_cache: return "Pipeline Cache";
case object_pipeline_layout: return "Pipeline Layout";
case object_render_pass: return "Render Pass";
case object_pipeline: return "Pipeline";
case object_descriptor_set_layout: return "Descriptor Set Layout";
case object_sampler: return "Sampler";
case object_descriptor_pool: return "Descriptor Pool";
case object_descriptor_set: return "Descriptor Set";
case object_framebuffer: return "Framebuffer";
case object_command_pool: return "Command Pool";
case object_sampler_ycbcr_conversion: return "YCBCR Conversion Sampler";
case object_descriptor_update_template: return "Descriptor Update Template";
case object_private_data_slot: return "Private Data Slot";
case object_debug_report_callback_ext: return "Report Callback";
case object_debug_utils_messenger_ext: return "Debug Messenger";
case object_validation_cache_ext: return "Validation Cache";
case object_micromap_ext: return "Micro-Map";
case object_shader_ext: return "Shader";
case object_indirect_commands_layout_ext: return "Indirect Commands Layout";
case object_indirect_execution_set_ext: return "Indirect Execution Set";
case object_surface: return "Surface";
case object_swapchain: return "Swap-Chain";
case object_display: return "Display";
case object_display_mode: return "Display Mode";
case object_video_session: return "Video Session";
case object_video_session_parameters: return "Video Session Parameters";
case object_acceleration_structure: return "Acceleration Structure";
case object_deferred_operation: return "Deferred Operation";
case object_pipeline_binary: return "Pipeline Binary";
case object_acceleration_structure_NV: return "NV Acceleration Structure";
case object_indirect_commands_layout_NV: return "NV Indirect Commands Layout";
case object_optical_flow_session_NV: return "NV Optical Flow Session";
case object_external_compute_queue_NV: return "NV External Compute Queue";
case object_cu_module_NVX: return "NVX CU Module";
case object_cu_function_NVX: return "NVX CU Function";
case object_performance_configuration_INTEL: return "Intel Performance Configuration";
case object_buffer_collection_FUCHSIA: return "Fuchsia Buffer Collection";
case object_tensor_ARM: return "ARM Tensor";
case object_tensor_view_ARM: return "ARM Tensor View";
case object_data_graph_pipeline_session_ARM: return "ARM Data Graph Pipeline Session";
// Beta Extensions
#ifdef VK_ENABLE_BETA_EXTENSIONS
case object_cuda_module_NV: return "NV CUDA Module",
case object_cuda_function_NV: return "NV CUDA Function",
#endif
}
}
// Physical Devices ====================================================================================================
///
/// \brief An enum representing the Vulkan physical device types
enum device_ : uint32_t {
device_other = VK_PHYSICAL_DEVICE_TYPE_OTHER, //!< Other Type
device_integrated = VK_PHYSICAL_DEVICE_TYPE_INTEGRATED_GPU, //!< Integrated GPU
device_discrete = VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU, //!< Discrete / Dedicated GPU
device_virtual = VK_PHYSICAL_DEVICE_TYPE_VIRTUAL_GPU, //!< Virtualized / Software GPU
device_cpu = VK_PHYSICAL_DEVICE_TYPE_CPU, //!< CPU
};
///
/// \brief Get a descriptor string for the provided device type.
/// \param type The device type.
/// \returns A cstring containing a short description.
inline cstring device_string(uint32_t type) {
switch (type) {
default:
case device_other: return "Other";
case device_integrated: return "iGPU";
case device_discrete: return "dGPU";
case device_virtual: return "Virtual";
case device_cpu: return "CPU";
}
}
// Instances ===========================================================================================================
///
/// \brief An enum representing the Vulkan instance creation flags
enum instance_flag_ : uint32_t {
instance_flag_portability = VK_INSTANCE_CREATE_ENUMERATE_PORTABILITY_BIT_KHR, //!< Portability, allow non-conformant devices
instance_flag_none = 0, //!< No flags
instance_flag_all = instance_flag_portability, //!< All flags
};
///
/// \brief Get a descriptor string for the provided device type.
/// \param flag The instance flag.
/// \returns A cstring containing a short description.
inline cstring instance_flag_string(uint32_t flag) {
switch (flag) {
default:
case instance_flag_none: return "None";
case instance_flag_portability: return "Portability";
// TODO: Multi-Flags
//case instance_flag_all: return cstring("All");
}
}
// Debugging ===========================================================================================================
///
/// \brief An enum representing the Vulkan debug message severity flags
enum debug_message_severity_ : uint32_t {
debug_message_severity_verbose = VK_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT, //!< Verbose Message
debug_message_severity_info = VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT, //!< Info Message
debug_message_severity_warning = VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT, //!< Warning Message
debug_message_severity_error = VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT, //!< Error Message
debug_message_severity_none = 0, //!< No flags
debug_message_severity_all = debug_message_severity_verbose
| debug_message_severity_info
| debug_message_severity_warning
| debug_message_severity_error, //!< All flags
};
///
/// \brief Get a descriptor string for the provided message severity.
/// \param flag The severity flag.
/// \returns A cstring containing a short description.
inline cstring message_severity_string(uint32_t flag) {
switch (flag) {
default:
case debug_message_severity_none: return "None";
case debug_message_severity_verbose: return "Verbose";
case debug_message_severity_info: return "Info";
case debug_message_severity_warning: return "Warning";
case debug_message_severity_error: return "Error";
// TODO: Multi-Flags
case debug_message_severity_all: return "All";
}
}
///
/// \brief An enum representing the Vulkan debug message type flags
enum debug_message_type_ : uint32_t {
debug_message_type_general = VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT, //!< General Message
debug_message_type_validation = VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT, //!< Validation Message
debug_message_type_performance = VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT, //!< Performance Message
debug_message_type_none = 0, //!< No flags
debug_message_type_all = debug_message_type_general
| debug_message_type_validation
| debug_message_type_performance, //!< All flags
};
///
/// \brief Get a descriptor string for the provided message type.
/// \param flag The type flag.
/// \returns A cstring containing a short description.
inline cstring message_type_string(uint32_t flag) {
switch (flag) {
default:
case debug_message_type_none: return "None";
case debug_message_type_general: return "General";
case debug_message_type_validation: return "Validation";
case debug_message_type_performance: return "Performance";
// TODO: Multi-Flags
case debug_message_type_all: return "All";
}
}
///
/// \brief An enum representing the Vulkan debug report flags
enum debug_report_ : uint32_t {
debug_report_information = VK_DEBUG_REPORT_INFORMATION_BIT_EXT, //!< Information Report
debug_report_warning = VK_DEBUG_REPORT_WARNING_BIT_EXT, //!< Warning Report
debug_report_performance = VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT, //!< Performance Warning Report
debug_report_error = VK_DEBUG_REPORT_ERROR_BIT_EXT, //!< Error Report
debug_report_debug = VK_DEBUG_REPORT_DEBUG_BIT_EXT, //!< Debug Report
debug_report_none = 0, //!< No flags
debug_report_all = debug_report_information
| debug_report_warning
| debug_report_performance
| debug_report_error
| debug_report_debug, //!< All flags
};
///
/// \brief Get a descriptor string for the provided report type.
/// \param flag The type flag.
/// \returns A cstring containing a short description.
inline cstring report_string(uint32_t flag) {
switch (flag) {
default:
case debug_report_none: return "None";
case debug_report_information: return "Information";
case debug_report_warning: return "Warning";
case debug_report_performance: return "Performance";
case debug_report_error: return "Error";
case debug_report_debug: return "Debug";
// TODO: Multi-Flags
case debug_report_all: return "All";
}
}
}
#endif // FENNEC_RENDERERS_VULKAN_LIB_ENUM_H

View File

@@ -1,6 +1,6 @@
// =====================================================================================================================
// fennec, a free and open source game engine
// Copyright © 2025 - 2026 Medusa Slockbower
// Copyright © 2025 Medusa Slockbower
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
@@ -16,20 +16,31 @@
// along with this program. If not, see <https://www.gnu.org/licenses/>.
// =====================================================================================================================
///
/// \file forward.h
/// \brief
///
///
/// \details
/// \author Medusa Slockbower
///
/// \copyright Copyright © 2025 - 2026 Medusa Slockbower ([GPLv3](https://www.gnu.org/licenses/gpl-3.0.en.html))
///
///
#include <fennec/renderers/vulkan/vkcontext.h>
namespace fennec {
#ifndef FENNEC_RENDERERS_VULKAN_LIB_FORWARD_H
#define FENNEC_RENDERERS_VULKAN_LIB_FORWARD_H
#include <volk.h>
namespace fennec::vk
{
struct app_info;
struct instance;
struct physical_device;
vkcontext::vkcontext(display_server* display)
: gfxcontext(display) {
}
vkcontext::~vkcontext() {
}
bool vkcontext::is_valid() {
return false;
}
} // fennec
#endif // FENNEC_RENDERERS_VULKAN_LIB_FORWARD_H

View File

@@ -32,10 +32,11 @@
#ifndef FENNEC_RENDERERS_VULKAN_LIB_INSTANCE_H
#define FENNEC_RENDERERS_VULKAN_LIB_INSTANCE_H
#include <volk.h>
#include <fennec/containers/dynarray.h>
#include <fennec/renderers/vulkan/lib/forward.h>
#include <fennec/renderers/vulkan/lib/app_info.h>
#include <fennec/renderers/vulkan/lib/physical_device.h>
#include <fennec/containers/dynarray.h>
namespace fennec::vk
{
@@ -46,6 +47,10 @@ struct instance {
// Definitions =========================================================================================================
public:
/// \name Definitions
/// @{
using create_flags = VkInstanceCreateFlags; //!< Alias for VkInstanceCreateFlags
@@ -56,16 +61,19 @@ public:
// Constructors & Destructor ---------------------------------------------------------------------------------------
public:
/// \name Constructors & Destructor
/// @{
///
/// \brief Constructor, acts as default constructor, takes \f$nullptr\f$ for \f$info\f$
/// \param flags
/// \param ext
/// \brief Null App Info Constructor
/// \param flags The flags to create the instance with.
///
/// \note Acts as Default Constructor.
create_info(
create_flags flags = {}, nullptr_t = nullptr,
void* ext = nullptr
create_flags flags = {}, nullptr_t = nullptr
) : VkInstanceCreateInfo {
.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO,
.pNext = ext,
.pNext = nullptr,
.flags = flags,
.pApplicationInfo = nullptr,
.enabledLayerCount = 0,
@@ -76,16 +84,17 @@ public:
}
///
/// \brief
/// \param flags
/// \param info
/// \param ext
/// \brief App Info Constructor
/// \param flags The flags to create the instance with.
/// \param info A const-qualified reference to an \ref fennec::vk::app_info "app_info" object.
///
/// \note The object referenced by \emph{info} must have a lifetime that extends until an
/// \ref fennec::vk::instance "instance" is constructed.
create_info(
create_flags flags, const app_info& info,
void* ext = nullptr
create_flags flags, const app_info& info
) : VkInstanceCreateInfo {
.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO,
.pNext = ext,
.pNext = nullptr,
.flags = flags,
.pApplicationInfo = info,
.enabledLayerCount = 0,
@@ -95,14 +104,22 @@ public:
} {
}
///
/// \brief Layer Constructor
/// \tparam LayersN The number of layers
/// \param flags The flags to create the instance with.
/// \param info A const-qualified reference to an \ref fennec::vk::app_info "app_info" object.
/// \param layers An array of layer names to enable.
///
/// \note The object referenced by \emph{info} must have a lifetime that extends until an
/// \ref fennec::vk::instance "instance" is constructed.
template<size_t LayersN>
create_info(
create_flags flags, const app_info& info,
const cstring (&layers)[LayersN], nullptr_t,
void* ext
const cstring (&layers)[LayersN], nullptr_t
) : VkInstanceCreateInfo {
.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO,
.pNext = ext,
.pNext = nullptr,
.flags = flags,
.pApplicationInfo = info,
.enabledLayerCount = LayersN,
@@ -111,20 +128,31 @@ public:
.ppEnabledExtensionNames = nullptr,
} {
_layers.reserve(LayersN);
for (const auto& layer : layers) { _layers.push_back(layer); }
for (const auto& layer : layers) {
_layers.push_back(layer);
}
ppEnabledLayerNames = _layers.data();
ppEnabledExtensionNames = _extensions.data();
}
///
/// \brief Extension Constructor
/// \tparam ExtensionsN The number of extensions
/// \param flags The flags to create the instance with.
/// \param info A const-qualified reference to an \ref fennec::vk::app_info "app_info" object.
/// \param extensions An array of extension names to enable.
///
/// \note The object referenced by \emph{info} must have a lifetime that extends until an
/// \ref fennec::vk::instance "instance" is constructed.
template<size_t ExtensionsN>
create_info(
create_flags flags, const app_info& info,
nullptr_t, const cstring (&extensions)[ExtensionsN],
void* ext
nullptr_t, const cstring (&extensions)[ExtensionsN]
) : VkInstanceCreateInfo {
.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO,
.pNext = ext,
.pNext = nullptr,
.flags = flags,
.pApplicationInfo = info,
.enabledLayerCount = 0,
@@ -133,20 +161,32 @@ public:
.ppEnabledExtensionNames = nullptr,
} {
_extensions.reserve(ExtensionsN);
for (const auto& extension : extensions) { _extensions.push_back(extension); }
for (const auto& extension : extensions) {
_extensions.push_back(extension);
}
ppEnabledLayerNames = _layers.data();
ppEnabledExtensionNames = _extensions.data();
}
///
/// \brief Layer-Extension Constructor
/// \tparam LayersN The number of layers
/// \tparam ExtensionsN The number of extensions
/// \param flags The flags to create the instance with.
/// \param info A const-qualified reference to an \ref fennec::vk::app_info "app_info" object.
/// \param layers An array of layer names to enable.
/// \param extensions An array of extension names to enable.
///
/// \note The object referenced by \emph{info} must have a lifetime that extends until an
/// \ref fennec::vk::instance "instance" is constructed.
template<size_t LayersN, size_t ExtensionsN>
create_info(
create_flags flags, const app_info& info,
const cstring (&layers)[LayersN], const cstring (&extensions)[ExtensionsN],
void* ext
const cstring (&layers)[LayersN], const cstring (&extensions)[ExtensionsN]
) : VkInstanceCreateInfo {
.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO,
.pNext = ext,
.pNext = nullptr,
.flags = flags,
.pApplicationInfo = info,
.enabledLayerCount = LayersN,
@@ -155,92 +195,299 @@ public:
.ppEnabledExtensionNames = nullptr,
} {
_layers.reserve(LayersN);
for (const auto& layer : layers) { _layers.push_back(layer); }
for (const auto& layer : layers) {
_layers.push_back(layer);
}
_extensions.reserve(ExtensionsN);
for (const auto& extension : extensions) { _extensions.push_back(extension); }
for (const auto& extension : extensions) {
_extensions.push_back(extension);
}
ppEnabledLayerNames = _layers.data();
ppEnabledExtensionNames = _extensions.data();
}
///
/// \brief Dynamic Layer Constructor
/// \param flags The flags to create the instance with.
/// \param info A const-qualified reference to an \ref fennec::vk::app_info "app_info" object.
/// \param layers An array of layer names to enable.
///
/// \note The object referenced by \emph{info} must have a lifetime that extends until an
/// \ref fennec::vk::instance "instance" is constructed.
create_info(
create_flags flags, const app_info& info,
const dynarray<cstring>& layers, nullptr_t,
void* ext
const dynarray<cstring>& layers, nullptr_t
) : VkInstanceCreateInfo {
.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO,
.pNext = ext,
.pNext = nullptr,
.flags = flags,
.pApplicationInfo = info,
.enabledLayerCount = layers.size(),
.enabledLayerCount = static_cast<uint32_t>(layers.size()),
.ppEnabledLayerNames = nullptr,
.enabledExtensionCount = 0,
.ppEnabledExtensionNames = nullptr,
} {
_layers.reserve(enabledLayerCount);
for (const auto& layer : layers) { _layers.push_back(layer); }
for (const auto& layer : layers) {
_layers.push_back(layer);
}
ppEnabledLayerNames = _layers.data();
ppEnabledExtensionNames = _extensions.data();
}
///
/// \brief Dynamic Extension Constructor
/// \param flags The flags to create the instance with.
/// \param info A const-qualified reference to an \ref fennec::vk::app_info "app_info" object.
/// \param extensions An array of extension names to enable.
/// \param ext An extension structure.
///
/// \note The object referenced by \emph{info} must have a lifetime that extends until an
/// \ref fennec::vk::instance "instance" is constructed.
create_info(
create_flags flags, const app_info& info,
nullptr_t, const dynarray<cstring>& extensions,
void* ext
nullptr_t, const dynarray<cstring>& extensions
) : VkInstanceCreateInfo {
.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO,
.pNext = ext,
.pNext = nullptr,
.flags = flags,
.pApplicationInfo = info,
.enabledLayerCount = 0,
.ppEnabledLayerNames = nullptr,
.enabledExtensionCount = extensions.size(),
.enabledExtensionCount = static_cast<uint32_t>(extensions.size()),
.ppEnabledExtensionNames = nullptr,
} {
_extensions.reserve(enabledExtensionCount);
for (const auto& extension : extensions) { _extensions.push_back(extension); }
for (const auto& extension : extensions) {
_extensions.push_back(extension);
}
ppEnabledLayerNames = _layers.data();
ppEnabledExtensionNames = _extensions.data();
}
///
/// \brief Dynamic Layer-Extension Constructor
/// \param flags The flags to create the instance with.
/// \param info A const-qualified reference to an \ref fennec::vk::app_info "app_info" object.
/// \param layers An array of layer names to enable.
/// \param extensions An array of extension names to enable.
///
/// \note The object referenced by \emph{info} must have a lifetime that extends until an
/// \ref fennec::vk::instance "instance" is constructed.
create_info(
create_flags flags, const app_info& info,
const dynarray<cstring>& layers, const dynarray<cstring>& extensions,
void* ext
const dynarray<cstring>& layers, const dynarray<cstring>& extensions
) : VkInstanceCreateInfo {
.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO,
.pNext = ext,
.pNext = nullptr,
.flags = flags,
.pApplicationInfo = info,
.enabledLayerCount = layers.size(),
.enabledLayerCount = static_cast<uint32_t>(layers.size()),
.ppEnabledLayerNames = nullptr,
.enabledExtensionCount = extensions.size(),
.enabledExtensionCount = static_cast<uint32_t>(extensions.size()),
.ppEnabledExtensionNames = nullptr,
} {
_layers.reserve(enabledLayerCount);
for (const auto& layer : layers) { _layers.push_back(layer); }
for (const auto& layer : layers) {
_layers.push_back(layer);
}
_extensions.reserve(enabledExtensionCount);
for (const auto& extension : extensions) { _extensions.push_back(extension); }
for (const auto& extension : extensions) {
_extensions.push_back(extension);
}
ppEnabledLayerNames = _layers.data();
ppEnabledExtensionNames = _extensions.data();
}
///
/// \brief Destructor
~create_info() = default;
/// @}
// Assignment ------------------------------------------------------------------------------------------------------
public:
/// \name Assignment
/// @{
///
/// \brief Copy Assignment
/// \param rhs Create info to copy
/// \returns A reference to \emph{this} after having copied \emph{rhs}
create_info& operator=(const create_info& rhs) {
pNext = rhs.pNext;
flags = rhs.flags;
pApplicationInfo = rhs.pApplicationInfo;
_layers = rhs._layers;
ppEnabledLayerNames = _layers.data();
enabledLayerCount = _layers.size();
_extensions = rhs._extensions;
ppEnabledExtensionNames = _extensions.data();
enabledExtensionCount = _extensions.size();
return *this;
}
///
/// \brief Move Assignment
/// \param rhs Create info to move
/// \returns A reference to \emph{this} after having taken ownership of \emph{rhs}
create_info& operator=(create_info&& rhs) noexcept {
pNext = rhs.pNext;
flags = rhs.flags;
pApplicationInfo = rhs.pApplicationInfo;
_layers = move(rhs._layers);
ppEnabledLayerNames = _layers.data();
enabledLayerCount = _layers.size();
_extensions = move(rhs._extensions);
ppEnabledExtensionNames = _extensions.data();
enabledExtensionCount = _extensions.size();
return *this;
}
/// @}
// Layers & Extensions ---------------------------------------------------------------------------------------------
public:
/// \name Layers & Extensions
/// @{
///
/// \brief Enable the specified layer.
/// \param layer The layer name to enable.
void enable_layer(const cstring& layer) {
_layers.emplace_back(layer.data());
enabledLayerCount = _layers.size();
ppEnabledLayerNames = _layers.data();
}
///
/// \brief Enable the specified extension.
/// \param extension The extension name to enable.
void enable_extension(const cstring& extension) {
_extensions.emplace_back(extension.data());
enabledExtensionCount = _extensions.size();
ppEnabledExtensionNames = _extensions.data();
}
///
/// \brief Attach a debugger.
/// \param dbg The debugger to attach.
void attach_debugger(const debugger& dbg) {
_info = make_unique<debugger::info>(dbg);
pNext = *_info;
}
/// @}
// Implicit Conversions --------------------------------------------------------------------------------------------
public:
/// \name Implicit Conversions
/// @{
///
/// \returns \emph{this} as if it were a pointer to the underlying type, \emph{VkInstanceCreateInfo}.
operator VkInstanceCreateInfo*() noexcept {
return this;
}
///
/// \brief Implicit Pointer Conversion
/// \returns \emph{this} as if it were a pointer to the underlying type, \emph{VkInstanceCreateInfo}.
operator const VkInstanceCreateInfo*() const noexcept {
return this;
}
/// @}
// Private Member Variables ----------------------------------------------------------------------------------------
private:
dynarray<const char*> _layers;
dynarray<const char*> _extensions;
unique_ptr<debugger::info> _info;
};
instance();
/// @}
private:
VkInstance _handle;
using device_list = dynarray<physical_device>;
// Constructors & Destructor ===========================================================================================
public:
/// \name Constructors & Destructor
/// @{
///
/// \brief Instance Constructor
/// \param info The info to create the instance with.
/// \details Initializes a new \emph{VkInstance} using \emph{info}.
instance(const create_info& info) {
assertf((vkCreateInstance(info, nullptr, &_handle)), "Failed to create Vulkan instance.");
uint32_t count = 0;
vkEnumeratePhysicalDevices(_handle, &count, nullptr);
dynarray<VkPhysicalDevice> devices(count);
vkEnumeratePhysicalDevices(_handle, &count, devices.data());
_devices = devices;
}
///
/// Copy Constructor
/// \details Deleted, no semantics for copying an instance
instance(const instance&) = delete;
///
/// \brief Instance Destructor
/// \details Cleans up the held \emph{VkInstance}.
~instance() {
vkDestroyInstance(_handle, nullptr);
}
/// @}
// Properties ==========================================================================================================
public:
const device_list& available_devices() const {
return _devices;
}
// Access ==============================================================================================================
operator VkInstance() const {
return _handle;
}
// Private Member Variables ============================================================================================
private:
VkInstance _handle;
device_list _devices;
};
}

View File

@@ -0,0 +1,61 @@
// =====================================================================================================================
// fennec, a free and open source game engine
// Copyright © 2025 Medusa Slockbower
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
// =====================================================================================================================
///
/// \file logical_device.h
/// \brief
///
///
/// \details
/// \author Medusa Slockbower
///
/// \copyright Copyright © 2025 - 2026 Medusa Slockbower ([GPLv3](https://www.gnu.org/licenses/gpl-3.0.en.html))
///
///
#ifndef FENNEC_RENDERERS_VULKAN_LIB_LOGICAL_DEVICE_H
#define FENNEC_RENDERERS_VULKAN_LIB_LOGICAL_DEVICE_H
#include <fennec/renderers/vulkan/lib/physical_device.h>
namespace fennec::vk
{
class logical_device {
public:
logical_device(physical_device& device)
: _physical(&device) {
VkDeviceCreateInfo info {
};
vkCreateDevice(_physical, )
}
const physical_device& physical() const {
return *_physical;
}
private:
physical_device* _physical;
};
}
#endif // FENNEC_RENDERERS_VULKAN_LIB_LOGICAL_DEVICE_H

View File

@@ -0,0 +1,276 @@
// =====================================================================================================================
// fennec, a free and open source game engine
// Copyright © 2025 Medusa Slockbower
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
// =====================================================================================================================
///
/// \file physical_device.h
/// \brief
///
///
/// \details
/// \author Medusa Slockbower
///
/// \copyright Copyright © 2025 - 2026 Medusa Slockbower ([GPLv3](https://www.gnu.org/licenses/gpl-3.0.en.html))
///
///
#ifndef FENNEC_RENDERERS_VULKAN_LIB_PHYSICAL_DEVICE_H
#define FENNEC_RENDERERS_VULKAN_LIB_PHYSICAL_DEVICE_H
#include <fennec/renderers/vulkan/lib/forward.h>
#include <fennec/renderers/vulkan/lib/physical_device_properties.h>
#include <fennec/renderers/vulkan/lib/physical_device_features.h>
#include <fennec/containers/dynarray.h>
#include <fennec/core/version.h>
namespace fennec::vk
{
// Queue Families ======================================================================================================
///
/// \brief Struct representing the queue families a device has available.
struct device_queue_families {
// Definitions ---------------------------------------------------------------------------------------------------------
private:
using properties_t = dynarray<VkQueueFamilyProperties>;
using properties2_t = dynarray<VkQueueFamilyProperties2>;
// Constructors & Destructor -------------------------------------------------------------------------------------------
public:
/// \name Constructors & Destructor
/// @{
///
/// \brief Queue Families Constructor
/// \param device The device to obtain queue family information from.
explicit device_queue_families(VkPhysicalDevice device)
: _use_deprecated(vkGetPhysicalDeviceQueueFamilyProperties2 == nullptr) {
uint32_t count = 0;
if (_use_deprecated) {
vkGetPhysicalDeviceQueueFamilyProperties(device, &count, nullptr);
_queues2.resize(count);
vkGetPhysicalDeviceQueueFamilyProperties(device, &count, _queues.data());
} else {
vkGetPhysicalDeviceQueueFamilyProperties2(device, &count, nullptr);
_queues2.resize(count);
vkGetPhysicalDeviceQueueFamilyProperties2(device, &count, _queues2.data());
}
// TODO: Extensions
}
///
/// \brief Destructor
~device_queue_families() = default;
/// @}
// Properties ----------------------------------------------------------------------------------------------------------
public:
/// \name Properties
/// @{
///
/// \returns The number of queue families associated with the device.
size_t size() const {
return _use_deprecated ? _queues.size() : _queues2.size();
}
/// @}
// Access --------------------------------------------------------------------------------------------------------------
public:
/// \name Access
/// @{
///
/// \brief Queue Properties Access.
/// \param i The index of the queue family.
/// \returns A reference to the properties of the specified queue family.
const VkQueueFamilyProperties& operator[](size_t i) const {
return _use_deprecated ? _queues[i] : _queues2[i].queueFamilyProperties;
}
/// @}
// Private Member Variables --------------------------------------------------------------------------------------------
private:
bool _use_deprecated;
properties_t _queues;
properties2_t _queues2;
};
// Physical Device =====================================================================================================
///
/// \brief RAII Wrapper for VkPhysicalDevice.
/// \details Acquires information about the physical device at construction.
struct physical_device {
// Definitions ---------------------------------------------------------------------------------------------------------
public:
/// \name Definitions
/// @{
using handle_t = VkPhysicalDevice; //!< The underlying handle type
/// @}
// Constructors & Destructor -------------------------------------------------------------------------------------------
public:
/// \name Constructors & Destructor
/// @{
///
/// \brief Device Constructor
/// \param handle The handle to acquire.
/// \details Acquires device information.
explicit physical_device(VkPhysicalDevice handle)
: _handle(handle)
, _properties(handle)
, _features(handle, _properties)
, _queue_families(handle) { }
///
/// \brief Move Constructor
/// \param device The device to acquire.
/// \details Moves already gathered information instead polling the driver again.
physical_device(physical_device&& device) noexcept
: _handle(device._handle)
, _properties(move(device._properties))
, _features(move(device._features))
, _queue_families(move(device._queue_families)) { }
/// @}
// Assignment ----------------------------------------------------------------------------------------------------------
public:
///
/// \brief Move Assignment
/// \param device
/// \return
physical_device& operator=(physical_device&& device) noexcept {
_handle = device._handle;
_properties = move(device._properties);
_features = move(device._features);
_queue_families = move(device._queue_families);
return *this;
}
// Properties ----------------------------------------------------------------------------------------------------------
public:
///
/// \returns The API version supported by the device
version api_version() const {
return {
.major = VK_API_VERSION_MAJOR(_properties.core10->apiVersion),
.minor = VK_API_VERSION_MINOR(_properties.core10->apiVersion),
.patch = VK_API_VERSION_PATCH(_properties.core10->apiVersion),
.meta = VK_API_VERSION_VARIANT(_properties.core10->apiVersion),
};
}
///
/// \returns The version of the device's driver
version driver_version() const {
return {
.major = VK_VERSION_MAJOR(_properties.core10->driverVersion),
.minor = VK_VERSION_MINOR(_properties.core10->driverVersion),
.patch = VK_VERSION_PATCH(_properties.core10->driverVersion),
};
}
///
/// \returns The type of the device.
/// \see fennec::vk::device_type_
uint32_t type() const {
return _properties.core10->deviceType;
}
cstring name() const {
return _properties.core10->deviceName;
}
const device_properties& properties() const {
return _properties;
}
const device_features& features() const {
return _features;
}
const device_queue_families& queue_families() const {
return _queue_families;
}
uint32_t score() const {
uint32_t score = 0;
version api = api_version();
score += 1000 * api.major + 100 * api.minor;
score += 1000 * _type_score();
return score;
}
// Private Member Variables --------------------------------------------------------------------------------------------
private:
handle_t _handle;
device_properties _properties;
device_features _features;
device_queue_families _queue_families;
// Private Helpers -----------------------------------------------------------------------------------------------------
private:
uint32_t _type_score() const {
switch (_properties.core10->deviceType) {
default:
case VK_PHYSICAL_DEVICE_TYPE_OTHER: return 1;
case VK_PHYSICAL_DEVICE_TYPE_CPU: return 2;
case VK_PHYSICAL_DEVICE_TYPE_VIRTUAL_GPU: return 3;
case VK_PHYSICAL_DEVICE_TYPE_INTEGRATED_GPU: return 4;
case VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU: return 5;
}
}
};
}
#endif // FENNEC_RENDERERS_VULKAN_LIB_PHYSICAL_DEVICE_H

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,59 @@
// =====================================================================================================================
// fennec, a free and open source game engine
// Copyright © 2025 Medusa Slockbower
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
// =====================================================================================================================
///
/// \file surface.h
/// \brief
///
///
/// \details
/// \author Medusa Slockbower
///
/// \copyright Copyright © 2025 - 2026 Medusa Slockbower ([GPLv3](https://www.gnu.org/licenses/gpl-3.0.en.html))
///
///
#ifndef FENNEC_RENDERERS_VULKAN_LIB_SURFACE_H
#define FENNEC_RENDERERS_VULKAN_LIB_SURFACE_H
#include <vulkan/vulkan_core.h>
namespace fennec::vk
{
class surface {
public:
///
/// \brief Surface Constructor.
/// \param surface The surface to take ownership of.
surface(VkSurfaceKHR surface)
: _handle(surface) {
}
VkSurfaceKHR handle() const {
return _handle;
}
private:
VkSurfaceKHR _handle;
};
}
#endif // FENNEC_RENDERERS_VULKAN_LIB_SURFACE_H

View File

@@ -32,20 +32,88 @@
#ifndef FENNEC_PLATFORM_VULKAN_VKCONTEXT_H
#define FENNEC_PLATFORM_VULKAN_VKCONTEXT_H
#include <fennec/platform/interface/forward.h>
#include <fennec/core/logger.h>
#include <fennec/renderers/interface/gfxcontext.h>
#include <fennec/renderers/vulkan/lib/debug.h>
#include <fennec/renderers/vulkan/lib/instance.h>
namespace fennec
{
class vkcontext : public gfxcontext {
public:
vkcontext(display_server* display);
~vkcontext();
///
/// \brief Vulkan Context
class vkcontext : public gfxcontext, public vk::debugger {
// Constructor & Destructor ============================================================================================
public:
/// \name Constructor & Destructor
/// @{
///
/// \brief Context Constructor
/// \param display The display server
/// \param extensions The required extensions for the implementation
///
/// \note An override ***should not*** accept \emph{extensions} as an argument and should instead provide it directly
/// to the constructor for the extensions your implementation needs. For example:
/// ```cpp
/// class wayland_vkcontext : public vkcontext {
/// wayland_vkcontext(display_server* display)
/// : vkcontext(display, { "VK_KHR_wayland_surface" }) {
/// }
/// }
/// ```
explicit vkcontext(display_server* display, const dynarray<cstring>& extensions);
///
/// \brief Context Destructor
~vkcontext() override;
/// @}
// Properties ==========================================================================================================
public:
/// \name Properties
/// @{
///
/// \brief Context Validity
/// \returns \emph{true} if the context is initialized and valid, \emph{false} otherwise.
bool is_valid() override;
vk::instance* get_instance() {
return instance.get();
}
/// @}
// Debug Callbacks =====================================================================================================
public:
void message(uint32_t severity,
uint32_t type,
const cstring& id,
const cstring& message,
const dynarray<cstring>& queue,
const dynarray<cstring>& commands,
const dynarray<string>& objects) override;
static uint32_t translate_severity(uint32_t x) {
switch (x) {
default:
case vk::debug_message_severity_info: return logger::info;
case vk::debug_message_severity_verbose: return logger::alert;
case vk::debug_message_severity_warning: return logger::warning;
case vk::debug_message_severity_error: return logger::error;
}
}
protected:
unique_ptr<vk::instance> instance;
};
} // fennec

View File

@@ -0,0 +1,63 @@
// =====================================================================================================================
// fennec, a free and open source game engine
// Copyright © 2025 Medusa Slockbower
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
// =====================================================================================================================
///
/// \file vksurface.h
/// \brief
///
///
/// \details
/// \author Medusa Slockbower
///
/// \copyright Copyright © 2025 - 2026 Medusa Slockbower ([GPLv3](https://www.gnu.org/licenses/gpl-3.0.en.html))
///
///
#ifndef FENNEC_RENDERERS_VULKAN_VKSURFACE_H
#define FENNEC_RENDERERS_VULKAN_VKSURFACE_H
#include <fennec/renderers/interface/gfxsurface.h>
#include <fennec/renderers/vulkan/lib/surface.h>
namespace fennec
{
class vksurface : public gfxsurface {
private:
using surface_t = unique_ptr<vk::surface>;
public:
vksurface(fennec::window* win, gfxcontext* ctx, surface_t&& surface);
~vksurface();
void make_current() override;
void swap() override;
void resize(const ivec2& size) override;
private:
surface_t _surface;
};
}
#endif // FENNEC_RENDERERS_VULKAN_VKSURFACE_H