From abe2c6e1e17fa6ee48f0e5a2e01fdedef37cad8e Mon Sep 17 00:00:00 2001 From: light7734 Date: Sun, 28 Dec 2025 15:38:29 +0330 Subject: [PATCH] wip: x11 -> wayland transition --- modules/surface/system.cppm | 246 +++++++++++++++++++++++++++++++++++- 1 file changed, 244 insertions(+), 2 deletions(-) diff --git a/modules/surface/system.cppm b/modules/surface/system.cppm index 74f83a9..07d87c7 100644 --- a/modules/surface/system.cppm +++ b/modules/surface/system.cppm @@ -1,5 +1,21 @@ +module; +#if defined(LIGHT_PLATFORM_LINUX) + #define _POSIX_C_SOURCE 200112L + #include + #include + #include + #include + #include + #include + #include +#else + #error "Unsupported platform" +#endif + +import logger; export module surface.system; export import :components; +import debug.assertions; import app.system; import ecs.registry; import math.vec2; @@ -7,9 +23,9 @@ import surface.requests; import memory.reference; import std; -namespace lt::surface { +export namespace lt::surface { -export class System: public app::ISystem +class System: public app::ISystem { public: [[nodiscard]] System(memory::Ref registry); @@ -38,6 +54,16 @@ public: } private: +#if defined(LIGHT_PLATFORM_LINUX) + static void registry_handle_global( + void *data, + wl_registry *registry, + std::uint32_t name, + const char *interface, + std::uint32_t version + ); +#endif + void on_surface_destruct(ecs::Registry ®istry, ecs::EntityId entity); void handle_requests(SurfaceComponent &surface); @@ -61,6 +87,222 @@ private: memory::Ref m_registry; app::TickResult m_last_tick_result; + +#if defined(LIGHT_PLATFORM_LINUX) + wl_display *m_wl_display {}; + + wl_registry *m_wl_registry {}; + + wl_registry_listener m_wl_registry_listener {}; + + wl_compositor *m_wl_compositor {}; + + wl_surface *m_wl_surface {}; + + wl_shm *m_wl_shm {}; + + wl_shm_pool *m_wl_shm_pool {}; +#endif }; } // namespace lt::surface + +module :private; +namespace lt::surface { + +#ifdef LIGHT_PLATFORM_LINUX + +void System::registry_handle_global( + void *data, + wl_registry *registry, + std::uint32_t name, + const char *interface, + std::uint32_t version +) + +{ + auto *system = std::bit_cast(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) + { + system->m_wl_compositor = std::bit_cast( + wl_registry_bind(registry, name, &wl_compositor_interface, 4) + ); + 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) + { + system->m_wl_shm = std::bit_cast( + wl_registry_bind(registry, name, &wl_shm_interface, 1) + ); + + log::info("Bound successfuly to the wl_shm global"); + } + + + if (std::strcmp(interface, xdg_)) +} + +void registry_handle_global_remove(void *data, wl_registry *registry, std::uint32_t name) +{ + log::trace("Registry global remove:"); + 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 registry) + : m_wl_registry_listener( + { + .global = registry_handle_global, + .global_remove = registry_handle_global_remove, + } + ) +{ + // NOLINTNEXTLINE + m_wl_display = wl_display_connect({}); + + debug::ensure(m_wl_display, "Failed to connect to Wayland display"); + + log::info("Wayland connection established"); + + // NOLINTNEXTLINE + m_wl_registry = wl_display_get_registry(m_wl_display); + + // 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_display_roundtrip(m_wl_display); + + debug::ensure(m_wl_compositor, "Could not bind to the Wayland's compositor global"); + debug::ensure(m_wl_shm, "Could not bind to the Wayland's compositor 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( + 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() +{ + wl_display_disconnect(m_wl_display); +} + +void System::on_register() +{ +} + +void System::on_unregister() +{ +} + +void System::create_surface_component(ecs::EntityId entity, SurfaceComponent::CreateInfo info) +{ +} + +void System::tick(app::TickInfo tick) +{ +} + +#endif + +#ifdef LIGHT_PLATFORM_WINDOWS +#endif + +} // namespace lt::surface