use crate::errors::{EGLError, LayerShikaError, Result}; use glutin::{ api::egl::{config::Config, context::PossiblyCurrentContext, display::Display}, config::ConfigTemplateBuilder, context::ContextAttributesBuilder, prelude::*, }; use log::{info, warn}; use raw_window_handle::{RawDisplayHandle, WaylandDisplayHandle}; use std::{ffi::c_void, ptr::NonNull, rc::Rc}; use wayland_client::backend::ObjectId; pub struct RenderContextManager { display: Display, config: Config, root_context: PossiblyCurrentContext, } impl RenderContextManager { pub fn new(display_id: &ObjectId) -> Result> { info!("Initializing RenderContextManager with independent root context"); let display_handle = create_wayland_display_handle(display_id)?; let display = unsafe { Display::new(display_handle) } .map_err(|e| EGLError::DisplayCreation { source: e.into() })?; let config_template = ConfigTemplateBuilder::default(); let config = select_config(&display, config_template)?; let root_context = Self::create_root_context(&display, &config)?; info!("RenderContextManager initialized successfully"); Ok(Rc::new(Self { display, config, root_context, })) } fn create_root_context(display: &Display, config: &Config) -> Result { if let Ok(context) = Self::try_create_surfaceless_context(display, config) { info!("Created surfaceless root EGL context"); return Ok(context); } warn!( "Surfaceless context not available, using workaround with make_current_surfaceless anyway" ); Self::create_surfaceless_fallback(display, config) } fn try_create_surfaceless_context( display: &Display, config: &Config, ) -> Result { let context_attributes = ContextAttributesBuilder::default(); let not_current = unsafe { display.create_context(config, &context_attributes.build(None)) } .map_err(|e| EGLError::ContextCreation { source: e.into() })?; not_current .make_current_surfaceless() .map_err(|e| EGLError::MakeCurrent { source: e.into() }.into()) } fn create_surfaceless_fallback( display: &Display, config: &Config, ) -> Result { let context_attributes = ContextAttributesBuilder::default(); let not_current = unsafe { display.create_context(config, &context_attributes.build(None)) } .map_err(|e| EGLError::ContextCreation { source: e.into() })?; not_current .make_current_surfaceless() .map_err(|e| EGLError::MakeCurrent { source: e.into() }.into()) } pub fn display(&self) -> &Display { &self.display } pub fn config(&self) -> &Config { &self.config } pub fn root_context(&self) -> &PossiblyCurrentContext { &self.root_context } } fn create_wayland_display_handle(display_id: &ObjectId) -> Result { let display = NonNull::new(display_id.as_ptr().cast::()).ok_or_else(|| { LayerShikaError::InvalidInput { message: "Failed to create NonNull pointer for display".into(), } })?; let handle = WaylandDisplayHandle::new(display); Ok(RawDisplayHandle::Wayland(handle)) } fn select_config( glutin_display: &Display, config_template: ConfigTemplateBuilder, ) -> Result { let mut configs = unsafe { glutin_display.find_configs(config_template.build()) } .map_err(|e| EGLError::ConfigSelection { source: e.into() })?; configs .next() .ok_or_else(|| EGLError::NoCompatibleConfig.into()) }