diff --git a/Cargo.lock b/Cargo.lock index f28c4a1ab6..5aee4b89a6 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -23,6 +23,12 @@ dependencies = [ "memchr", ] +[[package]] +name = "android_glue" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "000444226fcff248f2bc4c7625be32c63caccfecc2723a2b9f78a7487a49c407" + [[package]] name = "approx" version = "0.4.0" @@ -202,6 +208,15 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fd16c4719339c4530435d38e511904438d07cce7950afa3718a84ac36c10e89e" +[[package]] +name = "cgl" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ced0551234e87afee12411d535648dd89d2e7f34c78b753395567aff3d447ff" +dependencies = [ + "libc", +] + [[package]] name = "cgmath" version = "0.18.0" @@ -598,6 +613,17 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "gl_generator" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a95dfc23a2b4a9a2f5ab41d194f8bfda3cabec42af4e39f08c339eb2a0c124d" +dependencies = [ + "khronos_api", + "log", + "xml-rs", +] + [[package]] name = "glow" version = "0.11.1" @@ -610,6 +636,78 @@ dependencies = [ "web-sys", ] +[[package]] +name = "glutin" +version = "0.28.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "00ea9dbe544bc8a657c4c4a798c2d16cd01b549820e47657297549d28371f6d2" +dependencies = [ + "android_glue", + "cgl", + "cocoa", + "core-foundation 0.9.1", + "glutin_egl_sys", + "glutin_emscripten_sys", + "glutin_gles2_sys", + "glutin_glx_sys", + "glutin_wgl_sys", + "lazy_static", + "libloading", + "log", + "objc", + "osmesa-sys", + "parking_lot", + "wayland-client", + "wayland-egl", + "winapi", + "winit", +] + +[[package]] +name = "glutin_egl_sys" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2abb6aa55523480c4adc5a56bbaa249992e2dddb2fc63dc96e04a3355364c211" +dependencies = [ + "gl_generator", + "winapi", +] + +[[package]] +name = "glutin_emscripten_sys" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "80de4146df76e8a6c32b03007bc764ff3249dcaeb4f675d68a06caf1bac363f1" + +[[package]] +name = "glutin_gles2_sys" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e8094e708b730a7c8a1954f4f8a31880af00eb8a1c5b5bf85d28a0a3c6d69103" +dependencies = [ + "gl_generator", + "objc", +] + +[[package]] +name = "glutin_glx_sys" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7e393c8fc02b807459410429150e9c4faffdb312d59b8c038566173c81991351" +dependencies = [ + "gl_generator", + "x11-dl", +] + +[[package]] +name = "glutin_wgl_sys" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3da5951a1569dbab865c6f2a863efafff193a93caf05538d193e9e3816d21696" +dependencies = [ + "gl_generator", +] + [[package]] name = "gpu-alloc" version = "0.5.2" @@ -745,6 +843,12 @@ dependencies = [ "libloading", ] +[[package]] +name = "khronos_api" +version = "3.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2db585e1d738fc771bf08a151420d3ed193d9d895a36df7f6f8a9456b911ddc" + [[package]] name = "lazy_static" version = "1.4.0" @@ -1049,6 +1153,15 @@ version = "1.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "692fcb63b64b1758029e0a96ee63e049ce8c5948587f2f7208df04625e5f6b56" +[[package]] +name = "osmesa-sys" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "88cfece6e95d2e717e0872a7f53a8684712ad13822a7979bc760b9c77ec0013b" +dependencies = [ + "shared_library", +] + [[package]] name = "parking" version = "2.0.0" @@ -1335,6 +1448,16 @@ dependencies = [ "syn", ] +[[package]] +name = "shared_library" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a9e7e0f2bfae24d8a5b5a66c5b257a83c7412304311512a0c054cd5e619da11" +dependencies = [ + "lazy_static", + "libc", +] + [[package]] name = "slab" version = "0.4.4" @@ -1575,6 +1698,16 @@ dependencies = [ "xcursor", ] +[[package]] +name = "wayland-egl" +version = "0.29.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "accf27d1e5e1f64ba30b683fd926c2c916cc1014bea3376fb258e80abf622e40" +dependencies = [ + "wayland-client", + "wayland-sys", +] + [[package]] name = "wayland-protocols" version = "0.29.1" @@ -1691,6 +1824,7 @@ dependencies = [ "foreign-types", "fxhash", "glow", + "glutin", "gpu-alloc", "gpu-descriptor", "inplace_it", diff --git a/wgpu-hal/Cargo.toml b/wgpu-hal/Cargo.toml index 7da904e01f..88e0835b63 100644 --- a/wgpu-hal/Cargo.toml +++ b/wgpu-hal/Cargo.toml @@ -19,6 +19,13 @@ gles = ["naga/glsl-out", "glow", "egl", "libloading"] dx12 = ["naga/hlsl-out", "native", "bit-set", "range-alloc", "winapi/d3d12", "winapi/d3d12shader", "winapi/d3d12sdklayers", "winapi/dxgi1_6"] renderdoc = ["libloading", "renderdoc-sys"] +[[example]] +name = "halmark" + +[[example]] +name = "raw-gles" +required-features = ["gles"] + [dependencies] bitflags = "1.0" parking_lot = "0.11" @@ -86,4 +93,5 @@ features = ["wgsl-in"] [dev-dependencies] env_logger = "0.8" -winit = "0.26" +winit = "0.26" # for "halmark" example +glutin = "0.28" # for "gles" example diff --git a/wgpu-hal/examples/halmark/main.rs b/wgpu-hal/examples/halmark/main.rs index cdaf6797f8..db999445f4 100644 --- a/wgpu-hal/examples/halmark/main.rs +++ b/wgpu-hal/examples/halmark/main.rs @@ -1,3 +1,5 @@ +//! This example shows basic usage of wgpu-hal by rendering +//! a ton of moving sprites, each with a separate texture and draw call. extern crate wgpu_hal as hal; use hal::{ diff --git a/wgpu-hal/examples/raw-gles.rs b/wgpu-hal/examples/raw-gles.rs new file mode 100644 index 0000000000..65dadbc79f --- /dev/null +++ b/wgpu-hal/examples/raw-gles.rs @@ -0,0 +1,118 @@ +//! This example shows interop with raw GLES contexts - +//! the ability to hook up wgpu-hal to an existing context and draw into it. + +extern crate wgpu_hal as hal; +use hal::{Adapter as _, CommandEncoder as _, Device as _, Queue as _}; + +fn main() { + env_logger::init(); + println!("Initializing external GL context"); + + let event_loop = glutin::event_loop::EventLoop::new(); + let window_builder = glutin::window::WindowBuilder::new(); + let gl_context = unsafe { + glutin::ContextBuilder::new() + .with_gl(glutin::GlRequest::Specific(glutin::Api::OpenGlEs, (3, 0))) + .build_windowed(window_builder, &event_loop) + .unwrap() + .make_current() + .unwrap() + }; + let inner_size = gl_context.window().inner_size(); + + println!("Hooking up to wgpu-hal"); + let exposed = unsafe { + ::Adapter::new_external(|name| { + gl_context.get_proc_address(name) + }) + } + .expect("GL adapter can't be initialized"); + let mut od = unsafe { + exposed + .adapter + .open(wgt::Features::empty(), &wgt::Limits::downlevel_defaults()) + } + .unwrap(); + + let format = wgt::TextureFormat::Rgba8UnormSrgb; + let texture = ::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() + }; + + println!("Filling the screen"); + let mut encoder = unsafe { + od.device + .create_command_encoder(&hal::CommandEncoderDescriptor { + label: None, + queue: &od.queue, + }) + .unwrap() + }; + let rp_desc = hal::RenderPassDescriptor { + label: None, + extent: wgt::Extent3d { + width: inner_size.width, + height: inner_size.height, + depth_or_array_layers: 1, + }, + sample_count: 1, + color_attachments: &[hal::ColorAttachment { + target: hal::Attachment { + view: &view, + usage: hal::TextureUses::COLOR_TARGET, + }, + resolve_target: None, + ops: hal::AttachmentOps::STORE, + clear_value: wgt::Color::BLUE, + }], + depth_stencil_attachment: None, + multiview: None, + }; + unsafe { + encoder.begin_encoding(None).unwrap(); + encoder.begin_render_pass(&rp_desc); + encoder.end_render_pass(); + let cmd_buf = encoder.end_encoding().unwrap(); + od.queue.submit(&[&cmd_buf], None).unwrap(); + } + + println!("Showing the window"); + gl_context.swap_buffers().unwrap(); + + event_loop.run(move |event, _, control_flow| { + use glutin::{ + event::{Event, KeyboardInput, VirtualKeyCode, WindowEvent}, + event_loop::ControlFlow, + }; + *control_flow = ControlFlow::Wait; + + match event { + Event::LoopDestroyed => return, + Event::WindowEvent { event, .. } => match event { + WindowEvent::CloseRequested + | WindowEvent::KeyboardInput { + input: + KeyboardInput { + virtual_keycode: Some(VirtualKeyCode::Escape), + .. + }, + .. + } => *control_flow = ControlFlow::Exit, + _ => (), + }, + _ => (), + } + }); +} diff --git a/wgpu-hal/src/gles/command.rs b/wgpu-hal/src/gles/command.rs index 645d1c952e..a2e80e0f6c 100644 --- a/wgpu-hal/src/gles/command.rs +++ b/wgpu-hal/src/gles/command.rs @@ -386,54 +386,72 @@ impl crate::CommandEncoder for super::CommandEncoder { self.state.has_pass_label = true; } - // set the framebuffer - self.cmd_buffer.commands.push(C::ResetFramebuffer); - for (i, cat) in desc.color_attachments.iter().enumerate() { - let attachment = glow::COLOR_ATTACHMENT0 + i as u32; - self.cmd_buffer.commands.push(C::BindAttachment { - attachment, - view: cat.target.view.clone(), - }); - if let Some(ref rat) = cat.resolve_target { - self.state - .resolve_attachments - .push((attachment, rat.view.clone())); + match desc + .color_attachments + .first() + .map(|at| &at.target.view.inner) + { + // default framebuffer (provided externally) + Some(&super::TextureInner::DefaultRenderbuffer) => { + self.cmd_buffer + .commands + .push(C::ResetFramebuffer { is_default: true }); } - if !cat.ops.contains(crate::AttachmentOps::STORE) { - self.state.invalidate_attachments.push(attachment); - } - } - if let Some(ref dsat) = desc.depth_stencil_attachment { - let aspects = dsat.target.view.aspects; - let attachment = match aspects { - crate::FormatAspects::DEPTH => glow::DEPTH_ATTACHMENT, - crate::FormatAspects::STENCIL => glow::STENCIL_ATTACHMENT, - _ => glow::DEPTH_STENCIL_ATTACHMENT, - }; - self.cmd_buffer.commands.push(C::BindAttachment { - attachment, - view: dsat.target.view.clone(), - }); - if aspects.contains(crate::FormatAspects::DEPTH) - && !dsat.depth_ops.contains(crate::AttachmentOps::STORE) - { - self.state - .invalidate_attachments - .push(glow::DEPTH_ATTACHMENT); - } - if aspects.contains(crate::FormatAspects::STENCIL) - && !dsat.stencil_ops.contains(crate::AttachmentOps::STORE) - { - self.state - .invalidate_attachments - .push(glow::STENCIL_ATTACHMENT); + _ => { + // set the framebuffer + self.cmd_buffer + .commands + .push(C::ResetFramebuffer { is_default: false }); + + for (i, cat) in desc.color_attachments.iter().enumerate() { + let attachment = glow::COLOR_ATTACHMENT0 + i as u32; + self.cmd_buffer.commands.push(C::BindAttachment { + attachment, + view: cat.target.view.clone(), + }); + if let Some(ref rat) = cat.resolve_target { + self.state + .resolve_attachments + .push((attachment, rat.view.clone())); + } + if !cat.ops.contains(crate::AttachmentOps::STORE) { + self.state.invalidate_attachments.push(attachment); + } + } + if let Some(ref dsat) = desc.depth_stencil_attachment { + let aspects = dsat.target.view.aspects; + let attachment = match aspects { + crate::FormatAspects::DEPTH => glow::DEPTH_ATTACHMENT, + crate::FormatAspects::STENCIL => glow::STENCIL_ATTACHMENT, + _ => glow::DEPTH_STENCIL_ATTACHMENT, + }; + self.cmd_buffer.commands.push(C::BindAttachment { + attachment, + view: dsat.target.view.clone(), + }); + if aspects.contains(crate::FormatAspects::DEPTH) + && !dsat.depth_ops.contains(crate::AttachmentOps::STORE) + { + self.state + .invalidate_attachments + .push(glow::DEPTH_ATTACHMENT); + } + if aspects.contains(crate::FormatAspects::STENCIL) + && !dsat.stencil_ops.contains(crate::AttachmentOps::STORE) + { + self.state + .invalidate_attachments + .push(glow::STENCIL_ATTACHMENT); + } + } + + // set the draw buffers and states + self.cmd_buffer + .commands + .push(C::SetDrawColorBuffers(desc.color_attachments.len() as u8)); } } - // set the draw buffers and states - self.cmd_buffer - .commands - .push(C::SetDrawColorBuffers(desc.color_attachments.len() as u8)); let rect = crate::Rect { x: 0, y: 0, diff --git a/wgpu-hal/src/gles/device.rs b/wgpu-hal/src/gles/device.rs index 00b7f3cdf8..a85301fa2c 100644 --- a/wgpu-hal/src/gles/device.rs +++ b/wgpu-hal/src/gles/device.rs @@ -656,6 +656,7 @@ impl crate::Device for super::Device { super::TextureInner::Renderbuffer { raw, .. } => { gl.delete_renderbuffer(raw); } + super::TextureInner::DefaultRenderbuffer => {} super::TextureInner::Texture { raw, .. } => { gl.delete_texture(raw); } @@ -889,14 +890,8 @@ impl crate::Device for super::Device { log::error!("Unable to create a sampled texture binding for non-zero mipmap level or array layer.\n{}", "This is an implementation problem of wgpu-hal/gles backend.") } - match view.inner { - super::TextureInner::Renderbuffer { .. } => { - panic!("Unable to use a renderbuffer in a group") - } - super::TextureInner::Texture { raw, target } => { - super::RawBinding::Texture { raw, target } - } - } + let (raw, target) = view.inner.as_native(); + super::RawBinding::Texture { raw, target } } wgt::BindingType::StorageTexture { access, @@ -905,24 +900,18 @@ impl crate::Device for super::Device { } => { let view = desc.textures[entry.resource_index as usize].view; let format_desc = self.shared.describe_texture_format(format); - match view.inner { - super::TextureInner::Renderbuffer { .. } => { - panic!("Unable to use a renderbuffer in a group") - } - super::TextureInner::Texture { raw, .. } => { - super::RawBinding::Image(super::ImageBinding { - raw, - mip_level: view.mip_levels.start, - array_layer: match view_dimension { - wgt::TextureViewDimension::D2Array - | wgt::TextureViewDimension::CubeArray => None, - _ => Some(view.array_layers.start), - }, - access: conv::map_storage_access(access), - format: format_desc.internal, - }) - } - } + let (raw, _target) = view.inner.as_native(); + super::RawBinding::Image(super::ImageBinding { + raw, + mip_level: view.mip_levels.start, + array_layer: match view_dimension { + wgt::TextureViewDimension::D2Array + | wgt::TextureViewDimension::CubeArray => None, + _ => Some(view.array_layers.start), + }, + access: conv::map_storage_access(access), + format: format_desc.internal, + }) } }; contents.push(binding); @@ -1133,11 +1122,10 @@ impl crate::Device for super::Device { unsafe fn start_capture(&self) -> bool { #[cfg(feature = "renderdoc")] - { - self.render_doc - .start_frame_capture(self.shared.context.egl_context.as_ptr(), ptr::null_mut()) - } - #[cfg(not(feature = "renderdoc"))] + return self + .render_doc + .start_frame_capture(self.shared.context.raw_context(), ptr::null_mut()); + #[allow(unreachable_code)] false } unsafe fn stop_capture(&self) { diff --git a/wgpu-hal/src/gles/egl.rs b/wgpu-hal/src/gles/egl.rs index f1c7695355..6b18339da4 100644 --- a/wgpu-hal/src/gles/egl.rs +++ b/wgpu-hal/src/gles/egl.rs @@ -2,7 +2,7 @@ use glow::HasContext; use parking_lot::{Mutex, MutexGuard}; use raw_window_handle::{HasRawWindowHandle, RawWindowHandle}; -use std::{ffi::CStr, os::raw, ptr, sync::Arc, time::Duration}; +use std::{ffi, os::raw, ptr, sync::Arc, time::Duration}; /// The amount of time to wait while trying to obtain a lock to the adapter context const CONTEXT_LOCK_TIMEOUT_SECS: u64 = 1; @@ -88,11 +88,11 @@ unsafe extern "system" fn egl_debug_proc( EGL_DEBUG_MSG_INFO_KHR => log::Level::Info, _ => log::Level::Debug, }; - let command = CStr::from_ptr(command_raw).to_string_lossy(); + let command = ffi::CStr::from_ptr(command_raw).to_string_lossy(); let message = if message_raw.is_null() { "".into() } else { - CStr::from_ptr(message_raw).to_string_lossy() + ffi::CStr::from_ptr(message_raw).to_string_lossy() }; log::log!( @@ -261,40 +261,73 @@ fn gl_debug_message_callback(source: u32, gltype: u32, id: u32, severity: u32, m } } +#[derive(Clone, Debug)] +struct EglContext { + instance: Arc>, + display: egl::Display, + raw: egl::Context, + pbuffer: Option, +} + +impl EglContext { + fn make_current(&self) { + self.instance + .make_current(self.display, self.pbuffer, self.pbuffer, Some(self.raw)) + .unwrap(); + } + fn unmake_current(&self) { + self.instance + .make_current(self.display, None, None, None) + .unwrap(); + } +} + /// A wrapper around a [`glow::Context`] and the required EGL context that uses locking to guarantee /// exclusive access when shared with multiple threads. pub struct AdapterContext { - glow_context: Mutex, - egl: Arc>, - egl_display: egl::Display, - pub(super) egl_context: egl::Context, - egl_pbuffer: Option, + glow: Mutex, + egl: Option, } unsafe impl Sync for AdapterContext {} unsafe impl Send for AdapterContext {} +impl AdapterContext { + #[cfg(feature = "renderdoc")] + pub fn raw_context(&self) -> *mut raw::c_void { + match self.egl { + Some(ref egl) => egl.raw.as_ptr(), + None => ptr::null_mut(), + } + } +} + +struct EglContextLock<'a> { + instance: &'a Arc>, + display: egl::Display, +} + /// A guard containing a lock to an [`AdapterContext`] pub struct AdapterContextLock<'a> { - glow_context: MutexGuard<'a, glow::Context>, - egl: &'a Arc>, - egl_display: egl::Display, + glow: MutexGuard<'a, glow::Context>, + egl: Option>, } impl<'a> std::ops::Deref for AdapterContextLock<'a> { type Target = glow::Context; fn deref(&self) -> &Self::Target { - &self.glow_context + &self.glow } } impl<'a> Drop for AdapterContextLock<'a> { fn drop(&mut self) { - // Make the EGL context *not* current on this thread - self.egl - .make_current(self.egl_display, None, None, None) - .expect("Cannot make EGL context not current"); + if let Some(egl) = self.egl.take() { + egl.instance + .make_current(egl.display, None, None, None) + .unwrap(); + } } } @@ -311,7 +344,7 @@ impl AdapterContext { /// > **Note:** Calling this function **will** still lock the [`glow::Context`] which adds an /// > extra safe-guard against accidental concurrent access to the context. pub unsafe fn get_without_egl_lock(&self) -> MutexGuard { - self.glow_context + self.glow .try_lock_for(Duration::from_secs(CONTEXT_LOCK_TIMEOUT_SECS)) .expect("Could not lock adapter context. This is most-likely a deadlcok.") } @@ -320,43 +353,34 @@ impl AdapterContext { /// do rendering. #[track_caller] pub fn lock<'a>(&'a self) -> AdapterContextLock<'a> { - let glow_context = self - .glow_context + let glow = self + .glow // Don't lock forever. If it takes longer than 1 second to get the lock we've got a // deadlock and should panic to show where we got stuck .try_lock_for(Duration::from_secs(CONTEXT_LOCK_TIMEOUT_SECS)) .expect("Could not lock adapter context. This is most-likely a deadlcok."); - // Make the EGL context current on this thread - self.egl - .make_current( - self.egl_display, - self.egl_pbuffer, - self.egl_pbuffer, - Some(self.egl_context), - ) - .expect("Cannot make EGL context current"); + let egl = self.egl.as_ref().map(|egl| { + egl.make_current(); + EglContextLock { + instance: &egl.instance, + display: egl.display, + } + }); - AdapterContextLock { - glow_context, - egl: &self.egl, - egl_display: self.egl_display, - } + AdapterContextLock { glow, egl } } } #[derive(Debug)] struct Inner { - egl: Arc>, + /// Note: the context contains a dummy pbuffer (1x1). + /// Required for `eglMakeCurrent` on platforms that doesn't supports `EGL_KHR_surfaceless_context`. + egl: EglContext, #[allow(unused)] version: (i32, i32), supports_native_window: bool, - display: egl::Display, config: egl::Config, - context: egl::Context, - /// Dummy pbuffer (1x1). - /// Required for `eglMakeCurrent` on platforms that doesn't supports `EGL_KHR_surfaceless_context`. - pbuffer: Option, wl_display: Option<*mut raw::c_void>, /// Method by which the framebuffer should support srgb srgb_kind: SrgbFrameBufferKind, @@ -481,13 +505,15 @@ impl Inner { }; Ok(Self { - egl, - display, + egl: EglContext { + instance: egl, + display, + raw: context, + pbuffer, + }, version, supports_native_window, config, - context, - pbuffer, wl_display: None, srgb_kind, }) @@ -496,10 +522,14 @@ impl Inner { impl Drop for Inner { fn drop(&mut self) { - if let Err(e) = self.egl.destroy_context(self.display, self.context) { + if let Err(e) = self + .egl + .instance + .destroy_context(self.egl.display, self.egl.raw) + { log::warn!("Error in destroy_context: {:?}", e); } - if let Err(e) = self.egl.terminate(self.display) { + if let Err(e) = self.egl.instance.terminate(self.egl.display) { log::warn!("Error in terminate: {:?}", e); } } @@ -676,7 +706,8 @@ impl crate::Instance for Instance { Rwh::AndroidNdk(handle) => { let format = inner .egl - .get_config_attrib(inner.display, inner.config, egl::NATIVE_VISUAL_ID) + .instance + .get_config_attrib(inner.egl.display, inner.config, egl::NATIVE_VISUAL_ID) .unwrap(); let ret = ANativeWindow_setBuffersGeometry(handle.a_native_window, 0, 0, format); @@ -703,6 +734,7 @@ impl crate::Instance for Instance { let display_attributes = [egl::ATTRIB_NONE]; let display = inner .egl + .instance .upcast::() .unwrap() .get_platform_display( @@ -712,8 +744,9 @@ impl crate::Instance for Instance { ) .unwrap(); - let new_inner = Inner::create(self.flags, inner.egl.clone(), display) - .map_err(|_| crate::InstanceError)?; + let new_inner = + Inner::create(self.flags, Arc::clone(&inner.egl.instance), display) + .map_err(|_| crate::InstanceError)?; let old_inner = std::mem::replace(inner.deref_mut(), new_inner); inner.wl_display = Some(handle.display); @@ -726,19 +759,13 @@ impl crate::Instance for Instance { } }; - inner - .egl - .make_current(inner.display, None, None, None) - .unwrap(); + inner.egl.unmake_current(); Ok(Surface { - egl: Arc::clone(&inner.egl), + egl: inner.egl.clone(), wsi: self.wsi.clone(), config: inner.config, - display: inner.display, - context: inner.context, presentable: inner.supports_native_window, - pbuffer: inner.pbuffer, raw_window_handle, swapchain: None, srgb_kind: inner.srgb_kind, @@ -748,19 +775,12 @@ impl crate::Instance for Instance { unsafe fn enumerate_adapters(&self) -> Vec> { let inner = self.inner.lock(); - inner - .egl - .make_current( - inner.display, - inner.pbuffer, - inner.pbuffer, - Some(inner.context), - ) - .unwrap(); + inner.egl.make_current(); let gl = glow::Context::from_loader_function(|name| { inner .egl + .instance .get_proc_address(name) .map_or(ptr::null(), |p| p as *const _) }); @@ -778,23 +798,28 @@ impl crate::Instance for Instance { gl.debug_message_callback(gl_debug_message_callback); } - inner - .egl - .make_current(inner.display, None, None, None) - .unwrap(); + inner.egl.unmake_current(); super::Adapter::expose(AdapterContext { - glow_context: Mutex::new(gl), - egl: inner.egl.clone(), - egl_display: inner.display, - egl_context: inner.context, - egl_pbuffer: inner.pbuffer, + glow: Mutex::new(gl), + egl: Some(inner.egl.clone()), }) .into_iter() .collect() } } +impl super::Adapter { + pub unsafe fn new_external( + fun: impl FnMut(&str) -> *const ffi::c_void, + ) -> Option> { + Self::expose(AdapterContext { + glow: Mutex::new(glow::Context::from_loader_function(fun)), + egl: None, + }) + } +} + #[derive(Debug)] pub struct Swapchain { surface: egl::Surface, @@ -811,13 +836,9 @@ pub struct Swapchain { #[derive(Debug)] pub struct Surface { - egl: Arc>, + egl: EglContext, wsi: WindowSystemInterface, config: egl::Config, - display: egl::Display, - context: egl::Context, - #[allow(unused)] - pbuffer: Option, pub(super) presentable: bool, raw_window_handle: RawWindowHandle, swapchain: Option, @@ -836,11 +857,12 @@ impl Surface { let sc = self.swapchain.as_ref().unwrap(); self.egl + .instance .make_current( - self.display, + self.egl.display, Some(sc.surface), Some(sc.surface), - Some(self.context), + Some(self.egl.raw), ) .map_err(|e| { log::error!("make_current(surface) failed: {}", e); @@ -870,13 +892,15 @@ impl Surface { gl.bind_framebuffer(glow::READ_FRAMEBUFFER, None); self.egl - .swap_buffers(self.display, sc.surface) + .instance + .swap_buffers(self.egl.display, sc.surface) .map_err(|e| { log::error!("swap_buffers failed: {}", e); crate::SurfaceError::Lost })?; self.egl - .make_current(self.display, None, None, None) + .instance + .make_current(self.egl.display, None, None, None) .map_err(|e| { log::error!("make_current(null) failed: {}", e); crate::SurfaceError::Lost @@ -987,21 +1011,21 @@ impl crate::Surface for Surface { attributes.push(egl::ATTRIB_NONE as i32); // Careful, we can still be in 1.4 version even if `upcast` succeeds - let raw_result = match self.egl.upcast::() { + let raw_result = match self.egl.instance.upcast::() { Some(egl) if self.wsi.kind != WindowKind::Unknown => { let attributes_usize = attributes .into_iter() .map(|v| v as usize) .collect::>(); egl.create_platform_window_surface( - self.display, + self.egl.display, self.config, native_window_ptr, &attributes_usize, ) } - _ => self.egl.create_window_surface( - self.display, + _ => self.egl.instance.create_window_surface( + self.egl.display, self.config, native_window_ptr, Some(&attributes), @@ -1068,7 +1092,10 @@ impl crate::Surface for Surface { unsafe fn unconfigure(&mut self, device: &super::Device) { if let Some((surface, wl_window)) = self.unconfigure_impl(device) { - self.egl.destroy_surface(self.display, surface).unwrap(); + self.egl + .instance + .destroy_surface(self.egl.display, surface) + .unwrap(); if let Some(window) = wl_window { let wl_egl_window_destroy: libloading::Symbol = self .wsi diff --git a/wgpu-hal/src/gles/mod.rs b/wgpu-hal/src/gles/mod.rs index 1d59b7f743..d5e1980b21 100644 --- a/wgpu-hal/src/gles/mod.rs +++ b/wgpu-hal/src/gles/mod.rs @@ -230,6 +230,7 @@ enum TextureInner { Renderbuffer { raw: glow::Renderbuffer, }, + DefaultRenderbuffer, Texture { raw: glow::Texture, target: BindTarget, @@ -239,7 +240,7 @@ enum TextureInner { impl TextureInner { fn as_native(&self) -> (glow::Texture, BindTarget) { match *self { - Self::Renderbuffer { .. } => { + Self::Renderbuffer { .. } | Self::DefaultRenderbuffer => { panic!("Unexpected renderbuffer"); } Self::Texture { raw, target } => (raw, target), @@ -258,6 +259,27 @@ pub struct Texture { copy_size: crate::CopyExtent, } +impl Texture { + pub fn default_framebuffer(format: wgt::TextureFormat) -> Self { + Self { + inner: TextureInner::DefaultRenderbuffer, + mip_level_count: 1, + array_layer_count: 1, + format, + format_desc: TextureFormatDesc { + internal: 0, + external: 0, + data_type: 0, + }, + copy_size: crate::CopyExtent { + width: 0, + height: 0, + depth: 0, + }, + } + } +} + #[derive(Clone, Debug)] pub struct TextureView { inner: TextureInner, @@ -612,7 +634,9 @@ enum Command { dst_target: BindTarget, dst_offset: wgt::BufferAddress, }, - ResetFramebuffer, + ResetFramebuffer { + is_default: bool, + }, BindAttachment { attachment: u32, view: TextureView, diff --git a/wgpu-hal/src/gles/queue.rs b/wgpu-hal/src/gles/queue.rs index 91631f4913..18e1439943 100644 --- a/wgpu-hal/src/gles/queue.rs +++ b/wgpu-hal/src/gles/queue.rs @@ -82,6 +82,7 @@ impl super::Queue { super::TextureInner::Renderbuffer { raw } => { gl.framebuffer_renderbuffer(fbo_target, attachment, glow::RENDERBUFFER, Some(raw)); } + super::TextureInner::DefaultRenderbuffer => panic!("Unexpected default RBO"), super::TextureInner::Texture { raw, target } => { if is_layered_target(target) { gl.framebuffer_texture_layer( @@ -636,24 +637,28 @@ impl super::Queue { } } } - C::ResetFramebuffer => { - gl.bind_framebuffer(glow::DRAW_FRAMEBUFFER, Some(self.draw_fbo)); - gl.framebuffer_texture_2d( - glow::DRAW_FRAMEBUFFER, - glow::DEPTH_STENCIL_ATTACHMENT, - glow::TEXTURE_2D, - None, - 0, - ); - for i in 0..crate::MAX_COLOR_TARGETS { - let target = glow::COLOR_ATTACHMENT0 + i as u32; + C::ResetFramebuffer { is_default } => { + if is_default { + gl.bind_framebuffer(glow::DRAW_FRAMEBUFFER, None); + } else { + gl.bind_framebuffer(glow::DRAW_FRAMEBUFFER, Some(self.draw_fbo)); gl.framebuffer_texture_2d( glow::DRAW_FRAMEBUFFER, - target, + glow::DEPTH_STENCIL_ATTACHMENT, glow::TEXTURE_2D, None, 0, ); + for i in 0..crate::MAX_COLOR_TARGETS { + let target = glow::COLOR_ATTACHMENT0 + i as u32; + gl.framebuffer_texture_2d( + glow::DRAW_FRAMEBUFFER, + target, + glow::TEXTURE_2D, + None, + 0, + ); + } } gl.color_mask(true, true, true, true); gl.depth_mask(true);