//! This example shows interop with raw GLES contexts - //! the ability to hook up wgpu-hal to an existing context and draw into it. //! //! Emscripten build: //! 1. install emsdk //! 2. build this example with cargo: //! EMCC_CFLAGS="-g -s ERROR_ON_UNDEFINED_SYMBOLS=0 --no-entry -s FULL_ES3=1" cargo build --example raw-gles --target wasm32-unknown-emscripten //! 3. copy raw-gles.em.html into target directory and open it in browser: //! cp wgpu-hal/examples/raw-gles.em.html target/wasm32-unknown-emscripten/debug/examples
use glutin::{
config::GlConfig as _,
context::{NotCurrentGlContext as _, PossiblyCurrentGlContext as _, Version},
display::{GetGlDisplay as _, GlDisplay as _},
surface::GlSurface as _,
}; use glutin_winit::GlWindow as _; use rwh_05::HasRawWindowHandle as _;
let event_loop = winit::event_loop::EventLoop::new().unwrap(); // Only Windows requires the window to be present before creating the display. // Other platforms don't really need one. let window_builder = cfg!(windows).then(|| {
winit::window::WindowBuilder::new()
.with_title("WGPU raw GLES example (press Escape to exit)")
});
// The template will match only the configurations supporting rendering // to Windows. let template = glutin::config::ConfigTemplateBuilder::new();
let display_builder = glutin_winit::DisplayBuilder::new().with_window_builder(window_builder);
// Find the config with the maximum number of samples, so our triangle will be // smooth. pubfn gl_config_picker(
configs: Box<dyn Iterator<Item = glutin::config::Config> + '_>,
) -> glutin::config::Config {
configs
.reduce(|accum, config| { if config.num_samples() > accum.num_samples() {
config
} else {
accum
}
})
.expect("Failed to find a matching config")
}
let (mut window, gl_config) = display_builder
.build(&event_loop, template, gl_config_picker)
.expect("Failed to build window and config from display");
println!("Picked a config with {} samples", gl_config.num_samples());
let raw_window_handle = window.as_ref().map(|window| window.raw_window_handle());
// XXX The display could be obtained from any object created by it, so we can // query it from the config. let gl_display = gl_config.display();
// Glutin tries to create an OpenGL context by default. Force it to use any version of GLES. let context_attributes = glutin::context::ContextAttributesBuilder::new() // WGPU expects GLES 3.0+.
.with_context_api(glutin::context::ContextApi::Gles(Some(Version::new(3, 0))))
.build(raw_window_handle);
match event { // Event::LoopExiting => (),
Event::WindowEvent {
window_id: _,
event:
WindowEvent::CloseRequested
| WindowEvent::KeyboardInput {
event:
KeyEvent {
logical_key: Key::Named(NamedKey::Escape),
..
},
..
},
} => window_target.exit(),
Event::Resumed => { let window = window.take().unwrap_or_else(|| { let window_builder = winit::window::WindowBuilder::new()
.with_title("WGPU raw GLES example (press Escape to exit)");
glutin_winit::finalize_window(window_target, window_builder, &gl_config)
.unwrap()
});
let attrs = window.build_surface_attributes(Default::default()); let gl_surface = unsafe {
gl_config
.display()
.create_window_surface(&gl_config, &attrs)
.expect("Cannot create GL WindowSurface")
};
// Make it current. let gl_context = not_current_gl_context
.take()
.unwrap()
.make_current(&gl_surface)
.expect("GL context cannot be made current with WindowSurface");
// The context needs to be current for the Renderer to set up shaders and // buffers. It also performs function loading, which needs a current context on // WGL.
println!("Hooking up to wgpu-hal");
exposed.get_or_insert_with(|| { unsafe {
<hal::api::Gles as hal::Api>::Adapter::new_external(|name| { // XXX: On WGL this should only be called after the context was made current
gl_config
.display()
.get_proc_address(&CString::new(name).expect(name))
})
}
.expect("GL adapter can't be initialized")
});
assert!(state.replace((gl_context, gl_surface, window)).is_none());
}
Event::Suspended => { // This event is only raised on Android, where the backing NativeWindow for a GL // Surface can appear and disappear at any moment.
println!("Android window removed");
// Destroy the GL Surface and un-current the GL Context before ndk-glue releases // the window back to the system. let (gl_context, ..) = state.take().unwrap();
assert!(not_current_gl_context
.replace(gl_context.make_not_current().unwrap())
.is_none());
}
Event::WindowEvent {
window_id: _,
event: WindowEvent::Resized(size),
} => { if size.width != 0 && size.height != 0 { // Some platforms like EGL require resizing GL surface to update the size // Notable platforms here are Wayland and macOS, other don't require it // and the function is no-op, but it's wise to resize it for portability // reasons. iflet Some((gl_context, gl_surface, _)) = &state {
gl_surface.resize(
gl_context,
NonZeroU32::new(size.width).unwrap(),
NonZeroU32::new(size.height).unwrap(),
); // XXX: If there's a state for fill_screen(), this would need to be updated too.
}
}
}
Event::WindowEvent {
window_id: _,
event: WindowEvent::RedrawRequested,
} => { iflet (Some(exposed), Some((gl_context, gl_surface, window))) =
(&exposed, &state)
{ let inner_size = window.inner_size();
let config = egl
.choose_first_config(display, &attributes)
.unwrap()
.expect("unable to choose config"); let surface = unsafe { let window = std::ptr::null_mut::<std::ffi::c_void>();
egl.create_window_surface(display, config, window, None)
}
.expect("unable to create surface");
let context_attributes = [khronos_egl::CONTEXT_CLIENT_VERSION, 3, khronos_egl::NONE];
let gl_context = egl
.create_context(display, config, None, &context_attributes)
.expect("unable to create context");
egl.make_current(display, Some(surface), Some(surface), Some(gl_context))
.expect("can't make context current");
println!("Hooking up to wgpu-hal"); let exposed = unsafe {
<hal::api::Gles as hal::Api>::Adapter::new_external(|name| {
egl.get_proc_address(name)
.map_or(std::ptr::null(), |p| p as *const _)
})
}
.expect("GL adapter can't be initialized");
fill_screen(&exposed, 640, 400);
}
#[cfg(any(
all(target_arch = "wasm32", not(target_os = "emscripten")),
target_os = "ios",
target_os = "visionos"
))] fn main() {
eprintln!("This example is not supported on Windows and non-emscripten wasm32")
}
#[cfg(not(any(
all(target_arch = "wasm32", not(target_os = "emscripten")),
target_os = "ios",
target_os = "visionos"
)))] fn fill_screen(exposed: &hal::ExposedAdapter<hal::api::Gles>, width: u32, height: u32) { use hal::{Adapter as _, CommandEncoder as _, Device as _, Queue as _};
let od = unsafe {
exposed.adapter.open(
wgt::Features::empty(),
&wgt::Limits::downlevel_defaults(),
&wgt::MemoryHints::default(),
)
}
.unwrap();
let format = wgt::TextureFormat::Rgba8UnormSrgb; let texture = <hal::api::Gles as hal::Api>::Texture::default_framebuffer(format); let view = unsafe {
od.device
.create_texture_view(
&texture,
&hal::TextureViewDescriptor {
label: None,
format,
dimension: wgt::TextureViewDimension::D2,
usage: hal::TextureUses::COLOR_TARGET,
range: wgt::ImageSubresourceRange::default(),
},
)
.unwrap()
};
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.