@ -305,7 +305,145 @@ mod glow_integration {
// Conceptually this will be split out eventually so that the rest of the state
// can be persistent.
gl_window : glutin ::WindowedContext < glutin ::PossiblyCurrent > ,
gl_window : GlutinWindowContext ,
}
struct GlutinWindowContext {
window : winit ::window ::Window ,
gl_context : glutin ::context ::PossiblyCurrentContext ,
gl_display : glutin ::display ::Display ,
gl_surface : glutin ::surface ::Surface < glutin ::surface ::WindowSurface > ,
}
impl GlutinWindowContext {
// refactor this function to use `glutin-winit` crate eventually.
// preferably add android support at the same time.
#[ allow(unsafe_code) ]
unsafe fn new (
winit_window : winit ::window ::Window ,
native_options : & epi ::NativeOptions ,
) -> Self {
use glutin ::prelude ::* ;
use raw_window_handle ::* ;
let hardware_acceleration = match native_options . hardware_acceleration {
crate ::HardwareAcceleration ::Required = > Some ( true ) ,
crate ::HardwareAcceleration ::Preferred = > None ,
crate ::HardwareAcceleration ::Off = > Some ( false ) ,
} ;
let raw_display_handle = winit_window . raw_display_handle ( ) ;
let raw_window_handle = winit_window . raw_window_handle ( ) ;
// EGL is crossplatform and the official khronos way
// but sometimes platforms/drivers may not have it, so we use back up options where possible.
// TODO: check whether we can expose these options as "features", so that users can select the relevant backend they want.
// try egl and fallback to windows wgl. Windows is the only platform that *requires* window handle to create display.
#[ cfg(target_os = " windows " ) ]
let preference = glutin ::display ::DisplayApiPreference ::EglThenWgl ( Some ( window_handle ) ) ;
// try egl and fallback to x11 glx
#[ cfg(target_os = " linux " ) ]
let preference = glutin ::display ::DisplayApiPreference ::EglThenGlx ( Box ::new (
winit ::platform ::unix ::register_xlib_error_hook ,
) ) ;
#[ cfg(target_os = " macos " ) ]
let preference = glutin ::display ::DisplayApiPreference ::Cgl ;
#[ cfg(target_os = " android " ) ]
let preference = glutin ::display ::DisplayApiPreference ::Egl ;
let gl_display = glutin ::display ::Display ::new ( raw_display_handle , preference )
. expect ( "failed to create glutin display" ) ;
let swap_interval = if native_options . vsync {
glutin ::surface ::SwapInterval ::Wait ( std ::num ::NonZeroU32 ::new ( 1 ) . unwrap ( ) )
} else {
glutin ::surface ::SwapInterval ::DontWait
} ;
let config_template = glutin ::config ::ConfigTemplateBuilder ::new ( )
. prefer_hardware_accelerated ( hardware_acceleration )
. with_depth_size ( native_options . depth_buffer ) ;
// we don't know if multi sampling option is set. so, check if its more than 0.
let config_template = if native_options . multisampling > 0 {
config_template . with_multisampling (
native_options
. multisampling
. try_into ( )
. expect ( "failed to fit multisamples into u8" ) ,
)
} else {
config_template
} ;
let config_template = config_template
. with_stencil_size ( native_options . stencil_buffer )
. with_transparency ( native_options . transparent )
. compatible_with_native_window ( raw_window_handle )
. build ( ) ;
// finds all valid configurations supported by this display that match the config_template
// this is where we will try to get a "fallback" config if we are okay with ignoring some native
// options required by user like multi sampling, srgb, transparency etc..
// TODO: need to figure out a good fallback config template
let config = gl_display
. find_configs ( config_template )
. expect ( "failed to find even a single matching configuration" )
. next ( )
. expect ( "failed to find a matching configuration for creating opengl context" ) ;
let context_attributes =
glutin ::context ::ContextAttributesBuilder ::new ( ) . build ( Some ( raw_window_handle ) ) ;
// for surface creation.
let ( width , height ) : ( u32 , u32 ) = winit_window . inner_size ( ) . into ( ) ;
let surface_attributes =
glutin ::surface ::SurfaceAttributesBuilder ::< glutin ::surface ::WindowSurface > ::new ( )
. build (
raw_window_handle ,
std ::num ::NonZeroU32 ::new ( width ) . unwrap ( ) ,
std ::num ::NonZeroU32 ::new ( height ) . unwrap ( ) ,
) ;
// start creating the gl objects
let gl_context = gl_display
. create_context ( & config , & context_attributes )
. expect ( "failed to create opengl context" ) ;
let gl_surface = gl_display
. create_window_surface ( & config , & surface_attributes )
. expect ( "failed to create glutin window surface" ) ;
let gl_context = gl_context
. make_current ( & gl_surface )
. expect ( "failed to make gl context current" ) ;
gl_surface
. set_swap_interval ( & gl_context , swap_interval )
. expect ( "failed to set vsync swap interval" ) ;
GlutinWindowContext {
window : winit_window ,
gl_context ,
gl_display ,
gl_surface ,
}
}
fn window ( & self ) -> & winit ::window ::Window {
& self . window
}
fn resize ( & self , physical_size : winit ::dpi ::PhysicalSize < u32 > ) {
use glutin ::surface ::GlSurface ;
self . gl_surface . resize (
& self . gl_context ,
physical_size
. width
. try_into ( )
. expect ( "physical size must not be zero" ) ,
physical_size
. height
. try_into ( )
. expect ( "physical size must not be zero" ) ,
) ;
}
fn swap_buffers ( & self ) -> glutin ::error ::Result < ( ) > {
use glutin ::surface ::GlSurface ;
self . gl_surface . swap_buffers ( & self . gl_context )
}
fn get_proc_address ( & self , addr : & std ::ffi ::CStr ) -> * const std ::ffi ::c_void {
use glutin ::display ::GlDisplay ;
self . gl_display . get_proc_address ( addr )
}
}
struct GlowWinitApp {
@ -347,44 +485,33 @@ mod glow_integration {
storage : Option < & dyn epi ::Storage > ,
title : & String ,
native_options : & NativeOptions ,
) -> (
glutin ::WindowedContext < glutin ::PossiblyCurrent > ,
glow ::Context ,
) {
) -> ( GlutinWindowContext , glow ::Context ) {
crate ::profile_function ! ( ) ;
use crate ::HardwareAcceleration ;
let hardware_acceleration = match native_options . hardware_acceleration {
HardwareAcceleration ::Required = > Some ( true ) ,
HardwareAcceleration ::Preferred = > None ,
HardwareAcceleration ::Off = > Some ( false ) ,
} ;
let window_settings = epi_integration ::load_window_settings ( storage ) ;
let window_builder = epi_integration ::window_builder ( native_options , & window_settings )
. with_title ( title )
. with_transparent ( native_options . transparent )
// Keep hidden until we've painted something. See https://github.com/emilk/egui/pull/2279
// We must also keep the window hidden until AccessKit is initialized.
. with_visible ( false ) ;
let gl_window = unsafe {
glutin ::ContextBuilder ::new ( )
. with_hardware_acceleration ( hardware_acceleration )
. with_depth_buffer ( native_options . depth_buffer )
. with_multisampling ( native_options . multisampling )
. with_stencil_buffer ( native_options . stencil_buffer )
. with_vsync ( native_options . vsync )
. build_windowed ( window_builder , event_loop )
. unwrap ( )
. make_current ( )
. unwrap ( )
let winit_window = window_builder
. build ( event_loop )
. expect ( "failed to create winit window" ) ;
// a lot of the code below has been lifted from glutin example in their repo.
let glutin_window_context =
unsafe { GlutinWindowContext ::new ( winit_window , native_options ) } ;
let gl = unsafe {
glow ::Context ::from_loader_function ( | s | {
let s = std ::ffi ::CString ::new ( s )
. expect ( "failed to construct C string from string for gl proc address" ) ;
glutin_window_context . get_proc_address ( & s )
} )
} ;
let gl =
unsafe { glow ::Context ::from_loader_function ( | s | gl_window . get_proc_address ( s ) ) } ;
( gl_window , gl )
( glutin_window_context , gl )
}
fn init_run_state ( & mut self , event_loop : & EventLoopWindowTarget < UserEvent > ) {