- Sponsor
-
Notifications
You must be signed in to change notification settings - Fork 482
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
ERROR_CLASS_DOES_NOT_EXIST opening window from DLL #1445
Comments
Fixed in #1435. |
I'm running into a similar issue:
let gl_window = unsafe {
ContextBuilder::new()
.with_depth_buffer(0)
.with_srgb(true)
.with_stencil_buffer(0)
.with_vsync(true)
.build_windowed(window_builder, event_loop)
.unwrap() // Panics on this line
.make_current()
.unwrap()
}; This code used to work before with glutin 0.28. @kchibisov That PR was merged on September 3rd, and glutin 0.29.1 was released on August 10th, so this fix is only in glutin 0.30, right? I want to upgrade to glutin 0.30 but I cannot find This is my code that I need to upgrade: pub struct GuiState {
event_loop: EventLoop<()>,
gl_window: WindowedContext<PossiblyCurrent>,
gl: Arc<glow::Context>,
egui_glow: egui_glow::EguiGlow,
clear_color: [f32; 3],
}
impl GuiState {
pub fn new(title: &str) -> Self {
fn create_display(
event_loop: &EventLoop<()>,
title: &str,
) -> (WindowedContext<PossiblyCurrent>, glow::Context) {
let window_builder = WindowBuilder::new()
.with_resizable(true)
.with_inner_size(LogicalSize { width: 1600., height: 1000. })
.with_maximized(true)
.with_title(title);
let gl_window = unsafe {
ContextBuilder::new()
.with_depth_buffer(0)
.with_srgb(true)
.with_stencil_buffer(0)
.with_vsync(true)
.build_windowed(window_builder, event_loop)
.unwrap()
.make_current()
.unwrap()
};
let gl = unsafe { glow::Context::from_loader_function(|s| gl_window.get_proc_address(s)) };
(gl_window, gl)
}
let event_loop = EventLoopBuilder::new().with_any_thread(true).build();
let (gl_window, gl) = create_display(&event_loop, title);
let gl = std::sync::Arc::new(gl);
let egui_glow = egui_glow::EguiGlow::new(&event_loop, gl.clone());
egui_glow.egui_ctx.set_pixels_per_point(gl_window.window().scale_factor() as _);
let fonts = FontDefinitions::default();
egui_glow.egui_ctx.set_fonts(fonts);
egui_glow.egui_ctx.set_visuals(egui::style::Visuals::dark());
Self { event_loop, gl_window, gl, egui_glow, clear_color: [0.1, 0.1, 0.1] }
}
// ... |
@Boscop I'd suggest to look into the example. It has everything in place and should provide you with enough of information on how to adjust your current code. Basically you have separate context, config, and a window. So what you'd need to do here is to pass your |
@kchibisov Thanks for the quick reply! Btw, which example do you mean I should look at? |
Thanks, I was able to make it compile, but I'm not sure if my new code is equivalent to the old code. pub struct GuiState {
event_loop: EventLoop<()>,
gl_window: GlWindow,
gl_context: PossiblyCurrentContext,
gl: Arc<glow::Context>,
egui_glow: egui_glow::EguiGlow,
clear_color: [f32; 3],
}
impl GuiState {
pub fn new(title: &str) -> Self {
fn create_display(
event_loop: &EventLoop<()>,
title: &str,
) -> (GlWindow, PossiblyCurrentContext, glow::Context) {
let window_builder = WindowBuilder::new()
.with_resizable(true)
.with_inner_size(LogicalSize { width: 1600., height: 1000. })
.with_maximized(true)
.with_title(title);
let template = ConfigTemplateBuilder::new()
.with_alpha_size(8)
.with_depth_size(0)
.with_stencil_size(0);
let display_builder = DisplayBuilder::new()
.with_window_builder(Some(window_builder));
let (window, gl_config) = display_builder
.build(&event_loop, template, |configs| {
// Find the config with the maximum number of samples
configs
.reduce(
|accum, config| {
if config.num_samples() > accum.num_samples() { config } else { accum }
},
)
.unwrap()
})
.unwrap();
let window = window.unwrap();
debug!("Picked a config with {} samples", gl_config.num_samples());
let raw_window_handle = window.raw_window_handle();
// XXX The display could be obtained from the any object created by it, so we
// can query it from the config.
let gl_display = gl_config.display();
// The context creation part. It can be created before surface and that's how
// it's expected in multithreaded + multiwindow operation mode, since you
// can send NotCurrentContext, but not Surface.
let context_attributes = ContextAttributesBuilder::new()
// .with_profile(GlProfile::Core)
.build(raw_window_handle);
// Since glutin by default tries to create OpenGL core context, which may not be
// present we should try gles.
let fallback_context_attributes = ContextAttributesBuilder::new()
.with_context_api(ContextApi::OpenGl(None /* Some(Version::new(4, 6)) */))
.build(raw_window_handle);
let mut not_current_gl_context = Some(unsafe {
gl_display.create_context(&gl_config, &context_attributes).unwrap_or_else(|_| {
gl_display
.create_context(&gl_config, &fallback_context_attributes)
.expect("failed to create context")
})
});
let gl_window = GlWindow::new(window, &gl_config);
// Make it current.
let gl_context = not_current_gl_context.take().unwrap().make_current(&gl_window.surface).unwrap();
// Try setting vsync
if let Err(res) = gl_window
.surface
.set_swap_interval(&gl_context, SwapInterval::Wait(NonZeroU32::new(1).unwrap()))
{
error!("Error setting vsync: {:?}", res);
}
let gl = unsafe {
glow::Context::from_loader_function(|s| {
gl_display.get_proc_address(CString::new(s).unwrap().as_c_str())
})
};
(gl_window, gl_context, gl)
}
let event_loop = EventLoopBuilder::new().with_any_thread(true).build();
let (gl_window, gl_context, gl) = create_display(&event_loop, title);
let gl = Arc::new(gl);
let egui_glow = egui_glow::EguiGlow::new(&event_loop, Arc::clone(&gl));
egui_glow.egui_ctx.set_pixels_per_point(gl_window.window.scale_factor() as _);
let fonts = FontDefinitions::default();
egui_glow.egui_ctx.set_fonts(fonts);
egui_glow.egui_ctx.set_visuals(egui::style::Visuals::dark());
Self { event_loop, gl_window, gl_context, gl, egui_glow, clear_color: [0.1, 0.1, 0.1] }
}
// ...
}
// From: https://github.com/rust-windowing/glutin/blob/b4d54f9a766db90fcd1b08048e35310313e89d1a/glutin_examples/src/lib.rs#L176
struct GlWindow {
// XXX the surface must be dropped before the window.
surface: Surface<WindowSurface>,
window: Window,
}
impl GlWindow {
fn new(window: Window, config: &Config) -> Self {
let (width, height): (u32, u32) = window.inner_size().into();
let raw_window_handle = window.raw_window_handle();
let attrs = SurfaceAttributesBuilder::<WindowSurface>::new().build(
raw_window_handle,
NonZeroU32::new(width).unwrap(),
NonZeroU32::new(height).unwrap(),
);
let surface = unsafe { config.display().create_window_surface(config, &attrs).unwrap() };
Self { window, surface }
}
} It works but I'm wondering:
Btw, since I need to run the GUI in the same thread, I'm using pub fn run_frame_blocking(&mut self, mut frame: impl FnMut(&egui::Context)) -> bool {
let mut running = true;
// TODO: Don't block while window/mouse events arrive
self.event_loop.run_return(|event, _, control_flow| {
let mut redraw = || {
// This was before, with egui 0.18
// let needs_repaint = self.egui_glow.run(self.gl_window.window(), |ctx| frame(ctx));
// The return value changed with egui 0.19
let _time_until_next_repaint = self.egui_glow.run(&self.gl_window.window, |ctx| frame(ctx));
let needs_repaint = false; // TODO: Determine based on time_until_next_repaint
*control_flow = if needs_repaint {
self.gl_window.window.request_redraw();
ControlFlow::Poll
} else {
ControlFlow::Exit
};
{
unsafe {
use glow::HasContext as _;
self.gl.clear_color(
self.clear_color[0],
self.clear_color[1],
self.clear_color[2],
1.0,
);
self.gl.clear(glow::COLOR_BUFFER_BIT);
}
// draw things behind egui here
self.egui_glow.paint(&self.gl_window.window);
// draw things on top of egui here
self.gl_window.surface.swap_buffers(&self.gl_context).unwrap();
}
};
// Based on: https://github.com/emilk/egui/blob/7eeb292adfacd9311a420ac3ea225e2261a8f8d3/egui_glow/examples/pure_glow.rs#L56
match event {
// Platform-dependent event handlers to workaround a winit bug
// See: https://github.com/rust-windowing/winit/issues/987
// See: https://github.com/rust-windowing/winit/issues/1619
Event::RedrawEventsCleared if cfg!(windows) => redraw(),
Event::RedrawRequested(_) if !cfg!(windows) => redraw(),
Event::WindowEvent { event, .. } => {
if matches!(event, WindowEvent::CloseRequested | WindowEvent::Destroyed) {
running = false;
}
if let WindowEvent::Resized(size) = &event {
self.gl_window.surface.resize(
&self.gl_context,
NonZeroU32::new(size.width).unwrap(),
NonZeroU32::new(size.height).unwrap(),
);
} else if let WindowEvent::ScaleFactorChanged { new_inner_size: size, scale_factor } =
&event
{
self.gl_window.surface.resize(
&self.gl_context,
NonZeroU32::new(size.width).unwrap(),
NonZeroU32::new(size.height).unwrap(),
);
self.egui_glow.egui_ctx.set_pixels_per_point(*scale_factor as _);
}
self.egui_glow.on_event(&event);
self.gl_window.window.request_redraw();
}
/*Event::LoopDestroyed => {
self.egui_glow.destroy();
}*/
_ => (),
}
});
running
} |
Unfortunately OpenGL has no such way to do so. Just request a version you want and fallback on versions you can work with limited set of features? Desktop GL tends to pick max available though, but it's not defined in the standard.
If you use OpenGL 4.6 then yes? If you only use OpenGL 3.3 you should request 3.3?
You filter configs by
Yes.
Multiple surfaces can use the same context, vsync is per surface and define during runtime and not on context creation. Also it may be disabled by the driver so you'll fail to activate it.
Not really, since before you were not asking for any multisampling. You might either pick first or filter by
That's out of scope glutin. In general it looks sort of good. |
Thanks :) For the setting the let time_until_next_repaint = self.egui_glow.run(&self.gl_window.window, |ctx| frame(ctx));
let needs_repaint = time_until_next_repaint.is_zero();
*control_flow = if needs_repaint {
self.gl_window.window.request_redraw();
ControlFlow::Poll
} else {
ControlFlow::Exit
}; Btw, also another issue appeared after upgrading winit/glutin, do you have any idea what changed in the window drop/destroy code that causes this? rust-windowing/winit#2583 |
Building a glutin context compiled as a dynamically loaded DLL causes:
This error is caused by the
GetModuleHandleW(std::ptr::null())
usage inglutin/src/api/wgl/mod.rs
, the function returns the handle for the executable, not the DLL.A similar bug was fixed in winit, see winit/2301
The text was updated successfully, but these errors were encountered: