From 0360e60c11f7c4e924999c86e5cd7d3dee17bb0a Mon Sep 17 00:00:00 2001 From: i509VCB Date: Thu, 22 Sep 2022 21:57:30 -0500 Subject: [PATCH 1/2] allow creation of wgpu_hal textures for gles backend This should be enough to allow RGB external textures to work on Linux. For Android, we still need to implement logic to generate shaders with samplerOESExternal and select the correct shader depending on the type of texture being created. --- CHANGELOG.md | 2 + Cargo.lock | 10 +-- wgpu-hal/Cargo.toml | 4 +- wgpu-hal/src/auxil/mod.rs | 11 +++ wgpu-hal/src/gles/device.rs | 125 +++++++++++++++++++++++--------- wgpu-hal/src/gles/egl.rs | 1 + wgpu-hal/src/gles/mod.rs | 41 ++++++++++- wgpu-hal/src/gles/web.rs | 1 + wgpu-hal/src/lib.rs | 5 +- wgpu-hal/src/vulkan/device.rs | 4 +- wgpu-hal/src/vulkan/instance.rs | 2 +- wgpu-hal/src/vulkan/mod.rs | 6 +- 12 files changed, 158 insertions(+), 54 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6fd4e5348e..bb6b6f2f86 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -75,6 +75,7 @@ SurfaceConfiguration { - 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) ### Bug Fixes @@ -126,6 +127,7 @@ SurfaceConfiguration { - 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) ### Performance diff --git a/Cargo.lock b/Cargo.lock index 5e2ac814c2..8401afea73 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -337,12 +337,6 @@ dependencies = [ "web-sys", ] -[[package]] -name = "copyless" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a2df960f5d869b2dd8532793fde43eb5427cceb126c929747a26823ab0eeb536" - [[package]] name = "core-foundation" version = "0.9.3" @@ -754,8 +748,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", @@ -2249,7 +2242,6 @@ dependencies = [ "bitflags", "cfg_aliases", "codespan-reporting", - "copyless", "fxhash", "log", "naga", diff --git a/wgpu-hal/Cargo.toml b/wgpu-hal/Cargo.toml index a8cfe5e4a4..f564b22615 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 d8675ac0d0..8d29021726 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..2a9d16e242 100644 --- a/wgpu-hal/src/gles/device.rs +++ b/wgpu-hal/src/gles/device.rs @@ -10,6 +10,9 @@ use std::{ #[cfg(not(target_arch = "wasm32"))] use std::mem; +#[cfg(any(not(target_arch = "wasm32"), feature = "emscripten"))] +use std::num::NonZeroU32; + type ShaderStage<'a> = ( naga::ShaderStage, &'a crate::ProgrammableStage<'a, super::Api>, @@ -84,6 +87,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: 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: 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 +655,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 +713,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 +727,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 717502f2c6..0017552db1 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 396fdad04b..6acc6288c4 100644 --- a/wgpu-hal/src/gles/web.rs +++ b/wgpu-hal/src/gles/web.rs @@ -295,6 +295,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 cbaf803d9a..a77b02ac67 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 b9d74e36e3..8f6b9c16b0 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 79045ff061..43fd649ca2 100644 --- a/wgpu-hal/src/vulkan/instance.rs +++ b/wgpu-hal/src/vulkan/instance.rs @@ -230,7 +230,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 d3416a50ed..bb139c78d2 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, From b5f78a261a232538e049766d6f2b73ce9702b6aa Mon Sep 17 00:00:00 2001 From: i509VCB Date: Thu, 13 Oct 2022 01:19:46 -0500 Subject: [PATCH 2/2] Name NonZeroU32 explicitly --- wgpu-hal/src/gles/device.rs | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/wgpu-hal/src/gles/device.rs b/wgpu-hal/src/gles/device.rs index 2a9d16e242..6756d1884c 100644 --- a/wgpu-hal/src/gles/device.rs +++ b/wgpu-hal/src/gles/device.rs @@ -10,9 +10,6 @@ use std::{ #[cfg(not(target_arch = "wasm32"))] use std::mem; -#[cfg(any(not(target_arch = "wasm32"), feature = "emscripten"))] -use std::num::NonZeroU32; - type ShaderStage<'a> = ( naga::ShaderStage, &'a crate::ProgrammableStage<'a, super::Api>, @@ -97,7 +94,7 @@ impl super::Device { #[cfg(any(not(target_arch = "wasm32"), feature = "emscripten"))] pub unsafe fn texture_from_raw( &self, - name: NonZeroU32, + name: std::num::NonZeroU32, desc: &crate::TextureDescriptor, drop_guard: Option, ) -> super::Texture { @@ -134,7 +131,7 @@ impl super::Device { #[cfg(any(not(target_arch = "wasm32"), feature = "emscripten"))] pub unsafe fn texture_from_raw_renderbuffer( &self, - name: NonZeroU32, + name: std::num::NonZeroU32, desc: &crate::TextureDescriptor, drop_guard: Option, ) -> super::Texture {