diff --git a/CHANGELOG.md b/CHANGELOG.md index 7d46d70179..3125569c92 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -134,6 +134,7 @@ both `raw_window_handle::HasRawWindowHandle` and `raw_window_handle::HasRawDispl - Split Blendability and Filterability into Two Different TextureFormatFeatureFlags; by @stakka in [#3012](https://github.com/gfx-rs/wgpu/pull/3012) - Expose `alpha_mode` on SurfaceConfiguration, by @jinleili in [#2836](https://github.com/gfx-rs/wgpu/pull/2836) - Introduce fields for driver name and info in `AdapterInfo`, by @i509VCB in [#3037](https://github.com/gfx-rs/wgpu/pull/3037) +- Add way to create gles hal textures from raw gl names to allow externally managed textures. By @i509VCB [#3046](https://github.com/gfx-rs/wgpu/pull/3046) - Implemented `copy_external_image_to_texture` on WebGPU, by @ybiletskyi in [#2781](https://github.com/gfx-rs/wgpu/pull/2781) ### Bug Fixes @@ -202,6 +203,7 @@ both `raw_window_handle::HasRawWindowHandle` and `raw_window_handle::HasRawDispl - Provide a means for `wgpu` users to access `vk::Queue` and the queue index. By @anlumo in [#2950](https://github.com/gfx-rs/wgpu/pull/2950) - Use the use effective api version for determining device features instead of wrongly assuming `VkPhysicalDeviceProperties.apiVersion` is the actual version of the device. By @i509VCB in [#3011](https://github.com/gfx-rs/wgpu/pull/3011) +- `DropGuard` has been moved to the root of the wgpu-hal crate. By @i509VCB [#3046](https://github.com/gfx-rs/wgpu/pull/3046) #### GLES diff --git a/Cargo.lock b/Cargo.lock index ad7cf41b37..a95cefa901 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -743,8 +743,7 @@ checksum = "518faa5064866338b013ff9b2350dc318e14cc4fcd6cb8206d7e7c9886c98815" [[package]] name = "glow" version = "0.11.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d8bd5877156a19b8ac83a29b2306fe20537429d318f3ff0a1a2119f8d9c61919" +source = "git+https://github.com/grovesNL/glow/?rev=c8a011fcd57a5c68cc917ed394baa484bdefc909#c8a011fcd57a5c68cc917ed394baa484bdefc909" dependencies = [ "js-sys", "slotmap", diff --git a/wgpu-hal/Cargo.toml b/wgpu-hal/Cargo.toml index c7c5a76bb5..b68d30f13e 100644 --- a/wgpu-hal/Cargo.toml +++ b/wgpu-hal/Cargo.toml @@ -54,7 +54,9 @@ gpu-descriptor = { version = "0.2", optional = true } smallvec = { version = "1", optional = true, features = ["union"] } # backend: Gles -glow = { version = "0.11.1", optional = true } +#glow = { version = "0.11.2", optional = true } +# TODO: New glow release +glow = { git = "https://github.com/grovesNL/glow/", rev = "c8a011fcd57a5c68cc917ed394baa484bdefc909", optional = true } # backend: Dx12 bit-set = { version = "0.5", optional = true } diff --git a/wgpu-hal/src/auxil/mod.rs b/wgpu-hal/src/auxil/mod.rs index cd2bedfbbc..b496692bea 100644 --- a/wgpu-hal/src/auxil/mod.rs +++ b/wgpu-hal/src/auxil/mod.rs @@ -66,6 +66,17 @@ pub fn align_to(value: u32, alignment: u32) -> u32 { } impl crate::CopyExtent { + pub fn map_extent_to_copy_size(extent: &wgt::Extent3d, dim: wgt::TextureDimension) -> Self { + Self { + width: extent.width, + height: extent.height, + depth: match dim { + wgt::TextureDimension::D1 | wgt::TextureDimension::D2 => 1, + wgt::TextureDimension::D3 => extent.depth_or_array_layers, + }, + } + } + pub fn min(&self, other: &Self) -> Self { Self { width: self.width.min(other.width), diff --git a/wgpu-hal/src/gles/device.rs b/wgpu-hal/src/gles/device.rs index 04ecdffe02..6756d1884c 100644 --- a/wgpu-hal/src/gles/device.rs +++ b/wgpu-hal/src/gles/device.rs @@ -84,6 +84,77 @@ impl CompilationContext<'_> { } impl super::Device { + /// # Safety + /// + /// - `name` must be created respecting `desc` + /// - `name` must be a texture + /// - If `drop_guard` is [`None`], wgpu-hal will take ownership of the texture. If `drop_guard` is + /// [`Some`], the texture must be valid until the drop implementation + /// of the drop guard is called. + #[cfg(any(not(target_arch = "wasm32"), feature = "emscripten"))] + pub unsafe fn texture_from_raw( + &self, + name: std::num::NonZeroU32, + desc: &crate::TextureDescriptor, + drop_guard: Option, + ) -> super::Texture { + let mut copy_size = crate::CopyExtent::map_extent_to_copy_size(&desc.size, desc.dimension); + + let (target, _, is_cubemap) = super::Texture::get_info_from_desc(&mut copy_size, desc); + + super::Texture { + inner: super::TextureInner::Texture { + raw: glow::NativeTexture(name), + target, + }, + drop_guard, + mip_level_count: desc.mip_level_count, + array_layer_count: if desc.dimension == wgt::TextureDimension::D2 { + desc.size.depth_or_array_layers + } else { + 1 + }, + format: desc.format, + format_desc: self.shared.describe_texture_format(desc.format), + copy_size, + is_cubemap, + } + } + + /// # Safety + /// + /// - `name` must be created respecting `desc` + /// - `name` must be a renderbuffer + /// - If `drop_guard` is [`None`], wgpu-hal will take ownership of the renderbuffer. If `drop_guard` is + /// [`Some`], the renderbuffer must be valid until the drop implementation + /// of the drop guard is called. + #[cfg(any(not(target_arch = "wasm32"), feature = "emscripten"))] + pub unsafe fn texture_from_raw_renderbuffer( + &self, + name: std::num::NonZeroU32, + desc: &crate::TextureDescriptor, + drop_guard: Option, + ) -> super::Texture { + let copy_size = crate::CopyExtent::map_extent_to_copy_size(&desc.size, desc.dimension); + + super::Texture { + inner: super::TextureInner::Renderbuffer { + raw: glow::NativeRenderbuffer(name), + }, + drop_guard, + mip_level_count: desc.mip_level_count, + array_layer_count: if desc.dimension == wgt::TextureDimension::D2 { + desc.size.depth_or_array_layers + } else { + 1 + }, + format: desc.format, + format_desc: self.shared.describe_texture_format(desc.format), + copy_size, + is_cubemap: false, + } + } + unsafe fn compile_shader( gl: &glow::Context, shader: &str, @@ -581,32 +652,8 @@ impl crate::Device for super::Device { (super::TextureInner::Renderbuffer { raw }, false) } else { let raw = gl.create_texture().unwrap(); - let (target, is_3d, is_cubemap) = match desc.dimension { - wgt::TextureDimension::D1 | wgt::TextureDimension::D2 => { - if desc.size.depth_or_array_layers > 1 { - //HACK: detect a cube map - let cube_count = if desc.size.width == desc.size.height - && desc.size.depth_or_array_layers % 6 == 0 - && desc.sample_count == 1 - { - Some(desc.size.depth_or_array_layers / 6) - } else { - None - }; - match cube_count { - None => (glow::TEXTURE_2D_ARRAY, true, false), - Some(1) => (glow::TEXTURE_CUBE_MAP, false, true), - Some(_) => (glow::TEXTURE_CUBE_MAP_ARRAY, true, true), - } - } else { - (glow::TEXTURE_2D, false, false) - } - } - wgt::TextureDimension::D3 => { - copy_size.depth = desc.size.depth_or_array_layers; - (glow::TEXTURE_3D, true, false) - } - }; + let (target, is_3d, is_cubemap) = + super::Texture::get_info_from_desc(&mut copy_size, desc); gl.bind_texture(target, Some(raw)); //Note: this has to be done before defining the storage! @@ -663,6 +710,7 @@ impl crate::Device for super::Device { Ok(super::Texture { inner, + drop_guard: None, mip_level_count: desc.mip_level_count, array_layer_count: if desc.dimension == wgt::TextureDimension::D2 { desc.size.depth_or_array_layers @@ -676,16 +724,22 @@ impl crate::Device for super::Device { }) } unsafe fn destroy_texture(&self, texture: super::Texture) { - let gl = &self.shared.context.lock(); - match texture.inner { - super::TextureInner::Renderbuffer { raw, .. } => { - gl.delete_renderbuffer(raw); - } - super::TextureInner::DefaultRenderbuffer => {} - super::TextureInner::Texture { raw, .. } => { - gl.delete_texture(raw); + if texture.drop_guard.is_none() { + let gl = &self.shared.context.lock(); + match texture.inner { + super::TextureInner::Renderbuffer { raw, .. } => { + gl.delete_renderbuffer(raw); + } + super::TextureInner::DefaultRenderbuffer => {} + super::TextureInner::Texture { raw, .. } => { + gl.delete_texture(raw); + } } } + + // For clarity, we explicitly drop the drop guard. Although this has no real semantic effect as the + // end of the scope will drop the drop guard since this function takes ownership of the texture. + drop(texture.drop_guard); } unsafe fn create_texture_view( diff --git a/wgpu-hal/src/gles/egl.rs b/wgpu-hal/src/gles/egl.rs index 32264276c6..1f4cae00a1 100644 --- a/wgpu-hal/src/gles/egl.rs +++ b/wgpu-hal/src/gles/egl.rs @@ -1241,6 +1241,7 @@ impl crate::Surface for Surface { inner: super::TextureInner::Renderbuffer { raw: sc.renderbuffer, }, + drop_guard: None, array_layer_count: 1, mip_level_count: 1, format: sc.format, diff --git a/wgpu-hal/src/gles/mod.rs b/wgpu-hal/src/gles/mod.rs index 37582cafc7..929f369833 100644 --- a/wgpu-hal/src/gles/mod.rs +++ b/wgpu-hal/src/gles/mod.rs @@ -68,6 +68,8 @@ mod conv; mod device; mod queue; +use crate::{CopyExtent, TextureDescriptor}; + #[cfg(any(not(target_arch = "wasm32"), feature = "emscripten"))] pub use self::egl::{AdapterContext, AdapterContextLock}; #[cfg(any(not(target_arch = "wasm32"), feature = "emscripten"))] @@ -265,12 +267,13 @@ impl TextureInner { #[derive(Debug)] pub struct Texture { inner: TextureInner, + drop_guard: Option, mip_level_count: u32, array_layer_count: u32, format: wgt::TextureFormat, #[allow(unused)] format_desc: TextureFormatDesc, - copy_size: crate::CopyExtent, + copy_size: CopyExtent, is_cubemap: bool, } @@ -278,6 +281,7 @@ impl Texture { pub fn default_framebuffer(format: wgt::TextureFormat) -> Self { Self { inner: TextureInner::DefaultRenderbuffer, + drop_guard: None, mip_level_count: 1, array_layer_count: 1, format, @@ -286,7 +290,7 @@ impl Texture { external: 0, data_type: 0, }, - copy_size: crate::CopyExtent { + copy_size: CopyExtent { width: 0, height: 0, depth: 0, @@ -294,6 +298,39 @@ impl Texture { is_cubemap: false, } } + + /// Returns the `target`, whether the image is 3d and whether the image is a cubemap. + fn get_info_from_desc( + copy_size: &mut CopyExtent, + desc: &TextureDescriptor, + ) -> (u32, bool, bool) { + match desc.dimension { + wgt::TextureDimension::D1 | wgt::TextureDimension::D2 => { + if desc.size.depth_or_array_layers > 1 { + //HACK: detect a cube map + let cube_count = if desc.size.width == desc.size.height + && desc.size.depth_or_array_layers % 6 == 0 + && desc.sample_count == 1 + { + Some(desc.size.depth_or_array_layers / 6) + } else { + None + }; + match cube_count { + None => (glow::TEXTURE_2D_ARRAY, true, false), + Some(1) => (glow::TEXTURE_CUBE_MAP, false, true), + Some(_) => (glow::TEXTURE_CUBE_MAP_ARRAY, true, true), + } + } else { + (glow::TEXTURE_2D, false, false) + } + } + wgt::TextureDimension::D3 => { + copy_size.depth = desc.size.depth_or_array_layers; + (glow::TEXTURE_3D, true, false) + } + } + } } #[derive(Clone, Debug)] diff --git a/wgpu-hal/src/gles/web.rs b/wgpu-hal/src/gles/web.rs index 648fd70877..e2f9df0e26 100644 --- a/wgpu-hal/src/gles/web.rs +++ b/wgpu-hal/src/gles/web.rs @@ -327,6 +327,7 @@ impl crate::Surface for Surface { raw: self.texture.unwrap(), target: glow::TEXTURE_2D, }, + drop_guard: None, array_layer_count: 1, mip_level_count: 1, format: sc.format, diff --git a/wgpu-hal/src/lib.rs b/wgpu-hal/src/lib.rs index e8531643d5..02fa246431 100644 --- a/wgpu-hal/src/lib.rs +++ b/wgpu-hal/src/lib.rs @@ -106,7 +106,10 @@ pub type Label<'a> = Option<&'a str>; pub type MemoryRange = Range; pub type FenceValue = u64; -#[derive(Clone, Debug, Eq, PartialEq, Error)] +/// Drop guard to signal wgpu-hal is no longer using an externally created object. +pub type DropGuard = Box; + +#[derive(Clone, Debug, PartialEq, Eq, Error)] pub enum DeviceError { #[error("out of memory")] OutOfMemory, diff --git a/wgpu-hal/src/vulkan/device.rs b/wgpu-hal/src/vulkan/device.rs index 41b5e00284..65d5c70e24 100644 --- a/wgpu-hal/src/vulkan/device.rs +++ b/wgpu-hal/src/vulkan/device.rs @@ -609,7 +609,7 @@ impl super::Device { pub unsafe fn texture_from_raw( vk_image: vk::Image, desc: &crate::TextureDescriptor, - drop_guard: Option, + drop_guard: Option, ) -> super::Texture { super::Texture { raw: vk_image, @@ -619,7 +619,7 @@ impl super::Device { aspects: crate::FormatAspects::from(desc.format), format_info: desc.format.describe(), raw_flags: vk::ImageCreateFlags::empty(), - copy_size: conv::map_extent_to_copy_size(&desc.size, desc.dimension), + copy_size: crate::CopyExtent::map_extent_to_copy_size(&desc.size, desc.dimension), } } diff --git a/wgpu-hal/src/vulkan/instance.rs b/wgpu-hal/src/vulkan/instance.rs index bb566c178c..19d7684eb2 100644 --- a/wgpu-hal/src/vulkan/instance.rs +++ b/wgpu-hal/src/vulkan/instance.rs @@ -229,7 +229,7 @@ impl super::Instance { extensions: Vec<&'static CStr>, flags: crate::InstanceFlags, has_nv_optimus: bool, - drop_guard: Option, + drop_guard: Option, ) -> Result { log::info!("Instance version: 0x{:x}", driver_api_version); diff --git a/wgpu-hal/src/vulkan/mod.rs b/wgpu-hal/src/vulkan/mod.rs index 8fbc520ea5..fd1266de37 100644 --- a/wgpu-hal/src/vulkan/mod.rs +++ b/wgpu-hal/src/vulkan/mod.rs @@ -43,8 +43,6 @@ use parking_lot::Mutex; const MILLIS_TO_NANOS: u64 = 1_000_000; const MAX_TOTAL_ATTACHMENTS: usize = crate::MAX_COLOR_ATTACHMENTS * 2 + 1; -pub type DropGuard = Box; - #[derive(Clone)] pub struct Api; @@ -82,7 +80,7 @@ struct DebugUtils { pub struct InstanceShared { raw: ash::Instance, extensions: Vec<&'static CStr>, - drop_guard: Option, + drop_guard: Option, flags: crate::InstanceFlags, debug_utils: Option, get_physical_device_properties: Option, @@ -347,7 +345,7 @@ pub struct Buffer { #[derive(Debug)] pub struct Texture { raw: vk::Image, - drop_guard: Option, + drop_guard: Option, block: Option>, usage: crate::TextureUses, aspects: crate::FormatAspects,