feat(renderer): contextn, test utils, refactors & changes
This commit is contained in:
parent
405c707e23
commit
5148b8836c
23 changed files with 836 additions and 155 deletions
|
@ -1,5 +1,6 @@
|
||||||
add_library_module(renderer
|
add_library_module(renderer
|
||||||
system.cpp
|
system.cpp
|
||||||
|
vk/debug/messenger.cpp
|
||||||
vk/context/instance.cpp
|
vk/context/instance.cpp
|
||||||
vk/context/surface.cpp
|
vk/context/surface.cpp
|
||||||
vk/context/device.cpp
|
vk/context/device.cpp
|
||||||
|
@ -12,6 +13,7 @@ target_link_libraries(renderer
|
||||||
PUBLIC
|
PUBLIC
|
||||||
app
|
app
|
||||||
ecs
|
ecs
|
||||||
|
memory
|
||||||
PRIVATE
|
PRIVATE
|
||||||
surface
|
surface
|
||||||
pthread
|
pthread
|
||||||
|
@ -19,6 +21,8 @@ PRIVATE
|
||||||
|
|
||||||
add_test_module(renderer
|
add_test_module(renderer
|
||||||
system.test.cpp
|
system.test.cpp
|
||||||
|
vk/test_utils.cpp
|
||||||
|
vk/debug/messenger.test.cpp
|
||||||
vk/context/instance.test.cpp
|
vk/context/instance.test.cpp
|
||||||
vk/context/surface.test.cpp
|
vk/context/surface.test.cpp
|
||||||
vk/context/device.test.cpp
|
vk/context/device.test.cpp
|
||||||
|
@ -26,3 +30,8 @@ add_test_module(renderer
|
||||||
vk/context/context.test.cpp
|
vk/context/context.test.cpp
|
||||||
vk/pipeline.test.cpp
|
vk/pipeline.test.cpp
|
||||||
)
|
)
|
||||||
|
target_link_libraries(renderer_tests
|
||||||
|
PRIVATE
|
||||||
|
surface
|
||||||
|
pthread
|
||||||
|
)
|
||||||
|
|
|
@ -108,7 +108,7 @@ private:
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
Suite raii = [] {
|
Suite raii = "raii"_suite = [] {
|
||||||
Case { "happy path won't throw" } = [&] {
|
Case { "happy path won't throw" } = [&] {
|
||||||
ignore = create_system();
|
ignore = create_system();
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,4 +1,3 @@
|
||||||
#include <ranges>
|
|
||||||
#include <renderer/vk/context/context.hpp>
|
#include <renderer/vk/context/context.hpp>
|
||||||
#include <renderer/vk/context/instance.hpp>
|
#include <renderer/vk/context/instance.hpp>
|
||||||
|
|
||||||
|
|
0
modules/renderer/private/vk/context/context.test.cpp
Normal file
0
modules/renderer/private/vk/context/context.test.cpp
Normal file
|
@ -1,9 +1,14 @@
|
||||||
#include <renderer/vk/context/device.hpp>
|
#include <renderer/vk/context/device.hpp>
|
||||||
|
#include <renderer/vk/context/instance.hpp>
|
||||||
|
#include <renderer/vk/context/surface.hpp>
|
||||||
|
#include <renderer/vk/debug/validation.hpp>
|
||||||
|
|
||||||
namespace lt::renderer::vk {
|
namespace lt::renderer::vk {
|
||||||
|
|
||||||
Device::Device(const Surface &surface)
|
Device::Device(const Surface &surface)
|
||||||
{
|
{
|
||||||
|
ensure(surface.vk(), "Failed to initialize vk::Device: null vulkan surface");
|
||||||
|
|
||||||
initialize_physical_device();
|
initialize_physical_device();
|
||||||
initialize_logical_device();
|
initialize_logical_device();
|
||||||
Instance::load_device_functions(m_device);
|
Instance::load_device_functions(m_device);
|
||||||
|
|
|
@ -1,15 +1,14 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <memory/pointer_types/null_on_move.hpp>
|
#include <memory/pointer_types/null_on_move.hpp>
|
||||||
#include <renderer/vk/context/instance.hpp>
|
#include <renderer/vk/vulkan.hpp>
|
||||||
#include <renderer/vk/context/surface.hpp>
|
|
||||||
|
|
||||||
namespace lt::renderer::vk {
|
namespace lt::renderer::vk {
|
||||||
|
|
||||||
class Device
|
class Device
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
Device(const Surface &surface);
|
Device(const class Surface &surface);
|
||||||
|
|
||||||
~Device();
|
~Device();
|
||||||
|
|
||||||
|
@ -41,7 +40,7 @@ private:
|
||||||
|
|
||||||
void initialize_logical_device();
|
void initialize_logical_device();
|
||||||
|
|
||||||
void initialize_queue(const Surface &surface);
|
void initialize_queue(const class Surface &surface);
|
||||||
|
|
||||||
[[nodiscard]] auto find_suitable_queue_family() const -> uint32_t;
|
[[nodiscard]] auto find_suitable_queue_family() const -> uint32_t;
|
||||||
|
|
||||||
|
|
99
modules/renderer/private/vk/context/device.test.cpp
Normal file
99
modules/renderer/private/vk/context/device.test.cpp
Normal file
|
@ -0,0 +1,99 @@
|
||||||
|
#include <ranges>
|
||||||
|
#include <renderer/vk/context/device.hpp>
|
||||||
|
#include <renderer/vk/context/surface.hpp>
|
||||||
|
#include <surface/components.hpp>
|
||||||
|
#include <surface/system.hpp>
|
||||||
|
#include <test/test.hpp>
|
||||||
|
|
||||||
|
using namespace lt;
|
||||||
|
using renderer::vk::Device;
|
||||||
|
using renderer::vk::Surface;
|
||||||
|
using test::Case;
|
||||||
|
using test::expect_ne;
|
||||||
|
using test::expect_throw;
|
||||||
|
using test::Suite;
|
||||||
|
|
||||||
|
constexpr auto resolution = math::uvec2 { 800u, 600u };
|
||||||
|
|
||||||
|
Suite raii = "device_raii"_suite = [] {
|
||||||
|
Case { "happy path won't throw" } = [] {
|
||||||
|
auto registry = create_ref<ecs::Registry>();
|
||||||
|
auto surface_system = surface::System { registry };
|
||||||
|
auto entity = ecs::Entity { registry, registry->create_entity() };
|
||||||
|
entity.add<surface::SurfaceComponent>(surface::SurfaceComponent::CreateInfo {
|
||||||
|
.resolution = resolution,
|
||||||
|
.visible = true,
|
||||||
|
});
|
||||||
|
|
||||||
|
auto surface = Surface { entity };
|
||||||
|
auto device = Device { surface };
|
||||||
|
};
|
||||||
|
|
||||||
|
Case { "many won't freeze/throw" } = [] {
|
||||||
|
auto registry = create_ref<ecs::Registry>();
|
||||||
|
auto surface_system = surface::System { registry };
|
||||||
|
auto entity = ecs::Entity { registry, registry->create_entity() };
|
||||||
|
entity.add<surface::SurfaceComponent>(surface::SurfaceComponent::CreateInfo {
|
||||||
|
.resolution = resolution,
|
||||||
|
.visible = true,
|
||||||
|
});
|
||||||
|
auto surface = Surface { entity };
|
||||||
|
|
||||||
|
// it takes a loong time to initialize vulkan + setup device
|
||||||
|
for (auto idx : std::views::iota(0, 10))
|
||||||
|
{
|
||||||
|
Device { surface };
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
Case { "unhappy path throws" } = [] {
|
||||||
|
auto registry = create_ref<ecs::Registry>();
|
||||||
|
auto surface_system = surface::System { registry };
|
||||||
|
auto entity = ecs::Entity { registry, registry->create_entity() };
|
||||||
|
entity.add<surface::SurfaceComponent>(surface::SurfaceComponent::CreateInfo {
|
||||||
|
.resolution = resolution,
|
||||||
|
.visible = true,
|
||||||
|
});
|
||||||
|
|
||||||
|
auto moved_out_surface = Surface { entity };
|
||||||
|
auto surface = std::move(moved_out_surface);
|
||||||
|
|
||||||
|
expect_throw([&] { Device { moved_out_surface }; });
|
||||||
|
};
|
||||||
|
|
||||||
|
Case { "post construct has correct state" } = [] {
|
||||||
|
auto registry = create_ref<ecs::Registry>();
|
||||||
|
auto surface_system = surface::System { registry };
|
||||||
|
auto entity = ecs::Entity { registry, registry->create_entity() };
|
||||||
|
entity.add<surface::SurfaceComponent>(surface::SurfaceComponent::CreateInfo {
|
||||||
|
.resolution = resolution,
|
||||||
|
.visible = true,
|
||||||
|
});
|
||||||
|
|
||||||
|
auto surface = Surface { entity };
|
||||||
|
auto device = Device { surface };
|
||||||
|
|
||||||
|
for (auto &index : device.get_family_indices())
|
||||||
|
{
|
||||||
|
expect_ne(index, VK_QUEUE_FAMILY_IGNORED);
|
||||||
|
}
|
||||||
|
test::expect_true(device.physical());
|
||||||
|
test::expect_true(device.vk());
|
||||||
|
};
|
||||||
|
|
||||||
|
Case { "post destruct has correct state" } = [] {
|
||||||
|
auto registry = create_ref<ecs::Registry>();
|
||||||
|
auto surface_system = surface::System { registry };
|
||||||
|
auto entity = ecs::Entity { registry, registry->create_entity() };
|
||||||
|
entity.add<surface::SurfaceComponent>(surface::SurfaceComponent::CreateInfo {
|
||||||
|
.resolution = resolution,
|
||||||
|
.visible = true,
|
||||||
|
});
|
||||||
|
|
||||||
|
auto surface = Surface { entity };
|
||||||
|
|
||||||
|
{
|
||||||
|
auto device = Device { surface };
|
||||||
|
}
|
||||||
|
};
|
||||||
|
};
|
|
@ -1,5 +1,6 @@
|
||||||
#include <app/system.hpp>
|
#include <app/system.hpp>
|
||||||
#include <renderer/vk/context/instance.hpp>
|
#include <renderer/vk/context/instance.hpp>
|
||||||
|
#include <renderer/vk/debug/validation.hpp>
|
||||||
|
|
||||||
#if defined(_WIN32)
|
#if defined(_WIN32)
|
||||||
#error "Unsupported platform (currently)"
|
#error "Unsupported platform (currently)"
|
||||||
|
@ -113,17 +114,11 @@ Instance::Instance()
|
||||||
|
|
||||||
initialize_instance();
|
initialize_instance();
|
||||||
load_instance_functions();
|
load_instance_functions();
|
||||||
initialize_debug_messenger();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Instance::~Instance()
|
Instance::~Instance()
|
||||||
{
|
{
|
||||||
if (m_instance)
|
vk_destroy_instance(m_instance, nullptr);
|
||||||
{
|
|
||||||
vk_destroy_debug_messenger(m_instance, m_debug_messenger, nullptr);
|
|
||||||
vk_destroy_instance(m_instance, nullptr);
|
|
||||||
}
|
|
||||||
|
|
||||||
unload_library();
|
unload_library();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -143,12 +138,83 @@ void Instance::initialize_instance()
|
||||||
VK_KHR_SURFACE_EXTENSION_NAME,
|
VK_KHR_SURFACE_EXTENSION_NAME,
|
||||||
VK_KHR_XLIB_SURFACE_EXTENSION_NAME,
|
VK_KHR_XLIB_SURFACE_EXTENSION_NAME,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const char *layer_name = "VK_LAYER_KHRONOS_validation";
|
||||||
|
const auto setting_validate_core = VkBool32 { VK_TRUE };
|
||||||
|
const auto setting_validate_sync = VkBool32 { VK_TRUE };
|
||||||
|
const auto setting_thread_safety = VkBool32 { VK_TRUE };
|
||||||
|
const auto *setting_debug_action = "";
|
||||||
|
const auto setting_enable_message_limit = VkBool32 { VK_TRUE };
|
||||||
|
const auto setting_duplicate_message_limit = uint32_t { 3u };
|
||||||
|
auto setting_report_flags = std::array<const char *, 5> {
|
||||||
|
"info", "warn", "perf", "error", "verbose",
|
||||||
|
};
|
||||||
|
|
||||||
|
const auto settings = std::array<VkLayerSettingEXT, 7>({
|
||||||
|
{
|
||||||
|
.pLayerName = layer_name,
|
||||||
|
.pSettingName = "validate_core",
|
||||||
|
.type = VK_LAYER_SETTING_TYPE_BOOL32_EXT,
|
||||||
|
.valueCount = 1,
|
||||||
|
.pValues = &setting_validate_core,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.pLayerName = layer_name,
|
||||||
|
.pSettingName = "validate_sync",
|
||||||
|
.type = VK_LAYER_SETTING_TYPE_BOOL32_EXT,
|
||||||
|
.valueCount = 1,
|
||||||
|
.pValues = &setting_validate_sync,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.pLayerName = layer_name,
|
||||||
|
.pSettingName = "thread_safety",
|
||||||
|
.type = VK_LAYER_SETTING_TYPE_BOOL32_EXT,
|
||||||
|
.valueCount = 1,
|
||||||
|
.pValues = &setting_thread_safety,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.pLayerName = layer_name,
|
||||||
|
.pSettingName = "debug_action",
|
||||||
|
.type = VK_LAYER_SETTING_TYPE_STRING_EXT,
|
||||||
|
.valueCount = 1,
|
||||||
|
.pValues = static_cast<const void *>(&setting_debug_action),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.pLayerName = layer_name,
|
||||||
|
.pSettingName = "report_flags",
|
||||||
|
.type = VK_LAYER_SETTING_TYPE_STRING_EXT,
|
||||||
|
.valueCount = setting_report_flags.size(),
|
||||||
|
.pValues = static_cast<const void *>(setting_report_flags.data()),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.pLayerName = layer_name,
|
||||||
|
.pSettingName = "enable_message_limit",
|
||||||
|
.type = VK_LAYER_SETTING_TYPE_BOOL32_EXT,
|
||||||
|
.valueCount = 1,
|
||||||
|
.pValues = &setting_enable_message_limit,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.pLayerName = layer_name,
|
||||||
|
.pSettingName = "duplicate_message_limit",
|
||||||
|
.type = VK_LAYER_SETTING_TYPE_UINT32_EXT,
|
||||||
|
.valueCount = 1u,
|
||||||
|
.pValues = &setting_duplicate_message_limit,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const VkLayerSettingsCreateInfoEXT layer_settings_create_info = {
|
||||||
|
.sType = VK_STRUCTURE_TYPE_LAYER_SETTINGS_CREATE_INFO_EXT,
|
||||||
|
.settingCount = settings.size(),
|
||||||
|
.pSettings = settings.data()
|
||||||
|
};
|
||||||
|
|
||||||
auto layers = std::vector<const char *> {
|
auto layers = std::vector<const char *> {
|
||||||
"VK_LAYER_KHRONOS_validation",
|
"VK_LAYER_KHRONOS_validation",
|
||||||
};
|
};
|
||||||
|
|
||||||
auto instance_info = VkInstanceCreateInfo {
|
auto instance_info = VkInstanceCreateInfo {
|
||||||
.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO,
|
.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO,
|
||||||
|
.pNext = &layer_settings_create_info,
|
||||||
.pApplicationInfo = &app_info,
|
.pApplicationInfo = &app_info,
|
||||||
.enabledLayerCount = static_cast<uint32_t>(layers.size()),
|
.enabledLayerCount = static_cast<uint32_t>(layers.size()),
|
||||||
.ppEnabledLayerNames = layers.data(),
|
.ppEnabledLayerNames = layers.data(),
|
||||||
|
@ -174,32 +240,6 @@ void Instance::initialize_instance()
|
||||||
ensure(m_instance, "Failed to create vulkan instance");
|
ensure(m_instance, "Failed to create vulkan instance");
|
||||||
}
|
}
|
||||||
|
|
||||||
void Instance::initialize_debug_messenger()
|
|
||||||
{
|
|
||||||
const auto info = VkDebugUtilsMessengerCreateInfoEXT {
|
|
||||||
.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT,
|
|
||||||
|
|
||||||
.messageSeverity = VK_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT
|
|
||||||
| VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT
|
|
||||||
| VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT
|
|
||||||
| VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT,
|
|
||||||
|
|
||||||
.messageType = VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT
|
|
||||||
| VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT
|
|
||||||
| VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT,
|
|
||||||
|
|
||||||
|
|
||||||
.pfnUserCallback = &validation_layers_callback,
|
|
||||||
|
|
||||||
.pUserData = {},
|
|
||||||
};
|
|
||||||
|
|
||||||
ensure(
|
|
||||||
!vk_create_debug_messenger(m_instance, &info, nullptr, &m_debug_messenger),
|
|
||||||
"Failed to create vulkan debug utils messenger"
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Instance::load_library()
|
void Instance::load_library()
|
||||||
{
|
{
|
||||||
library = dlopen("libvulkan.so", RTLD_NOW | RTLD_LOCAL);
|
library = dlopen("libvulkan.so", RTLD_NOW | RTLD_LOCAL);
|
||||||
|
|
|
@ -1,103 +1,9 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#define VK_NO_PROTOTYPES
|
#include <renderer/vk/vulkan.hpp>
|
||||||
#define VK_USE_PLATFORM_XLIB_KHR
|
|
||||||
#include <vulkan/vulkan.h>
|
|
||||||
#include <vulkan/vulkan_xlib.h>
|
|
||||||
|
|
||||||
namespace lt::renderer::vk {
|
namespace lt::renderer::vk {
|
||||||
|
|
||||||
inline void vkc(VkResult result)
|
|
||||||
{
|
|
||||||
if (result)
|
|
||||||
{
|
|
||||||
throw std::runtime_error {
|
|
||||||
std::format("Vulkan call failed with result: {}", std::to_underlying(result))
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// NOLINTBEGIN(cppcoreguidelines-avoid-non-const-global-variables)
|
|
||||||
// global functions
|
|
||||||
extern PFN_vkGetInstanceProcAddr vk_get_instance_proc_address;
|
|
||||||
extern PFN_vkCreateInstance vk_create_instance;
|
|
||||||
extern PFN_vkEnumerateInstanceExtensionProperties vk_enumerate_instance_extension_properties;
|
|
||||||
extern PFN_vkEnumerateInstanceLayerProperties vk_enumerate_instance_layer_properties;
|
|
||||||
|
|
||||||
// instance functions
|
|
||||||
extern PFN_vkDestroyInstance vk_destroy_instance;
|
|
||||||
extern PFN_vkEnumeratePhysicalDevices vk_enumerate_physical_devices;
|
|
||||||
extern PFN_vkGetPhysicalDeviceProperties vk_get_physical_device_properties;
|
|
||||||
extern PFN_vkGetPhysicalDeviceQueueFamilyProperties vk_get_physical_device_queue_family_properties;
|
|
||||||
extern PFN_vkCreateDevice vk_create_device;
|
|
||||||
extern PFN_vkGetDeviceProcAddr vk_get_device_proc_address;
|
|
||||||
extern PFN_vkDestroyDevice vk_destroy_device;
|
|
||||||
extern PFN_vkGetPhysicalDeviceFeatures vk_get_physical_device_features;
|
|
||||||
extern PFN_vkEnumerateDeviceExtensionProperties vk_enumerate_device_extension_properties;
|
|
||||||
|
|
||||||
// extension instance functions
|
|
||||||
extern PFN_vkCmdBeginDebugUtilsLabelEXT vk_cmd_begin_debug_label;
|
|
||||||
extern PFN_vkCmdEndDebugUtilsLabelEXT vk_cmd_end_debug_label;
|
|
||||||
extern PFN_vkCmdInsertDebugUtilsLabelEXT vk_cmd_insert_debug_label;
|
|
||||||
extern PFN_vkCreateDebugUtilsMessengerEXT vk_create_debug_messenger;
|
|
||||||
extern PFN_vkDestroyDebugUtilsMessengerEXT vk_destroy_debug_messenger;
|
|
||||||
extern PFN_vkQueueBeginDebugUtilsLabelEXT vk_queue_begin_debug_label;
|
|
||||||
extern PFN_vkQueueEndDebugUtilsLabelEXT vk_queue_end_debug_label;
|
|
||||||
extern PFN_vkQueueInsertDebugUtilsLabelEXT vk_queue_insert_debug_label;
|
|
||||||
extern PFN_vkSetDebugUtilsObjectNameEXT vk_set_debug_object_name;
|
|
||||||
extern PFN_vkSetDebugUtilsObjectTagEXT vk_set_debug_object_tag;
|
|
||||||
extern PFN_vkSubmitDebugUtilsMessageEXT vk_submit_debug_message;
|
|
||||||
|
|
||||||
// surface instance functions
|
|
||||||
extern PFN_vkGetPhysicalDeviceSurfaceSupportKHR vk_get_physical_device_surface_support;
|
|
||||||
extern PFN_vkGetPhysicalDeviceSurfaceCapabilitiesKHR vk_get_physical_device_surface_capabilities;
|
|
||||||
extern PFN_vkGetPhysicalDeviceSurfaceFormatsKHR vk_get_physical_device_surface_formats;
|
|
||||||
extern PFN_vkCreateXlibSurfaceKHR vk_create_xlib_surface_khr;
|
|
||||||
extern PFN_vkDestroySurfaceKHR vk_destroy_surface_khr;
|
|
||||||
|
|
||||||
// device functions
|
|
||||||
extern PFN_vkGetDeviceQueue vk_get_device_queue;
|
|
||||||
extern PFN_vkCreateCommandPool vk_create_command_pool;
|
|
||||||
extern PFN_vkDestroyCommandPool vk_destroy_command_pool;
|
|
||||||
extern PFN_vkAllocateCommandBuffers vk_allocate_command_buffers;
|
|
||||||
extern PFN_vkFreeCommandBuffers vk_free_command_buffers;
|
|
||||||
extern PFN_vkBeginCommandBuffer vk_begin_command_buffer;
|
|
||||||
extern PFN_vkEndCommandBuffer vk_end_command_buffer;
|
|
||||||
extern PFN_vkCmdPipelineBarrier vk_cmd_pipeline_barrier;
|
|
||||||
extern PFN_vkQueueSubmit vk_queue_submit;
|
|
||||||
extern PFN_vkQueueWaitIdle vk_queue_wait_idle;
|
|
||||||
extern PFN_vkDeviceWaitIdle vk_device_wait_idle;
|
|
||||||
extern PFN_vkCreateFence vk_create_fence;
|
|
||||||
extern PFN_vkDestroyFence vk_destroy_fence;
|
|
||||||
extern PFN_vkWaitForFences vk_wait_for_fences;
|
|
||||||
extern PFN_vkResetFences vk_reset_fences;
|
|
||||||
extern PFN_vkCreateSemaphore vk_create_semaphore;
|
|
||||||
extern PFN_vkDestroySemaphore vk_destroy_semaphore;
|
|
||||||
extern PFN_vkCreateSwapchainKHR vk_create_swapchain_khr;
|
|
||||||
extern PFN_vkDestroySwapchainKHR vk_destroy_swapchain_khr;
|
|
||||||
extern PFN_vkGetSwapchainImagesKHR vk_get_swapchain_images_khr;
|
|
||||||
extern PFN_vkAcquireNextImageKHR vk_acquire_next_image_khr;
|
|
||||||
extern PFN_vkQueuePresentKHR vk_queue_present_khr;
|
|
||||||
extern PFN_vkCreateImageView vk_create_image_view;
|
|
||||||
extern PFN_vkDestroyImageView vk_destroy_image_view;
|
|
||||||
extern PFN_vkCreateRenderPass vk_create_render_pass;
|
|
||||||
extern PFN_vkDestroyRenderPass vk_destroy_render_pass;
|
|
||||||
extern PFN_vkCreateFramebuffer vk_create_frame_buffer;
|
|
||||||
extern PFN_vkDestroyFramebuffer vk_destroy_frame_buffer;
|
|
||||||
extern PFN_vkCreateShaderModule vk_create_shader_module;
|
|
||||||
extern PFN_vkDestroyShaderModule vk_destroy_shader_module;
|
|
||||||
extern PFN_vkCreatePipelineLayout vk_create_pipeline_layout;
|
|
||||||
extern PFN_vkDestroyPipelineLayout vk_destroy_pipeline_layout;
|
|
||||||
extern PFN_vkCreateGraphicsPipelines vk_create_graphics_pipelines;
|
|
||||||
extern PFN_vkDestroyPipeline vk_destroy_pipeline;
|
|
||||||
extern PFN_vkCmdBeginRenderPass vk_cmd_begin_render_pass;
|
|
||||||
extern PFN_vkCmdEndRenderPass vk_cmd_end_render_pass;
|
|
||||||
extern PFN_vkCmdBindPipeline vk_cmd_bind_pipeline;
|
|
||||||
extern PFN_vkCmdDraw vk_cmd_draw;
|
|
||||||
extern PFN_vkCmdSetViewport vk_cmd_set_viewport;
|
|
||||||
extern PFN_vkCmdSetScissor vk_cmd_set_scissors;
|
|
||||||
|
|
||||||
// NOLINTEND(cppcoreguidelines-avoid-non-const-global-variables)
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Responsible for dynamically loading Vulkan library/functions.
|
* Responsible for dynamically loading Vulkan library/functions.
|
||||||
*
|
*
|
||||||
|
@ -141,8 +47,6 @@ private:
|
||||||
|
|
||||||
void initialize_instance();
|
void initialize_instance();
|
||||||
|
|
||||||
void initialize_debug_messenger();
|
|
||||||
|
|
||||||
void load_library();
|
void load_library();
|
||||||
|
|
||||||
void unload_library();
|
void unload_library();
|
||||||
|
@ -154,8 +58,6 @@ private:
|
||||||
void load_device_functions_impl(VkDevice device);
|
void load_device_functions_impl(VkDevice device);
|
||||||
|
|
||||||
VkInstance m_instance = VK_NULL_HANDLE;
|
VkInstance m_instance = VK_NULL_HANDLE;
|
||||||
|
|
||||||
VkDebugUtilsMessengerEXT m_debug_messenger = VK_NULL_HANDLE;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace lt::renderer::vk
|
} // namespace lt::renderer::vk
|
||||||
|
|
95
modules/renderer/private/vk/context/instance.test.cpp
Normal file
95
modules/renderer/private/vk/context/instance.test.cpp
Normal file
|
@ -0,0 +1,95 @@
|
||||||
|
#include <renderer/vk/context/instance.hpp>
|
||||||
|
#include <test/test.hpp>
|
||||||
|
|
||||||
|
using namespace lt;
|
||||||
|
using renderer::vk::Instance;
|
||||||
|
using test::Case;
|
||||||
|
using test::expect_not_nullptr;
|
||||||
|
using test::Suite;
|
||||||
|
|
||||||
|
// NOLINTNEXTLINE
|
||||||
|
Suite raii = "raii"_suite = [] {
|
||||||
|
Case { "post singleton insantiation state is correct" } = [] {
|
||||||
|
expect_not_nullptr(Instance::get());
|
||||||
|
|
||||||
|
using namespace renderer::vk;
|
||||||
|
expect_not_nullptr(vk_get_instance_proc_address);
|
||||||
|
expect_not_nullptr(vk_create_instance);
|
||||||
|
expect_not_nullptr(vk_enumerate_instance_extension_properties);
|
||||||
|
expect_not_nullptr(vk_enumerate_instance_layer_properties);
|
||||||
|
|
||||||
|
expect_not_nullptr(vk_destroy_instance);
|
||||||
|
expect_not_nullptr(vk_enumerate_physical_devices);
|
||||||
|
expect_not_nullptr(vk_get_physical_device_properties);
|
||||||
|
expect_not_nullptr(vk_get_physical_device_queue_family_properties);
|
||||||
|
expect_not_nullptr(vk_create_device);
|
||||||
|
expect_not_nullptr(vk_get_device_proc_address);
|
||||||
|
expect_not_nullptr(vk_destroy_device);
|
||||||
|
expect_not_nullptr(vk_get_physical_device_features);
|
||||||
|
expect_not_nullptr(vk_enumerate_device_extension_properties);
|
||||||
|
|
||||||
|
expect_not_nullptr(vk_cmd_begin_debug_label);
|
||||||
|
expect_not_nullptr(vk_cmd_end_debug_label);
|
||||||
|
expect_not_nullptr(vk_cmd_insert_debug_label);
|
||||||
|
expect_not_nullptr(vk_create_debug_messenger);
|
||||||
|
expect_not_nullptr(vk_destroy_debug_messenger);
|
||||||
|
expect_not_nullptr(vk_queue_begin_debug_label);
|
||||||
|
expect_not_nullptr(vk_queue_end_debug_label);
|
||||||
|
expect_not_nullptr(vk_queue_insert_debug_label);
|
||||||
|
expect_not_nullptr(vk_set_debug_object_name);
|
||||||
|
expect_not_nullptr(vk_set_debug_object_tag);
|
||||||
|
expect_not_nullptr(vk_submit_debug_message);
|
||||||
|
|
||||||
|
expect_not_nullptr(vk_get_physical_device_surface_support);
|
||||||
|
expect_not_nullptr(vk_get_physical_device_surface_capabilities);
|
||||||
|
expect_not_nullptr(vk_get_physical_device_surface_formats);
|
||||||
|
expect_not_nullptr(vk_create_xlib_surface_khr);
|
||||||
|
expect_not_nullptr(vk_destroy_surface_khr);
|
||||||
|
};
|
||||||
|
|
||||||
|
Case { "post load device functions state is correct" } = [] {
|
||||||
|
using namespace renderer::vk;
|
||||||
|
expect_not_nullptr(Instance::get());
|
||||||
|
|
||||||
|
expect_not_nullptr(vk_get_device_queue);
|
||||||
|
expect_not_nullptr(vk_create_command_pool);
|
||||||
|
expect_not_nullptr(vk_destroy_command_pool);
|
||||||
|
expect_not_nullptr(vk_allocate_command_buffers);
|
||||||
|
expect_not_nullptr(vk_free_command_buffers);
|
||||||
|
expect_not_nullptr(vk_begin_command_buffer);
|
||||||
|
expect_not_nullptr(vk_end_command_buffer);
|
||||||
|
expect_not_nullptr(vk_cmd_pipeline_barrier);
|
||||||
|
expect_not_nullptr(vk_queue_submit);
|
||||||
|
expect_not_nullptr(vk_queue_wait_idle);
|
||||||
|
expect_not_nullptr(vk_device_wait_idle);
|
||||||
|
expect_not_nullptr(vk_create_fence);
|
||||||
|
expect_not_nullptr(vk_destroy_fence);
|
||||||
|
expect_not_nullptr(vk_wait_for_fences);
|
||||||
|
expect_not_nullptr(vk_reset_fences);
|
||||||
|
expect_not_nullptr(vk_create_semaphore);
|
||||||
|
expect_not_nullptr(vk_destroy_semaphore);
|
||||||
|
expect_not_nullptr(vk_create_swapchain_khr);
|
||||||
|
expect_not_nullptr(vk_destroy_swapchain_khr);
|
||||||
|
expect_not_nullptr(vk_get_swapchain_images_khr);
|
||||||
|
expect_not_nullptr(vk_acquire_next_image_khr);
|
||||||
|
expect_not_nullptr(vk_queue_present_khr);
|
||||||
|
expect_not_nullptr(vk_create_image_view);
|
||||||
|
expect_not_nullptr(vk_destroy_image_view);
|
||||||
|
expect_not_nullptr(vk_create_render_pass);
|
||||||
|
expect_not_nullptr(vk_destroy_render_pass);
|
||||||
|
expect_not_nullptr(vk_create_frame_buffer);
|
||||||
|
expect_not_nullptr(vk_destroy_frame_buffer);
|
||||||
|
expect_not_nullptr(vk_create_shader_module);
|
||||||
|
expect_not_nullptr(vk_destroy_shader_module);
|
||||||
|
expect_not_nullptr(vk_create_pipeline_layout);
|
||||||
|
expect_not_nullptr(vk_destroy_pipeline_layout);
|
||||||
|
expect_not_nullptr(vk_create_graphics_pipelines);
|
||||||
|
expect_not_nullptr(vk_destroy_pipeline);
|
||||||
|
expect_not_nullptr(vk_cmd_begin_render_pass);
|
||||||
|
expect_not_nullptr(vk_cmd_end_render_pass);
|
||||||
|
expect_not_nullptr(vk_cmd_bind_pipeline);
|
||||||
|
expect_not_nullptr(vk_cmd_draw);
|
||||||
|
expect_not_nullptr(vk_cmd_set_viewport);
|
||||||
|
expect_not_nullptr(vk_cmd_set_scissors);
|
||||||
|
};
|
||||||
|
};
|
|
@ -1,4 +1,3 @@
|
||||||
#include <lt_debug/assertions.hpp>
|
|
||||||
#include <renderer/vk/context/surface.hpp>
|
#include <renderer/vk/context/surface.hpp>
|
||||||
#include <surface/components.hpp>
|
#include <surface/components.hpp>
|
||||||
|
|
||||||
|
@ -8,8 +7,8 @@ Surface::Surface(const ecs::Entity &surface_entity)
|
||||||
{
|
{
|
||||||
const auto &component = surface_entity.get<surface::SurfaceComponent>();
|
const auto &component = surface_entity.get<surface::SurfaceComponent>();
|
||||||
|
|
||||||
esnure(component.get_native_data().display, "Failed to initialize usrface: null x-display");
|
ensure(component.get_native_data().display, "Failed to initialize vk::Surface: null x-display");
|
||||||
esnure(component.get_native_data().window, "Failed to initialize usrface: null x-window");
|
ensure(component.get_native_data().window, "Failed to initialize vk::Surface: null x-window");
|
||||||
|
|
||||||
auto create_info = VkXlibSurfaceCreateInfoKHR {
|
auto create_info = VkXlibSurfaceCreateInfoKHR {
|
||||||
.sType = VK_STRUCTURE_TYPE_XLIB_SURFACE_CREATE_INFO_KHR,
|
.sType = VK_STRUCTURE_TYPE_XLIB_SURFACE_CREATE_INFO_KHR,
|
||||||
|
|
51
modules/renderer/private/vk/context/surface.test.cpp
Normal file
51
modules/renderer/private/vk/context/surface.test.cpp
Normal file
|
@ -0,0 +1,51 @@
|
||||||
|
#include <renderer/vk/context/surface.hpp>
|
||||||
|
#include <renderer/vk/debug/messenger.hpp>
|
||||||
|
#include <renderer/vk/test_utils.hpp>
|
||||||
|
#include <surface/components.hpp>
|
||||||
|
#include <surface/system.hpp>
|
||||||
|
#include <test/test.hpp>
|
||||||
|
|
||||||
|
using ::lt::ecs::Entity;
|
||||||
|
using ::lt::ecs::Registry;
|
||||||
|
using ::lt::renderer::vk::Surface;
|
||||||
|
using ::lt::surface::SurfaceComponent;
|
||||||
|
using ::lt::surface::System;
|
||||||
|
|
||||||
|
Suite raii = "surface"_suite = [] {
|
||||||
|
Case { "happy path won't throw" } = [&] {
|
||||||
|
auto observer = ValidationObserver {};
|
||||||
|
|
||||||
|
auto registry = lt::create_ref<Registry>();
|
||||||
|
auto entity = Entity { registry, registry->create_entity() };
|
||||||
|
auto surface_system = System(registry);
|
||||||
|
|
||||||
|
entity.add<SurfaceComponent>(SurfaceComponent::CreateInfo {
|
||||||
|
.title = "",
|
||||||
|
.resolution = constants::resolution,
|
||||||
|
.visible = true,
|
||||||
|
});
|
||||||
|
|
||||||
|
const auto surface = Surface { entity };
|
||||||
|
const auto &[x, y] = surface.get_framebuffer_size();
|
||||||
|
|
||||||
|
expect_eq(x, constants::resolution.x);
|
||||||
|
expect_eq(y, constants::resolution.y);
|
||||||
|
expect_not_nullptr(surface.vk());
|
||||||
|
expect_false(observer.had_any_messages());
|
||||||
|
};
|
||||||
|
|
||||||
|
Case { "unhappy path throws" } = [&] {
|
||||||
|
auto observer = ValidationObserver {};
|
||||||
|
auto registry = lt::create_ref<Registry>();
|
||||||
|
auto entity = Entity { registry, registry->create_entity() };
|
||||||
|
|
||||||
|
entity.add<SurfaceComponent>(SurfaceComponent::CreateInfo {
|
||||||
|
.title = "",
|
||||||
|
.resolution = constants::resolution,
|
||||||
|
.visible = true,
|
||||||
|
});
|
||||||
|
|
||||||
|
expect_throw([&] { Surface { entity }; });
|
||||||
|
expect_false(observer.had_any_messages());
|
||||||
|
};
|
||||||
|
};
|
|
@ -1,5 +1,9 @@
|
||||||
#include <ranges>
|
#include <ranges>
|
||||||
|
#include <renderer/vk/context/device.hpp>
|
||||||
|
#include <renderer/vk/context/instance.hpp>
|
||||||
|
#include <renderer/vk/context/surface.hpp>
|
||||||
#include <renderer/vk/context/swapchain.hpp>
|
#include <renderer/vk/context/swapchain.hpp>
|
||||||
|
#include <renderer/vk/debug/validation.hpp>
|
||||||
|
|
||||||
namespace lt::renderer::vk {
|
namespace lt::renderer::vk {
|
||||||
|
|
||||||
|
|
|
@ -1,15 +1,14 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <memory/pointer_types/null_on_move.hpp>
|
#include <memory/pointer_types/null_on_move.hpp>
|
||||||
#include <renderer/vk/context/device.hpp>
|
#include <renderer/vk/vulkan.hpp>
|
||||||
#include <renderer/vk/context/instance.hpp>
|
|
||||||
|
|
||||||
namespace lt::renderer::vk {
|
namespace lt::renderer::vk {
|
||||||
|
|
||||||
class Swapchain
|
class Swapchain
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
Swapchain(const Device &device, const Surface &surface);
|
Swapchain(const class Device &device, const class Surface &surface);
|
||||||
|
|
||||||
~Swapchain();
|
~Swapchain();
|
||||||
|
|
||||||
|
|
0
modules/renderer/private/vk/context/swapchain.test.cpp
Normal file
0
modules/renderer/private/vk/context/swapchain.test.cpp
Normal file
0
modules/renderer/private/vk/debug/messenger.cpp
Normal file
0
modules/renderer/private/vk/debug/messenger.cpp
Normal file
143
modules/renderer/private/vk/debug/messenger.hpp
Normal file
143
modules/renderer/private/vk/debug/messenger.hpp
Normal file
|
@ -0,0 +1,143 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <memory/pointer_types/null_on_move.hpp>
|
||||||
|
#include <renderer/vk/context/instance.hpp>
|
||||||
|
#include <renderer/vk/vulkan.hpp>
|
||||||
|
|
||||||
|
namespace lt::renderer::vk {
|
||||||
|
|
||||||
|
class Messenger
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
// NOLINTNEXTLINE(performance-enum-size)
|
||||||
|
enum Severity : decltype(std::to_underlying(
|
||||||
|
VK_DEBUG_UTILS_MESSAGE_SEVERITY_FLAG_BITS_MAX_ENUM_EXT
|
||||||
|
))
|
||||||
|
{
|
||||||
|
verbose = VK_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT,
|
||||||
|
info = VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT,
|
||||||
|
warning = VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT,
|
||||||
|
error = VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT,
|
||||||
|
|
||||||
|
all_severity = VK_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT
|
||||||
|
| VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT
|
||||||
|
| VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT
|
||||||
|
| VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT,
|
||||||
|
};
|
||||||
|
|
||||||
|
// NOLINTNEXTLINE(performance-enum-size)
|
||||||
|
enum Type : decltype(std::to_underlying(VK_DEBUG_UTILS_MESSAGE_TYPE_FLAG_BITS_MAX_ENUM_EXT))
|
||||||
|
{
|
||||||
|
general = VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT,
|
||||||
|
validation = VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT,
|
||||||
|
performance = VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT,
|
||||||
|
|
||||||
|
// address_binding = VK_DEBUG_UTILS_MESSAGE_TYPE_DEVICE_ADDRESS_BINDING_BIT_EXT,
|
||||||
|
|
||||||
|
/** @note: does not include address binding yet. */
|
||||||
|
all_type = VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT
|
||||||
|
| VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT
|
||||||
|
| VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT,
|
||||||
|
};
|
||||||
|
|
||||||
|
using CallbackData_T = const VkDebugUtilsMessengerCallbackDataEXT *;
|
||||||
|
|
||||||
|
using Callback_T = std::function<void(
|
||||||
|
Severity message_severity,
|
||||||
|
Type message_type,
|
||||||
|
CallbackData_T vulkan_data,
|
||||||
|
void *user_data
|
||||||
|
)>;
|
||||||
|
|
||||||
|
struct CreateInfo
|
||||||
|
{
|
||||||
|
Severity severity;
|
||||||
|
|
||||||
|
Type type;
|
||||||
|
|
||||||
|
Callback_T callback;
|
||||||
|
|
||||||
|
void *user_data;
|
||||||
|
};
|
||||||
|
|
||||||
|
explicit Messenger(CreateInfo info)
|
||||||
|
: m_callback(std::move(info.callback))
|
||||||
|
, m_user_data(info.user_data)
|
||||||
|
{
|
||||||
|
ensure(m_callback, "Failed to initialize vk::Messenger: null callback");
|
||||||
|
ensure(info.severity != Severity {}, "Failed to initialize vk::Messenger: null severity");
|
||||||
|
ensure(info.type != Type {}, "Failed to initialize vk::Messenger: null type");
|
||||||
|
|
||||||
|
// Instance may not be initialized yet
|
||||||
|
// Making it get initialized inside a call to vk_create_debug_messenger
|
||||||
|
// Which would invoke a nullptr...
|
||||||
|
if (!vk_create_debug_messenger)
|
||||||
|
{
|
||||||
|
Instance::get();
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto vulkan_info = VkDebugUtilsMessengerCreateInfoEXT {
|
||||||
|
.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT,
|
||||||
|
.messageSeverity = info.severity,
|
||||||
|
.messageType = info.type,
|
||||||
|
.pfnUserCallback = &validation_layers_callback,
|
||||||
|
.pUserData = this,
|
||||||
|
};
|
||||||
|
|
||||||
|
ensure(
|
||||||
|
!vk_create_debug_messenger(Instance::get(), &vulkan_info, nullptr, &m_debug_messenger),
|
||||||
|
"Failed to create vulkan debug utils messenger"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
~Messenger()
|
||||||
|
{
|
||||||
|
vk_destroy_debug_messenger(Instance::get(), m_debug_messenger, nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
Messenger(Messenger &&) = default;
|
||||||
|
|
||||||
|
Messenger(const Messenger &) = delete;
|
||||||
|
|
||||||
|
auto operator=(Messenger &&) -> Messenger & = default;
|
||||||
|
|
||||||
|
auto operator=(const Messenger &) const -> Messenger & = delete;
|
||||||
|
|
||||||
|
|
||||||
|
private:
|
||||||
|
static auto validation_layers_callback(
|
||||||
|
VkDebugUtilsMessageSeverityFlagBitsEXT const message_severity,
|
||||||
|
VkDebugUtilsMessageTypeFlagsEXT const message_type,
|
||||||
|
VkDebugUtilsMessengerCallbackDataEXT const *const callback_data,
|
||||||
|
void *const vulkan_user_data
|
||||||
|
) -> VkBool32
|
||||||
|
{
|
||||||
|
auto *messenger = (Messenger *)vulkan_user_data; // NOLINT
|
||||||
|
ensure(messenger, "Null vulkan_user_data received in messenger callback");
|
||||||
|
|
||||||
|
messenger->validation_layers_callback_impl(message_severity, message_type, callback_data);
|
||||||
|
return VK_FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
void validation_layers_callback_impl(
|
||||||
|
VkDebugUtilsMessageSeverityFlagBitsEXT message_severity,
|
||||||
|
VkDebugUtilsMessageTypeFlagsEXT message_type,
|
||||||
|
const VkDebugUtilsMessengerCallbackDataEXT *callback_data
|
||||||
|
)
|
||||||
|
{
|
||||||
|
m_callback(
|
||||||
|
static_cast<Severity>(message_severity),
|
||||||
|
static_cast<Type>(message_type),
|
||||||
|
callback_data,
|
||||||
|
m_user_data
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
memory::NullOnMove<VkDebugUtilsMessengerEXT> m_debug_messenger = VK_NULL_HANDLE;
|
||||||
|
|
||||||
|
Callback_T m_callback;
|
||||||
|
|
||||||
|
void *m_user_data;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace lt::renderer::vk
|
149
modules/renderer/private/vk/debug/messenger.test.cpp
Normal file
149
modules/renderer/private/vk/debug/messenger.test.cpp
Normal file
|
@ -0,0 +1,149 @@
|
||||||
|
#include <renderer/vk/context/surface.hpp>
|
||||||
|
#include <renderer/vk/debug/messenger.hpp>
|
||||||
|
#include <renderer/vk/test_utils.hpp>
|
||||||
|
#include <surface/components.hpp>
|
||||||
|
#include <surface/system.hpp>
|
||||||
|
#include <test/expects.hpp>
|
||||||
|
#include <test/test.hpp>
|
||||||
|
|
||||||
|
using namespace lt;
|
||||||
|
using renderer::vk::Messenger;
|
||||||
|
using renderer::vk::Surface;
|
||||||
|
using enum Messenger::Severity;
|
||||||
|
using enum Messenger::Type;
|
||||||
|
|
||||||
|
void noop_callback(
|
||||||
|
Messenger::Severity message_severity,
|
||||||
|
Messenger::Type message_type,
|
||||||
|
Messenger::CallbackData_T vulkan_data,
|
||||||
|
void *user_data
|
||||||
|
)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
Suite raii = "messenger_raii"_suite = [] {
|
||||||
|
Case { "happy path won't throw" } = [] {
|
||||||
|
Messenger(
|
||||||
|
Messenger::CreateInfo {
|
||||||
|
.severity = all_severity,
|
||||||
|
.type = all_type,
|
||||||
|
.callback = &noop_callback,
|
||||||
|
}
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
Case { "unhappy path throws" } = [] {
|
||||||
|
expect_throw([] {
|
||||||
|
Messenger(
|
||||||
|
Messenger::CreateInfo {
|
||||||
|
.severity = all_severity,
|
||||||
|
.type = all_type,
|
||||||
|
.callback = {},
|
||||||
|
}
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
expect_throw([] {
|
||||||
|
Messenger(
|
||||||
|
Messenger::CreateInfo {
|
||||||
|
.severity = {},
|
||||||
|
.type = all_type,
|
||||||
|
.callback = &noop_callback,
|
||||||
|
}
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
expect_throw([] {
|
||||||
|
Messenger(
|
||||||
|
Messenger::CreateInfo {
|
||||||
|
.severity = all_severity,
|
||||||
|
.type = {},
|
||||||
|
.callback = &noop_callback,
|
||||||
|
}
|
||||||
|
);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
// NOLINTNEXTLINE(cppcoreguidelines-interfaces-global-init)
|
||||||
|
Suite callback = "messenger_callback"_suite = [] {
|
||||||
|
Case { "callback gets called with correct arguments" } = [] {
|
||||||
|
auto total_messages = 0u;
|
||||||
|
auto first_message_is_severity = false;
|
||||||
|
auto second_message_is_type = false;
|
||||||
|
auto third_message_is_user_callback = false;
|
||||||
|
auto all_messages_are_error = true;
|
||||||
|
auto all_messages_are_validation = true;
|
||||||
|
auto user_data_is_always_69 = true;
|
||||||
|
|
||||||
|
auto callback = [&](Messenger::Severity message_severity,
|
||||||
|
Messenger::Type message_type,
|
||||||
|
Messenger::CallbackData_T vulkan_data,
|
||||||
|
void *user_data) {
|
||||||
|
++total_messages;
|
||||||
|
auto message = std::string_view { vulkan_data->pMessage };
|
||||||
|
|
||||||
|
// NOLINTNEXTLINE(cppcoreguidelines-pro-type-cstyle-cast)
|
||||||
|
user_data_is_always_69 = user_data_is_always_69 && *(size_t *)user_data == 69u;
|
||||||
|
|
||||||
|
all_messages_are_validation = all_messages_are_validation && message_type == validation;
|
||||||
|
all_messages_are_error = all_messages_are_error && message_severity == error;
|
||||||
|
|
||||||
|
if (total_messages == 1)
|
||||||
|
{
|
||||||
|
first_message_is_severity = message.starts_with(
|
||||||
|
"vkCreateDebugUtilsMessengerEXT(): pCreateInfo->messageSeverity is zero."
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if (total_messages == 2)
|
||||||
|
{
|
||||||
|
second_message_is_type = message.starts_with(
|
||||||
|
"vkCreateDebugUtilsMessengerEXT(): pCreateInfo->messageType is zero."
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (total_messages == 3)
|
||||||
|
{
|
||||||
|
third_message_is_user_callback = message.starts_with(
|
||||||
|
"vkCreateDebugUtilsMessengerEXT(): pCreateInfo->pfnUserCallback is NULL."
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
auto user_data = size_t { 69 };
|
||||||
|
auto messenger = Messenger(
|
||||||
|
Messenger::CreateInfo {
|
||||||
|
.severity = all_severity,
|
||||||
|
.type = all_type,
|
||||||
|
.callback = callback,
|
||||||
|
.user_data = &user_data,
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
{
|
||||||
|
auto *messenger = VkDebugUtilsMessengerEXT {};
|
||||||
|
auto info = VkDebugUtilsMessengerCreateInfoEXT {
|
||||||
|
.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT,
|
||||||
|
};
|
||||||
|
renderer::vk::vk_create_debug_messenger(
|
||||||
|
renderer::vk::Instance::get(),
|
||||||
|
&info,
|
||||||
|
nullptr,
|
||||||
|
&messenger
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
expect_eq(total_messages, 3u);
|
||||||
|
expect_true(first_message_is_severity);
|
||||||
|
expect_true(second_message_is_type);
|
||||||
|
expect_true(third_message_is_user_callback);
|
||||||
|
expect_true(all_messages_are_error);
|
||||||
|
expect_true(all_messages_are_validation);
|
||||||
|
expect_true(user_data_is_always_69);
|
||||||
|
};
|
||||||
|
};
|
17
modules/renderer/private/vk/debug/validation.hpp
Normal file
17
modules/renderer/private/vk/debug/validation.hpp
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <renderer/vk/vulkan.hpp>
|
||||||
|
|
||||||
|
namespace lt::renderer::vk {
|
||||||
|
|
||||||
|
inline void vkc(VkResult result)
|
||||||
|
{
|
||||||
|
if (result)
|
||||||
|
{
|
||||||
|
throw std::runtime_error {
|
||||||
|
std::format("Vulkan call failed with result: {}", std::to_underlying(result))
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace lt::renderer::vk
|
|
@ -1,22 +1,14 @@
|
||||||
#include <ranges>
|
|
||||||
#include <renderer/vk/context/context.hpp>
|
#include <renderer/vk/context/context.hpp>
|
||||||
#include <renderer/vk/pipeline.hpp>
|
#include <renderer/vk/pipeline.hpp>
|
||||||
|
#include <renderer/vk/test_utils.hpp>
|
||||||
#include <surface/system.hpp>
|
#include <surface/system.hpp>
|
||||||
#include <test/test.hpp>
|
#include <test/test.hpp>
|
||||||
|
|
||||||
using namespace lt;
|
using namespace lt;
|
||||||
|
|
||||||
using std::ignore;
|
|
||||||
using test::Case;
|
|
||||||
using test::expect_throw;
|
|
||||||
using test::expect_true;
|
|
||||||
using test::Suite;
|
|
||||||
|
|
||||||
using renderer::vk::Context;
|
using renderer::vk::Context;
|
||||||
using renderer::vk::Pipeline;
|
using renderer::vk::Pipeline;
|
||||||
|
|
||||||
constexpr auto resolution = math::uvec2 { 800, 600 };
|
|
||||||
|
|
||||||
class VkPipelineTest
|
class VkPipelineTest
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
@ -29,7 +21,7 @@ public:
|
||||||
m_surface_entity = create_scope<ecs::Entity>(m_registry, m_registry->create_entity());
|
m_surface_entity = create_scope<ecs::Entity>(m_registry, m_registry->create_entity());
|
||||||
m_surface_entity->add<surface::SurfaceComponent>(surface::SurfaceComponent::CreateInfo {
|
m_surface_entity->add<surface::SurfaceComponent>(surface::SurfaceComponent::CreateInfo {
|
||||||
.title = "",
|
.title = "",
|
||||||
.resolution = resolution,
|
.resolution = constants::resolution,
|
||||||
});
|
});
|
||||||
|
|
||||||
m_context = create_ref<Context>(*m_surface_entity, m_stats);
|
m_context = create_ref<Context>(*m_surface_entity, m_stats);
|
||||||
|
@ -57,7 +49,7 @@ private:
|
||||||
Ref<Context> m_context;
|
Ref<Context> m_context;
|
||||||
};
|
};
|
||||||
|
|
||||||
Suite raii = [] {
|
Suite raii = "raii"_suite = [] {
|
||||||
Case { "happy path won't throw" } = [] {
|
Case { "happy path won't throw" } = [] {
|
||||||
auto fixture = VkPipelineTest {};
|
auto fixture = VkPipelineTest {};
|
||||||
std::ignore = Pipeline { { .context = fixture.context() } };
|
std::ignore = Pipeline { { .context = fixture.context() } };
|
||||||
|
|
1
modules/renderer/private/vk/test_utils.cpp
Normal file
1
modules/renderer/private/vk/test_utils.cpp
Normal file
|
@ -0,0 +1 @@
|
||||||
|
#include <renderer/vk/test_utils.hpp>
|
87
modules/renderer/private/vk/test_utils.hpp
Normal file
87
modules/renderer/private/vk/test_utils.hpp
Normal file
|
@ -0,0 +1,87 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <ranges>
|
||||||
|
#include <renderer/vk/context/surface.hpp>
|
||||||
|
#include <renderer/vk/debug/messenger.hpp>
|
||||||
|
#include <surface/components.hpp>
|
||||||
|
#include <surface/system.hpp>
|
||||||
|
#include <test/test.hpp>
|
||||||
|
|
||||||
|
using ::lt::test::Case;
|
||||||
|
using ::lt::test::expect_eq;
|
||||||
|
using ::lt::test::expect_false;
|
||||||
|
using ::lt::test::expect_not_nullptr;
|
||||||
|
using ::lt::test::expect_throw;
|
||||||
|
using ::lt::test::expect_true;
|
||||||
|
using ::lt::test::Suite;
|
||||||
|
using ::std::ignore;
|
||||||
|
|
||||||
|
namespace constants {
|
||||||
|
|
||||||
|
constexpr auto resolution = lt::math::uvec2 { 800u, 600u };
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
class ValidationObserver
|
||||||
|
{
|
||||||
|
using Messenger = lt::renderer::vk::Messenger;
|
||||||
|
using enum Messenger::Type;
|
||||||
|
using enum Messenger::Severity;
|
||||||
|
|
||||||
|
public:
|
||||||
|
ValidationObserver()
|
||||||
|
: m_messenger(
|
||||||
|
Messenger::CreateInfo {
|
||||||
|
.severity = all_severity,
|
||||||
|
.type = lt::renderer::vk::Messenger::all_type,
|
||||||
|
.callback = &callback,
|
||||||
|
.user_data = &m_had_any_messages,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] auto had_any_messages() const -> bool
|
||||||
|
{
|
||||||
|
return m_had_any_messages;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
static void callback(
|
||||||
|
Messenger::Severity message_severity,
|
||||||
|
Messenger::Type message_type,
|
||||||
|
Messenger::CallbackData_T vulkan_data,
|
||||||
|
void *user_data
|
||||||
|
)
|
||||||
|
{
|
||||||
|
std::ignore = message_severity;
|
||||||
|
std::ignore = message_type;
|
||||||
|
|
||||||
|
std::println("Validation message: {}", vulkan_data->pMessage);
|
||||||
|
|
||||||
|
// NOLINTNEXTLINE(cppcoreguidelines-pro-type-cstyle-cast)
|
||||||
|
*(bool *)user_data = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
Messenger m_messenger;
|
||||||
|
bool m_had_any_messages = false;
|
||||||
|
};
|
||||||
|
|
||||||
|
template<>
|
||||||
|
struct std::formatter<VkExtent2D>
|
||||||
|
{
|
||||||
|
constexpr auto parse(std::format_parse_context &context)
|
||||||
|
{
|
||||||
|
return context.begin();
|
||||||
|
}
|
||||||
|
|
||||||
|
auto format(const VkExtent2D &val, std::format_context &context) const
|
||||||
|
{
|
||||||
|
return std::format_to(context.out(), "{}, {}", val.width, val.height);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
inline auto operator==(VkExtent2D lhs, VkExtent2D rhs) -> bool
|
||||||
|
{
|
||||||
|
return lhs.width == rhs.width && lhs.height == rhs.height;
|
||||||
|
}
|
91
modules/renderer/private/vk/vulkan.hpp
Normal file
91
modules/renderer/private/vk/vulkan.hpp
Normal file
|
@ -0,0 +1,91 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#define VK_NO_PROTOTYPES
|
||||||
|
#define VK_USE_PLATFORM_XLIB_KHR
|
||||||
|
#include <vulkan/vulkan.h>
|
||||||
|
#include <vulkan/vulkan_xlib.h>
|
||||||
|
|
||||||
|
namespace lt::renderer::vk {
|
||||||
|
|
||||||
|
// NOLINTBEGIN(cppcoreguidelines-avoid-non-const-global-variables)
|
||||||
|
// global functions
|
||||||
|
extern PFN_vkGetInstanceProcAddr vk_get_instance_proc_address;
|
||||||
|
extern PFN_vkCreateInstance vk_create_instance;
|
||||||
|
extern PFN_vkEnumerateInstanceExtensionProperties vk_enumerate_instance_extension_properties;
|
||||||
|
extern PFN_vkEnumerateInstanceLayerProperties vk_enumerate_instance_layer_properties;
|
||||||
|
|
||||||
|
// instance functions
|
||||||
|
extern PFN_vkDestroyInstance vk_destroy_instance;
|
||||||
|
extern PFN_vkEnumeratePhysicalDevices vk_enumerate_physical_devices;
|
||||||
|
extern PFN_vkGetPhysicalDeviceProperties vk_get_physical_device_properties;
|
||||||
|
extern PFN_vkGetPhysicalDeviceQueueFamilyProperties vk_get_physical_device_queue_family_properties;
|
||||||
|
extern PFN_vkCreateDevice vk_create_device;
|
||||||
|
extern PFN_vkGetDeviceProcAddr vk_get_device_proc_address;
|
||||||
|
extern PFN_vkDestroyDevice vk_destroy_device;
|
||||||
|
extern PFN_vkGetPhysicalDeviceFeatures vk_get_physical_device_features;
|
||||||
|
extern PFN_vkEnumerateDeviceExtensionProperties vk_enumerate_device_extension_properties;
|
||||||
|
|
||||||
|
// extension instance functions
|
||||||
|
extern PFN_vkCmdBeginDebugUtilsLabelEXT vk_cmd_begin_debug_label;
|
||||||
|
extern PFN_vkCmdEndDebugUtilsLabelEXT vk_cmd_end_debug_label;
|
||||||
|
extern PFN_vkCmdInsertDebugUtilsLabelEXT vk_cmd_insert_debug_label;
|
||||||
|
extern PFN_vkCreateDebugUtilsMessengerEXT vk_create_debug_messenger;
|
||||||
|
extern PFN_vkDestroyDebugUtilsMessengerEXT vk_destroy_debug_messenger;
|
||||||
|
extern PFN_vkQueueBeginDebugUtilsLabelEXT vk_queue_begin_debug_label;
|
||||||
|
extern PFN_vkQueueEndDebugUtilsLabelEXT vk_queue_end_debug_label;
|
||||||
|
extern PFN_vkQueueInsertDebugUtilsLabelEXT vk_queue_insert_debug_label;
|
||||||
|
extern PFN_vkSetDebugUtilsObjectNameEXT vk_set_debug_object_name;
|
||||||
|
extern PFN_vkSetDebugUtilsObjectTagEXT vk_set_debug_object_tag;
|
||||||
|
extern PFN_vkSubmitDebugUtilsMessageEXT vk_submit_debug_message;
|
||||||
|
|
||||||
|
// surface instance functions
|
||||||
|
extern PFN_vkGetPhysicalDeviceSurfaceSupportKHR vk_get_physical_device_surface_support;
|
||||||
|
extern PFN_vkGetPhysicalDeviceSurfaceCapabilitiesKHR vk_get_physical_device_surface_capabilities;
|
||||||
|
extern PFN_vkGetPhysicalDeviceSurfaceFormatsKHR vk_get_physical_device_surface_formats;
|
||||||
|
extern PFN_vkCreateXlibSurfaceKHR vk_create_xlib_surface_khr;
|
||||||
|
extern PFN_vkDestroySurfaceKHR vk_destroy_surface_khr;
|
||||||
|
|
||||||
|
// device functions
|
||||||
|
extern PFN_vkGetDeviceQueue vk_get_device_queue;
|
||||||
|
extern PFN_vkCreateCommandPool vk_create_command_pool;
|
||||||
|
extern PFN_vkDestroyCommandPool vk_destroy_command_pool;
|
||||||
|
extern PFN_vkAllocateCommandBuffers vk_allocate_command_buffers;
|
||||||
|
extern PFN_vkFreeCommandBuffers vk_free_command_buffers;
|
||||||
|
extern PFN_vkBeginCommandBuffer vk_begin_command_buffer;
|
||||||
|
extern PFN_vkEndCommandBuffer vk_end_command_buffer;
|
||||||
|
extern PFN_vkCmdPipelineBarrier vk_cmd_pipeline_barrier;
|
||||||
|
extern PFN_vkQueueSubmit vk_queue_submit;
|
||||||
|
extern PFN_vkQueueWaitIdle vk_queue_wait_idle;
|
||||||
|
extern PFN_vkDeviceWaitIdle vk_device_wait_idle;
|
||||||
|
extern PFN_vkCreateFence vk_create_fence;
|
||||||
|
extern PFN_vkDestroyFence vk_destroy_fence;
|
||||||
|
extern PFN_vkWaitForFences vk_wait_for_fences;
|
||||||
|
extern PFN_vkResetFences vk_reset_fences;
|
||||||
|
extern PFN_vkCreateSemaphore vk_create_semaphore;
|
||||||
|
extern PFN_vkDestroySemaphore vk_destroy_semaphore;
|
||||||
|
extern PFN_vkCreateSwapchainKHR vk_create_swapchain_khr;
|
||||||
|
extern PFN_vkDestroySwapchainKHR vk_destroy_swapchain_khr;
|
||||||
|
extern PFN_vkGetSwapchainImagesKHR vk_get_swapchain_images_khr;
|
||||||
|
extern PFN_vkAcquireNextImageKHR vk_acquire_next_image_khr;
|
||||||
|
extern PFN_vkQueuePresentKHR vk_queue_present_khr;
|
||||||
|
extern PFN_vkCreateImageView vk_create_image_view;
|
||||||
|
extern PFN_vkDestroyImageView vk_destroy_image_view;
|
||||||
|
extern PFN_vkCreateRenderPass vk_create_render_pass;
|
||||||
|
extern PFN_vkDestroyRenderPass vk_destroy_render_pass;
|
||||||
|
extern PFN_vkCreateFramebuffer vk_create_frame_buffer;
|
||||||
|
extern PFN_vkDestroyFramebuffer vk_destroy_frame_buffer;
|
||||||
|
extern PFN_vkCreateShaderModule vk_create_shader_module;
|
||||||
|
extern PFN_vkDestroyShaderModule vk_destroy_shader_module;
|
||||||
|
extern PFN_vkCreatePipelineLayout vk_create_pipeline_layout;
|
||||||
|
extern PFN_vkDestroyPipelineLayout vk_destroy_pipeline_layout;
|
||||||
|
extern PFN_vkCreateGraphicsPipelines vk_create_graphics_pipelines;
|
||||||
|
extern PFN_vkDestroyPipeline vk_destroy_pipeline;
|
||||||
|
extern PFN_vkCmdBeginRenderPass vk_cmd_begin_render_pass;
|
||||||
|
extern PFN_vkCmdEndRenderPass vk_cmd_end_render_pass;
|
||||||
|
extern PFN_vkCmdBindPipeline vk_cmd_bind_pipeline;
|
||||||
|
extern PFN_vkCmdDraw vk_cmd_draw;
|
||||||
|
extern PFN_vkCmdSetViewport vk_cmd_set_viewport;
|
||||||
|
extern PFN_vkCmdSetScissor vk_cmd_set_scissors;
|
||||||
|
// NOLINTEND(cppcoreguidelines-avoid-non-const-global-variables)
|
||||||
|
|
||||||
|
} // namespace lt::renderer::vk
|
Loading…
Add table
Reference in a new issue