From e6f3cbbad976627e962e20f5dd8acc83846d9c77 Mon Sep 17 00:00:00 2001 From: Connor Fitzgerald Date: Wed, 23 Feb 2022 00:18:01 -0500 Subject: [PATCH 01/12] Typo in readme --- .gitignore | 3 +++ README.md | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index 52a6ae4010..fb57a85163 100644 --- a/.gitignore +++ b/.gitignore @@ -24,3 +24,6 @@ wgpu/red.png # Readme says to check out CTS here cts/ + +# Readme says to put angle in working directory +*.dll diff --git a/README.md b/README.md index 11c526e9e9..ec9a9ed283 100644 --- a/README.md +++ b/README.md @@ -84,7 +84,7 @@ Both [HLSL](https://github.com/Microsoft/DirectXShaderCompiler) and [GLSL](https have compilers to target SPIR-V. All of these shader languages can be used with any backend, we will handle all of the conversion. Additionally, support for these shader inputs is not going away. -While WebGPU does not support any shader language other than WGSL, we will automatically convert your +While WebGPU does not support any shading language other than WGSL, we will automatically convert your non-WGSL shaders if you're running on WebGPU. WGSL is always supported by default, but GLSL and SPIR-V need features enabled to compile in support. From 563a31eae2d2d7c7f347598f77495c671d62b2e2 Mon Sep 17 00:00:00 2001 From: Connor Fitzgerald Date: Wed, 23 Feb 2022 00:23:23 -0500 Subject: [PATCH 02/12] Always enable vk and gl in wgpu-info --- wgpu-info/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/wgpu-info/Cargo.toml b/wgpu-info/Cargo.toml index 13767cc2c8..f5a601a6d1 100644 --- a/wgpu-info/Cargo.toml +++ b/wgpu-info/Cargo.toml @@ -11,4 +11,4 @@ license = "MIT OR Apache-2.0" [dependencies] env_logger = "0.9" -wgpu = { version = "0.12", path = "../wgpu" } +wgpu = { version = "0.12", path = "../wgpu", features = ["angle", "vulkan-portability"] } From 10d4027a20c24875a8a253bea530792689deb66a Mon Sep 17 00:00:00 2001 From: Connor Fitzgerald Date: Wed, 23 Feb 2022 00:23:56 -0500 Subject: [PATCH 03/12] Always check texture features if we're running on a downlevel platform --- wgpu-core/src/device/mod.rs | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/wgpu-core/src/device/mod.rs b/wgpu-core/src/device/mod.rs index 51168a044a..2699878169 100644 --- a/wgpu-core/src/device/mod.rs +++ b/wgpu-core/src/device/mod.rs @@ -2735,10 +2735,13 @@ impl Device { let format_desc = format.describe(); self.require_features(format_desc.required_features)?; - if self + let using_device_features = self .features - .contains(wgt::Features::TEXTURE_ADAPTER_SPECIFIC_FORMAT_FEATURES) - { + .contains(wgt::Features::TEXTURE_ADAPTER_SPECIFIC_FORMAT_FEATURES); + // If we're running downlevel, we need to manually ask the backend what we can use as we can't trust WebGPU. + let downlevel = !self.downlevel.is_webgpu_compliant(); + + if using_device_features || downlevel { Ok(adapter.get_texture_format_features(format)) } else { Ok(format_desc.guaranteed_format_features) From 054dec0a96a42cda13195df3fe4d8df6b63831f0 Mon Sep 17 00:00:00 2001 From: Connor Fitzgerald Date: Wed, 23 Feb 2022 01:48:57 -0500 Subject: [PATCH 04/12] hal/gles: fix handling of rows_per_image for compressed texture uploads --- wgpu-hal/src/gles/queue.rs | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/wgpu-hal/src/gles/queue.rs b/wgpu-hal/src/gles/queue.rs index e6f9f549f6..2c9b9978fb 100644 --- a/wgpu-hal/src/gles/queue.rs +++ b/wgpu-hal/src/gles/queue.rs @@ -452,9 +452,18 @@ impl super::Queue { _ => unreachable!(), } } else { - let bytes_per_image = - copy.buffer_layout.rows_per_image.map_or(1, |rpi| rpi.get()) - * copy.buffer_layout.bytes_per_row.map_or(1, |bpr| bpr.get()); + let bytes_per_row = copy + .buffer_layout + .bytes_per_row + .map_or(copy.size.width * format_info.block_size as u32, |bpr| { + bpr.get() + }); + let rows_per_image = copy.buffer_layout.rows_per_image.map_or( + copy.size.height / format_info.block_dimensions.1 as u32, + |rpi| rpi.get(), + ); + + let bytes_per_image = bytes_per_row * rows_per_image; let offset = copy.buffer_layout.offset as u32; let buffer_data; From c0ee4298e13e2b33b26d4e356537088f93a21481 Mon Sep 17 00:00:00 2001 From: Connor Fitzgerald Date: Wed, 23 Feb 2022 01:49:50 -0500 Subject: [PATCH 05/12] hal/gles: improve gles texture format conversions --- wgpu-hal/src/gles/conv.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/wgpu-hal/src/gles/conv.rs b/wgpu-hal/src/gles/conv.rs index 45468c2452..ef71bd0394 100644 --- a/wgpu-hal/src/gles/conv.rs +++ b/wgpu-hal/src/gles/conv.rs @@ -8,7 +8,7 @@ impl super::AdapterShared { let (internal, external, data_type) = match texture_format { Tf::R8Unorm => (glow::R8, glow::RED, glow::UNSIGNED_BYTE), - Tf::R8Snorm => (glow::R8, glow::RED, glow::BYTE), + Tf::R8Snorm => (glow::R8_SNORM, glow::RED, glow::BYTE), Tf::R8Uint => (glow::R8UI, glow::RED_INTEGER, glow::UNSIGNED_BYTE), Tf::R8Sint => (glow::R8I, glow::RED_INTEGER, glow::BYTE), Tf::R16Uint => (glow::R16UI, glow::RED_INTEGER, glow::UNSIGNED_SHORT), @@ -17,7 +17,7 @@ impl super::AdapterShared { Tf::R16Snorm => (glow::R16_SNORM, glow::RED, glow::SHORT), Tf::R16Float => (glow::R16F, glow::RED, glow::HALF_FLOAT), Tf::Rg8Unorm => (glow::RG8, glow::RG, glow::UNSIGNED_BYTE), - Tf::Rg8Snorm => (glow::RG8, glow::RG, glow::BYTE), + Tf::Rg8Snorm => (glow::RG8_SNORM, glow::RG, glow::BYTE), Tf::Rg8Uint => (glow::RG8UI, glow::RG_INTEGER, glow::UNSIGNED_BYTE), Tf::Rg8Sint => (glow::RG8I, glow::RG_INTEGER, glow::BYTE), Tf::R32Uint => (glow::R32UI, glow::RED_INTEGER, glow::UNSIGNED_INT), @@ -31,8 +31,8 @@ impl super::AdapterShared { Tf::Rgba8Unorm => (glow::RGBA8, glow::RGBA, glow::UNSIGNED_BYTE), Tf::Rgba8UnormSrgb => (glow::SRGB8_ALPHA8, glow::RGBA, glow::UNSIGNED_BYTE), Tf::Bgra8UnormSrgb => (glow::SRGB8_ALPHA8, glow::RGBA, glow::UNSIGNED_BYTE), //TODO? - Tf::Rgba8Snorm => (glow::RGBA8, glow::RGBA, glow::BYTE), - Tf::Bgra8Unorm => (glow::RGBA8, glow::BGRA, glow::UNSIGNED_BYTE), + Tf::Rgba8Snorm => (glow::RGBA8_SNORM, glow::RGBA, glow::BYTE), + Tf::Bgra8Unorm => (glow::RGBA8, glow::RGBA, glow::UNSIGNED_BYTE), //TODO? Tf::Rgba8Uint => (glow::RGBA8UI, glow::RGBA_INTEGER, glow::UNSIGNED_BYTE), Tf::Rgba8Sint => (glow::RGBA8I, glow::RGBA_INTEGER, glow::BYTE), Tf::Rgb10a2Unorm => ( From 188bb2fb1a65c41a352c11d0afcbdd2533246f81 Mon Sep 17 00:00:00 2001 From: Connor Fitzgerald Date: Wed, 23 Feb 2022 14:32:08 -0500 Subject: [PATCH 06/12] hal/gles: support bcn textures --- wgpu-hal/src/gles/adapter.rs | 22 ++++++++++++++++++++-- wgpu-hal/src/gles/conv.rs | 16 ++++++++-------- 2 files changed, 28 insertions(+), 10 deletions(-) diff --git a/wgpu-hal/src/gles/adapter.rs b/wgpu-hal/src/gles/adapter.rs index 3d9cd38e34..5564c83f3c 100644 --- a/wgpu-hal/src/gles/adapter.rs +++ b/wgpu-hal/src/gles/adapter.rs @@ -303,13 +303,31 @@ impl super::Adapter { downlevel_flags.contains(wgt::DownlevelFlags::VERTEX_STORAGE) && vertex_shader_storage_textures != 0, ); + let gles_bcn_exts = [ + "GL_EXT_texture_compression_s3tc_srgb", + "GL_EXT_texture_compression_rgtc", + "GL_EXT_texture_compression_bptc", + ]; + let webgl_bcn_exts = [ + "WEBGL_compressed_texture_s3tc", + "WEBGL_compressed_texture_s3tc_srgb", + "EXT_texture_compression_rgtc", + "EXT_texture_compression_bptc", + ]; + let bcn_exts = if cfg!(target_arch = "wasm32") { + &webgl_bcn_exts[..] + } else { + &gles_bcn_exts[..] + }; + features.set( + wgt::Features::TEXTURE_COMPRESSION_BC, + bcn_exts.iter().all(|&ext| extensions.contains(ext)), + ); features.set( wgt::Features::TEXTURE_COMPRESSION_ETC2, // This is a part of GLES-3 but not WebGL2 core !cfg!(target_arch = "wasm32") || extensions.contains("WEBGL_compressed_texture_etc"), ); - //Note: `wgt::Features::TEXTURE_COMPRESSION_BC` can't be fully supported, but there are - // "WEBGL_compressed_texture_s3tc" and "WEBGL_compressed_texture_s3tc_srgb" which could partially cover it features.set( wgt::Features::TEXTURE_COMPRESSION_ASTC_LDR, extensions.contains("GL_KHR_texture_compression_astc_ldr") diff --git a/wgpu-hal/src/gles/conv.rs b/wgpu-hal/src/gles/conv.rs index ef71bd0394..966152fd30 100644 --- a/wgpu-hal/src/gles/conv.rs +++ b/wgpu-hal/src/gles/conv.rs @@ -74,14 +74,14 @@ impl super::AdapterShared { Tf::Bc2RgbaUnormSrgb => (glow::COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT, glow::RGBA, 0), Tf::Bc3RgbaUnorm => (glow::COMPRESSED_RGBA_S3TC_DXT5_EXT, glow::RGBA, 0), Tf::Bc3RgbaUnormSrgb => (glow::COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT, glow::RGBA, 0), - Tf::Bc4RUnorm - | Tf::Bc4RSnorm - | Tf::Bc5RgUnorm - | Tf::Bc5RgSnorm - | Tf::Bc6hRgbUfloat - | Tf::Bc6hRgbSfloat - | Tf::Bc7RgbaUnorm - | Tf::Bc7RgbaUnormSrgb => unimplemented!(), + Tf::Bc4RUnorm => (glow::COMPRESSED_RED_RGTC1, glow::RED, 0), + Tf::Bc4RSnorm => (glow::COMPRESSED_SIGNED_RED_RGTC1, glow::RED, 0), + Tf::Bc5RgUnorm => (glow::COMPRESSED_RG_RGTC2, glow::RG, 0), + Tf::Bc5RgSnorm => (glow::COMPRESSED_SIGNED_RG_RGTC2, glow::RG, 0), + Tf::Bc6hRgbUfloat => (glow::COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT, glow::RGB, 0), + Tf::Bc6hRgbSfloat => (glow::COMPRESSED_RGB_BPTC_SIGNED_FLOAT, glow::RGB, 0), + Tf::Bc7RgbaUnorm => (glow::COMPRESSED_RGBA_BPTC_UNORM, glow::RGBA, 0), + Tf::Bc7RgbaUnormSrgb => (glow::COMPRESSED_SRGB_ALPHA_BPTC_UNORM, glow::RGBA, 0), Tf::Etc2Rgb8Unorm => (glow::COMPRESSED_RGB8_ETC2, glow::RGB, 0), Tf::Etc2Rgb8UnormSrgb => (glow::COMPRESSED_SRGB8_ETC2, glow::RGB, 0), Tf::Etc2Rgb8A1Unorm => ( From 587f23c712fa1c50076e7f82f7129c6242aaab36 Mon Sep 17 00:00:00 2001 From: Connor Fitzgerald Date: Wed, 23 Feb 2022 15:56:34 -0500 Subject: [PATCH 07/12] Rename get_downlevel_properties to get_downlevel_capabilities --- wgpu-core/src/instance.rs | 2 +- wgpu-info/src/main.rs | 2 +- wgpu/examples/framework.rs | 2 +- wgpu/examples/shadow/main.rs | 2 +- wgpu/src/backend/direct.rs | 4 ++-- wgpu/src/backend/web.rs | 2 +- wgpu/src/lib.rs | 6 +++--- wgpu/tests/common/mod.rs | 8 ++++---- 8 files changed, 14 insertions(+), 14 deletions(-) diff --git a/wgpu-core/src/instance.rs b/wgpu-core/src/instance.rs index f525d2eed0..565173703f 100644 --- a/wgpu-core/src/instance.rs +++ b/wgpu-core/src/instance.rs @@ -878,7 +878,7 @@ impl Global { .map_err(|_| InvalidAdapter) } - pub fn adapter_downlevel_properties( + pub fn adapter_downlevel_capabilities( &self, adapter_id: AdapterId, ) -> Result { diff --git a/wgpu-info/src/main.rs b/wgpu-info/src/main.rs index 769fdfe753..833670f7ac 100644 --- a/wgpu-info/src/main.rs +++ b/wgpu-info/src/main.rs @@ -8,7 +8,7 @@ use std::{ #[rustfmt::skip] fn print_info_from_adapter(adapter: &wgpu::Adapter, idx: usize) { let info = adapter.get_info(); - let downlevel = adapter.get_downlevel_properties(); + let downlevel = adapter.get_downlevel_capabilities(); let features = adapter.features(); let limits = adapter.limits(); diff --git a/wgpu/examples/framework.rs b/wgpu/examples/framework.rs index c19e2066ec..3a50656a4c 100644 --- a/wgpu/examples/framework.rs +++ b/wgpu/examples/framework.rs @@ -151,7 +151,7 @@ async fn setup(title: &str) -> Setup { ); let required_downlevel_capabilities = E::required_downlevel_capabilities(); - let downlevel_capabilities = adapter.get_downlevel_properties(); + let downlevel_capabilities = adapter.get_downlevel_capabilities(); assert!( downlevel_capabilities.shader_model >= required_downlevel_capabilities.shader_model, "Adapter does not support the minimum shader model required to run this example: {:?}", diff --git a/wgpu/examples/shadow/main.rs b/wgpu/examples/shadow/main.rs index 53daf5e237..b6219f6b71 100644 --- a/wgpu/examples/shadow/main.rs +++ b/wgpu/examples/shadow/main.rs @@ -220,7 +220,7 @@ impl framework::Example for Example { _queue: &wgpu::Queue, ) -> Self { let supports_storage_resources = adapter - .get_downlevel_properties() + .get_downlevel_capabilities() .flags .contains(wgpu::DownlevelFlags::VERTEX_STORAGE) && device.limits().max_storage_buffers_per_shader_stage > 0; diff --git a/wgpu/src/backend/direct.rs b/wgpu/src/backend/direct.rs index e0dfea8923..82336dc070 100644 --- a/wgpu/src/backend/direct.rs +++ b/wgpu/src/backend/direct.rs @@ -882,9 +882,9 @@ impl crate::Context for Context { } } - fn adapter_downlevel_properties(&self, adapter: &Self::AdapterId) -> DownlevelCapabilities { + fn adapter_downlevel_capabilities(&self, adapter: &Self::AdapterId) -> DownlevelCapabilities { let global = &self.0; - match wgc::gfx_select!(*adapter => global.adapter_downlevel_properties(*adapter)) { + match wgc::gfx_select!(*adapter => global.adapter_downlevel_capabilities(*adapter)) { Ok(downlevel) => downlevel, Err(err) => self.handle_error_fatal(err, "Adapter::downlevel_properties"), } diff --git a/wgpu/src/backend/web.rs b/wgpu/src/backend/web.rs index 9f3e55edba..dd5800d8b3 100644 --- a/wgpu/src/backend/web.rs +++ b/wgpu/src/backend/web.rs @@ -1157,7 +1157,7 @@ impl crate::Context for Context { } } - fn adapter_downlevel_properties( + fn adapter_downlevel_capabilities( &self, _adapter: &Self::AdapterId, ) -> wgt::DownlevelCapabilities { diff --git a/wgpu/src/lib.rs b/wgpu/src/lib.rs index d940164619..8e23f43efc 100644 --- a/wgpu/src/lib.rs +++ b/wgpu/src/lib.rs @@ -218,7 +218,7 @@ trait Context: Debug + Send + Sized + Sync { ) -> bool; fn adapter_features(&self, adapter: &Self::AdapterId) -> Features; fn adapter_limits(&self, adapter: &Self::AdapterId) -> Limits; - fn adapter_downlevel_properties(&self, adapter: &Self::AdapterId) -> DownlevelCapabilities; + fn adapter_downlevel_capabilities(&self, adapter: &Self::AdapterId) -> DownlevelCapabilities; fn adapter_get_info(&self, adapter: &Self::AdapterId) -> AdapterInfo; fn adapter_get_texture_format_features( &self, @@ -1671,8 +1671,8 @@ impl Adapter { } /// Get info about the adapter itself. - pub fn get_downlevel_properties(&self) -> DownlevelCapabilities { - Context::adapter_downlevel_properties(&*self.context, &self.id) + pub fn get_downlevel_capabilities(&self) -> DownlevelCapabilities { + Context::adapter_downlevel_capabilities(&*self.context, &self.id) } /// Returns the features supported for a given texture format by this adapter. diff --git a/wgpu/tests/common/mod.rs b/wgpu/tests/common/mod.rs index 9993d3bc92..b9a9b63507 100644 --- a/wgpu/tests/common/mod.rs +++ b/wgpu/tests/common/mod.rs @@ -161,7 +161,7 @@ pub fn initialize_test(parameters: TestParameters, test_function: impl FnOnce(Te let adapter_lowercase_name = adapter_info.name.to_lowercase(); let adapter_features = adapter.features(); let adapter_limits = adapter.limits(); - let adapter_downlevel_properties = adapter.get_downlevel_properties(); + let adapter_downlevel_capabilities = adapter.get_downlevel_capabilities(); let missing_features = parameters.required_features - adapter_features; if !missing_features.is_empty() { @@ -175,7 +175,7 @@ pub fn initialize_test(parameters: TestParameters, test_function: impl FnOnce(Te } let missing_downlevel_flags = - parameters.required_downlevel_properties.flags - adapter_downlevel_properties.flags; + parameters.required_downlevel_properties.flags - adapter_downlevel_capabilities.flags; if !missing_downlevel_flags.is_empty() { println!( "TEST SKIPPED: MISSING DOWNLEVEL FLAGS {:?}", @@ -184,12 +184,12 @@ pub fn initialize_test(parameters: TestParameters, test_function: impl FnOnce(Te return; } - if adapter_downlevel_properties.shader_model + if adapter_downlevel_capabilities.shader_model < parameters.required_downlevel_properties.shader_model { println!( "TEST SKIPPED: LOW SHADER MODEL {:?}", - adapter_downlevel_properties.shader_model + adapter_downlevel_capabilities.shader_model ); return; } From dc04bbd928abbdba85a9ceee6206f6c18a18403c Mon Sep 17 00:00:00 2001 From: Connor Fitzgerald Date: Wed, 23 Feb 2022 15:58:40 -0500 Subject: [PATCH 08/12] tests/gles: properly label tests that don't run without some downlevel features --- wgpu/examples/hello-compute/tests.rs | 16 +++++-- wgpu/tests/clear_texture.rs | 62 ++++++++++++++++------------ wgpu/tests/common/mod.rs | 10 ++++- 3 files changed, 56 insertions(+), 32 deletions(-) diff --git a/wgpu/examples/hello-compute/tests.rs b/wgpu/examples/hello-compute/tests.rs index f7e9cfd863..fa518a06cb 100644 --- a/wgpu/examples/hello-compute/tests.rs +++ b/wgpu/examples/hello-compute/tests.rs @@ -9,7 +9,9 @@ use common::{initialize_test, TestParameters}; #[test] fn test_compute_1() { initialize_test( - TestParameters::default().specific_failure(None, None, Some("V3D"), true), + TestParameters::default() + .downlevel_flags(wgpu::DownlevelFlags::COMPUTE_SHADERS) + .specific_failure(None, None, Some("V3D"), true), |ctx| { let input = &[1, 2, 3, 4]; @@ -26,7 +28,9 @@ fn test_compute_1() { #[test] fn test_compute_2() { initialize_test( - TestParameters::default().specific_failure(None, None, Some("V3D"), true), + TestParameters::default() + .downlevel_flags(wgpu::DownlevelFlags::COMPUTE_SHADERS) + .specific_failure(None, None, Some("V3D"), true), |ctx| { let input = &[5, 23, 10, 9]; @@ -43,7 +47,9 @@ fn test_compute_2() { #[test] fn test_compute_overflow() { initialize_test( - TestParameters::default().specific_failure(None, None, Some("V3D"), true), + TestParameters::default() + .downlevel_flags(wgpu::DownlevelFlags::COMPUTE_SHADERS) + .specific_failure(None, None, Some("V3D"), true), |ctx| { let input = &[77031, 837799, 8400511, 63728127]; pollster::block_on(assert_execute_gpu( @@ -59,7 +65,9 @@ fn test_compute_overflow() { #[test] fn test_multithreaded_compute() { initialize_test( - TestParameters::default().specific_failure(None, None, Some("V3D"), true), + TestParameters::default() + .downlevel_flags(wgpu::DownlevelFlags::COMPUTE_SHADERS) + .specific_failure(None, None, Some("V3D"), true), |ctx| { use std::{sync::mpsc, thread, time::Duration}; diff --git a/wgpu/tests/clear_texture.rs b/wgpu/tests/clear_texture.rs index 0a2c9dd152..788a37b12b 100644 --- a/wgpu/tests/clear_texture.rs +++ b/wgpu/tests/clear_texture.rs @@ -239,7 +239,12 @@ fn single_texture_clear_test( // TODO: Read back and check zeroness? } -fn clear_texture_tests(ctx: &TestingContext, formats: &[wgpu::TextureFormat], supports_1d: bool) { +fn clear_texture_tests( + ctx: &TestingContext, + formats: &[wgpu::TextureFormat], + supports_1d: bool, + supports_3d: bool, +) { for &format in formats { // 1D texture if supports_1d { @@ -265,29 +270,31 @@ fn clear_texture_tests(ctx: &TestingContext, formats: &[wgpu::TextureFormat], su }, wgpu::TextureDimension::D2, ); - // 2D array texture - single_texture_clear_test( - ctx, - format, - wgpu::Extent3d { - width: 64, - height: 64, - depth_or_array_layers: 4, - }, - wgpu::TextureDimension::D2, - ); - // volume texture - if format.describe().sample_type != wgt::TextureSampleType::Depth { + if supports_3d { + // 2D array texture single_texture_clear_test( ctx, format, wgpu::Extent3d { - width: 16, - height: 16, - depth_or_array_layers: 16, + width: 64, + height: 64, + depth_or_array_layers: 4, }, - wgpu::TextureDimension::D3, + wgpu::TextureDimension::D2, ); + // volume texture + if format.describe().sample_type != wgt::TextureSampleType::Depth { + single_texture_clear_test( + ctx, + format, + wgpu::Extent3d { + width: 16, + height: 16, + depth_or_array_layers: 16, + }, + wgpu::TextureDimension::D3, + ); + } } } } @@ -297,8 +304,8 @@ fn clear_texture_2d_uncompressed() { initialize_test( TestParameters::default().features(wgpu::Features::CLEAR_TEXTURE), |ctx| { - clear_texture_tests(&ctx, TEXTURE_FORMATS_UNCOMPRESSED, true); - clear_texture_tests(&ctx, TEXTURE_FORMATS_DEPTH, false); + clear_texture_tests(&ctx, TEXTURE_FORMATS_UNCOMPRESSED, true, true); + clear_texture_tests(&ctx, TEXTURE_FORMATS_DEPTH, false, true); }, ) } @@ -307,9 +314,10 @@ fn clear_texture_2d_uncompressed() { fn clear_texture_2d_bc() { initialize_test( TestParameters::default() - .features(wgpu::Features::CLEAR_TEXTURE | wgpu::Features::TEXTURE_COMPRESSION_BC), + .features(wgpu::Features::CLEAR_TEXTURE | wgpu::Features::TEXTURE_COMPRESSION_BC) + .specific_failure(Some(wgpu::Backends::GL), None, None, true), |ctx| { - clear_texture_tests(&ctx, TEXTURE_FORMATS_BC, false); + clear_texture_tests(&ctx, TEXTURE_FORMATS_BC, false, true); }, ) } @@ -318,9 +326,10 @@ fn clear_texture_2d_bc() { fn clear_texture_2d_astc() { initialize_test( TestParameters::default() - .features(wgpu::Features::CLEAR_TEXTURE | wgpu::Features::TEXTURE_COMPRESSION_ASTC_LDR), + .features(wgpu::Features::CLEAR_TEXTURE | wgpu::Features::TEXTURE_COMPRESSION_ASTC_LDR) + .specific_failure(Some(wgpu::Backends::GL), None, None, true), |ctx| { - clear_texture_tests(&ctx, TEXTURE_FORMATS_ASTC, false); + clear_texture_tests(&ctx, TEXTURE_FORMATS_ASTC, false, true); }, ) } @@ -329,9 +338,10 @@ fn clear_texture_2d_astc() { fn clear_texture_2d_etc2() { initialize_test( TestParameters::default() - .features(wgpu::Features::CLEAR_TEXTURE | wgpu::Features::TEXTURE_COMPRESSION_ETC2), + .features(wgpu::Features::CLEAR_TEXTURE | wgpu::Features::TEXTURE_COMPRESSION_ETC2) + .specific_failure(Some(wgpu::Backends::GL), None, None, true), |ctx| { - clear_texture_tests(&ctx, TEXTURE_FORMATS_ETC2, false); + clear_texture_tests(&ctx, TEXTURE_FORMATS_ETC2, false, true); }, ) } diff --git a/wgpu/tests/common/mod.rs b/wgpu/tests/common/mod.rs index b9a9b63507..9e97b47d6b 100644 --- a/wgpu/tests/common/mod.rs +++ b/wgpu/tests/common/mod.rs @@ -34,7 +34,10 @@ async fn initialize_device( pub struct TestingContext { pub adapter: Adapter, pub adapter_info: wgt::AdapterInfo, + pub adapter_downlevel_capabilities: wgt::DownlevelCapabilities, pub device: Device, + pub device_features: wgt::Features, + pub device_limits: wgt::Limits, pub queue: Queue, } @@ -156,7 +159,7 @@ pub fn initialize_test(parameters: TestParameters, test_function: impl FnOnce(Te )) .expect("could not find sutable adapter on the system"); - let required_limits = Limits::downlevel_defaults(); + let required_limits = Limits::downlevel_webgl2_defaults(); let adapter_info = adapter.get_info(); let adapter_lowercase_name = adapter_info.name.to_lowercase(); let adapter_features = adapter.features(); @@ -197,13 +200,16 @@ pub fn initialize_test(parameters: TestParameters, test_function: impl FnOnce(Te let (device, queue) = pollster::block_on(initialize_device( &adapter, parameters.required_features, - required_limits, + required_limits.clone(), )); let context = TestingContext { adapter, adapter_info: adapter_info.clone(), + adapter_downlevel_capabilities, device, + device_features: parameters.required_features, + device_limits: required_limits, queue, }; From 9669fc97278c7e60b2571891ae9b7c2de029dbda Mon Sep 17 00:00:00 2001 From: Connor Fitzgerald Date: Wed, 23 Feb 2022 16:31:01 -0500 Subject: [PATCH 09/12] Move limit comparison logic into wgpu-types for easy reuse --- wgpu-core/src/instance.rs | 47 ++++--------------------- wgpu-types/src/lib.rs | 72 ++++++++++++++++++++++++++++++++++++++- 2 files changed, 78 insertions(+), 41 deletions(-) diff --git a/wgpu-core/src/instance.rs b/wgpu-core/src/instance.rs index 565173703f..b23a983d90 100644 --- a/wgpu-core/src/instance.rs +++ b/wgpu-core/src/instance.rs @@ -28,49 +28,16 @@ pub struct FailedLimit { } fn check_limits(requested: &wgt::Limits, allowed: &wgt::Limits) -> Vec { - use std::cmp::Ordering; let mut failed = Vec::new(); - macro_rules! compare { - ($name:ident, $ordering:ident) => { - match requested.$name.cmp(&allowed.$name) { - Ordering::$ordering | Ordering::Equal => (), - _ => failed.push(FailedLimit { - name: stringify!($name), - requested: requested.$name, - allowed: allowed.$name, - }), - } - }; - } + requested.check_limits_with_fail_fn(allowed, false, |name, requested, allowed| { + failed.push(FailedLimit { + name, + requested, + allowed, + }) + }); - compare!(max_texture_dimension_1d, Less); - compare!(max_texture_dimension_2d, Less); - compare!(max_texture_dimension_3d, Less); - compare!(max_texture_array_layers, Less); - compare!(max_bind_groups, Less); - compare!(max_dynamic_uniform_buffers_per_pipeline_layout, Less); - compare!(max_dynamic_storage_buffers_per_pipeline_layout, Less); - compare!(max_sampled_textures_per_shader_stage, Less); - compare!(max_samplers_per_shader_stage, Less); - compare!(max_storage_buffers_per_shader_stage, Less); - compare!(max_storage_textures_per_shader_stage, Less); - compare!(max_uniform_buffers_per_shader_stage, Less); - compare!(max_uniform_buffer_binding_size, Less); - compare!(max_storage_buffer_binding_size, Less); - compare!(max_vertex_buffers, Less); - compare!(max_vertex_attributes, Less); - compare!(max_vertex_buffer_array_stride, Less); - compare!(max_push_constant_size, Less); - compare!(min_uniform_buffer_offset_alignment, Greater); - compare!(min_storage_buffer_offset_alignment, Greater); - compare!(max_inter_stage_shader_components, Less); - compare!(max_compute_workgroup_storage_size, Less); - compare!(max_compute_invocations_per_workgroup, Less); - compare!(max_compute_workgroup_size_x, Less); - compare!(max_compute_workgroup_size_y, Less); - compare!(max_compute_workgroup_size_z, Less); - compare!(max_compute_workgroups_per_dimension, Less); failed } diff --git a/wgpu-types/src/lib.rs b/wgpu-types/src/lib.rs index 575d48a494..4a3a3dff1e 100644 --- a/wgpu-types/src/lib.rs +++ b/wgpu-types/src/lib.rs @@ -617,7 +617,7 @@ impl Features { /// /// See also: #[repr(C)] -#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] +#[derive(Clone, Debug, PartialEq, Eq, Hash)] #[cfg_attr(feature = "trace", derive(Serialize))] #[cfg_attr(feature = "replay", derive(Deserialize))] #[cfg_attr(feature = "serde", serde(rename_all = "camelCase"))] @@ -820,6 +820,76 @@ impl Limits { ..self } } + + /// Compares every limits within self is within the limits given in `allowed`. + /// + /// If you need detailed information on failures, look at [`Limits::check_limits_with_fail_fn`]. + pub fn check_limits(&self, allowed: &Self) -> bool { + let mut within = true; + self.check_limits_with_fail_fn(allowed, true, |_, _, _| within = false); + within + } + + /// Compares every limits within self is within the limits given in `allowed`. + /// For an easy to use binary choice, use [`Limits::check_limits`]. + /// + /// If a value is not within the allowed limit, this function calls the `fail_fn` + /// with the: + /// - limit name + /// - self's limit + /// - allowed's limit. + /// + /// If fatal is true, a single failure bails out the comparison after a single failure. + pub fn check_limits_with_fail_fn( + &self, + allowed: &Self, + fatal: bool, + mut fail_fn: impl FnMut(&'static str, u32, u32), + ) { + use std::cmp::Ordering; + + macro_rules! compare { + ($name:ident, $ordering:ident) => { + match self.$name.cmp(&allowed.$name) { + Ordering::$ordering | Ordering::Equal => (), + _ => { + fail_fn(stringify!($name), self.$name, allowed.$name); + if fatal { + return; + } + } + } + }; + } + + compare!(max_texture_dimension_1d, Less); + compare!(max_texture_dimension_2d, Less); + compare!(max_texture_dimension_3d, Less); + compare!(max_texture_array_layers, Less); + compare!(max_bind_groups, Less); + compare!(max_dynamic_uniform_buffers_per_pipeline_layout, Less); + compare!(max_dynamic_storage_buffers_per_pipeline_layout, Less); + compare!(max_sampled_textures_per_shader_stage, Less); + compare!(max_samplers_per_shader_stage, Less); + compare!(max_storage_buffers_per_shader_stage, Less); + compare!(max_storage_textures_per_shader_stage, Less); + compare!(max_uniform_buffers_per_shader_stage, Less); + compare!(max_uniform_buffer_binding_size, Less); + compare!(max_storage_buffer_binding_size, Less); + compare!(max_vertex_buffers, Less); + compare!(max_vertex_attributes, Less); + compare!(max_vertex_buffer_array_stride, Less); + compare!(max_push_constant_size, Less); + compare!(min_uniform_buffer_offset_alignment, Greater); + compare!(min_storage_buffer_offset_alignment, Greater); + compare!(max_inter_stage_shader_components, Less); + compare!(max_compute_workgroup_storage_size, Less); + compare!(max_compute_invocations_per_workgroup, Less); + compare!(max_compute_workgroup_size_x, Less); + compare!(max_compute_workgroup_size_y, Less); + compare!(max_compute_workgroup_size_z, Less); + compare!(max_compute_workgroups_per_dimension, Less); + } } /// Represents the sets of additional limits on an adapter, From bb70367ffa7dd426b4156eaf93b0a830edf5e0af Mon Sep 17 00:00:00 2001 From: Connor Fitzgerald Date: Wed, 23 Feb 2022 16:32:24 -0500 Subject: [PATCH 10/12] Make tests properly request their own limits --- wgpu/examples/boids/main.rs | 3 ++- wgpu/examples/hello-compute/tests.rs | 4 ++++ wgpu/tests/common/mod.rs | 20 ++++++++++++++------ wgpu/tests/vertex_indices/mod.rs | 8 ++++---- 4 files changed, 24 insertions(+), 11 deletions(-) diff --git a/wgpu/examples/boids/main.rs b/wgpu/examples/boids/main.rs index 043d4bc3f9..61cbb34494 100644 --- a/wgpu/examples/boids/main.rs +++ b/wgpu/examples/boids/main.rs @@ -340,7 +340,8 @@ fn boids() { height: 768, optional_features: wgpu::Features::default(), base_test_parameters: framework::test_common::TestParameters::default() - .downlevel_flags(wgpu::DownlevelFlags::COMPUTE_SHADERS), + .downlevel_flags(wgpu::DownlevelFlags::COMPUTE_SHADERS) + .limits(wgpu::Limits::downlevel_defaults()), tolerance: 0, max_outliers: 2500, // Currently bounded by WARP }); diff --git a/wgpu/examples/hello-compute/tests.rs b/wgpu/examples/hello-compute/tests.rs index fa518a06cb..64d49bf15b 100644 --- a/wgpu/examples/hello-compute/tests.rs +++ b/wgpu/examples/hello-compute/tests.rs @@ -11,6 +11,7 @@ fn test_compute_1() { initialize_test( TestParameters::default() .downlevel_flags(wgpu::DownlevelFlags::COMPUTE_SHADERS) + .limits(wgpu::Limits::downlevel_defaults()) .specific_failure(None, None, Some("V3D"), true), |ctx| { let input = &[1, 2, 3, 4]; @@ -30,6 +31,7 @@ fn test_compute_2() { initialize_test( TestParameters::default() .downlevel_flags(wgpu::DownlevelFlags::COMPUTE_SHADERS) + .limits(wgpu::Limits::downlevel_defaults()) .specific_failure(None, None, Some("V3D"), true), |ctx| { let input = &[5, 23, 10, 9]; @@ -49,6 +51,7 @@ fn test_compute_overflow() { initialize_test( TestParameters::default() .downlevel_flags(wgpu::DownlevelFlags::COMPUTE_SHADERS) + .limits(wgpu::Limits::downlevel_defaults()) .specific_failure(None, None, Some("V3D"), true), |ctx| { let input = &[77031, 837799, 8400511, 63728127]; @@ -67,6 +70,7 @@ fn test_multithreaded_compute() { initialize_test( TestParameters::default() .downlevel_flags(wgpu::DownlevelFlags::COMPUTE_SHADERS) + .limits(wgpu::Limits::downlevel_defaults()) .specific_failure(None, None, Some("V3D"), true), |ctx| { use std::{sync::mpsc, thread, time::Duration}; diff --git a/wgpu/tests/common/mod.rs b/wgpu/tests/common/mod.rs index 9e97b47d6b..0cf7a6a6f6 100644 --- a/wgpu/tests/common/mod.rs +++ b/wgpu/tests/common/mod.rs @@ -60,6 +60,7 @@ pub struct FailureCase { pub struct TestParameters { pub required_features: Features, pub required_downlevel_properties: DownlevelCapabilities, + pub required_limits: Limits, // Backends where test should fail. pub failures: Vec, } @@ -69,6 +70,7 @@ impl Default for TestParameters { Self { required_features: Features::empty(), required_downlevel_properties: lowest_downlevel_properties(), + required_limits: Limits::downlevel_webgl2_defaults(), failures: Vec::new(), } } @@ -85,9 +87,10 @@ bitflags::bitflags! { // Builder pattern to make it easier impl TestParameters { - /// Set of common features that most tests require. - pub fn test_features(self) -> Self { + /// Set of common features that most internal tests require for readback. + pub fn test_features_limits(self) -> Self { self.features(Features::MAPPABLE_PRIMARY_BUFFERS | Features::VERTEX_WRITABLE_STORAGE) + .limits(wgpu::Limits::downlevel_defaults()) } /// Set the list of features this test requires. @@ -101,6 +104,12 @@ impl TestParameters { self } + /// Set the limits needed for the test. + pub fn limits(mut self, limits: Limits) -> Self { + self.required_limits = limits; + self + } + /// Mark the test as always failing, equivilant to specific_failure(None, None, None) pub fn failure(mut self) -> Self { self.failures.push(FailureCase { @@ -159,7 +168,6 @@ pub fn initialize_test(parameters: TestParameters, test_function: impl FnOnce(Te )) .expect("could not find sutable adapter on the system"); - let required_limits = Limits::downlevel_webgl2_defaults(); let adapter_info = adapter.get_info(); let adapter_lowercase_name = adapter_info.name.to_lowercase(); let adapter_features = adapter.features(); @@ -172,7 +180,7 @@ pub fn initialize_test(parameters: TestParameters, test_function: impl FnOnce(Te return; } - if adapter_limits < required_limits { + if !parameters.required_limits.check_limits(&adapter_limits) { println!("TEST SKIPPED: LIMIT TOO LOW"); return; } @@ -200,7 +208,7 @@ pub fn initialize_test(parameters: TestParameters, test_function: impl FnOnce(Te let (device, queue) = pollster::block_on(initialize_device( &adapter, parameters.required_features, - required_limits.clone(), + parameters.required_limits.clone(), )); let context = TestingContext { @@ -209,7 +217,7 @@ pub fn initialize_test(parameters: TestParameters, test_function: impl FnOnce(Te adapter_downlevel_capabilities, device, device_features: parameters.required_features, - device_limits: required_limits, + device_limits: parameters.required_limits, queue, }; diff --git a/wgpu/tests/vertex_indices/mod.rs b/wgpu/tests/vertex_indices/mod.rs index d75d3e4919..fa85ae62d9 100644 --- a/wgpu/tests/vertex_indices/mod.rs +++ b/wgpu/tests/vertex_indices/mod.rs @@ -132,7 +132,7 @@ fn pulling_common( #[test] fn draw() { - initialize_test(TestParameters::default().test_features(), |ctx| { + initialize_test(TestParameters::default().test_features_limits(), |ctx| { pulling_common(ctx, &[0, 1, 2, 3, 4, 5], |cmb| { cmb.draw(0..6, 0..1); }) @@ -143,7 +143,7 @@ fn draw() { fn draw_vertex_offset() { initialize_test( TestParameters::default() - .test_features() + .test_features_limits() .backend_failure(wgpu::Backends::DX11), |ctx| { pulling_common(ctx, &[0, 1, 2, 3, 4, 5], |cmb| { @@ -156,7 +156,7 @@ fn draw_vertex_offset() { #[test] fn draw_instanced() { - initialize_test(TestParameters::default().test_features(), |ctx| { + initialize_test(TestParameters::default().test_features_limits(), |ctx| { pulling_common(ctx, &[0, 1, 2, 3, 4, 5], |cmb| { cmb.draw(0..3, 0..2); }) @@ -167,7 +167,7 @@ fn draw_instanced() { fn draw_instanced_offset() { initialize_test( TestParameters::default() - .test_features() + .test_features_limits() .backend_failure(wgpu::Backends::DX11), |ctx| { pulling_common(ctx, &[0, 1, 2, 3, 4, 5], |cmb| { From fcfe7c64bd6b57466c5be060823b1d9b00653a27 Mon Sep 17 00:00:00 2001 From: Connor Fitzgerald Date: Wed, 23 Feb 2022 16:39:47 -0500 Subject: [PATCH 11/12] Update ANGLE instructions in the PATH --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index ec9a9ed283..1280a93c8b 100644 --- a/README.md +++ b/README.md @@ -99,7 +99,7 @@ We support running our GLES3 backend over it in order to reach platforms with GL In order to run with Angle, "angle" feature has to be enabled, and Angle libraries placed in a location visible to the application. These binaries can be downloaded from [gfbuild-angle](https://github.com/DileSoft/gfbuild-angle) artifacts. -On Windows, you generally need to copy them into the working directory, or in the same directory as the executable. +On Windows, you generally need to copy them into the working directory, in the same directory as the executable, or somewhere in your path. On Linux, you can point to them using `LD_LIBRARY_PATH` environment. ## Environment Variables From f08c34a76ea2f9cb6c513c3c71befb175ae509af Mon Sep 17 00:00:00 2001 From: Connor Fitzgerald Date: Thu, 24 Feb 2022 00:23:55 -0500 Subject: [PATCH 12/12] Fix up some downlevel capabilities --- wgpu-core/src/resource.rs | 2 +- wgpu-hal/src/gles/adapter.rs | 1 - wgpu-types/src/lib.rs | 31 ++++++++++++++++++------------- 3 files changed, 19 insertions(+), 15 deletions(-) diff --git a/wgpu-core/src/resource.rs b/wgpu-core/src/resource.rs index 95bf121833..f970cd1028 100644 --- a/wgpu-core/src/resource.rs +++ b/wgpu-core/src/resource.rs @@ -309,7 +309,7 @@ pub enum CreateTextureError { InvalidFormatUsages(wgt::TextureUsages, wgt::TextureFormat), #[error("Texture usages {0:?} are not allowed on a texture of dimensions {1:?}")] InvalidDimensionUsages(wgt::TextureUsages, wgt::TextureDimension), - #[error("Texture format {0:?} can't be used")] + #[error("Texture format {0:?} can't be used due to missing features.")] MissingFeatures(wgt::TextureFormat, #[source] MissingFeatures), } diff --git a/wgpu-hal/src/gles/adapter.rs b/wgpu-hal/src/gles/adapter.rs index 5564c83f3c..e599b428df 100644 --- a/wgpu-hal/src/gles/adapter.rs +++ b/wgpu-hal/src/gles/adapter.rs @@ -261,7 +261,6 @@ impl super::Adapter { }; let mut downlevel_flags = wgt::DownlevelFlags::empty() - | wgt::DownlevelFlags::DEVICE_LOCAL_IMAGE_COPIES | wgt::DownlevelFlags::NON_POWER_OF_TWO_MIPMAPPED_TEXTURES | wgt::DownlevelFlags::CUBE_ARRAY_TEXTURES | wgt::DownlevelFlags::COMPARISON_SAMPLERS; diff --git a/wgpu-types/src/lib.rs b/wgpu-types/src/lib.rs index 4a3a3dff1e..b1bb6180a1 100644 --- a/wgpu-types/src/lib.rs +++ b/wgpu-types/src/lib.rs @@ -951,41 +951,46 @@ bitflags::bitflags! { /// [`DownlevelCapabilities::is_webgpu_compliant()`] function. pub struct DownlevelFlags: u32 { /// The device supports compiling and using compute shaders. + /// + /// DX11 on FL10 level hardware, WebGL2, and GLES3.0 devices do not support compute. const COMPUTE_SHADERS = 1 << 0; /// Supports binding storage buffers and textures to fragment shaders. const FRAGMENT_WRITABLE_STORAGE = 1 << 1; /// Supports indirect drawing and dispatching. + /// + /// DX11 on FL10 level hardware, WebGL2, and GLES 3.0 devices do not support indirect. const INDIRECT_EXECUTION = 1 << 2; /// Supports non-zero `base_vertex` parameter to indexed draw calls. const BASE_VERTEX = 1 << 3; /// Supports reading from a depth/stencil buffer while using as a read-only depth/stencil /// attachment. + /// + /// The WebGL2 and GLES backends do not support RODS. const READ_ONLY_DEPTH_STENCIL = 1 << 4; - /// Supports: - /// - copy_image_to_image - /// - copy_buffer_to_image and copy_image_to_buffer with a buffer without a MAP_* usage - const DEVICE_LOCAL_IMAGE_COPIES = 1 << 5; /// Supports textures with mipmaps which have a non power of two size. - const NON_POWER_OF_TWO_MIPMAPPED_TEXTURES = 1 << 6; + const NON_POWER_OF_TWO_MIPMAPPED_TEXTURES = 1 << 5; /// Supports textures that are cube arrays. - const CUBE_ARRAY_TEXTURES = 1 << 7; + const CUBE_ARRAY_TEXTURES = 1 << 6; /// Supports comparison samplers. - const COMPARISON_SAMPLERS = 1 << 8; + const COMPARISON_SAMPLERS = 1 << 7; /// Supports different blend operations per color attachment. - const INDEPENDENT_BLEND = 1 << 9; + const INDEPENDENT_BLEND = 1 << 8; /// Supports storage buffers in vertex shaders. - const VERTEX_STORAGE = 1 << 10; + const VERTEX_STORAGE = 1 << 9; /// Supports samplers with anisotropic filtering. Note this isn't actually required by /// WebGPU, the implementation is allowed to completely ignore aniso clamp. This flag is /// here for native backends so they can comunicate to the user of aniso is enabled. - const ANISOTROPIC_FILTERING = 1 << 11; + /// + /// All backends and all devices support anisotropic filtering. + const ANISOTROPIC_FILTERING = 1 << 10; /// Supports storage buffers in fragment shaders. - const FRAGMENT_STORAGE = 1 << 12; + const FRAGMENT_STORAGE = 1 << 11; + + /// Supports sample-rate shading. + const MULTISAMPLED_SHADING = 1 << 12; - /// Supports sample shading and multisample interpolation. - const MULTISAMPLED_SHADING = 1 << 13; } }