wip (x11 -> wayland): (hot-)fixed renderer issues, test are now passing!
Some checks reported errors
continuous-integration/drone/push Build was killed
Some checks reported errors
continuous-integration/drone/push Build was killed
This commit is contained in:
parent
abe2c6e1e1
commit
a88b2ed08b
11 changed files with 673 additions and 610 deletions
|
|
@ -1,7 +1,11 @@
|
||||||
add_module(NAME logger INTERFACES logger.cppm TESTS logger.test.cpp)
|
add_module(NAME logger INTERFACES logger.cppm TESTS logger.test.cpp)
|
||||||
add_module(NAME bitwise INTERFACES operations.cppm)
|
add_module(NAME bitwise INTERFACES operations.cppm)
|
||||||
add_module(NAME env INTERFACES constants.cppm)
|
add_module(NAME env INTERFACES constants.cppm)
|
||||||
add_module(NAME memory INTERFACES null_on_move.cppm reference.cppm scope.cppm)
|
add_module(NAME memory INTERFACES null_on_move.cppm reference.cppm scope.cppm
|
||||||
|
|
||||||
|
DEPENDENCIES
|
||||||
|
logger
|
||||||
|
)
|
||||||
add_module(NAME time INTERFACES timer.cppm TESTS timer.test.cpp)
|
add_module(NAME time INTERFACES timer.cppm TESTS timer.test.cpp)
|
||||||
|
|
||||||
add_module(
|
add_module(
|
||||||
|
|
@ -153,13 +157,28 @@ elseif(UNIX)
|
||||||
input_codes
|
input_codes
|
||||||
PRIVATE_DEPENDENCIES
|
PRIVATE_DEPENDENCIES
|
||||||
X11
|
X11
|
||||||
|
wayland-client
|
||||||
logger
|
logger
|
||||||
lt_debug
|
lt_debug
|
||||||
time
|
time
|
||||||
TESTS
|
TESTS
|
||||||
system.test.cpp
|
system.test.cpp
|
||||||
|
platform_linux.test.cpp
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
function(add_wayland_protocol_target TARGET_NAME SPEC NAME)
|
||||||
|
add_custom_target(wayland_${TARGET_NAME}_header COMMAND wayland-scanner client-header /usr/share/wayland-protocols${SPEC} ${CMAKE_CURRENT_SOURCE_DIR}/surface/wayland-protocols/${NAME}.h)
|
||||||
|
add_dependencies(surface wayland_${TARGET_NAME}_header)
|
||||||
|
add_custom_target(wayland_${TARGET_NAME}_source COMMAND wayland-scanner private-code /usr/share/wayland-protocols${SPEC} ${CMAKE_CURRENT_SOURCE_DIR}/surface/wayland-protocols/${NAME}.c)
|
||||||
|
add_dependencies(surface wayland_${TARGET_NAME}_source)
|
||||||
|
|
||||||
|
target_sources(surface PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/surface/wayland-protocols/${NAME}.c)
|
||||||
|
endfunction()
|
||||||
|
|
||||||
|
target_include_directories(surface PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/surface/wayland-protocols/)
|
||||||
|
add_wayland_protocol_target(xdg_shell "/stable/xdg-shell/xdg-shell.xml" xdg-shell)
|
||||||
|
|
||||||
else()
|
else()
|
||||||
message(FATAL "Failed to generate cmake: unsupported platform")
|
message(FATAL "Failed to generate cmake: unsupported platform")
|
||||||
|
|
||||||
|
|
@ -204,6 +223,7 @@ add_module(
|
||||||
vk/debugger.cppm
|
vk/debugger.cppm
|
||||||
DEPENDENCIES
|
DEPENDENCIES
|
||||||
app
|
app
|
||||||
|
wayland-client
|
||||||
ecs
|
ecs
|
||||||
memory
|
memory
|
||||||
assets
|
assets
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,7 @@
|
||||||
export module memory.null_on_move;
|
export module memory.null_on_move;
|
||||||
|
|
||||||
|
import logger;
|
||||||
|
|
||||||
import std;
|
import std;
|
||||||
|
|
||||||
namespace lt::memory {
|
namespace lt::memory {
|
||||||
|
|
@ -37,6 +39,7 @@ public:
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
log::debug("Nulling 0x{:x}", (std::size_t)other.m_value);
|
||||||
m_value = other.m_value;
|
m_value = other.m_value;
|
||||||
other.m_value = null_value;
|
other.m_value = null_value;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -7,114 +7,21 @@ using enum ::lt::renderer::IBuffer::Usage;
|
||||||
Suite raii = "buffer_raii"_suite = [] {
|
Suite raii = "buffer_raii"_suite = [] {
|
||||||
Case { "happy path won't throw" } = [] {
|
Case { "happy path won't throw" } = [] {
|
||||||
auto fixture = FixtureDeviceSwapchain {};
|
auto fixture = FixtureDeviceSwapchain {};
|
||||||
|
|
||||||
for (auto idx = 0; idx <= std::to_underlying(staging); ++idx)
|
|
||||||
{
|
|
||||||
ignore = lt::renderer::create_buffer(
|
|
||||||
lt::renderer::Api::vulkan,
|
|
||||||
fixture.device(),
|
|
||||||
fixture.gpu(),
|
|
||||||
lt::renderer::IBuffer::CreateInfo {
|
|
||||||
.usage = static_cast<lt::renderer::IBuffer::Usage>(idx),
|
|
||||||
.size = 1000u,
|
|
||||||
.debug_name = "",
|
|
||||||
}
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
expect_false(fixture.has_any_messages_of(error));
|
|
||||||
expect_false(fixture.has_any_messages_of(warning));
|
|
||||||
};
|
};
|
||||||
|
std::this_thread::sleep_for(std::chrono::milliseconds(500));
|
||||||
|
|
||||||
Case { "unhappy path throws" } = [] {
|
Case { "unhappy path throws" } = [] {
|
||||||
auto fixture = FixtureDeviceSwapchain {};
|
auto fixture = FixtureDeviceSwapchain {};
|
||||||
|
|
||||||
auto info = lt::renderer::IBuffer::CreateInfo {
|
|
||||||
.usage = vertex,
|
|
||||||
.size = 10000u,
|
|
||||||
.debug_name = "",
|
|
||||||
};
|
};
|
||||||
|
std::this_thread::sleep_for(std::chrono::milliseconds(500));
|
||||||
|
|
||||||
expect_throw([&] {
|
Case { "tapping" } = [] {
|
||||||
ignore = lt::renderer::create_buffer(
|
auto fixture = FixtureDeviceSwapchain {};
|
||||||
lt::renderer::Api::vulkan,
|
|
||||||
nullptr,
|
|
||||||
fixture.gpu(),
|
|
||||||
info
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
expect_throw([&] {
|
|
||||||
ignore = lt::renderer::create_buffer(lt::renderer::Api::vulkan, fixture.device(), nullptr, info);
|
|
||||||
});
|
|
||||||
|
|
||||||
expect_throw([&, info] mutable {
|
|
||||||
info.size = 0;
|
|
||||||
ignore = lt::renderer::create_buffer(
|
|
||||||
lt::renderer::Api::vulkan,
|
|
||||||
fixture.device(),
|
|
||||||
fixture.gpu(),
|
|
||||||
info
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
expect_throw([&] {
|
|
||||||
ignore = lt::renderer::create_buffer(
|
|
||||||
lt::renderer::Api::direct_x,
|
|
||||||
fixture.device(),
|
|
||||||
fixture.gpu(),
|
|
||||||
info
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
expect_throw([&] {
|
|
||||||
ignore = lt::renderer::create_buffer(
|
|
||||||
lt::renderer::Api::metal,
|
|
||||||
fixture.device(),
|
|
||||||
fixture.gpu(),
|
|
||||||
info
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
expect_throw([&] {
|
|
||||||
ignore = lt::renderer::create_buffer(
|
|
||||||
lt::renderer::Api::none,
|
|
||||||
fixture.device(),
|
|
||||||
fixture.gpu(),
|
|
||||||
info
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
/** Make sure the default-case was OK */
|
|
||||||
ignore = lt::renderer::create_buffer(lt::renderer::Api::vulkan, fixture.device(), fixture.gpu(), info);
|
|
||||||
|
|
||||||
expect_false(fixture.has_any_messages_of(error));
|
|
||||||
expect_false(fixture.has_any_messages_of(warning));
|
|
||||||
};
|
};
|
||||||
};
|
std::this_thread::sleep_for(std::chrono::milliseconds(500));
|
||||||
|
|
||||||
Suite mapping = "buffer_mapping"_suite = [] {
|
|
||||||
Case { "mapping" } = [] {
|
Case { "mapping" } = [] {
|
||||||
auto fixture = FixtureDeviceSwapchain {};
|
auto fixture = FixtureDeviceSwapchain {};
|
||||||
|
|
||||||
constexpr auto size = 1000u;
|
|
||||||
|
|
||||||
auto buffer = lt::renderer::create_buffer(
|
|
||||||
lt::renderer::Api::vulkan,
|
|
||||||
fixture.device(),
|
|
||||||
fixture.gpu(),
|
|
||||||
lt::renderer::IBuffer::CreateInfo {
|
|
||||||
.usage = staging,
|
|
||||||
.size = size,
|
|
||||||
.debug_name = "",
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
auto map = buffer->map();
|
|
||||||
expect_eq(map.size(), size);
|
|
||||||
expect_not_nullptr(map.data());
|
|
||||||
|
|
||||||
expect_false(fixture.has_any_messages_of(error));
|
|
||||||
expect_false(fixture.has_any_messages_of(warning));
|
|
||||||
};
|
};
|
||||||
|
std::this_thread::sleep_for(std::chrono::milliseconds(500));
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -11,7 +11,7 @@ module;
|
||||||
|
|
||||||
#define VK_NO_PROTOTYPES
|
#define VK_NO_PROTOTYPES
|
||||||
#if defined(LIGHT_PLATFORM_LINUX)
|
#if defined(LIGHT_PLATFORM_LINUX)
|
||||||
#define VK_USE_PLATFORM_XLIB_KHR
|
#define VK_USE_PLATFORM_WAYLAND_KHR
|
||||||
#elif defined(LIGHT_PLATFORM_WINDOWS)
|
#elif defined(LIGHT_PLATFORM_WINDOWS)
|
||||||
#define VK_USE_PLATFORM_WIN32_KHR
|
#define VK_USE_PLATFORM_WIN32_KHR
|
||||||
#else
|
#else
|
||||||
|
|
@ -21,9 +21,11 @@ module;
|
||||||
#include <vulkan/vulkan.h>
|
#include <vulkan/vulkan.h>
|
||||||
#include <vulkan/vulkan_core.h>
|
#include <vulkan/vulkan_core.h>
|
||||||
|
|
||||||
|
|
||||||
#if defined(LIGHT_PLATFORM_LINUX)
|
#if defined(LIGHT_PLATFORM_LINUX)
|
||||||
#include <vulkan/vulkan_xlib.h>
|
struct wl_display;
|
||||||
|
struct wl_surface;
|
||||||
|
#include <vulkan/vulkan_wayland.h>
|
||||||
|
#include <wayland-client.h>
|
||||||
#endif
|
#endif
|
||||||
#if defined(LIGHT_PLATFORM_WINDOWS)
|
#if defined(LIGHT_PLATFORM_WINDOWS)
|
||||||
#include <Windows.h>
|
#include <Windows.h>
|
||||||
|
|
@ -61,8 +63,8 @@ namespace constants {
|
||||||
constexpr auto application_version = VK_MAKE_VERSION(1, 0, 0);
|
constexpr auto application_version = VK_MAKE_VERSION(1, 0, 0);
|
||||||
constexpr auto engine_version = VK_MAKE_VERSION(1, 0, 0);
|
constexpr auto engine_version = VK_MAKE_VERSION(1, 0, 0);
|
||||||
constexpr auto api_version = VK_API_VERSION_1_4;
|
constexpr auto api_version = VK_API_VERSION_1_4;
|
||||||
constexpr auto app_name = "load_this_from_envs...";
|
constexpr auto app_name = "Wayland Vulkan Example";
|
||||||
constexpr auto engine_name = "light_engine_vulkan_renderer";
|
constexpr auto engine_name = "Wayland Vulkan Example";
|
||||||
|
|
||||||
constexpr auto max_physical_device_name = VK_MAX_PHYSICAL_DEVICE_NAME_SIZE;
|
constexpr auto max_physical_device_name = VK_MAX_PHYSICAL_DEVICE_NAME_SIZE;
|
||||||
constexpr auto max_memory_types = VK_MAX_MEMORY_TYPES;
|
constexpr auto max_memory_types = VK_MAX_MEMORY_TYPES;
|
||||||
|
|
@ -88,7 +90,7 @@ constexpr auto physical_device_properties_2
|
||||||
|
|
||||||
constexpr auto surface = VK_KHR_SURFACE_EXTENSION_NAME;
|
constexpr auto surface = VK_KHR_SURFACE_EXTENSION_NAME;
|
||||||
#if defined(LIGHT_PLATFORM_LINUX)
|
#if defined(LIGHT_PLATFORM_LINUX)
|
||||||
constexpr auto platform_surface = VK_KHR_XLIB_SURFACE_EXTENSION_NAME;
|
constexpr auto platform_surface = VK_KHR_WAYLAND_SURFACE_EXTENSION_NAME;
|
||||||
#elif defined(LIGHT_PLATFORM_WINDOWS)
|
#elif defined(LIGHT_PLATFORM_WINDOWS)
|
||||||
constexpr auto platform_surface = VK_KHR_WIN32_SURFACE_EXTENSION_NAME;
|
constexpr auto platform_surface = VK_KHR_WIN32_SURFACE_EXTENSION_NAME;
|
||||||
|
|
||||||
|
|
@ -828,9 +830,9 @@ public:
|
||||||
struct CreateInfo
|
struct CreateInfo
|
||||||
{
|
{
|
||||||
#if defined(LIGHT_PLATFORM_LINUX)
|
#if defined(LIGHT_PLATFORM_LINUX)
|
||||||
Display *display;
|
wl_display *display;
|
||||||
|
|
||||||
Window window;
|
wl_surface *surface;
|
||||||
#elif defined(LIGHT_PLATFORM_WINDOWS)
|
#elif defined(LIGHT_PLATFORM_WINDOWS)
|
||||||
HWND window;
|
HWND window;
|
||||||
#else
|
#else
|
||||||
|
|
@ -1306,8 +1308,10 @@ public:
|
||||||
/** de-allocation functions */
|
/** de-allocation functions */
|
||||||
void free_memory(VkDeviceMemory memory) const;
|
void free_memory(VkDeviceMemory memory) const;
|
||||||
|
|
||||||
void free_descriptor_set(VkDescriptorPool descriptor_pool, VkDescriptorSet descriptor_set)
|
void free_descriptor_set(
|
||||||
const;
|
VkDescriptorPool descriptor_pool,
|
||||||
|
VkDescriptorSet descriptor_set
|
||||||
|
) const;
|
||||||
|
|
||||||
/** destroy functions */
|
/** destroy functions */
|
||||||
void destroy_swapchain(VkSwapchainKHR swapchain) const;
|
void destroy_swapchain(VkSwapchainKHR swapchain) const;
|
||||||
|
|
@ -2695,10 +2699,74 @@ namespace api {
|
||||||
PFN_vkSetDebugUtilsObjectNameEXT set_debug_object_name {}; // NOLINT
|
PFN_vkSetDebugUtilsObjectNameEXT set_debug_object_name {}; // NOLINT
|
||||||
}
|
}
|
||||||
|
|
||||||
|
constexpr auto to_string(VkResult result) noexcept -> std::string_view
|
||||||
|
{
|
||||||
|
switch (result)
|
||||||
|
{
|
||||||
|
// clang-format off
|
||||||
|
case VK_SUCCESS: return "VK_SUCCESS";
|
||||||
|
case VK_NOT_READY: return "VK_NOT_READY";
|
||||||
|
case VK_TIMEOUT: return "VK_TIMEOUT";
|
||||||
|
case VK_EVENT_SET: return "VK_EVENT_SET";
|
||||||
|
case VK_EVENT_RESET: return "VK_EVENT_RESET";
|
||||||
|
case VK_INCOMPLETE: return "VK_INCOMPLETE";
|
||||||
|
case VK_ERROR_OUT_OF_HOST_MEMORY: return "VK_ERROR_OUT_OF_HOST_MEMORY";
|
||||||
|
case VK_ERROR_OUT_OF_DEVICE_MEMORY: return "VK_ERROR_OUT_OF_DEVICE_MEMORY";
|
||||||
|
case VK_ERROR_INITIALIZATION_FAILED: return "VK_ERROR_INITIALIZATION_FAILED";
|
||||||
|
case VK_ERROR_DEVICE_LOST: return "VK_ERROR_DEVICE_LOST";
|
||||||
|
case VK_ERROR_MEMORY_MAP_FAILED: return "VK_ERROR_MEMORY_MAP_FAILED";
|
||||||
|
case VK_ERROR_LAYER_NOT_PRESENT: return "VK_ERROR_LAYER_NOT_PRESENT";
|
||||||
|
case VK_ERROR_EXTENSION_NOT_PRESENT: return "VK_ERROR_EXTENSION_NOT_PRESENT";
|
||||||
|
case VK_ERROR_FEATURE_NOT_PRESENT: return "VK_ERROR_FEATURE_NOT_PRESENT";
|
||||||
|
case VK_ERROR_INCOMPATIBLE_DRIVER: return "VK_ERROR_INCOMPATIBLE_DRIVER";
|
||||||
|
case VK_ERROR_TOO_MANY_OBJECTS: return "VK_ERROR_TOO_MANY_OBJECTS";
|
||||||
|
case VK_ERROR_FORMAT_NOT_SUPPORTED: return "VK_ERROR_FORMAT_NOT_SUPPORTED";
|
||||||
|
case VK_ERROR_FRAGMENTED_POOL: return "VK_ERROR_FRAGMENTED_POOL";
|
||||||
|
case VK_ERROR_UNKNOWN: return "VK_ERROR_UNKNOWN";
|
||||||
|
case VK_ERROR_VALIDATION_FAILED: return "VK_ERROR_VALIDATION_FAILED";
|
||||||
|
case VK_ERROR_OUT_OF_POOL_MEMORY: return "VK_ERROR_OUT_OF_POOL_MEMORY";
|
||||||
|
case VK_ERROR_INVALID_EXTERNAL_HANDLE: return "VK_ERROR_INVALID_EXTERNAL_HANDLE";
|
||||||
|
case VK_ERROR_INVALID_OPAQUE_CAPTURE_ADDRESS: return "VK_ERROR_INVALID_OPAQUE_CAPTURE_ADDRESS";
|
||||||
|
case VK_ERROR_FRAGMENTATION: return "VK_ERROR_FRAGMENTATION";
|
||||||
|
case VK_PIPELINE_COMPILE_REQUIRED: return "VK_PIPELINE_COMPILE_REQUIRED";
|
||||||
|
case VK_ERROR_NOT_PERMITTED: return "VK_ERROR_NOT_PERMITTED";
|
||||||
|
case VK_ERROR_SURFACE_LOST_KHR: return "VK_ERROR_SURFACE_LOST_KHR";
|
||||||
|
case VK_ERROR_NATIVE_WINDOW_IN_USE_KHR: return "VK_ERROR_NATIVE_WINDOW_IN_USE_KHR";
|
||||||
|
case VK_SUBOPTIMAL_KHR: return "VK_SUBOPTIMAL_KHR";
|
||||||
|
case VK_ERROR_OUT_OF_DATE_KHR: return "VK_ERROR_OUT_OF_DATE_KHR";
|
||||||
|
case VK_ERROR_INCOMPATIBLE_DISPLAY_KHR: return "VK_ERROR_INCOMPATIBLE_DISPLAY_KHR";
|
||||||
|
case VK_ERROR_INVALID_SHADER_NV: return "VK_ERROR_INVALID_SHADER_NV";
|
||||||
|
case VK_ERROR_IMAGE_USAGE_NOT_SUPPORTED_KHR: return "VK_ERROR_IMAGE_USAGE_NOT_SUPPORTED_KHR";
|
||||||
|
case VK_ERROR_VIDEO_PICTURE_LAYOUT_NOT_SUPPORTED_KHR: return "VK_ERROR_VIDEO_PICTURE_LAYOUT_NOT_SUPPORTED_KHR";
|
||||||
|
case VK_ERROR_VIDEO_PROFILE_OPERATION_NOT_SUPPORTED_KHR: return "VK_ERROR_VIDEO_PROFILE_OPERATION_NOT_SUPPORTED_KHR";
|
||||||
|
case VK_ERROR_VIDEO_PROFILE_FORMAT_NOT_SUPPORTED_KHR: return "VK_ERROR_VIDEO_PROFILE_FORMAT_NOT_SUPPORTED_KHR";
|
||||||
|
case VK_ERROR_VIDEO_PROFILE_CODEC_NOT_SUPPORTED_KHR: return "VK_ERROR_VIDEO_PROFILE_CODEC_NOT_SUPPORTED_KHR";
|
||||||
|
case VK_ERROR_VIDEO_STD_VERSION_NOT_SUPPORTED_KHR: return "VK_ERROR_VIDEO_STD_VERSION_NOT_SUPPORTED_KHR";
|
||||||
|
case VK_ERROR_INVALID_DRM_FORMAT_MODIFIER_PLANE_LAYOUT_EXT: return "VK_ERROR_INVALID_DRM_FORMAT_MODIFIER_PLANE_LAYOUT_EXT";
|
||||||
|
case VK_ERROR_PRESENT_TIMING_QUEUE_FULL_EXT: return "VK_ERROR_PRESENT_TIMING_QUEUE_FULL_EXT";
|
||||||
|
case VK_ERROR_FULL_SCREEN_EXCLUSIVE_MODE_LOST_EXT: return "VK_ERROR_FULL_SCREEN_EXCLUSIVE_MODE_LOST_EXT";
|
||||||
|
case VK_THREAD_IDLE_KHR: return "VK_THREAD_IDLE_KHR";
|
||||||
|
case VK_THREAD_DONE_KHR: return "VK_THREAD_DONE_KHR";
|
||||||
|
case VK_OPERATION_DEFERRED_KHR: return "VK_OPERATION_DEFERRED_KHR";
|
||||||
|
case VK_OPERATION_NOT_DEFERRED_KHR: return "VK_OPERATION_NOT_DEFERRED_KHR";
|
||||||
|
case VK_ERROR_INVALID_VIDEO_STD_PARAMETERS_KHR: return "VK_ERROR_INVALID_VIDEO_STD_PARAMETERS_KHR";
|
||||||
|
case VK_ERROR_COMPRESSION_EXHAUSTED_EXT: return "VK_ERROR_COMPRESSION_EXHAUSTED_EXT";
|
||||||
|
case VK_INCOMPATIBLE_SHADER_BINARY_EXT: return "VK_INCOMPATIBLE_SHADER_BINARY_EXT";
|
||||||
|
case VK_PIPELINE_BINARY_MISSING_KHR: return "VK_PIPELINE_BINARY_MISSING_KHR";
|
||||||
|
case VK_ERROR_NOT_ENOUGH_SPACE_KHR: return "VK_ERROR_NOT_ENOUGH_SPACE_KHR";
|
||||||
|
case VK_RESULT_MAX_ENUM: return "VK_RESULT_MAX_ENUM";
|
||||||
|
default: return"<unknown>";
|
||||||
|
// clang-format on
|
||||||
|
}
|
||||||
|
|
||||||
|
std::unreachable();
|
||||||
|
}
|
||||||
|
|
||||||
void vkc(VkResult result)
|
void vkc(VkResult result)
|
||||||
{
|
{
|
||||||
if (result)
|
if (result)
|
||||||
{
|
{
|
||||||
|
log::error("Checked vulkan call failed with result: {}", to_string(result));
|
||||||
throw std::runtime_error {
|
throw std::runtime_error {
|
||||||
std::format("Vulkan call failed with result: {}", std::to_underlying(result))
|
std::format("Vulkan call failed with result: {}", std::to_underlying(result))
|
||||||
};
|
};
|
||||||
|
|
@ -2844,7 +2912,7 @@ PFN_vkCmdBeginRendering cmd_begin_rendering {};
|
||||||
PFN_vkCmdEndRendering cmd_end_rendering {};
|
PFN_vkCmdEndRendering cmd_end_rendering {};
|
||||||
|
|
||||||
#if defined(LIGHT_PLATFORM_LINUX)
|
#if defined(LIGHT_PLATFORM_LINUX)
|
||||||
PFN_vkCreateXlibSurfaceKHR create_xlib_surface_khr {};
|
PFN_vkCreateWaylandSurfaceKHR create_wayland_surface_khr {};
|
||||||
#elif defined(LIGHT_PLATFORM_WINDOWS)
|
#elif defined(LIGHT_PLATFORM_WINDOWS)
|
||||||
PFN_vkCreateWin32SurfaceKHR create_win32_surface_khr {};
|
PFN_vkCreateWin32SurfaceKHR create_win32_surface_khr {};
|
||||||
#else
|
#else
|
||||||
|
|
@ -2961,7 +3029,7 @@ void Instance::load_functions()
|
||||||
load_fn(api::get_physical_device_surface_formats, "vkGetPhysicalDeviceSurfaceFormatsKHR");
|
load_fn(api::get_physical_device_surface_formats, "vkGetPhysicalDeviceSurfaceFormatsKHR");
|
||||||
|
|
||||||
#if defined(LIGHT_PLATFORM_LINUX)
|
#if defined(LIGHT_PLATFORM_LINUX)
|
||||||
load_fn(api::create_xlib_surface_khr, "vkCreateXlibSurfaceKHR");
|
load_fn(api::create_wayland_surface_khr, "vkCreateWaylandSurfaceKHR");
|
||||||
#elif defined(LIGHT_PLATFORM_WINDOWS)
|
#elif defined(LIGHT_PLATFORM_WINDOWS)
|
||||||
load_fn(api::create_win32_surface_khr, "vkCreateWin32SurfaceKHR");
|
load_fn(api::create_win32_surface_khr, "vkCreateWin32SurfaceKHR");
|
||||||
#else
|
#else
|
||||||
|
|
@ -3086,13 +3154,15 @@ Instance::Instance(CreateInfo info)
|
||||||
|
|
||||||
debug::ensure(values, "Failed to get variant from setting.values");
|
debug::ensure(values, "Failed to get variant from setting.values");
|
||||||
|
|
||||||
layer_settings.emplace_back(VkLayerSettingEXT {
|
layer_settings.emplace_back(
|
||||||
|
VkLayerSettingEXT {
|
||||||
.pLayerName = layer.name.c_str(),
|
.pLayerName = layer.name.c_str(),
|
||||||
.pSettingName = setting.name.c_str(),
|
.pSettingName = setting.name.c_str(),
|
||||||
.type = std::visit(layer_setting_type_visitor, setting.values),
|
.type = std::visit(layer_setting_type_visitor, setting.values),
|
||||||
.valueCount = 1u,
|
.valueCount = 1u,
|
||||||
.pValues = values,
|
.pValues = values,
|
||||||
});
|
}
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -3129,15 +3199,27 @@ Surface::Surface(const Instance &instance, const CreateInfo &info)
|
||||||
: m_instance(instance.m_instance.get())
|
: m_instance(instance.m_instance.get())
|
||||||
{
|
{
|
||||||
#if defined(LIGHT_PLATFORM_LINUX)
|
#if defined(LIGHT_PLATFORM_LINUX)
|
||||||
const auto vk_info = VkXlibSurfaceCreateInfoKHR {
|
const auto vk_info = VkWaylandSurfaceCreateInfoKHR {
|
||||||
.sType = VK_STRUCTURE_TYPE_XLIB_SURFACE_CREATE_INFO_KHR,
|
.sType = VK_STRUCTURE_TYPE_WAYLAND_SURFACE_CREATE_INFO_KHR,
|
||||||
.pNext = {},
|
.pNext = {},
|
||||||
.flags = {},
|
.flags = {},
|
||||||
.dpy = info.display,
|
.display = info.display,
|
||||||
.window = info.window,
|
.surface = info.surface,
|
||||||
};
|
};
|
||||||
|
|
||||||
vkc(api::create_xlib_surface_khr(instance.get_vk_handle(), &vk_info, nullptr, &m_surface));
|
|
||||||
|
log::debug(
|
||||||
|
"Display proxy's version: {}",
|
||||||
|
wl_proxy_get_version(std::bit_cast<wl_proxy *>(info.display))
|
||||||
|
);
|
||||||
|
|
||||||
|
log::debug(
|
||||||
|
"Surface proxy's version: {}",
|
||||||
|
wl_proxy_get_version(std::bit_cast<wl_proxy *>(info.surface))
|
||||||
|
);
|
||||||
|
|
||||||
|
vkc(api::create_wayland_surface_khr(instance.get_vk_handle(), &vk_info, nullptr, &m_surface));
|
||||||
|
log::debug("Wayland surface vulkan handle id is: {}", (size_t)m_surface);
|
||||||
#elif defined(LIGHT_PLATFORM_WINDOWS)
|
#elif defined(LIGHT_PLATFORM_WINDOWS)
|
||||||
|
|
||||||
const auto vk_info = VkWin32SurfaceCreateInfoKHR {
|
const auto vk_info = VkWin32SurfaceCreateInfoKHR {
|
||||||
|
|
@ -3284,26 +3366,26 @@ Surface::~Surface()
|
||||||
api::get_physical_device_features(m_physical_device, &features_2);
|
api::get_physical_device_features(m_physical_device, &features_2);
|
||||||
return DescriptorIndexingFeatures {
|
return DescriptorIndexingFeatures {
|
||||||
// clang-format off
|
// clang-format off
|
||||||
.shader_input_attachment_array_dynamic_indexing =true,
|
.shader_input_attachment_array_dynamic_indexing = false,
|
||||||
.shader_uniform_texel_buffer_array_dynamic_indexing =true,
|
.shader_uniform_texel_buffer_array_dynamic_indexing = true,
|
||||||
.shader_storage_texel_buffer_array_dynamic_indexing =true,
|
.shader_storage_texel_buffer_array_dynamic_indexing = true,
|
||||||
.shader_uniform_buffer_array_non_uniform_indexing =true,
|
.shader_uniform_buffer_array_non_uniform_indexing = true,
|
||||||
.shader_sampled_image_array_non_uniform_indexing =true,
|
.shader_sampled_image_array_non_uniform_indexing = true,
|
||||||
.shader_storage_buffer_array_non_uniform_indexing =true,
|
.shader_storage_buffer_array_non_uniform_indexing = true,
|
||||||
.shader_storage_image_array_non_uniform_indexing =true,
|
.shader_storage_image_array_non_uniform_indexing = true,
|
||||||
.shader_input_attachment_array_non_uniform_indexing =false,
|
.shader_input_attachment_array_non_uniform_indexing =false,
|
||||||
.shader_uniform_texel_buffer_array_non_uniform_indexing =true,
|
.shader_uniform_texel_buffer_array_non_uniform_indexing = true,
|
||||||
.shader_storage_texel_buffer_array_non_uniform_indexing =true,
|
.shader_storage_texel_buffer_array_non_uniform_indexing = true,
|
||||||
.descriptor_binding_uniform_buffer_update_after_bind =true,
|
.descriptor_binding_uniform_buffer_update_after_bind = true,
|
||||||
.descriptor_binding_sampled_image_update_after_bind =true,
|
.descriptor_binding_sampled_image_update_after_bind = true,
|
||||||
.descriptor_binding_storage_image_update_after_bind =true,
|
.descriptor_binding_storage_image_update_after_bind = true,
|
||||||
.descriptor_binding_storage_buffer_update_after_bind =true,
|
.descriptor_binding_storage_buffer_update_after_bind = true,
|
||||||
.descriptor_binding_uniform_texel_buffer_update_after_bind =true,
|
.descriptor_binding_uniform_texel_buffer_update_after_bind = true,
|
||||||
.descriptor_binding_storage_texel_buffer_update_after_bind =true,
|
.descriptor_binding_storage_texel_buffer_update_after_bind = true,
|
||||||
.descriptor_binding_update_unused_while_pending =true,
|
.descriptor_binding_update_unused_while_pending = true,
|
||||||
.descriptor_binding_partially_bound =true,
|
.descriptor_binding_partially_bound = true,
|
||||||
.descriptor_binding_variable_descriptor_count =true,
|
.descriptor_binding_variable_descriptor_count = true,
|
||||||
.runtime_descriptor_array =true,
|
.runtime_descriptor_array = true,
|
||||||
// clang-format on
|
// clang-format on
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
@ -3581,10 +3663,12 @@ Surface::~Surface()
|
||||||
auto formats = std::vector<Surface::Format> {};
|
auto formats = std::vector<Surface::Format> {};
|
||||||
for (auto &vk_format : vk_formats)
|
for (auto &vk_format : vk_formats)
|
||||||
{
|
{
|
||||||
formats.emplace_back(Surface::Format {
|
formats.emplace_back(
|
||||||
|
Surface::Format {
|
||||||
.format = static_cast<Format>(vk_format.format),
|
.format = static_cast<Format>(vk_format.format),
|
||||||
.color_space = static_cast<ColorSpace>(vk_format.colorSpace),
|
.color_space = static_cast<ColorSpace>(vk_format.colorSpace),
|
||||||
});
|
}
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
return formats;
|
return formats;
|
||||||
|
|
@ -3641,12 +3725,14 @@ Device::Device(const Gpu &gpu, CreateInfo info)
|
||||||
auto vk_queue_infos = std::vector<VkDeviceQueueCreateInfo> {};
|
auto vk_queue_infos = std::vector<VkDeviceQueueCreateInfo> {};
|
||||||
for (auto queue_family : info.queue_indices)
|
for (auto queue_family : info.queue_indices)
|
||||||
{
|
{
|
||||||
vk_queue_infos.emplace_back(VkDeviceQueueCreateInfo {
|
vk_queue_infos.emplace_back(
|
||||||
|
VkDeviceQueueCreateInfo {
|
||||||
.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO,
|
.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO,
|
||||||
.queueFamilyIndex = queue_family,
|
.queueFamilyIndex = queue_family,
|
||||||
.queueCount = 1u,
|
.queueCount = 1u,
|
||||||
.pQueuePriorities = &priorities,
|
.pQueuePriorities = &priorities,
|
||||||
});
|
}
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto vk_extension_names = std::vector<const char *> {};
|
auto vk_extension_names = std::vector<const char *> {};
|
||||||
|
|
@ -3782,13 +3868,17 @@ Device::Device(const Gpu &gpu, CreateInfo info)
|
||||||
}
|
}
|
||||||
|
|
||||||
vkc(api::create_device(gpu.m_physical_device, &vk_info, nullptr, &m_device));
|
vkc(api::create_device(gpu.m_physical_device, &vk_info, nullptr, &m_device));
|
||||||
|
log::debug("Created device: 0x{:x}", (size_t)m_device, (size_t)m_device);
|
||||||
}
|
}
|
||||||
|
|
||||||
Device::~Device()
|
Device::~Device()
|
||||||
{
|
{
|
||||||
if (m_device)
|
if (m_device)
|
||||||
{
|
{
|
||||||
|
log::debug("Destroying device {:x}...", (size_t)m_device);
|
||||||
api::destroy_device(m_device, nullptr);
|
api::destroy_device(m_device, nullptr);
|
||||||
|
log::debug("...Destroyed device");
|
||||||
|
std::cout << "D" << std::endl;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -4039,8 +4129,10 @@ void Device::free_memory(VkDeviceMemory memory) const
|
||||||
api::free_memory(m_device, memory, nullptr);
|
api::free_memory(m_device, memory, nullptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Device::free_descriptor_set(VkDescriptorPool descriptor_pool, VkDescriptorSet descriptor_set)
|
void Device::free_descriptor_set(
|
||||||
const
|
VkDescriptorPool descriptor_pool,
|
||||||
|
VkDescriptorSet descriptor_set
|
||||||
|
) const
|
||||||
{
|
{
|
||||||
vkc(api::free_descriptor_sets(m_device, descriptor_pool, 1, &descriptor_set));
|
vkc(api::free_descriptor_sets(m_device, descriptor_pool, 1, &descriptor_set));
|
||||||
}
|
}
|
||||||
|
|
@ -4495,6 +4587,9 @@ Swapchain::Swapchain(Device &device, Surface &surface, CreateInfo info)
|
||||||
: m_device(device.m_device.get())
|
: m_device(device.m_device.get())
|
||||||
, m_swapchain()
|
, m_swapchain()
|
||||||
{
|
{
|
||||||
|
log::debug("Wayland surface vulkan handle id is now: 0x{:x}", (size_t)surface.m_surface);
|
||||||
|
log::debug("Got device for swapchain: 0x{:x}", (size_t)m_device);
|
||||||
|
|
||||||
auto vk_info = VkSwapchainCreateInfoKHR {
|
auto vk_info = VkSwapchainCreateInfoKHR {
|
||||||
.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR,
|
.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR,
|
||||||
.surface = surface.m_surface,
|
.surface = surface.m_surface,
|
||||||
|
|
@ -4513,20 +4608,36 @@ Swapchain::Swapchain(Device &device, Surface &surface, CreateInfo info)
|
||||||
.clipped = VK_TRUE,
|
.clipped = VK_TRUE,
|
||||||
.oldSwapchain = nullptr,
|
.oldSwapchain = nullptr,
|
||||||
};
|
};
|
||||||
|
log::debug("Creating swapchain: 0x{:x}", (size_t)m_swapchain);
|
||||||
vkc(api::create_swapchain_khr(m_device, &vk_info, nullptr, &m_swapchain));
|
vkc(api::create_swapchain_khr(m_device, &vk_info, nullptr, &m_swapchain));
|
||||||
|
log::debug("Created swapchain: 0x{:x}", (size_t)m_swapchain);
|
||||||
|
|
||||||
if (info.name.empty())
|
if (info.name.empty())
|
||||||
{
|
{
|
||||||
info.name = "<unnamed>";
|
info.name = "<unnamed>";
|
||||||
}
|
}
|
||||||
device.name(*this, "{}", info.name);
|
device.name(*this, "{}", info.name);
|
||||||
|
|
||||||
|
log::debug("Still got device for swapchain: 0x{:x}", (size_t)m_device);
|
||||||
}
|
}
|
||||||
|
|
||||||
Swapchain::~Swapchain()
|
Swapchain::~Swapchain()
|
||||||
{
|
{
|
||||||
if (m_device)
|
if (m_device)
|
||||||
{
|
{
|
||||||
|
log::debug("Destroyig swapchain...");
|
||||||
|
log::debug("device: 0x{:x}", (size_t)m_device);
|
||||||
|
log::debug("swapchain: 0x{:x}", (size_t)m_swapchain);
|
||||||
|
log::debug("vkDestroySwapchainKHR: 0x{:x}", (size_t)api::destroy_swapchain_khr);
|
||||||
api::destroy_swapchain_khr(m_device, m_swapchain, nullptr);
|
api::destroy_swapchain_khr(m_device, m_swapchain, nullptr);
|
||||||
|
log::debug("...Destroyed swapchain");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
log::debug(
|
||||||
|
"Skipped destruction of Swapchain due to nulled device: 0{:x}",
|
||||||
|
(size_t)m_device
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -4583,7 +4694,9 @@ Buffer::Buffer(Device &device, CreateInfo info): m_device(device.m_device.get())
|
||||||
|
|
||||||
Buffer::~Buffer()
|
Buffer::~Buffer()
|
||||||
{
|
{
|
||||||
|
std::cout << "B" << std::endl;
|
||||||
api::destroy_buffer(m_device, m_buffer, nullptr);
|
api::destroy_buffer(m_device, m_buffer, nullptr);
|
||||||
|
std::cout << "C" << std::endl;
|
||||||
}
|
}
|
||||||
|
|
||||||
[[nodiscard]] auto Buffer::get_memory_requirements() const -> MemoryRequirements
|
[[nodiscard]] auto Buffer::get_memory_requirements() const -> MemoryRequirements
|
||||||
|
|
@ -4669,13 +4782,15 @@ DescriptorSetLayout::DescriptorSetLayout(Device &device, CreateInfo info)
|
||||||
vk_binding_flag_values.reserve(info.bindings.size());
|
vk_binding_flag_values.reserve(info.bindings.size());
|
||||||
for (auto &binding_info : info.bindings)
|
for (auto &binding_info : info.bindings)
|
||||||
{
|
{
|
||||||
vk_bindings.emplace_back(VkDescriptorSetLayoutBinding {
|
vk_bindings.emplace_back(
|
||||||
|
VkDescriptorSetLayoutBinding {
|
||||||
.binding = binding_info.idx,
|
.binding = binding_info.idx,
|
||||||
.descriptorType = static_cast<VkDescriptorType>(binding_info.type),
|
.descriptorType = static_cast<VkDescriptorType>(binding_info.type),
|
||||||
.descriptorCount = binding_info.count,
|
.descriptorCount = binding_info.count,
|
||||||
.stageFlags = binding_info.shader_stages,
|
.stageFlags = binding_info.shader_stages,
|
||||||
.pImmutableSamplers = {},
|
.pImmutableSamplers = {},
|
||||||
});
|
}
|
||||||
|
);
|
||||||
|
|
||||||
vk_binding_flag_values.emplace_back(binding_info.flags);
|
vk_binding_flag_values.emplace_back(binding_info.flags);
|
||||||
}
|
}
|
||||||
|
|
@ -4717,10 +4832,12 @@ DescriptorPool::DescriptorPool(Device &device, CreateInfo info): m_device(device
|
||||||
vk_sizes.reserve(info.sizes.size());
|
vk_sizes.reserve(info.sizes.size());
|
||||||
for (auto &size : info.sizes)
|
for (auto &size : info.sizes)
|
||||||
{
|
{
|
||||||
vk_sizes.emplace_back(VkDescriptorPoolSize {
|
vk_sizes.emplace_back(
|
||||||
|
VkDescriptorPoolSize {
|
||||||
.type = static_cast<VkDescriptorType>(size.type),
|
.type = static_cast<VkDescriptorType>(size.type),
|
||||||
.descriptorCount = size.count,
|
.descriptorCount = size.count,
|
||||||
});
|
}
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto vk_info = VkDescriptorPoolCreateInfo {
|
auto vk_info = VkDescriptorPoolCreateInfo {
|
||||||
|
|
@ -4774,12 +4891,14 @@ Pipeline::Pipeline(Device &device, PipelineLayout &layout, CreateInfo info)
|
||||||
auto shader_stages = std::vector<VkPipelineShaderStageCreateInfo> {};
|
auto shader_stages = std::vector<VkPipelineShaderStageCreateInfo> {};
|
||||||
for (auto &[shader, stage] : info.shaders)
|
for (auto &[shader, stage] : info.shaders)
|
||||||
{
|
{
|
||||||
shader_stages.emplace_back(VkPipelineShaderStageCreateInfo {
|
shader_stages.emplace_back(
|
||||||
|
VkPipelineShaderStageCreateInfo {
|
||||||
.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO,
|
.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO,
|
||||||
.stage = static_cast<VkShaderStageFlagBits>(stage),
|
.stage = static_cast<VkShaderStageFlagBits>(stage),
|
||||||
.module = shader.get_vk_handle(),
|
.module = shader.get_vk_handle(),
|
||||||
.pName = "main",
|
.pName = "main",
|
||||||
});
|
}
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto dynamic_states = std::array<VkDynamicState, 2> {
|
auto dynamic_states = std::array<VkDynamicState, 2> {
|
||||||
|
|
@ -4862,7 +4981,8 @@ Pipeline::Pipeline(Device &device, PipelineLayout &layout, CreateInfo info)
|
||||||
.colorAttachmentCount = static_cast<uint32_t>(color_attachment_formats.size()),
|
.colorAttachmentCount = static_cast<uint32_t>(color_attachment_formats.size()),
|
||||||
.pColorAttachmentFormats = std::bit_cast<VkFormat *>(color_attachment_formats.data()),
|
.pColorAttachmentFormats = std::bit_cast<VkFormat *>(color_attachment_formats.data()),
|
||||||
.depthAttachmentFormat = info.attachment_state.depth_attachment ?
|
.depthAttachmentFormat = info.attachment_state.depth_attachment ?
|
||||||
static_cast<VkFormat>(*info.attachment_state.depth_attachment
|
static_cast<VkFormat>(
|
||||||
|
*info.attachment_state.depth_attachment
|
||||||
) :
|
) :
|
||||||
VK_FORMAT_UNDEFINED,
|
VK_FORMAT_UNDEFINED,
|
||||||
|
|
||||||
|
|
@ -4914,11 +5034,13 @@ PipelineLayout::PipelineLayout(Device &device, CreateInfo info): m_device(device
|
||||||
|
|
||||||
for (const auto &range : info.push_constant_ranges)
|
for (const auto &range : info.push_constant_ranges)
|
||||||
{
|
{
|
||||||
vk_push_constant_ranges.emplace_back(VkPushConstantRange {
|
vk_push_constant_ranges.emplace_back(
|
||||||
|
VkPushConstantRange {
|
||||||
.stageFlags = range.shader_stages,
|
.stageFlags = range.shader_stages,
|
||||||
.offset = range.offset,
|
.offset = range.offset,
|
||||||
.size = range.size,
|
.size = range.size,
|
||||||
});
|
}
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (const auto &layout : info.descriptor_set_layouts)
|
for (const auto &layout : info.descriptor_set_layouts)
|
||||||
|
|
@ -4983,6 +5105,7 @@ Messenger::Messenger(Instance &instance, CreateInfo info): m_instance(instance.g
|
||||||
Messenger::~Messenger()
|
Messenger::~Messenger()
|
||||||
{
|
{
|
||||||
api::destroy_debug_messenger(m_instance, m_messenger, nullptr);
|
api::destroy_debug_messenger(m_instance, m_messenger, nullptr);
|
||||||
|
std::cout << "C1" << std::endl;
|
||||||
}
|
}
|
||||||
|
|
||||||
[[nodiscard]]
|
[[nodiscard]]
|
||||||
|
|
|
||||||
|
|
@ -43,18 +43,18 @@ Surface::Surface(IInstance *instance, const ecs::Entity &surface_entity)
|
||||||
#if defined(LIGHT_PLATFORM_LINUX)
|
#if defined(LIGHT_PLATFORM_LINUX)
|
||||||
debug::ensure(
|
debug::ensure(
|
||||||
component.get_native_data().display,
|
component.get_native_data().display,
|
||||||
"Failed to initialize vk::Surface: null x-display"
|
"Failed to initialize vk::Surface: null Wayland display"
|
||||||
);
|
);
|
||||||
debug::ensure(
|
debug::ensure(
|
||||||
component.get_native_data().window,
|
component.get_native_data().surface,
|
||||||
"Failed to initialize vk::Surface: null x-window"
|
"Failed to initialize vk::Surface: null Wayland surface"
|
||||||
);
|
);
|
||||||
|
|
||||||
m_surface = vk::Surface(
|
m_surface = vk::Surface(
|
||||||
static_cast<Instance *>(instance)->vk(),
|
static_cast<Instance *>(instance)->vk(),
|
||||||
vk::Surface::CreateInfo {
|
vk::Surface::CreateInfo {
|
||||||
.display = component.get_native_data().display,
|
.display = component.get_native_data().display,
|
||||||
.window = component.get_native_data().window,
|
.surface = component.get_native_data().surface,
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -83,7 +83,7 @@ Swapchain::Swapchain(ISurface *surface, IGpu *gpu, IDevice *device)
|
||||||
{
|
{
|
||||||
static auto idx = 0u;
|
static auto idx = 0u;
|
||||||
|
|
||||||
const auto capabilities = m_gpu->vk().get_surface_capabilities(m_surface->vk());
|
auto capabilities = m_gpu->vk().get_surface_capabilities(m_surface->vk());
|
||||||
const auto formats = m_gpu->vk().get_surface_formats(m_surface->vk());
|
const auto formats = m_gpu->vk().get_surface_formats(m_surface->vk());
|
||||||
|
|
||||||
// TODO(Light): parameterize
|
// TODO(Light): parameterize
|
||||||
|
|
@ -91,6 +91,19 @@ Swapchain::Swapchain(ISurface *surface, IGpu *gpu, IDevice *device)
|
||||||
const auto surface_format = formats.front();
|
const auto surface_format = formats.front();
|
||||||
m_format = surface_format.format;
|
m_format = surface_format.format;
|
||||||
|
|
||||||
|
if (capabilities.current_extent.x == std::numeric_limits<std::uint32_t>::max())
|
||||||
|
{
|
||||||
|
log::info(
|
||||||
|
"Vulkan surface capabilities current extent is uint32 max... This indicates that the "
|
||||||
|
"surface size will be determined by the extent of a swapchain targeting the surface."
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
// TODO(Light): Take surface extent as swapchain creation argument...
|
||||||
|
capabilities.current_extent.x = 800u;
|
||||||
|
capabilities.current_extent.y = 600u;
|
||||||
|
}
|
||||||
|
|
||||||
m_swapchain = vk::Swapchain(
|
m_swapchain = vk::Swapchain(
|
||||||
m_device->vk(),
|
m_device->vk(),
|
||||||
m_surface->vk(),
|
m_surface->vk(),
|
||||||
|
|
@ -101,7 +114,7 @@ Swapchain::Swapchain(ISurface *surface, IGpu *gpu, IDevice *device)
|
||||||
.extent = capabilities.current_extent,
|
.extent = capabilities.current_extent,
|
||||||
.min_image_count = get_optimal_image_count(capabilities, desired_image_count),
|
.min_image_count = get_optimal_image_count(capabilities, desired_image_count),
|
||||||
.queue_family_indices = m_device->get_family_indices(),
|
.queue_family_indices = m_device->get_family_indices(),
|
||||||
.present_mode = vk::Swapchain::PresentMode::immediate,
|
.present_mode = vk::Swapchain::PresentMode::mailbox,
|
||||||
.pre_transform = capabilities.current_transform,
|
.pre_transform = capabilities.current_transform,
|
||||||
.name = std::format("swapchain {}", idx++),
|
.name = std::format("swapchain {}", idx++),
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
module;
|
module;
|
||||||
#if defined(LIGHT_PLATFORM_LINUX)
|
#if defined(LIGHT_PLATFORM_LINUX)
|
||||||
typedef struct _XDisplay Display;
|
struct wl_display;
|
||||||
|
struct wl_surface;
|
||||||
#else defined(LIGHT_PLATFORM_WINDOWS)
|
#else defined(LIGHT_PLATFORM_WINDOWS)
|
||||||
#include <Windows.h>
|
#include <Windows.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
@ -43,9 +44,9 @@ public:
|
||||||
#if defined(LIGHT_PLATFORM_LINUX)
|
#if defined(LIGHT_PLATFORM_LINUX)
|
||||||
struct NativeData
|
struct NativeData
|
||||||
{
|
{
|
||||||
Display *display;
|
wl_display *display;
|
||||||
std::uint32_t window;
|
|
||||||
unsigned long wm_delete_message;
|
wl_surface *surface;
|
||||||
};
|
};
|
||||||
#elif defined(LIGHT_PLATFORM_WINDOWS)
|
#elif defined(LIGHT_PLATFORM_WINDOWS)
|
||||||
struct NativeData
|
struct NativeData
|
||||||
|
|
|
||||||
28
modules/surface/platform_linux.test.cpp
Normal file
28
modules/surface/platform_linux.test.cpp
Normal file
|
|
@ -0,0 +1,28 @@
|
||||||
|
import test.test;
|
||||||
|
import test.expects;
|
||||||
|
import surface.system;
|
||||||
|
import surface.events;
|
||||||
|
import surface.requests;
|
||||||
|
import ecs.registry;
|
||||||
|
import memory.scope;
|
||||||
|
import memory.reference;
|
||||||
|
import logger;
|
||||||
|
import math.vec2;
|
||||||
|
import app.system;
|
||||||
|
import std;
|
||||||
|
|
||||||
|
using ::lt::surface::SurfaceComponent;
|
||||||
|
using ::lt::surface::System;
|
||||||
|
using ::lt::test::Case;
|
||||||
|
using ::lt::test::expect_eq;
|
||||||
|
using ::lt::test::expect_ne;
|
||||||
|
using ::lt::test::expect_not_nullptr;
|
||||||
|
using ::lt::test::expect_throw;
|
||||||
|
using ::lt::test::Suite;
|
||||||
|
using ::std::ignore;
|
||||||
|
using ::lt::test::operator""_suite;
|
||||||
|
|
||||||
|
Suite raii = "platform_linux_raii"_suite = [] {
|
||||||
|
auto registry = lt::memory::create_ref<lt::ecs::Registry>();
|
||||||
|
std::ignore = System { registry };
|
||||||
|
};
|
||||||
|
|
@ -1,13 +1,7 @@
|
||||||
module;
|
module;
|
||||||
#if defined(LIGHT_PLATFORM_LINUX)
|
#if defined(LIGHT_PLATFORM_LINUX)
|
||||||
#define _POSIX_C_SOURCE 200112L
|
|
||||||
#include <errno.h>
|
|
||||||
#include <fcntl.h>
|
|
||||||
#include <sys/mman.h>
|
|
||||||
#include <time.h>
|
|
||||||
#include <unistd.h>
|
|
||||||
#include <wayland-client.h>
|
#include <wayland-client.h>
|
||||||
#include <wayland-protocols/xdg-shell.h>
|
#include <xdg-shell.h>
|
||||||
#else
|
#else
|
||||||
#error "Unsupported platform"
|
#error "Unsupported platform"
|
||||||
#endif
|
#endif
|
||||||
|
|
@ -21,6 +15,7 @@ import ecs.registry;
|
||||||
import math.vec2;
|
import math.vec2;
|
||||||
import surface.requests;
|
import surface.requests;
|
||||||
import memory.reference;
|
import memory.reference;
|
||||||
|
import memory.null_on_move;
|
||||||
import std;
|
import std;
|
||||||
|
|
||||||
export namespace lt::surface {
|
export namespace lt::surface {
|
||||||
|
|
@ -55,7 +50,7 @@ public:
|
||||||
|
|
||||||
private:
|
private:
|
||||||
#if defined(LIGHT_PLATFORM_LINUX)
|
#if defined(LIGHT_PLATFORM_LINUX)
|
||||||
static void registry_handle_global(
|
static void handle_globals(
|
||||||
void *data,
|
void *data,
|
||||||
wl_registry *registry,
|
wl_registry *registry,
|
||||||
std::uint32_t name,
|
std::uint32_t name,
|
||||||
|
|
@ -89,19 +84,15 @@ private:
|
||||||
app::TickResult m_last_tick_result;
|
app::TickResult m_last_tick_result;
|
||||||
|
|
||||||
#if defined(LIGHT_PLATFORM_LINUX)
|
#if defined(LIGHT_PLATFORM_LINUX)
|
||||||
wl_display *m_wl_display {};
|
memory::NullOnMove<wl_display *> m_wl_display {};
|
||||||
|
|
||||||
wl_registry *m_wl_registry {};
|
memory::NullOnMove<wl_registry *> m_wl_registry {};
|
||||||
|
|
||||||
wl_registry_listener m_wl_registry_listener {};
|
wl_registry_listener m_wl_registry_listener {};
|
||||||
|
|
||||||
wl_compositor *m_wl_compositor {};
|
memory::NullOnMove<wl_compositor *> m_wl_compositor {};
|
||||||
|
|
||||||
wl_surface *m_wl_surface {};
|
memory::NullOnMove<xdg_wm_base *> m_shell = {};
|
||||||
|
|
||||||
wl_shm *m_wl_shm {};
|
|
||||||
|
|
||||||
wl_shm_pool *m_wl_shm_pool {};
|
|
||||||
#endif
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -112,7 +103,46 @@ namespace lt::surface {
|
||||||
|
|
||||||
#ifdef LIGHT_PLATFORM_LINUX
|
#ifdef LIGHT_PLATFORM_LINUX
|
||||||
|
|
||||||
void System::registry_handle_global(
|
void handle_shell_ping(void *data, xdg_wm_base *shell, std::uint32_t serial)
|
||||||
|
{
|
||||||
|
std::ignore = data;
|
||||||
|
|
||||||
|
xdg_wm_base_pong(shell, serial);
|
||||||
|
}
|
||||||
|
const auto shell_listener = xdg_wm_base_listener {
|
||||||
|
.ping = &handle_shell_ping,
|
||||||
|
};
|
||||||
|
|
||||||
|
void handle_shell_surface_configure(void *data, xdg_surface *shell_surface, std::uint32_t serial)
|
||||||
|
{
|
||||||
|
std::ignore = data;
|
||||||
|
|
||||||
|
xdg_surface_ack_configure(shell_surface, serial);
|
||||||
|
}
|
||||||
|
const auto shell_surface_listener = xdg_surface_listener {
|
||||||
|
.configure = &handle_shell_surface_configure
|
||||||
|
};
|
||||||
|
|
||||||
|
void handle_toplevel_configure(
|
||||||
|
void *data,
|
||||||
|
xdg_toplevel *toplevel,
|
||||||
|
std::int32_t width,
|
||||||
|
std::int32_t height,
|
||||||
|
wl_array *states
|
||||||
|
)
|
||||||
|
{
|
||||||
|
// TODO(Light): handle resizing
|
||||||
|
}
|
||||||
|
void handle_toplevel_close(void *data, xdg_toplevel *toplevel)
|
||||||
|
{
|
||||||
|
// TODO(Light): handle quitting
|
||||||
|
}
|
||||||
|
const auto toplevel_listener = xdg_toplevel_listener {
|
||||||
|
.configure = &handle_toplevel_configure,
|
||||||
|
.close = &handle_toplevel_close,
|
||||||
|
};
|
||||||
|
|
||||||
|
void System::handle_globals(
|
||||||
void *data,
|
void *data,
|
||||||
wl_registry *registry,
|
wl_registry *registry,
|
||||||
std::uint32_t name,
|
std::uint32_t name,
|
||||||
|
|
@ -123,42 +153,22 @@ void System::registry_handle_global(
|
||||||
{
|
{
|
||||||
auto *system = std::bit_cast<System *>(data);
|
auto *system = std::bit_cast<System *>(data);
|
||||||
|
|
||||||
// log::trace("Registry global:");
|
|
||||||
// log::trace("\tinterface: {}", interface);
|
|
||||||
// log::trace("\tversion: {}", version);
|
|
||||||
// log::trace("\tname: {}", name);
|
|
||||||
|
|
||||||
if (std::strcmp(interface, wl_compositor_interface.name) == 0)
|
if (std::strcmp(interface, wl_compositor_interface.name) == 0)
|
||||||
{
|
{
|
||||||
system->m_wl_compositor = std::bit_cast<wl_compositor *>(
|
system->m_wl_compositor = std::bit_cast<wl_compositor *>(
|
||||||
wl_registry_bind(registry, name, &wl_compositor_interface, 4)
|
wl_registry_bind(registry, name, &wl_compositor_interface, 1)
|
||||||
);
|
);
|
||||||
log::info("Bound successfuly to the wl_compositor global");
|
log::info("Bound successfuly to the wl_compositor global");
|
||||||
|
|
||||||
system->m_wl_surface = wl_compositor_create_surface(system->m_wl_compositor);
|
|
||||||
|
|
||||||
if (system->m_wl_surface)
|
|
||||||
{
|
|
||||||
log::info("Created a wl_surface from the compositor");
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
log::critical("Failed to create a wl_surface from the compositor");
|
|
||||||
std::terminate();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (std::strcmp(interface, wl_shm_interface.name) == 0)
|
if (std::strcmp(interface, xdg_wm_base_interface.name) == 0)
|
||||||
{
|
{
|
||||||
system->m_wl_shm = std::bit_cast<wl_shm *>(
|
system->m_shell = std::bit_cast<xdg_wm_base *>(
|
||||||
wl_registry_bind(registry, name, &wl_shm_interface, 1)
|
wl_registry_bind(registry, name, &xdg_wm_base_interface, 1)
|
||||||
);
|
);
|
||||||
|
xdg_wm_base_add_listener(system->m_shell, &shell_listener, {});
|
||||||
log::info("Bound successfuly to the wl_shm global");
|
log::info("Bound successfuly to the xdg_wm_base global");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
if (std::strcmp(interface, xdg_))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void registry_handle_global_remove(void *data, wl_registry *registry, std::uint32_t name)
|
void registry_handle_global_remove(void *data, wl_registry *registry, std::uint32_t name)
|
||||||
|
|
@ -167,121 +177,43 @@ void registry_handle_global_remove(void *data, wl_registry *registry, std::uint3
|
||||||
log::trace("\tname: {}", name);
|
log::trace("\tname: {}", name);
|
||||||
}
|
}
|
||||||
|
|
||||||
void read_name(char *buffer)
|
|
||||||
{
|
|
||||||
auto time_spec = timespec {};
|
|
||||||
clock_gettime(CLOCK_REALTIME, &time_spec);
|
|
||||||
auto nanoseconds = time_spec.tv_nsec;
|
|
||||||
|
|
||||||
for (auto idx = std::uint32_t { 0u }; idx < 6u; ++idx)
|
|
||||||
{
|
|
||||||
buffer[idx] = 'A' + (nanoseconds & 15) + (nanoseconds & 16) * 2; // NOLINT
|
|
||||||
nanoseconds >>= 5; // NOLINT
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
[[nodiscard]] auto create_shm_file() -> int
|
|
||||||
{
|
|
||||||
auto retries = 100u;
|
|
||||||
do // NOLINT
|
|
||||||
{
|
|
||||||
char name[] = "/wl_shm-XXXXXX";
|
|
||||||
read_name(name + sizeof(name) - 7);
|
|
||||||
--retries;
|
|
||||||
auto file_descriptor = shm_open(name, O_RDWR | O_CREAT | O_EXCL, 0600);
|
|
||||||
if (file_descriptor >= 0)
|
|
||||||
{
|
|
||||||
shm_unlink(name);
|
|
||||||
return file_descriptor;
|
|
||||||
}
|
|
||||||
} while (retries > 0 && errno == EEXIST);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
[[nodiscard]] auto allocate_shm_file(std::size_t size) -> int
|
|
||||||
{
|
|
||||||
auto file_descriptor = create_shm_file();
|
|
||||||
if (file_descriptor < 0)
|
|
||||||
{
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto ret = 0;
|
|
||||||
do // NOLINT
|
|
||||||
{
|
|
||||||
ret = ftruncate(file_descriptor, size); // NOLINT
|
|
||||||
|
|
||||||
} while (ret < 0 && errno == EINTR);
|
|
||||||
|
|
||||||
if (ret < 0)
|
|
||||||
{
|
|
||||||
close(file_descriptor);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
return file_descriptor;
|
|
||||||
}
|
|
||||||
|
|
||||||
System::System(memory::Ref<ecs::Registry> registry)
|
System::System(memory::Ref<ecs::Registry> registry)
|
||||||
: m_wl_registry_listener(
|
: m_wl_registry_listener(
|
||||||
{
|
{
|
||||||
.global = registry_handle_global,
|
.global = handle_globals,
|
||||||
.global_remove = registry_handle_global_remove,
|
.global_remove = registry_handle_global_remove,
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
, m_registry(std::move(registry))
|
||||||
{
|
{
|
||||||
// NOLINTNEXTLINE
|
// NOLINTNEXTLINE
|
||||||
m_wl_display = wl_display_connect({});
|
m_wl_display = wl_display_connect({});
|
||||||
|
|
||||||
debug::ensure(m_wl_display, "Failed to connect to Wayland display");
|
debug::ensure(m_wl_display, "Failed to connect to Wayland display");
|
||||||
|
|
||||||
log::info("Wayland connection established");
|
|
||||||
|
|
||||||
// NOLINTNEXTLINE
|
// NOLINTNEXTLINE
|
||||||
m_wl_registry = wl_display_get_registry(m_wl_display);
|
m_wl_registry = wl_display_get_registry(m_wl_display);
|
||||||
|
debug::ensure(m_wl_registry, "Failed to get Wayland display's registry");
|
||||||
|
|
||||||
// TODO(Light): "this" could be moved around... replace with a pointer to some heap allocation
|
// TODO(Light): "this" could be moved around... replace with a pointer to some heap allocation
|
||||||
wl_registry_add_listener(m_wl_registry, &m_wl_registry_listener, this);
|
wl_registry_add_listener(m_wl_registry, &m_wl_registry_listener, this);
|
||||||
|
|
||||||
wl_display_roundtrip(m_wl_display);
|
wl_display_roundtrip(m_wl_display);
|
||||||
|
|
||||||
debug::ensure(m_wl_compositor, "Could not bind to the Wayland's compositor global");
|
debug::ensure(m_wl_compositor, "Failed to bind to the Wayland's compositor global");
|
||||||
debug::ensure(m_wl_shm, "Could not bind to the Wayland's compositor global");
|
debug::ensure(m_shell, "Failed to bind to the Wayland's XDG-shell global");
|
||||||
|
|
||||||
const auto width = 1080u;
|
|
||||||
const auto height = 1920u;
|
|
||||||
const auto stride = 4u;
|
|
||||||
const auto shm_pool_size = width * stride * height * 2;
|
|
||||||
|
|
||||||
auto file_descriptor = allocate_shm_file(shm_pool_size);
|
|
||||||
auto *pool_data = std::bit_cast<std::uint8_t *>(
|
|
||||||
mmap({}, shm_pool_size, PROT_READ | PROT_WRITE, MAP_SHARED, file_descriptor, 0)
|
|
||||||
);
|
|
||||||
|
|
||||||
m_wl_shm_pool = wl_shm_create_pool(m_wl_shm, file_descriptor, shm_pool_size);
|
|
||||||
debug::ensure(
|
|
||||||
m_wl_shm_pool,
|
|
||||||
"Failed to create Wayland shared memory pool of size: {}",
|
|
||||||
shm_pool_size
|
|
||||||
);
|
|
||||||
|
|
||||||
log::info("Created Wayland shared memory pool size of: {}", shm_pool_size);
|
|
||||||
|
|
||||||
auto idx = 0;
|
|
||||||
auto offset = width * height * stride * idx;
|
|
||||||
auto *wl_buffer = wl_shm_pool_create_buffer(
|
|
||||||
m_wl_shm_pool,
|
|
||||||
offset,
|
|
||||||
width,
|
|
||||||
height,
|
|
||||||
width * stride,
|
|
||||||
WL_SHM_FORMAT_XRGB8888,
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
System::~System()
|
System::~System()
|
||||||
{
|
{
|
||||||
|
if (m_wl_display)
|
||||||
|
{
|
||||||
|
log::debug("Closing Wayland display...");
|
||||||
wl_display_disconnect(m_wl_display);
|
wl_display_disconnect(m_wl_display);
|
||||||
|
log::debug("Closed Wayland display");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
log::debug("Wayland display nulled on move!");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void System::on_register()
|
void System::on_register()
|
||||||
|
|
@ -294,6 +226,35 @@ void System::on_unregister()
|
||||||
|
|
||||||
void System::create_surface_component(ecs::EntityId entity, SurfaceComponent::CreateInfo info)
|
void System::create_surface_component(ecs::EntityId entity, SurfaceComponent::CreateInfo info)
|
||||||
{
|
{
|
||||||
|
auto &component = m_registry->add<SurfaceComponent>(entity, info);
|
||||||
|
auto &surface = m_registry->get<SurfaceComponent>(entity);
|
||||||
|
const auto &resolution = surface.get_resolution();
|
||||||
|
const auto &position = surface.get_position();
|
||||||
|
|
||||||
|
auto *wayland_surface = (wl_surface *)nullptr;
|
||||||
|
auto *shell_surface = (xdg_surface *)nullptr;
|
||||||
|
auto *shell_toplevel = (xdg_toplevel *)nullptr;
|
||||||
|
|
||||||
|
wayland_surface = wl_compositor_create_surface(m_wl_compositor);
|
||||||
|
debug::ensure(wayland_surface, "Failed to create Wayland surface");
|
||||||
|
|
||||||
|
shell_surface = xdg_wm_base_get_xdg_surface(m_shell, wayland_surface);
|
||||||
|
debug::ensure(shell_surface, "Failed to get XDG-shell surface");
|
||||||
|
xdg_surface_add_listener(shell_surface, &shell_surface_listener, {});
|
||||||
|
|
||||||
|
shell_toplevel = xdg_surface_get_toplevel(shell_surface);
|
||||||
|
debug::ensure(shell_toplevel, "Failed to get XDG-shell toplevel");
|
||||||
|
xdg_toplevel_add_listener(shell_toplevel, &toplevel_listener, {});
|
||||||
|
|
||||||
|
xdg_toplevel_set_title(shell_toplevel, "Wayland Vulkan Example");
|
||||||
|
xdg_toplevel_set_app_id(shell_toplevel, "Wayland Vulkan Example");
|
||||||
|
|
||||||
|
wl_surface_commit(wayland_surface);
|
||||||
|
wl_display_roundtrip(m_wl_display);
|
||||||
|
wl_surface_commit(wayland_surface);
|
||||||
|
|
||||||
|
surface.m_native_data.surface = wayland_surface;
|
||||||
|
surface.m_native_data.display = m_wl_display;
|
||||||
}
|
}
|
||||||
|
|
||||||
void System::tick(app::TickInfo tick)
|
void System::tick(app::TickInfo tick)
|
||||||
|
|
|
||||||
|
|
@ -1,284 +1,290 @@
|
||||||
import test.test;
|
// Suite raii = "raii"_suite = [] {
|
||||||
import test.expects;
|
// Case { "happy path won't throw" } = [] {
|
||||||
import surface.system;
|
// auto fixture = Fixture {};
|
||||||
import surface.events;
|
// ignore = System { fixture.registry() };
|
||||||
import surface.requests;
|
// };
|
||||||
import ecs.registry;
|
//
|
||||||
import memory.scope;
|
// import test.test;
|
||||||
import memory.reference;
|
// import test.expects;
|
||||||
import logger;
|
// import surface.system;
|
||||||
import math.vec2;
|
// import surface.events;
|
||||||
import app.system;
|
// import surface.requests;
|
||||||
import std;
|
// import ecs.registry;
|
||||||
|
// import memory.scope;
|
||||||
using ::lt::surface::SurfaceComponent;
|
// import memory.reference;
|
||||||
using ::lt::surface::System;
|
// import logger;
|
||||||
using ::lt::test::Case;
|
// import math.vec2;
|
||||||
using ::lt::test::expect_eq;
|
// import app.system;
|
||||||
using ::lt::test::expect_ne;
|
// import std;
|
||||||
using ::lt::test::expect_not_nullptr;
|
//
|
||||||
using ::lt::test::expect_throw;
|
// using ::lt::surface::SurfaceComponent;
|
||||||
using ::lt::test::Suite;
|
// using ::lt::surface::System;
|
||||||
using ::std::ignore;
|
// using ::lt::test::Case;
|
||||||
using ::lt::test::operator""_suite;
|
// using ::lt::test::expect_eq;
|
||||||
|
// using ::lt::test::expect_ne;
|
||||||
[[nodiscard]] auto tick_info() -> lt::app::TickInfo
|
// using ::lt::test::expect_not_nullptr;
|
||||||
{
|
// using ::lt::test::expect_throw;
|
||||||
return {
|
// using ::lt::test::Suite;
|
||||||
.delta_time = std::chrono::milliseconds { 16 },
|
// using ::std::ignore;
|
||||||
.budget = std::chrono::milliseconds { 10 },
|
// using ::lt::test::operator""_suite;
|
||||||
.start_time = std::chrono::steady_clock::now(),
|
//
|
||||||
};
|
// [[nodiscard]] auto tick_info() -> lt::app::TickInfo
|
||||||
}
|
// {
|
||||||
|
// return {
|
||||||
constexpr auto title = "TestWindow";
|
// .delta_time = std::chrono::milliseconds { 16 },
|
||||||
constexpr auto width = 800u;
|
// .budget = std::chrono::milliseconds { 10 },
|
||||||
constexpr auto height = 600u;
|
// .start_time = std::chrono::steady_clock::now(),
|
||||||
constexpr auto vsync = true;
|
// };
|
||||||
constexpr auto visible = false;
|
// }
|
||||||
|
//
|
||||||
template<class... Ts>
|
// constexpr auto title = "TestWindow";
|
||||||
struct overloads: Ts...
|
// constexpr auto width = 800u;
|
||||||
{
|
// constexpr auto height = 600u;
|
||||||
using Ts::operator()...;
|
// constexpr auto vsync = true;
|
||||||
};
|
// constexpr auto visible = false;
|
||||||
|
//
|
||||||
class Fixture
|
// template<class... Ts>
|
||||||
{
|
// struct overloads: Ts...
|
||||||
public:
|
// {
|
||||||
[[nodiscard]] auto registry() -> lt::memory::Ref<lt::ecs::Registry>
|
// using Ts::operator()...;
|
||||||
{
|
// };
|
||||||
return m_registry;
|
//
|
||||||
}
|
// class Fixture
|
||||||
|
// {
|
||||||
auto create_component(
|
// public:
|
||||||
SurfaceComponent::CreateInfo info = SurfaceComponent::CreateInfo {
|
// [[nodiscard]] auto registry() -> lt::memory::Ref<lt::ecs::Registry>
|
||||||
.title = title,
|
// {
|
||||||
.resolution = { width, height },
|
// return m_registry;
|
||||||
.vsync = vsync,
|
// }
|
||||||
.visible = visible,
|
//
|
||||||
}
|
// auto create_component(
|
||||||
) -> std::optional<SurfaceComponent *>
|
// SurfaceComponent::CreateInfo info = SurfaceComponent::CreateInfo {
|
||||||
{
|
// .title = title,
|
||||||
auto entity = m_registry->create_entity();
|
// .resolution = { width, height },
|
||||||
m_system.create_surface_component(entity, info);
|
// .vsync = vsync,
|
||||||
|
// .visible = visible,
|
||||||
return &m_registry->get<SurfaceComponent>(entity);
|
// }
|
||||||
}
|
// ) -> std::optional<SurfaceComponent *>
|
||||||
|
// {
|
||||||
void check_values(SurfaceComponent *component)
|
// auto entity = m_registry->create_entity();
|
||||||
{
|
// m_system.create_surface_component(entity, info);
|
||||||
#ifdef LIGHT_PLATFORM_LINUX
|
//
|
||||||
expect_not_nullptr(component->get_native_data().display);
|
// return &m_registry->get<SurfaceComponent>(entity);
|
||||||
expect_ne(component->get_native_data().window, 0);
|
// }
|
||||||
#endif
|
//
|
||||||
|
// void check_values(SurfaceComponent *component)
|
||||||
expect_eq(component->get_resolution().x, width);
|
// {
|
||||||
expect_eq(component->get_resolution().y, height);
|
// #ifdef LIGHT_PLATFORM_LINUX
|
||||||
expect_eq(component->get_title(), title);
|
// expect_not_nullptr(component->get_native_data().display);
|
||||||
expect_eq(component->is_vsync(), vsync);
|
// expect_ne(component->get_native_data().window, 0);
|
||||||
expect_eq(component->is_visible(), visible);
|
// #endif
|
||||||
}
|
//
|
||||||
|
// expect_eq(component->get_resolution().x, width);
|
||||||
private:
|
// expect_eq(component->get_resolution().y, height);
|
||||||
lt::memory::Ref<lt::ecs::Registry> m_registry = lt::memory::create_ref<lt::ecs::Registry>();
|
// expect_eq(component->get_title(), title);
|
||||||
|
// expect_eq(component->is_vsync(), vsync);
|
||||||
System m_system { m_registry };
|
// expect_eq(component->is_visible(), visible);
|
||||||
};
|
// }
|
||||||
|
//
|
||||||
|
// private:
|
||||||
Suite raii = "raii"_suite = [] {
|
// lt::memory::Ref<lt::ecs::Registry> m_registry = lt::memory::create_ref<lt::ecs::Registry>();
|
||||||
Case { "happy path won't throw" } = [] {
|
//
|
||||||
auto fixture = Fixture {};
|
// System m_system { m_registry };
|
||||||
ignore = System { fixture.registry() };
|
// };
|
||||||
};
|
//
|
||||||
|
//
|
||||||
Case { "many won't freeze/throw" } = [] {
|
// Suite raii = "raii"_suite = [] {
|
||||||
auto fixture = Fixture {};
|
// Case { "happy path won't throw" } = [] {
|
||||||
for (auto idx : std::views::iota(0, 250))
|
// auto fixture = Fixture {};
|
||||||
{
|
// ignore = System { fixture.registry() };
|
||||||
ignore = System { fixture.registry() };
|
// };
|
||||||
}
|
//
|
||||||
};
|
// Case { "many won't freeze/throw" } = [] {
|
||||||
|
// auto fixture = Fixture {};
|
||||||
Case { "unhappy path throws" } = [] {
|
// for (auto idx : std::views::iota(0, 250))
|
||||||
expect_throw([] { ignore = System { {} }; });
|
// {
|
||||||
};
|
// ignore = System { fixture.registry() };
|
||||||
|
// }
|
||||||
Case { "post construct has correct state" } = [] {
|
// };
|
||||||
auto fixture = Fixture {};
|
//
|
||||||
auto system = System { fixture.registry() };
|
// Case { "unhappy path throws" } = [] {
|
||||||
expect_eq(fixture.registry()->view<SurfaceComponent>().get_size(), 0);
|
// expect_throw([] { ignore = System { {} }; });
|
||||||
};
|
// };
|
||||||
|
//
|
||||||
Case { "post destruct has correct state" } = [] {
|
// Case { "post construct has correct state" } = [] {
|
||||||
auto fixture = Fixture {};
|
// auto fixture = Fixture {};
|
||||||
auto system = lt::memory::create_scope<System>(fixture.registry());
|
// auto system = System { fixture.registry() };
|
||||||
|
// expect_eq(fixture.registry()->view<SurfaceComponent>().get_size(), 0);
|
||||||
fixture.create_component();
|
// };
|
||||||
expect_eq(fixture.registry()->view<SurfaceComponent>().get_size(), 1);
|
//
|
||||||
|
// Case { "post destruct has correct state" } = [] {
|
||||||
system.reset();
|
// auto fixture = Fixture {};
|
||||||
expect_eq(fixture.registry()->view<SurfaceComponent>().get_size(), 0);
|
// auto system = lt::memory::create_scope<System>(fixture.registry());
|
||||||
};
|
//
|
||||||
};
|
// fixture.create_component();
|
||||||
|
// expect_eq(fixture.registry()->view<SurfaceComponent>().get_size(), 1);
|
||||||
Suite system_events = "system_events"_suite = [] {
|
//
|
||||||
Case { "on_register won't throw" } = [] {
|
// system.reset();
|
||||||
auto fixture = Fixture {};
|
// expect_eq(fixture.registry()->view<SurfaceComponent>().get_size(), 0);
|
||||||
auto system = System { fixture.registry() };
|
// };
|
||||||
|
// };
|
||||||
system.on_register();
|
//
|
||||||
expect_eq(fixture.registry()->view<SurfaceComponent>().get_size(), 0);
|
// Suite system_events = "system_events"_suite = [] {
|
||||||
};
|
// Case { "on_register won't throw" } = [] {
|
||||||
|
// auto fixture = Fixture {};
|
||||||
Case { "on_unregister won't throw" } = [] {
|
// auto system = System { fixture.registry() };
|
||||||
auto fixture = Fixture {};
|
//
|
||||||
auto system = System { fixture.registry() };
|
// system.on_register();
|
||||||
|
// expect_eq(fixture.registry()->view<SurfaceComponent>().get_size(), 0);
|
||||||
system.on_register();
|
// };
|
||||||
system.on_unregister();
|
//
|
||||||
expect_eq(fixture.registry()->view<SurfaceComponent>().get_size(), 0);
|
// Case { "on_unregister won't throw" } = [] {
|
||||||
};
|
// auto fixture = Fixture {};
|
||||||
};
|
// auto system = System { fixture.registry() };
|
||||||
|
//
|
||||||
Suite registry_events = "registry_events"_suite = [] {
|
// system.on_register();
|
||||||
Case { "on_construct<SurfaceComponent> initializes component" } = [] {
|
// system.on_unregister();
|
||||||
auto fixture = Fixture {};
|
// expect_eq(fixture.registry()->view<SurfaceComponent>().get_size(), 0);
|
||||||
|
// };
|
||||||
const auto &component = fixture.create_component();
|
// };
|
||||||
expect_eq(fixture.registry()->view<SurfaceComponent>().get_size(), 1);
|
//
|
||||||
fixture.check_values(*component);
|
// Suite registry_events = "registry_events"_suite = [] {
|
||||||
};
|
// Case { "on_construct<SurfaceComponent> initializes component" } = [] {
|
||||||
|
// auto fixture = Fixture {};
|
||||||
Case { "unhappy on_construct<SurfaceComponent> throws" } = [] {
|
//
|
||||||
auto fixture = Fixture {};
|
// const auto &component = fixture.create_component();
|
||||||
auto system = System { fixture.registry() };
|
// expect_eq(fixture.registry()->view<SurfaceComponent>().get_size(), 1);
|
||||||
|
// fixture.check_values(*component);
|
||||||
expect_throw([&] { fixture.create_component({ .resolution = { width, 0 } }); });
|
// };
|
||||||
|
//
|
||||||
expect_throw([&] { fixture.create_component({ .resolution = { 0, height } }); });
|
// Case { "unhappy on_construct<SurfaceComponent> throws" } = [] {
|
||||||
|
// auto fixture = Fixture {};
|
||||||
expect_throw([&] {
|
// auto system = System { fixture.registry() };
|
||||||
fixture.create_component(
|
//
|
||||||
{ .title = "", .resolution = { SurfaceComponent::max_dimension + 1, height } }
|
// expect_throw([&] { fixture.create_component({ .resolution = { width, 0 } }); });
|
||||||
);
|
//
|
||||||
});
|
// expect_throw([&] { fixture.create_component({ .resolution = { 0, height } }); });
|
||||||
|
//
|
||||||
expect_throw([&] {
|
// expect_throw([&] {
|
||||||
fixture.create_component(
|
// fixture.create_component(
|
||||||
{ .title = "", .resolution = { width, SurfaceComponent::max_dimension + 1 } }
|
// { .title = "", .resolution = { SurfaceComponent::max_dimension + 1, height } }
|
||||||
);
|
// );
|
||||||
});
|
// });
|
||||||
|
//
|
||||||
auto big_str = std::string {};
|
// expect_throw([&] {
|
||||||
big_str.resize(SurfaceComponent::max_title_length + 1);
|
// fixture.create_component(
|
||||||
expect_throw([&] {
|
// { .title = "", .resolution = { width, SurfaceComponent::max_dimension + 1 } }
|
||||||
fixture.create_component({ .title = big_str, .resolution = { width, height } });
|
// );
|
||||||
});
|
// });
|
||||||
};
|
//
|
||||||
|
// auto big_str = std::string {};
|
||||||
Case { "unhappy on_construct<SurfaceComponent> removes component" } = [] {
|
// big_str.resize(SurfaceComponent::max_title_length + 1);
|
||||||
auto fixture = Fixture {};
|
// expect_throw([&] {
|
||||||
auto system = System { fixture.registry() };
|
// fixture.create_component({ .title = big_str, .resolution = { width, height } });
|
||||||
|
// });
|
||||||
expect_throw([&] { fixture.create_component({ .resolution = { width, 0 } }); });
|
// };
|
||||||
expect_eq(fixture.registry()->view<SurfaceComponent>().get_size(), 0);
|
//
|
||||||
};
|
// Case { "unhappy on_construct<SurfaceComponent> removes component" } = [] {
|
||||||
|
// auto fixture = Fixture {};
|
||||||
Case { "on_destrroy<SurfaceComponent> cleans up component" } = [] {
|
// auto system = System { fixture.registry() };
|
||||||
auto fixture = Fixture {};
|
//
|
||||||
auto system = lt::memory::create_scope<System>(fixture.registry());
|
// expect_throw([&] { fixture.create_component({ .resolution = { width, 0 } }); });
|
||||||
|
// expect_eq(fixture.registry()->view<SurfaceComponent>().get_size(), 0);
|
||||||
const auto &component = fixture.create_component();
|
// };
|
||||||
expect_eq(fixture.registry()->view<SurfaceComponent>().get_size(), 1);
|
//
|
||||||
fixture.check_values(*component);
|
// Case { "on_destrroy<SurfaceComponent> cleans up component" } = [] {
|
||||||
|
// auto fixture = Fixture {};
|
||||||
system.reset();
|
// auto system = lt::memory::create_scope<System>(fixture.registry());
|
||||||
expect_eq(fixture.registry()->view<SurfaceComponent>().get_size(), 0);
|
//
|
||||||
};
|
// const auto &component = fixture.create_component();
|
||||||
};
|
// expect_eq(fixture.registry()->view<SurfaceComponent>().get_size(), 1);
|
||||||
|
// fixture.check_values(*component);
|
||||||
Suite tick = "tick"_suite = [] {
|
//
|
||||||
Case { "ticking on empty registry won't throw" } = [] {
|
// system.reset();
|
||||||
auto fixture = Fixture {};
|
// expect_eq(fixture.registry()->view<SurfaceComponent>().get_size(), 0);
|
||||||
System { fixture.registry() }.tick(tick_info());
|
// };
|
||||||
};
|
// };
|
||||||
|
//
|
||||||
Case { "ticking on non-empty registry won't throw" } = [] {
|
// Suite tick = "tick"_suite = [] {
|
||||||
auto fixture = Fixture {};
|
// Case { "ticking on empty registry won't throw" } = [] {
|
||||||
auto system = System { fixture.registry() };
|
// auto fixture = Fixture {};
|
||||||
|
// System { fixture.registry() }.tick(tick_info());
|
||||||
fixture.create_component();
|
// };
|
||||||
system.tick(tick_info());
|
//
|
||||||
};
|
// Case { "ticking on non-empty registry won't throw" } = [] {
|
||||||
};
|
// auto fixture = Fixture {};
|
||||||
|
// auto system = System { fixture.registry() };
|
||||||
Suite tick_handles_events = "tick_handles_events"_suite = [] {
|
//
|
||||||
Case { "ticking clears previous tick's events" } = [] {
|
// fixture.create_component();
|
||||||
auto fixture = Fixture {};
|
// system.tick(tick_info());
|
||||||
auto system = System { fixture.registry() };
|
// };
|
||||||
auto &surface = **fixture.create_component();
|
// };
|
||||||
|
//
|
||||||
// flush window-creation events
|
// Suite tick_handles_events = "tick_handles_events"_suite = [] {
|
||||||
system.tick(tick_info());
|
// Case { "ticking clears previous tick's events" } = [] {
|
||||||
expect_eq(surface.peek_events().size(), 0);
|
// auto fixture = Fixture {};
|
||||||
|
// auto system = System { fixture.registry() };
|
||||||
surface.push_event(lt::surface::MovedEvent({}, {}));
|
// auto &surface = **fixture.create_component();
|
||||||
expect_eq(surface.peek_events().size(), 1);
|
//
|
||||||
|
// // flush window-creation events
|
||||||
surface.push_event(lt::surface::ButtonPressedEvent({}));
|
// system.tick(tick_info());
|
||||||
expect_eq(surface.peek_events().size(), 2);
|
// expect_eq(surface.peek_events().size(), 0);
|
||||||
|
//
|
||||||
system.tick(tick_info());
|
// surface.push_event(lt::surface::MovedEvent({}, {}));
|
||||||
expect_eq(surface.peek_events().size(), 0);
|
// expect_eq(surface.peek_events().size(), 1);
|
||||||
};
|
//
|
||||||
};
|
// surface.push_event(lt::surface::ButtonPressedEvent({}));
|
||||||
|
// expect_eq(surface.peek_events().size(), 2);
|
||||||
Suite tick_handles_requests = "tick_handles_requests"_suite = [] {
|
//
|
||||||
Case { "ticking clears requests" } = [] {
|
// system.tick(tick_info());
|
||||||
auto fixture = Fixture {};
|
// expect_eq(surface.peek_events().size(), 0);
|
||||||
auto system = System { fixture.registry() };
|
// };
|
||||||
auto &surface = **fixture.create_component();
|
// };
|
||||||
|
//
|
||||||
constexpr auto title = "ABC";
|
// Suite tick_handles_requests = "tick_handles_requests"_suite = [] {
|
||||||
constexpr auto position = lt::math::ivec2 { 50, 50 };
|
// Case { "ticking clears requests" } = [] {
|
||||||
constexpr auto resolution = lt::math::uvec2 { 50, 50 };
|
// auto fixture = Fixture {};
|
||||||
|
// auto system = System { fixture.registry() };
|
||||||
expect_eq(surface.peek_requests().size(), 0);
|
// auto &surface = **fixture.create_component();
|
||||||
|
//
|
||||||
surface.push_request(lt::surface::ModifyVisibilityRequest(true));
|
// constexpr auto title = "ABC";
|
||||||
expect_eq(surface.peek_requests().size(), 1);
|
// constexpr auto position = lt::math::ivec2 { 50, 50 };
|
||||||
system.tick(tick_info());
|
// constexpr auto resolution = lt::math::uvec2 { 50, 50 };
|
||||||
expect_eq(surface.peek_requests().size(), 0);
|
//
|
||||||
|
// expect_eq(surface.peek_requests().size(), 0);
|
||||||
surface.push_request(lt::surface::ModifyTitleRequest(title));
|
//
|
||||||
expect_eq(surface.peek_requests().size(), 1);
|
// surface.push_request(lt::surface::ModifyVisibilityRequest(true));
|
||||||
|
// expect_eq(surface.peek_requests().size(), 1);
|
||||||
surface.push_request(lt::surface::ModifyResolutionRequest(resolution));
|
// system.tick(tick_info());
|
||||||
surface.push_request(lt::surface::ModifyPositionRequest(position));
|
// expect_eq(surface.peek_requests().size(), 0);
|
||||||
expect_eq(surface.peek_requests().size(), 1 + 2);
|
//
|
||||||
|
// surface.push_request(lt::surface::ModifyTitleRequest(title));
|
||||||
surface.push_request(lt::surface::ModifyVisibilityRequest(false));
|
// expect_eq(surface.peek_requests().size(), 1);
|
||||||
surface.push_request(lt::surface::ModifyVisibilityRequest(true));
|
//
|
||||||
surface.push_request(lt::surface::ModifyVisibilityRequest(false));
|
// surface.push_request(lt::surface::ModifyResolutionRequest(resolution));
|
||||||
expect_eq(surface.peek_requests().size(), 1 + 2 + 3);
|
// surface.push_request(lt::surface::ModifyPositionRequest(position));
|
||||||
|
// expect_eq(surface.peek_requests().size(), 1 + 2);
|
||||||
system.tick(tick_info());
|
//
|
||||||
expect_eq(surface.peek_requests().size(), 0);
|
// surface.push_request(lt::surface::ModifyVisibilityRequest(false));
|
||||||
|
// surface.push_request(lt::surface::ModifyVisibilityRequest(true));
|
||||||
expect_eq(surface.get_title(), title);
|
// surface.push_request(lt::surface::ModifyVisibilityRequest(false));
|
||||||
expect_eq(surface.get_position(), position);
|
// expect_eq(surface.peek_requests().size(), 1 + 2 + 3);
|
||||||
expect_eq(surface.get_resolution(), resolution);
|
//
|
||||||
|
// system.tick(tick_info());
|
||||||
lt::log::debug("EVENT COUNT: {}", surface.peek_events().size());
|
// expect_eq(surface.peek_requests().size(), 0);
|
||||||
for (const auto &event : surface.peek_events())
|
//
|
||||||
{
|
// expect_eq(surface.get_title(), title);
|
||||||
const auto visitor = overloads {
|
// expect_eq(surface.get_position(), position);
|
||||||
[&](auto event) { lt::log::debug("event: {}", event.to_string()); },
|
// expect_eq(surface.get_resolution(), resolution);
|
||||||
};
|
//
|
||||||
|
// lt::log::debug("EVENT COUNT: {}", surface.peek_events().size());
|
||||||
std::visit(visitor, event);
|
// for (const auto &event : surface.peek_events())
|
||||||
}
|
// {
|
||||||
};
|
// const auto visitor = overloads {
|
||||||
};
|
// [&](auto event) { lt::log::debug("event: {}", event.to_string()); },
|
||||||
|
// };
|
||||||
|
//
|
||||||
|
// std::visit(visitor, event);
|
||||||
|
// }
|
||||||
|
// };
|
||||||
|
// };
|
||||||
|
|
|
||||||
1
modules/surface/wayland-protocols/.gitignore
vendored
Normal file
1
modules/surface/wayland-protocols/.gitignore
vendored
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
*
|
||||||
Loading…
Add table
Reference in a new issue