From 39824de3a5022b93a7885e558bc0e65cd2d3e988 Mon Sep 17 00:00:00 2001 From: light7734 Date: Sun, 4 Jan 2026 13:14:55 +0330 Subject: [PATCH] wip: wayland input --- modules/CMakeLists.txt | 12 +- modules/memory/null_on_move.cppm | 1 - modules/renderer/_tests/system.cpp | 153 ++++++----- modules/renderer/vk/api_wrapper.cppm | 48 +--- modules/renderer/vk/renderer.cppm | 96 +++---- modules/surface/system.cppm | 284 ++++++++++++++++++-- modules/surface/system.test.cpp | 379 ++++++++++++++------------- 7 files changed, 615 insertions(+), 358 deletions(-) diff --git a/modules/CMakeLists.txt b/modules/CMakeLists.txt index bd18938..a0e6a75 100644 --- a/modules/CMakeLists.txt +++ b/modules/CMakeLists.txt @@ -230,12 +230,12 @@ add_module( PRIVATE_DEPENDENCIES surface TESTS - _tests/buffer.cpp - _tests/debugger.cpp - _tests/device.cpp - _tests/pass.cpp - _tests/renderer.cpp - _tests/surface.cpp + # _tests/buffer.cpp + # _tests/debugger.cpp + # _tests/device.cpp + # _tests/pass.cpp + # _tests/renderer.cpp + # _tests/surface.cpp _tests/system.cpp TEST_INTERFACES _tests/utils.cppm diff --git a/modules/memory/null_on_move.cppm b/modules/memory/null_on_move.cppm index 4c79cb6..e016f38 100644 --- a/modules/memory/null_on_move.cppm +++ b/modules/memory/null_on_move.cppm @@ -39,7 +39,6 @@ public: return *this; } - log::debug("Nulling 0x{:x}", (std::size_t)other.m_value); m_value = other.m_value; other.m_value = null_value; diff --git a/modules/renderer/_tests/system.cpp b/modules/renderer/_tests/system.cpp index 350f6b0..2184cd1 100644 --- a/modules/renderer/_tests/system.cpp +++ b/modules/renderer/_tests/system.cpp @@ -1,82 +1,111 @@ +import time; import renderer.frontend; import renderer.test_utils; struct SurfaceContext { lt::surface::System system; + lt::ecs::Entity entity; }; struct RendererContext { lt::memory::Ref registry; + lt::renderer::System system; }; - Suite raii = "system_raii"_suite = [] { - Case { "happy path won't throw" } = [] { - ignore = Fixture_RendererSystem {}; - }; - - Case { "happy path has no errors" } = [] { + Case { "sandbox" } = [] { auto fixture = Fixture_RendererSystem {}; - expect_false(fixture.has_any_messages_of(lt::renderer::IDebugger::MessageSeverity::error)); - expect_false( - fixture.has_any_messages_of(lt::renderer::IDebugger::MessageSeverity::warning) - ); + auto &surface_system = fixture.surface_system(); + auto &renderer_system = fixture.renderer_system(); + + auto timer = lt::time::Timer {}; + lt::log::trace("Ticking for 3 seconds..."); + + while (timer.elapsed_time() < std::chrono::seconds { 3 }) + { + surface_system.tick({}); + renderer_system.tick({}); + } + + lt::log::trace("Three seconds passed, quitting..."); }; - Case { "unhappy path throws" } = [] { - auto fixture = Fixture_SurfaceSystem {}; - auto empty_entity = lt::ecs::Entity { fixture.registry(), - fixture.registry()->create_entity() }; - auto info = fixture.renderer_system_create_info(); - - expect_throw([=] mutable { - info.registry = nullptr; - ignore = lt::renderer::System { info }; - }); - - expect_throw([=] mutable { - info.surface_entity = lt::ecs::Entity({}, {}); - ignore = lt::renderer::System { info }; - }); - - expect_throw([=] mutable { - info.config.target_api = lt::renderer::Api::none; - ignore = lt::renderer::System { info }; - }); - - // unsupported Apis - expect_throw([=] mutable { - info.config.target_api = lt::renderer::Api::direct_x; - ignore = lt::renderer::System { info }; - }); - - expect_throw([=] mutable { - info.config.target_api = lt::renderer::Api::metal; - ignore = lt::renderer::System { info }; - }); - - expect_throw([=] mutable { - constexpr auto limit = lt::renderer::System::frames_in_flight_upper_limit; - info.config.max_frames_in_flight = limit + 1u; - ignore = lt::renderer::System { info }; - }); - - expect_throw([=] mutable { - constexpr auto limit = lt::renderer::System::frames_in_flight_lower_limit; - info.config.max_frames_in_flight = limit - 1u; - ignore = lt::renderer::System { info }; - }); - - expect_throw([=] mutable { - info.debug_callback_info = lt::renderer::IDebugger::CreateInfo {}; - ignore = lt::renderer::System { info }; - }); - - // Make sure the base info is not at fault for unhappiness. - ignore = lt::renderer::System { info }; - }; + // Case { "happy path won't throw" } = [] { + // ignore = Fixture_RendererSystem {}; + // + // + // auto timer = lt::time::Timer {}; + // lt::log::trace("Ticking for 3 seconds..."); + // while (timer.elapsed_time() < std::chrono::seconds { 3 }) + // { + // system.tick({}); + // } + // + // lt::log::trace("Three seconds passed, quitting..."); + // }; + // + // Case { "happy path has no errors" } = [] { + // auto fixture = Fixture_RendererSystem {}; + // expect_false(fixture.has_any_messages_of(lt::renderer::IDebugger::MessageSeverity::error)); + // expect_false( + // fixture.has_any_messages_of(lt::renderer::IDebugger::MessageSeverity::warning) + // ); + // }; + // + // Case { "unhappy path throws" } = [] { + // auto fixture = Fixture_SurfaceSystem {}; + // auto empty_entity = lt::ecs::Entity { fixture.registry(), + // fixture.registry()->create_entity() }; + // auto info = fixture.renderer_system_create_info(); + // + // expect_throw([=] mutable { + // info.registry = nullptr; + // ignore = lt::renderer::System { info }; + // }); + // + // expect_throw([=] mutable { + // info.surface_entity = lt::ecs::Entity({}, {}); + // ignore = lt::renderer::System { info }; + // }); + // + // expect_throw([=] mutable { + // info.config.target_api = lt::renderer::Api::none; + // ignore = lt::renderer::System { info }; + // }); + // + // // unsupported Apis + // expect_throw([=] mutable { + // info.config.target_api = lt::renderer::Api::direct_x; + // ignore = lt::renderer::System { info }; + // }); + // + // expect_throw([=] mutable { + // info.config.target_api = lt::renderer::Api::metal; + // ignore = lt::renderer::System { info }; + // }); + // + // expect_throw([=] mutable { + // constexpr auto limit = lt::renderer::System::frames_in_flight_upper_limit; + // info.config.max_frames_in_flight = limit + 1u; + // ignore = lt::renderer::System { info }; + // }); + // + // expect_throw([=] mutable { + // constexpr auto limit = lt::renderer::System::frames_in_flight_lower_limit; + // info.config.max_frames_in_flight = limit - 1u; + // ignore = lt::renderer::System { info }; + // }); + // + // expect_throw([=] mutable { + // info.debug_callback_info = lt::renderer::IDebugger::CreateInfo {}; + // ignore = lt::renderer::System { info }; + // }); + // + // // Make sure the base info is not at fault for unhappiness. + // ignore = lt::renderer::System { info }; + // }; }; diff --git a/modules/renderer/vk/api_wrapper.cppm b/modules/renderer/vk/api_wrapper.cppm index 0680714..896e1f2 100644 --- a/modules/renderer/vk/api_wrapper.cppm +++ b/modules/renderer/vk/api_wrapper.cppm @@ -3207,19 +3207,7 @@ Surface::Surface(const Instance &instance, const CreateInfo &info) .surface = info.surface, }; - - log::debug( - "Display proxy's version: {}", - wl_proxy_get_version(std::bit_cast(info.display)) - ); - - log::debug( - "Surface proxy's version: {}", - wl_proxy_get_version(std::bit_cast(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) const auto vk_info = VkWin32SurfaceCreateInfoKHR { @@ -3868,17 +3856,13 @@ Device::Device(const Gpu &gpu, CreateInfo info) } 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() { if (m_device) { - log::debug("Destroying device {:x}...", (size_t)m_device); api::destroy_device(m_device, nullptr); - log::debug("...Destroyed device"); - std::cout << "D" << std::endl; } } @@ -4587,9 +4571,6 @@ Swapchain::Swapchain(Device &device, Surface &surface, CreateInfo info) : m_device(device.m_device.get()) , 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 { .sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR, .surface = surface.m_surface, @@ -4608,36 +4589,20 @@ Swapchain::Swapchain(Device &device, Surface &surface, CreateInfo info) .clipped = VK_TRUE, .oldSwapchain = nullptr, }; - log::debug("Creating swapchain: 0x{:x}", (size_t)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()) { info.name = ""; } device.name(*this, "{}", info.name); - - log::debug("Still got device for swapchain: 0x{:x}", (size_t)m_device); } Swapchain::~Swapchain() { 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); - log::debug("...Destroyed swapchain"); - } - else - { - log::debug( - "Skipped destruction of Swapchain due to nulled device: 0{:x}", - (size_t)m_device - ); } } @@ -4694,9 +4659,10 @@ Buffer::Buffer(Device &device, CreateInfo info): m_device(device.m_device.get()) Buffer::~Buffer() { - std::cout << "B" << std::endl; - api::destroy_buffer(m_device, m_buffer, nullptr); - std::cout << "C" << std::endl; + if (m_device) + { + api::destroy_buffer(m_device, m_buffer, nullptr); + } } [[nodiscard]] auto Buffer::get_memory_requirements() const -> MemoryRequirements @@ -5104,8 +5070,10 @@ Messenger::Messenger(Instance &instance, CreateInfo info): m_instance(instance.g Messenger::~Messenger() { - api::destroy_debug_messenger(m_instance, m_messenger, nullptr); - std::cout << "C1" << std::endl; + if (m_instance) + { + api::destroy_debug_messenger(m_instance, m_messenger, nullptr); + } } [[nodiscard]] diff --git a/modules/renderer/vk/renderer.cppm b/modules/renderer/vk/renderer.cppm index e4c4d8a..3e40d40 100644 --- a/modules/renderer/vk/renderer.cppm +++ b/modules/renderer/vk/renderer.cppm @@ -193,7 +193,7 @@ Renderer::Renderer( frame_fence.reset(); map_buffers(frame_idx); - submit_scene(); + // submit_scene(); record_cmd(cmd, image_idx); auto &submit_semaphore = m_submit_semaphores[image_idx]; @@ -250,35 +250,35 @@ void Renderer::record_cmd(vk::CommandBuffer &cmd, std::uint32_t image_idx) m_staging_buffer.unmap(); - if (m_current_sprite_idx) - { - cmd.copy( - { - .src_buffer = &m_staging_buffer.vk(), - .dst_buffer = &m_vertex_buffer.vk(), - .src_offset = m_staging_offset, - .dst_offset = m_staging_offset, - .size = m_current_sprite_idx * sizeof(components::Sprite::Vertex), - } - ); - } + // if (m_current_sprite_idx) + // { + // cmd.copy( + // { + // .src_buffer = &m_staging_buffer.vk(), + // .dst_buffer = &m_vertex_buffer.vk(), + // .src_offset = m_staging_offset, + // .dst_offset = m_staging_offset, + // .size = m_current_sprite_idx * sizeof(components::Sprite::Vertex), + // } + // ); + // } - cmd.push_constants( - { - .layout = &m_pass->get_pipeline_layout(), - .shader_stages = vk::ShaderStageFlags::vertex_bit, - .offset = 0u, - .size = sizeof(FrameConstants), - .data = &m_frame_constants, - } - ); - - cmd.bind_descriptor_set( - m_global_set, - vk::Pipeline::BindPoint::graphics, - m_pass->get_pipeline_layout(), - 0 - ); + // cmd.push_constants( + // { + // .layout = &m_pass->get_pipeline_layout(), + // .shader_stages = vk::ShaderStageFlags::vertex_bit, + // .offset = 0u, + // .size = sizeof(FrameConstants), + // .data = &m_frame_constants, + // } + // ); + // + // cmd.bind_descriptor_set( + // m_global_set, + // vk::Pipeline::BindPoint::graphics, + // m_pass->get_pipeline_layout(), + // 0 + // ); using AccessFlagBits = vk::CommandBuffer::ImageBarrierInfo::AccessFlagBits; cmd.image_barrier( @@ -310,25 +310,25 @@ void Renderer::record_cmd(vk::CommandBuffer &cmd, std::uint32_t image_idx) } } ); - cmd.bind_pipeline(m_pass->get_pipeline(), vk::Pipeline::BindPoint::graphics); - cmd.set_viewport( - { - .origin = {}, - .extent = { static_cast(m_resolution.x), static_cast(m_resolution.y) }, - .min_depth = 0.0f, - .max_depth = 1.0f, - } - ); - cmd.set_scissor({ .offset = {}, .extent = m_resolution }); - cmd.draw( - { - .vertex_count = static_cast(m_current_sprite_idx), - .instance_count = 1u, - .first_vertex = 0u, - .first_instance = 0u, - } - ); - + // cmd.bind_pipeline(m_pass->get_pipeline(), vk::Pipeline::BindPoint::graphics); + // cmd.set_viewport( + // { + // .origin = {}, + // .extent = { static_cast(m_resolution.x), static_cast(m_resolution.y) }, + // .min_depth = 0.0f, + // .max_depth = 1.0f, + // } + // ); + // cmd.set_scissor({ .offset = {}, .extent = m_resolution }); + // cmd.draw( + // { + // .vertex_count = static_cast(m_current_sprite_idx), + // .instance_count = 1u, + // .first_vertex = 0u, + // .first_instance = 0u, + // } + // ); + // cmd.end_rendering(); cmd.image_barrier( { diff --git a/modules/surface/system.cppm b/modules/surface/system.cppm index e6c57d0..8425472 100644 --- a/modules/surface/system.cppm +++ b/modules/surface/system.cppm @@ -6,7 +6,6 @@ module; #error "Unsupported platform" #endif -import logger; export module surface.system; export import :components; import debug.assertions; @@ -16,6 +15,7 @@ import math.vec2; import surface.requests; import memory.reference; import memory.null_on_move; +import logger; import std; export namespace lt::surface { @@ -50,13 +50,82 @@ public: private: #if defined(LIGHT_PLATFORM_LINUX) - static void handle_globals( + static void wayland_registry_listener( void *data, wl_registry *registry, std::uint32_t name, const char *interface, std::uint32_t version ); + + static void wayland_seat_capabilities_listener( + void *data, + wl_seat *seat, + std::uint32_t capabilities + ); + + static void wayland_pointer_leave_listener( + void *data, + wl_pointer *pointer, + std::uint32_t serial, + wl_surface *surface + ); + + static void wayland_pointer_enter_listener( + void *data, + wl_pointer *pointer, + std::uint32_t serial, + wl_surface *surface, + wl_fixed_t surface_x, + wl_fixed_t surface_y + ); + + static void wayland_pointer_motion_listener( + void *data, + wl_pointer *listener, + std::uint32_t time, + wl_fixed_t surface_x, + wl_fixed_t surface_y + ); + + static void wayland_pointer_button_listener( + void *data, + wl_pointer *pointer, + std::uint32_t serial, + std::uint32_t time, + std::uint32_t button, + std::uint32_t state + ); + + static void wayland_pointer_axis_listener( + void *data, + wl_pointer *pointer, + std::uint32_t time, + std::uint32_t axis, + wl_fixed_t value + ); + + static void wayland_pointer_axis_source_listener( + void *data, + wl_pointer *pointer, + std::uint32_t axis_source + ); + + static void wayland_pointer_axis_stop_listener( + void *data, + wl_pointer *pointer, + std::uint32_t time, + std::uint32_t axis_source + ); + + static void wayland_pointer_axis_discrete_listener( + void *data, + wl_pointer *pointer, + std::uint32_t axis, + std::int32_t discrete + ); + + static void wayland_pointer_frame_listener(void *data, wl_pointer *pointer); #endif void on_surface_destruct(ecs::Registry ®istry, ecs::EntityId entity); @@ -81,18 +150,32 @@ private: memory::Ref m_registry; - app::TickResult m_last_tick_result; + app::TickResult m_last_tick_result {}; #if defined(LIGHT_PLATFORM_LINUX) memory::NullOnMove m_wl_display {}; - memory::NullOnMove m_wl_registry {}; + wl_registry *m_wl_registry {}; wl_registry_listener m_wl_registry_listener {}; - memory::NullOnMove m_wl_compositor {}; + wl_seat_listener m_wl_seat_listener {}; + + wl_pointer_listener m_wl_pointer_listener {}; + + wl_compositor *m_wl_compositor {}; + + xdg_wm_base *m_shell = {}; + + wl_seat *m_wl_seat {}; + + wl_keyboard *m_wl_keyboard {}; + + wl_pointer *m_wl_pointer {}; + + wl_touch *m_wl_touch {}; // TODO(Light): Add touch support + - memory::NullOnMove m_shell = {}; #endif }; @@ -141,7 +224,143 @@ const auto toplevel_listener = xdg_toplevel_listener { .close = &handle_toplevel_close, }; -void System::handle_globals( +void wayland_pointer_leave_listener( + void *data, + wl_pointer *pointer, + std::uint32_t serial, + wl_surface *surface +) +{ + void *system = std::bit_cast(data); +} + +/* static */ void System::wayland_seat_capabilities_listener( + void *data, + wl_seat *seat, + std::uint32_t capabilities +) +{ + std::ignore = seat; + + auto *system = std::bit_cast(data); + const auto have_pointer = capabilities & WL_SEAT_CAPABILITY_POINTER; + + if (have_pointer && !system->m_wl_pointer) + { + system->m_wl_pointer = wl_seat_get_pointer(system->m_wl_seat); + wl_pointer_add_listener(system->m_wl_pointer, &system->m_wl_pointer_listener, system); + log::info( + "Added Wayland pointer (0x{:x})", + std::bit_cast(system->m_wl_pointer) + ); + } + else if (!have_pointer && system->m_wl_pointer) + { + wl_pointer_release(system->m_wl_pointer); + system->m_wl_pointer = nullptr; + + log::info( + "Released Wayland pointer (0x{:x})", + std::bit_cast(system->m_wl_pointer) + ); + } +} + +/* static */ void System::wayland_pointer_leave_listener( + void *data, + wl_pointer *pointer, + std::uint32_t serial, + wl_surface *surface +) +{ + log::debug("Pointer leave..."); +} + +/* static */ void System::wayland_pointer_enter_listener( + void *data, + wl_pointer *pointer, + std::uint32_t serial, + wl_surface *surface, + wl_fixed_t surface_x, + wl_fixed_t surface_y +) +{ + log::debug("Pointer enter..."); +} + +/* static */ void System::wayland_pointer_motion_listener( + void *data, + wl_pointer *listener, + std::uint32_t time, + wl_fixed_t surface_x, + wl_fixed_t surface_y +) +{ + log::debug("Pointer motion: [{} - {}]", surface_x, surface_y); +} + +/* static */ void System::wayland_pointer_button_listener( + void *data, + wl_pointer *pointer, + std::uint32_t serial, + std::uint32_t time, + std::uint32_t button, + std::uint32_t state +) +{ +} + +/* static */ void System::wayland_pointer_axis_listener( + void *data, + wl_pointer *pointer, + std::uint32_t time, + std::uint32_t axis, + wl_fixed_t value +) +{ +} + +/* static */ void System::wayland_pointer_axis_source_listener( + void *data, + wl_pointer *pointer, + std::uint32_t axis_source +) +{ +} + +/* static */ void System::wayland_pointer_axis_stop_listener( + void *data, + wl_pointer *pointer, + std::uint32_t time, + std::uint32_t axis_source +) +{ +} + +/* static */ void System::wayland_pointer_axis_discrete_listener( + void *data, + wl_pointer *pointer, + std::uint32_t axis, + std::int32_t discrete +) +{ +} + +/* static */ void System::wayland_pointer_frame_listener(void *data, wl_pointer *pointer) +{ + log::debug("Pointer frame..."); +} + +void seat_name_listener(void *data, wl_seat *seat, const char *name) +{ + std::ignore = data; + + log::info("Wayland seat:"); + log::info("\tname: {}", name); + log::info("\taddr: 0x{:x}", std::bit_cast(seat)); +} + +void System::wayland_registry_listener( void *data, wl_registry *registry, std::uint32_t name, @@ -150,6 +369,8 @@ void System::handle_globals( ) { + std::ignore = version; + auto *system = std::bit_cast(data); if (std::strcmp(interface, wl_compositor_interface.name) == 0) @@ -165,9 +386,18 @@ void System::handle_globals( system->m_shell = std::bit_cast( wl_registry_bind(registry, name, &xdg_wm_base_interface, 1) ); - xdg_wm_base_add_listener(system->m_shell, &shell_listener, {}); + xdg_wm_base_add_listener(system->m_shell, &shell_listener, system); log::info("Bound successfuly to the xdg_wm_base global"); } + + if (std::strcmp(interface, wl_seat_interface.name) == 0) + { + system->m_wl_seat = std::bit_cast( + wl_registry_bind(registry, name, &wl_seat_interface, 7u) + ); + wl_seat_add_listener(system->m_wl_seat, &system->m_wl_seat_listener, system); + log::info("Bound successfuly to the wl_seat_interface global"); + } } void registry_handle_global_remove(void *data, wl_registry *registry, std::uint32_t name) @@ -179,11 +409,30 @@ void registry_handle_global_remove(void *data, wl_registry *registry, std::uint3 System::System(memory::Ref registry) : m_wl_registry_listener( { - .global = handle_globals, + .global = wayland_registry_listener, .global_remove = registry_handle_global_remove, } ) + , m_wl_seat_listener( + wl_seat_listener { + .capabilities = &wayland_seat_capabilities_listener, + .name = &seat_name_listener, + } + ) , m_registry(std::move(registry)) + , m_wl_pointer_listener( + { + .enter = &wayland_pointer_enter_listener, + .leave = &wayland_pointer_leave_listener, + .motion = &wayland_pointer_motion_listener, + .button = &wayland_pointer_button_listener, + .axis = &wayland_pointer_axis_listener, + .frame = &wayland_pointer_frame_listener, + .axis_source = &wayland_pointer_axis_source_listener, + .axis_stop = &wayland_pointer_axis_stop_listener, + .axis_discrete = &wayland_pointer_axis_discrete_listener, + } + ) { // NOLINTNEXTLINE m_wl_display = wl_display_connect({}); @@ -197,30 +446,30 @@ System::System(memory::Ref registry) wl_registry_add_listener(m_wl_registry, &m_wl_registry_listener, this); wl_display_roundtrip(m_wl_display); + // Wayland seat gets named after the second roundtrip.... + // For reasons beyond my fragile comprehension :( + wl_display_roundtrip(m_wl_display); + debug::ensure(m_wl_compositor, "Failed to bind to the Wayland's compositor global"); debug::ensure(m_shell, "Failed to bind to the Wayland's XDG-shell global"); } System::~System() { - if (m_wl_display) + if (!m_wl_display) { - log::debug("Closing Wayland display..."); - wl_display_disconnect(m_wl_display); - log::debug("Closed Wayland display"); - } - else - { - log::debug("Wayland display nulled on move!"); + return; } } void System::on_register() { + log::info("surface::System::on_register"); } void System::on_unregister() { + log::info("surface::System::on_unregister"); } void System::create_surface_component(ecs::EntityId entity, SurfaceComponent::CreateInfo info) @@ -258,6 +507,7 @@ void System::create_surface_component(ecs::EntityId entity, SurfaceComponent::Cr void System::tick(app::TickInfo tick) { + wl_display_roundtrip(m_wl_display); } #endif diff --git a/modules/surface/system.test.cpp b/modules/surface/system.test.cpp index 386af95..8b74725 100644 --- a/modules/surface/system.test.cpp +++ b/modules/surface/system.test.cpp @@ -1,4 +1,5 @@ import test.test; +import time; import test.expects; import surface.system; import surface.events; @@ -90,195 +91,205 @@ private: Suite raii = "raii"_suite = [] { Case { "happy path won't throw" } = [] { auto fixture = Fixture {}; - ignore = System { fixture.registry() }; - }; + auto system = System { fixture.registry() }; - Case { "many won't freeze/throw" } = [] { - auto fixture = Fixture {}; - for (auto idx : std::views::iota(0, 250)) + auto timer = lt::time::Timer {}; + lt::log::trace("Ticking for 3 seconds..."); + while (timer.elapsed_time() < std::chrono::seconds { 3 }) { - ignore = System { fixture.registry() }; + system.tick({}); } + + lt::log::trace("Three seconds passed, quitting..."); }; - Case { "unhappy path throws" } = [] { - expect_throw([] { ignore = System { {} }; }); - }; - Case { "post construct has correct state" } = [] { - auto fixture = Fixture {}; - auto system = System { fixture.registry() }; - expect_eq(fixture.registry()->view().get_size(), 0); - }; - - Case { "post destruct has correct state" } = [] { - auto fixture = Fixture {}; - auto system = lt::memory::create_scope(fixture.registry()); - - fixture.create_component(); - expect_eq(fixture.registry()->view().get_size(), 1); - - system.reset(); - expect_eq(fixture.registry()->view().get_size(), 0); - }; + // Case { "many won't freeze/throw" } = [] { + // auto fixture = Fixture {}; + // for (auto idx : std::views::iota(0, 250)) + // { + // ignore = System { fixture.registry() }; + // } + // }; + // + // Case { "unhappy path throws" } = [] { + // expect_throw([] { ignore = System { {} }; }); + // }; + // + // Case { "post construct has correct state" } = [] { + // auto fixture = Fixture {}; + // auto system = System { fixture.registry() }; + // expect_eq(fixture.registry()->view().get_size(), 0); + // }; + // + // Case { "post destruct has correct state" } = [] { + // auto fixture = Fixture {}; + // auto system = lt::memory::create_scope(fixture.registry()); + // + // fixture.create_component(); + // expect_eq(fixture.registry()->view().get_size(), 1); + // + // system.reset(); + // expect_eq(fixture.registry()->view().get_size(), 0); + // }; }; -Suite system_events = "system_events"_suite = [] { - Case { "on_register won't throw" } = [] { - auto fixture = Fixture {}; - auto system = System { fixture.registry() }; - - system.on_register(); - expect_eq(fixture.registry()->view().get_size(), 0); - }; - - Case { "on_unregister won't throw" } = [] { - auto fixture = Fixture {}; - auto system = System { fixture.registry() }; - - system.on_register(); - system.on_unregister(); - expect_eq(fixture.registry()->view().get_size(), 0); - }; -}; - -Suite registry_events = "registry_events"_suite = [] { - Case { "on_construct initializes component" } = [] { - auto fixture = Fixture {}; - - const auto &component = fixture.create_component(); - expect_eq(fixture.registry()->view().get_size(), 1); - fixture.check_values(*component); - }; - - Case { "unhappy on_construct throws" } = [] { - auto fixture = Fixture {}; - auto system = System { fixture.registry() }; - - expect_throw([&] { fixture.create_component({ .resolution = { width, 0 } }); }); - - expect_throw([&] { fixture.create_component({ .resolution = { 0, height } }); }); - - expect_throw([&] { - fixture.create_component( - { .title = "", .resolution = { SurfaceComponent::max_dimension + 1, height } } - ); - }); - - expect_throw([&] { - fixture.create_component( - { .title = "", .resolution = { width, SurfaceComponent::max_dimension + 1 } } - ); - }); - - auto big_str = std::string {}; - big_str.resize(SurfaceComponent::max_title_length + 1); - expect_throw([&] { - fixture.create_component({ .title = big_str, .resolution = { width, height } }); - }); - }; - - Case { "unhappy on_construct removes component" } = [] { - auto fixture = Fixture {}; - auto system = System { fixture.registry() }; - - expect_throw([&] { fixture.create_component({ .resolution = { width, 0 } }); }); - expect_eq(fixture.registry()->view().get_size(), 0); - }; - - Case { "on_destrroy cleans up component" } = [] { - auto fixture = Fixture {}; - auto system = lt::memory::create_scope(fixture.registry()); - - const auto &component = fixture.create_component(); - expect_eq(fixture.registry()->view().get_size(), 1); - fixture.check_values(*component); - - system.reset(); - expect_eq(fixture.registry()->view().get_size(), 0); - }; -}; - -Suite tick = "tick"_suite = [] { - Case { "ticking on empty registry won't throw" } = [] { - auto fixture = Fixture {}; - System { fixture.registry() }.tick(tick_info()); - }; - - Case { "ticking on non-empty registry won't throw" } = [] { - auto fixture = Fixture {}; - auto system = System { fixture.registry() }; - - fixture.create_component(); - system.tick(tick_info()); - }; -}; - -Suite tick_handles_events = "tick_handles_events"_suite = [] { - Case { "ticking clears previous tick's events" } = [] { - auto fixture = Fixture {}; - auto system = System { fixture.registry() }; - auto &surface = **fixture.create_component(); - - // flush window-creation events - system.tick(tick_info()); - expect_eq(surface.peek_events().size(), 0); - - surface.push_event(lt::surface::MovedEvent({}, {})); - expect_eq(surface.peek_events().size(), 1); - - surface.push_event(lt::surface::ButtonPressedEvent({})); - expect_eq(surface.peek_events().size(), 2); - - system.tick(tick_info()); - expect_eq(surface.peek_events().size(), 0); - }; -}; - -Suite tick_handles_requests = "tick_handles_requests"_suite = [] { - Case { "ticking clears requests" } = [] { - auto fixture = Fixture {}; - auto system = System { fixture.registry() }; - auto &surface = **fixture.create_component(); - - constexpr auto title = "ABC"; - constexpr auto position = lt::math::ivec2 { 50, 50 }; - constexpr auto resolution = lt::math::uvec2 { 50, 50 }; - - expect_eq(surface.peek_requests().size(), 0); - - surface.push_request(lt::surface::ModifyVisibilityRequest(true)); - expect_eq(surface.peek_requests().size(), 1); - system.tick(tick_info()); - 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::ModifyResolutionRequest(resolution)); - surface.push_request(lt::surface::ModifyPositionRequest(position)); - expect_eq(surface.peek_requests().size(), 1 + 2); - - surface.push_request(lt::surface::ModifyVisibilityRequest(false)); - surface.push_request(lt::surface::ModifyVisibilityRequest(true)); - surface.push_request(lt::surface::ModifyVisibilityRequest(false)); - expect_eq(surface.peek_requests().size(), 1 + 2 + 3); - - system.tick(tick_info()); - expect_eq(surface.peek_requests().size(), 0); - - expect_eq(surface.get_title(), title); - expect_eq(surface.get_position(), position); - expect_eq(surface.get_resolution(), resolution); - - lt::log::debug("EVENT COUNT: {}", surface.peek_events().size()); - for (const auto &event : surface.peek_events()) - { - const auto visitor = overloads { - [&](auto event) { lt::log::debug("event: {}", event.to_string()); }, - }; - - std::visit(visitor, event); - } - }; -}; +// Suite system_events = "system_events"_suite = [] { +// Case { "on_register won't throw" } = [] { +// auto fixture = Fixture {}; +// auto system = System { fixture.registry() }; +// +// system.on_register(); +// expect_eq(fixture.registry()->view().get_size(), 0); +// }; +// +// Case { "on_unregister won't throw" } = [] { +// auto fixture = Fixture {}; +// auto system = System { fixture.registry() }; +// +// system.on_register(); +// system.on_unregister(); +// expect_eq(fixture.registry()->view().get_size(), 0); +// }; +// }; +// +// Suite registry_events = "registry_events"_suite = [] { +// Case { "on_construct initializes component" } = [] { +// auto fixture = Fixture {}; +// +// const auto &component = fixture.create_component(); +// expect_eq(fixture.registry()->view().get_size(), 1); +// fixture.check_values(*component); +// }; +// +// Case { "unhappy on_construct throws" } = [] { +// auto fixture = Fixture {}; +// auto system = System { fixture.registry() }; +// +// expect_throw([&] { fixture.create_component({ .resolution = { width, 0 } }); }); +// +// expect_throw([&] { fixture.create_component({ .resolution = { 0, height } }); }); +// +// expect_throw([&] { +// fixture.create_component( +// { .title = "", .resolution = { SurfaceComponent::max_dimension + 1, height } } +// ); +// }); +// +// expect_throw([&] { +// fixture.create_component( +// { .title = "", .resolution = { width, SurfaceComponent::max_dimension + 1 } } +// ); +// }); +// +// auto big_str = std::string {}; +// big_str.resize(SurfaceComponent::max_title_length + 1); +// expect_throw([&] { +// fixture.create_component({ .title = big_str, .resolution = { width, height } }); +// }); +// }; +// +// Case { "unhappy on_construct removes component" } = [] { +// auto fixture = Fixture {}; +// auto system = System { fixture.registry() }; +// +// expect_throw([&] { fixture.create_component({ .resolution = { width, 0 } }); }); +// expect_eq(fixture.registry()->view().get_size(), 0); +// }; +// +// Case { "on_destrroy cleans up component" } = [] { +// auto fixture = Fixture {}; +// auto system = lt::memory::create_scope(fixture.registry()); +// +// const auto &component = fixture.create_component(); +// expect_eq(fixture.registry()->view().get_size(), 1); +// fixture.check_values(*component); +// +// system.reset(); +// expect_eq(fixture.registry()->view().get_size(), 0); +// }; +// }; +// +// Suite tick = "tick"_suite = [] { +// Case { "ticking on empty registry won't throw" } = [] { +// auto fixture = Fixture {}; +// System { fixture.registry() }.tick(tick_info()); +// }; +// +// Case { "ticking on non-empty registry won't throw" } = [] { +// auto fixture = Fixture {}; +// auto system = System { fixture.registry() }; +// +// fixture.create_component(); +// system.tick(tick_info()); +// }; +// }; +// +// Suite tick_handles_events = "tick_handles_events"_suite = [] { +// Case { "ticking clears previous tick's events" } = [] { +// auto fixture = Fixture {}; +// auto system = System { fixture.registry() }; +// auto &surface = **fixture.create_component(); +// +// // flush window-creation events +// system.tick(tick_info()); +// expect_eq(surface.peek_events().size(), 0); +// +// surface.push_event(lt::surface::MovedEvent({}, {})); +// expect_eq(surface.peek_events().size(), 1); +// +// surface.push_event(lt::surface::ButtonPressedEvent({})); +// expect_eq(surface.peek_events().size(), 2); +// +// system.tick(tick_info()); +// expect_eq(surface.peek_events().size(), 0); +// }; +// }; +// +// Suite tick_handles_requests = "tick_handles_requests"_suite = [] { +// Case { "ticking clears requests" } = [] { +// auto fixture = Fixture {}; +// auto system = System { fixture.registry() }; +// auto &surface = **fixture.create_component(); +// +// constexpr auto title = "ABC"; +// constexpr auto position = lt::math::ivec2 { 50, 50 }; +// constexpr auto resolution = lt::math::uvec2 { 50, 50 }; +// +// expect_eq(surface.peek_requests().size(), 0); +// +// surface.push_request(lt::surface::ModifyVisibilityRequest(true)); +// expect_eq(surface.peek_requests().size(), 1); +// system.tick(tick_info()); +// 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::ModifyResolutionRequest(resolution)); +// surface.push_request(lt::surface::ModifyPositionRequest(position)); +// expect_eq(surface.peek_requests().size(), 1 + 2); +// +// surface.push_request(lt::surface::ModifyVisibilityRequest(false)); +// surface.push_request(lt::surface::ModifyVisibilityRequest(true)); +// surface.push_request(lt::surface::ModifyVisibilityRequest(false)); +// expect_eq(surface.peek_requests().size(), 1 + 2 + 3); +// +// system.tick(tick_info()); +// expect_eq(surface.peek_requests().size(), 0); +// +// expect_eq(surface.get_title(), title); +// expect_eq(surface.get_position(), position); +// expect_eq(surface.get_resolution(), resolution); +// +// lt::log::debug("EVENT COUNT: {}", surface.peek_events().size()); +// for (const auto &event : surface.peek_events()) +// { +// const auto visitor = overloads { +// [&](auto event) { lt::log::debug("event: {}", event.to_string()); }, +// }; +// +// std::visit(visitor, event); +// } +// }; +// };