From d88bc440e67e1ab881ab63f3c2a6caaf9dd32cda Mon Sep 17 00:00:00 2001 From: Dzmitry Malyshau Date: Sat, 19 Jun 2021 01:14:59 -0400 Subject: [PATCH] hal/gles: describe format, adapter info --- wgpu-hal/src/gles/adapter.rs | 116 ++++++++++++++++++ wgpu-hal/src/gles/conv.rs | 222 ++++++++++++++++++++++++++++++++++ wgpu-hal/src/gles/egl.rs | 63 +++++++--- wgpu-hal/src/gles/mod.rs | 46 +++---- wgpu-hal/src/lib.rs | 2 +- wgpu-hal/src/metal/adapter.rs | 2 +- 6 files changed, 413 insertions(+), 38 deletions(-) create mode 100644 wgpu-hal/src/gles/adapter.rs create mode 100644 wgpu-hal/src/gles/conv.rs diff --git a/wgpu-hal/src/gles/adapter.rs b/wgpu-hal/src/gles/adapter.rs new file mode 100644 index 0000000000..fc7b595eb5 --- /dev/null +++ b/wgpu-hal/src/gles/adapter.rs @@ -0,0 +1,116 @@ +use glow::HasContext; +use std::sync::Arc; + +// https://webgl2fundamentals.org/webgl/lessons/webgl-data-textures.html + +impl super::Adapter { + fn make_info(vendor_orig: String, renderer_orig: String) -> wgt::AdapterInfo { + let vendor = vendor_orig.to_lowercase(); + let renderer = renderer_orig.to_lowercase(); + + // opengl has no way to discern device_type, so we can try to infer it from the renderer string + let strings_that_imply_integrated = [ + " xpress", // space here is on purpose so we don't match express + "radeon hd 4200", + "radeon hd 4250", + "radeon hd 4290", + "radeon hd 4270", + "radeon hd 4225", + "radeon hd 3100", + "radeon hd 3200", + "radeon hd 3000", + "radeon hd 3300", + "radeon(tm) r4 graphics", + "radeon(tm) r5 graphics", + "radeon(tm) r6 graphics", + "radeon(tm) r7 graphics", + "radeon r7 graphics", + "nforce", // all nvidia nforce are integrated + "tegra", // all nvidia tegra are integrated + "shield", // all nvidia shield are integrated + "igp", + "mali", + "intel", + ]; + let strings_that_imply_cpu = ["mesa offscreen", "swiftshader", "lavapipe"]; + + //TODO: handle Intel Iris XE as discreet + let inferred_device_type = if vendor.contains("qualcomm") + || vendor.contains("intel") + || strings_that_imply_integrated + .iter() + .any(|&s| renderer.contains(s)) + { + wgt::DeviceType::IntegratedGpu + } else if strings_that_imply_cpu.iter().any(|&s| renderer.contains(s)) { + wgt::DeviceType::Cpu + } else { + wgt::DeviceType::DiscreteGpu + }; + + // source: Sascha Willems at Vulkan + let vendor_id = if vendor.contains("amd") { + 0x1002 + } else if vendor.contains("imgtec") { + 0x1010 + } else if vendor.contains("nvidia") { + 0x10DE + } else if vendor.contains("arm") { + 0x13B5 + } else if vendor.contains("qualcomm") { + 0x5143 + } else if vendor.contains("intel") { + 0x8086 + } else { + 0 + }; + + wgt::AdapterInfo { + name: renderer_orig, + vendor: vendor_id, + device: 0, + device_type: inferred_device_type, + backend: wgt::Backend::Gl, + } + } + + pub(super) unsafe fn expose(gl: glow::Context) -> crate::ExposedAdapter { + let vendor = gl.get_parameter_string(glow::VENDOR); + let renderer = gl.get_parameter_string(glow::RENDERER); + + let min_uniform_buffer_offset_alignment = + gl.get_parameter_i32(glow::UNIFORM_BUFFER_OFFSET_ALIGNMENT); + let min_storage_buffer_offset_alignment = if super::is_webgl() { + 256 + } else { + gl.get_parameter_i32(glow::SHADER_STORAGE_BUFFER_OFFSET_ALIGNMENT) + }; + + crate::ExposedAdapter { + adapter: super::Adapter { + shared: Arc::new(super::AdapterShared { + context: gl, + private_caps: super::PrivateCapabilities {}, + }), + }, + info: Self::make_info(vendor, renderer), + features: wgt::Features::empty(), //TODO + capabilities: crate::Capabilities { + limits: wgt::Limits::default(), //TODO + downlevel: wgt::DownlevelCapabilities::default(), //TODO + alignments: crate::Alignments { + buffer_copy_offset: wgt::BufferSize::new(4).unwrap(), + buffer_copy_pitch: wgt::BufferSize::new(4).unwrap(), + uniform_buffer_offset: wgt::BufferSize::new( + min_storage_buffer_offset_alignment as u64, + ) + .unwrap(), + storage_buffer_offset: wgt::BufferSize::new( + min_uniform_buffer_offset_alignment as u64, + ) + .unwrap(), + }, + }, + } + } +} diff --git a/wgpu-hal/src/gles/conv.rs b/wgpu-hal/src/gles/conv.rs new file mode 100644 index 0000000000..2bcc76e62b --- /dev/null +++ b/wgpu-hal/src/gles/conv.rs @@ -0,0 +1,222 @@ +impl super::PrivateCapabilities { + pub(super) fn describe_texture_format( + &self, + format: wgt::TextureFormat, + ) -> super::FormatDescription { + use super::VertexAttribKind as Vak; + use wgt::TextureFormat as Tf; + + let (tex_internal, tex_external, data_type, num_components, va_kind) = match format { + Tf::R8Unorm => (glow::R8, glow::RED, glow::UNSIGNED_BYTE, 1, Vak::Float), + Tf::R8Snorm => (glow::R8, glow::RED, glow::BYTE, 1, Vak::Float), + Tf::R8Uint => ( + glow::R8UI, + glow::RED_INTEGER, + glow::UNSIGNED_BYTE, + 1, + Vak::Integer, + ), + Tf::R8Sint => (glow::R8I, glow::RED_INTEGER, glow::BYTE, 1, Vak::Integer), + Tf::R16Uint => ( + glow::R16UI, + glow::RED_INTEGER, + glow::UNSIGNED_SHORT, + 1, + Vak::Integer, + ), + Tf::R16Sint => (glow::R16I, glow::RED_INTEGER, glow::SHORT, 1, Vak::Integer), + Tf::R16Float => (glow::R16F, glow::RED, glow::UNSIGNED_SHORT, 1, Vak::Float), + Tf::Rg8Unorm => (glow::RG8, glow::RG, glow::UNSIGNED_BYTE, 2, Vak::Float), + Tf::Rg8Snorm => (glow::RG8, glow::RG, glow::BYTE, 2, Vak::Float), + Tf::Rg8Uint => ( + glow::RG8UI, + glow::RG_INTEGER, + glow::UNSIGNED_BYTE, + 2, + Vak::Integer, + ), + Tf::Rg8Sint => (glow::RG8I, glow::RG_INTEGER, glow::BYTE, 2, Vak::Integer), + Tf::R32Uint => ( + glow::R32UI, + glow::RED_INTEGER, + glow::UNSIGNED_INT, + 1, + Vak::Integer, + ), + Tf::R32Sint => (glow::R32I, glow::RED_INTEGER, glow::INT, 1, Vak::Integer), + Tf::R32Float => (glow::R32F, glow::RED, glow::FLOAT, 1, Vak::Float), + Tf::Rg16Uint => ( + glow::RG16UI, + glow::RG_INTEGER, + glow::UNSIGNED_SHORT, + 2, + Vak::Integer, + ), + Tf::Rg16Sint => (glow::RG16I, glow::RG_INTEGER, glow::SHORT, 2, Vak::Integer), + Tf::Rg16Float => (glow::RG16F, glow::RG, glow::UNSIGNED_SHORT, 2, Vak::Float), + Tf::Rgba8Unorm => (glow::RGBA8, glow::RGBA, glow::UNSIGNED_BYTE, 4, Vak::Float), + Tf::Rgba8UnormSrgb => ( + glow::SRGB8_ALPHA8, + glow::RGBA, + glow::UNSIGNED_BYTE, + 4, + Vak::Float, + ), + Tf::Bgra8UnormSrgb => ( + glow::SRGB8_ALPHA8, + glow::RGBA, + glow::UNSIGNED_BYTE, + 4, + Vak::Float, + ), //TODO? + Tf::Rgba8Snorm => (glow::RGBA8, glow::RGBA, glow::BYTE, 4, Vak::Float), + Tf::Bgra8Unorm => (glow::RGBA8, glow::BGRA, glow::UNSIGNED_BYTE, 4, Vak::Float), + Tf::Rgba8Uint => ( + glow::RGBA8UI, + glow::RGBA_INTEGER, + glow::UNSIGNED_BYTE, + 4, + Vak::Integer, + ), + Tf::Rgba8Sint => ( + glow::RGBA8I, + glow::RGBA_INTEGER, + glow::BYTE, + 4, + Vak::Integer, + ), + Tf::Rgb10a2Unorm => ( + glow::RGB10_A2, + glow::RGBA, + glow::UNSIGNED_INT_2_10_10_10_REV, + 1, + Vak::Integer, + ), + Tf::Rg11b10Float => ( + glow::R11F_G11F_B10F, + glow::RGB, + glow::UNSIGNED_INT_10F_11F_11F_REV, + 1, + Vak::Integer, + ), + Tf::Rg32Uint => ( + glow::RG32UI, + glow::RG_INTEGER, + glow::UNSIGNED_INT, + 2, + Vak::Integer, + ), + Tf::Rg32Sint => (glow::RG32I, glow::RG_INTEGER, glow::INT, 2, Vak::Integer), + Tf::Rg32Float => (glow::RG32F, glow::RG, glow::FLOAT, 2, Vak::Float), + Tf::Rgba16Uint => ( + glow::RGBA16UI, + glow::RGBA_INTEGER, + glow::UNSIGNED_SHORT, + 4, + Vak::Integer, + ), + Tf::Rgba16Sint => ( + glow::RGBA16I, + glow::RGBA_INTEGER, + glow::SHORT, + 4, + Vak::Integer, + ), + Tf::Rgba16Float => (glow::RGBA16F, glow::RG, glow::UNSIGNED_SHORT, 4, Vak::Float), + Tf::Rgba32Uint => ( + glow::RGBA32UI, + glow::RGBA_INTEGER, + glow::UNSIGNED_INT, + 4, + Vak::Integer, + ), + Tf::Rgba32Sint => ( + glow::RGBA32I, + glow::RGBA_INTEGER, + glow::INT, + 4, + Vak::Integer, + ), + Tf::Rgba32Float => (glow::RGBA32F, glow::RGBA, glow::FLOAT, 4, Vak::Float), + Tf::Depth32Float => ( + glow::DEPTH_COMPONENT32F, + glow::DEPTH_COMPONENT, + glow::FLOAT, + 1, + Vak::Float, + ), + Tf::Depth24Plus => ( + glow::DEPTH_COMPONENT24, + glow::DEPTH_COMPONENT, + glow::UNSIGNED_NORMALIZED, + 2, + Vak::Float, + ), + Tf::Depth24PlusStencil8 => ( + glow::DEPTH24_STENCIL8, + glow::DEPTH_COMPONENT, + glow::UNSIGNED_INT, + 2, + Vak::Float, + ), + Tf::Bc1RgbaUnorm + | Tf::Bc1RgbaUnormSrgb + | Tf::Bc2RgbaUnorm + | Tf::Bc2RgbaUnormSrgb + | Tf::Bc3RgbaUnorm + | Tf::Bc3RgbaUnormSrgb + | Tf::Bc4RUnorm + | Tf::Bc4RSnorm + | Tf::Bc5RgUnorm + | Tf::Bc5RgSnorm + | Tf::Bc6hRgbSfloat + | Tf::Bc6hRgbUfloat + | Tf::Bc7RgbaUnorm + | Tf::Bc7RgbaUnormSrgb + | Tf::Etc2RgbUnorm + | Tf::Etc2RgbUnormSrgb + | Tf::Etc2RgbA1Unorm + | Tf::Etc2RgbA1UnormSrgb + | Tf::EacRUnorm + | Tf::EacRSnorm + | Tf::EtcRgUnorm + | Tf::EtcRgSnorm + | Tf::Astc4x4RgbaUnorm + | Tf::Astc4x4RgbaUnormSrgb + | Tf::Astc5x4RgbaUnorm + | Tf::Astc5x4RgbaUnormSrgb + | Tf::Astc5x5RgbaUnorm + | Tf::Astc5x5RgbaUnormSrgb + | Tf::Astc6x5RgbaUnorm + | Tf::Astc6x5RgbaUnormSrgb + | Tf::Astc6x6RgbaUnorm + | Tf::Astc6x6RgbaUnormSrgb + | Tf::Astc8x5RgbaUnorm + | Tf::Astc8x5RgbaUnormSrgb + | Tf::Astc8x6RgbaUnorm + | Tf::Astc8x6RgbaUnormSrgb + | Tf::Astc10x5RgbaUnorm + | Tf::Astc10x5RgbaUnormSrgb + | Tf::Astc10x6RgbaUnorm + | Tf::Astc10x6RgbaUnormSrgb + | Tf::Astc8x8RgbaUnorm + | Tf::Astc8x8RgbaUnormSrgb + | Tf::Astc10x8RgbaUnorm + | Tf::Astc10x8RgbaUnormSrgb + | Tf::Astc10x10RgbaUnorm + | Tf::Astc10x10RgbaUnormSrgb + | Tf::Astc12x10RgbaUnorm + | Tf::Astc12x10RgbaUnormSrgb + | Tf::Astc12x12RgbaUnorm + | Tf::Astc12x12RgbaUnormSrgb => unimplemented!(), + }; + + super::FormatDescription { + tex_internal, + tex_external, + data_type, + num_components, + va_kind, + } + } +} diff --git a/wgpu-hal/src/gles/egl.rs b/wgpu-hal/src/gles/egl.rs index f021f5e065..03987d2adb 100644 --- a/wgpu-hal/src/gles/egl.rs +++ b/wgpu-hal/src/gles/egl.rs @@ -238,7 +238,7 @@ unsafe impl Sync for Instance {} impl crate::Instance for Instance { unsafe fn init(desc: &crate::InstanceDescriptor) -> Result { - let egl = match unsafe { egl::DynamicInstance::::load_required() } { + let egl = match egl::DynamicInstance::::load_required() { Ok(egl) => Arc::new(egl), Err(e) => { log::warn!("Unable to open libEGL.so: {:?}", e); @@ -447,10 +447,43 @@ impl crate::Instance for Instance { swapchain: None, }) } - unsafe fn destroy_surface(&self, surface: Surface) {} + unsafe fn destroy_surface(&self, surface: Surface) { + let inner = self.inner.lock(); + inner + .egl + .destroy_surface(inner.display, surface.raw) + .unwrap(); + if let Some(wl_window) = surface.wl_window { + let wl_egl_window_destroy: libloading::Symbol = self + .wsi_library + .as_ref() + .expect("unsupported window") + .get(b"wl_egl_window_destroy") + .unwrap(); + wl_egl_window_destroy(wl_window) + } + } unsafe fn enumerate_adapters(&self) -> Vec> { - Vec::new() + let inner = self.inner.lock(); + inner + .egl + .make_current( + inner.display, + inner.pbuffer, + inner.pbuffer, + Some(inner.context), + ) + .unwrap(); + + let context = glow::Context::from_loader_function(|name| { + inner + .egl + .get_proc_address(name) + .map_or(ptr::null(), |p| p as *const _) + }); + + vec![super::Adapter::expose(context)] } } @@ -482,7 +515,7 @@ unsafe impl Sync for Surface {} impl crate::Surface for Surface { unsafe fn configure( &mut self, - device: &super::Context, + device: &super::Device, config: &crate::SurfaceConfiguration, ) -> Result<(), crate::SurfaceError> { self.unconfigure(device); @@ -500,15 +533,16 @@ impl crate::Surface for Surface { ); } - //let desc = conv::describe_format(config.format).unwrap(); - let desc: super::FormatDescription = unimplemented!(); - - let gl: glow::Context = unimplemented!(); //&device.share.context; + let format_desc = device + .shared + .private_caps + .describe_texture_format(config.format); + let gl = &device.shared.context; let renderbuffer = gl.create_renderbuffer().unwrap(); gl.bind_renderbuffer(glow::RENDERBUFFER, Some(renderbuffer)); gl.renderbuffer_storage( glow::RENDERBUFFER, - desc.tex_internal, + format_desc.tex_internal, config.extent.width as _, config.extent.height as _, ); @@ -527,20 +561,19 @@ impl crate::Surface for Surface { renderbuffer, framebuffer, extent: config.extent, - format: desc.tex_internal, + format: format_desc.tex_internal, sample_type: wgt::TextureSampleType::Float { filterable: false }, }); Ok(()) } - unsafe fn unconfigure(&mut self, device: &super::Context) { - /* - let gl = &device.share.context; + unsafe fn unconfigure(&mut self, device: &super::Device) { + let gl = &device.shared.context; if let Some(sc) = self.swapchain.take() { gl.delete_renderbuffer(sc.renderbuffer); gl.delete_framebuffer(sc.framebuffer); - }*/ + } } unsafe fn acquire_texture( @@ -552,5 +585,5 @@ impl crate::Surface for Surface { // native::SwapchainImage::new(sc.renderbuffer, sc.format, sc.extent, sc.channel); Ok(None) } - unsafe fn discard_texture(&mut self, texture: super::Resource) {} + unsafe fn discard_texture(&mut self, _texture: super::Resource) {} } diff --git a/wgpu-hal/src/gles/mod.rs b/wgpu-hal/src/gles/mod.rs index e4b76e2c57..19599654b4 100644 --- a/wgpu-hal/src/gles/mod.rs +++ b/wgpu-hal/src/gles/mod.rs @@ -3,10 +3,13 @@ #[cfg(not(target_arch = "wasm32"))] mod egl; +mod adapter; +mod conv; + #[cfg(not(target_arch = "wasm32"))] use self::egl::{Instance, Surface}; -use std::ops::Range; +use std::{ops::Range, sync::Arc}; #[derive(Clone)] pub struct Api; @@ -20,8 +23,8 @@ type DeviceResult = Result; impl crate::Api for Api { type Instance = Instance; type Surface = Surface; - type Adapter = Context; - type Device = Context; + type Adapter = Adapter; + type Device = Device; type Queue = Context; type CommandEncoder = Encoder; @@ -43,6 +46,10 @@ impl crate::Api for Api { type ComputePipeline = Resource; } +const fn is_webgl() -> bool { + cfg!(target_arch = "wasm32") +} + type TextureFormat = u32; #[derive(Debug, Clone, Copy)] @@ -60,25 +67,22 @@ struct FormatDescription { va_kind: VertexAttribKind, } -impl FormatDescription { - fn new( - tex_internal: u32, - tex_external: u32, - data_type: u32, - num_components: u8, - va_kind: VertexAttribKind, - ) -> Self { - FormatDescription { - tex_internal, - tex_external, - data_type, - num_components, - va_kind, - } - } +struct PrivateCapabilities {} + +struct AdapterShared { + context: glow::Context, + private_caps: PrivateCapabilities, } -impl crate::Adapter for Context { +pub struct Adapter { + shared: Arc, +} + +pub struct Device { + shared: Arc, +} + +impl crate::Adapter for Adapter { unsafe fn open(&self, features: wgt::Features) -> DeviceResult> { Err(crate::DeviceError::Lost) } @@ -110,7 +114,7 @@ impl crate::Queue for Context { } } -impl crate::Device for Context { +impl crate::Device for Device { unsafe fn exit(self) {} unsafe fn create_buffer(&self, desc: &crate::BufferDescriptor) -> DeviceResult { Ok(Resource) diff --git a/wgpu-hal/src/lib.rs b/wgpu-hal/src/lib.rs index 45db780473..cf67f8320e 100644 --- a/wgpu-hal/src/lib.rs +++ b/wgpu-hal/src/lib.rs @@ -624,8 +624,8 @@ pub struct Alignments { /// The alignment of the row pitch of the texture data stored in a buffer that is /// used in a GPU copy operation. pub buffer_copy_pitch: wgt::BufferSize, - pub storage_buffer_offset: wgt::BufferSize, pub uniform_buffer_offset: wgt::BufferSize, + pub storage_buffer_offset: wgt::BufferSize, } #[derive(Clone, Debug)] diff --git a/wgpu-hal/src/metal/adapter.rs b/wgpu-hal/src/metal/adapter.rs index 936a8423ed..ec3a6eb073 100644 --- a/wgpu-hal/src/metal/adapter.rs +++ b/wgpu-hal/src/metal/adapter.rs @@ -905,8 +905,8 @@ impl super::PrivateCapabilities { alignments: crate::Alignments { buffer_copy_offset: buffer_alignment, buffer_copy_pitch: wgt::BufferSize::new(4).unwrap(), - storage_buffer_offset: buffer_alignment, uniform_buffer_offset: buffer_alignment, + storage_buffer_offset: buffer_alignment, }, downlevel, }