From 81794e2a03fa44c35bd18ddd267866a76aaf0e67 Mon Sep 17 00:00:00 2001 From: Connor Fitzgerald Date: Wed, 23 Feb 2022 23:56:16 -0500 Subject: [PATCH 01/13] Add DownlevelFlag to prevent copies between Depth32 Textures --- wgpu-core/src/command/transfer.rs | 16 ++++- wgpu-hal/src/gles/adapter.rs | 30 +++++++++ wgpu-hal/src/gles/device.rs | 8 +-- wgpu-hal/src/gles/mod.rs | 2 + wgpu-hal/src/gles/queue.rs | 7 +- wgpu-types/src/lib.rs | 4 ++ wgpu/tests/zero_init_texture_after_discard.rs | 65 ++++++++++--------- 7 files changed, 94 insertions(+), 38 deletions(-) diff --git a/wgpu-core/src/command/transfer.rs b/wgpu-core/src/command/transfer.rs index 9e19828375..1033feecee 100644 --- a/wgpu-core/src/command/transfer.rs +++ b/wgpu-core/src/command/transfer.rs @@ -3,7 +3,7 @@ use crate::device::trace::Command as TraceCommand; use crate::{ command::{CommandBuffer, CommandEncoderError}, conv, - device::Device, + device::{Device, MissingDownlevelFlags}, error::{ErrorFormatter, PrettyError}, hub::{Global, GlobalIdentityHandlerFactory, HalApi, Storage, Token}, id::{BufferId, CommandEncoderId, Id, TextureId, Valid}, @@ -108,6 +108,8 @@ pub enum TransferError { }, #[error(transparent)] MemoryInitFailure(#[from] super::ClearError), + #[error("Cannot encode this copy because of a missing downelevel flag")] + MissingDownlevelFlags(#[from] MissingDownlevelFlags), } impl PrettyError for TransferError { @@ -839,6 +841,18 @@ impl Global { ); } + if format_desc.sample_type == wgt::TextureSampleType::Depth + && !device + .downlevel + .flags + .contains(wgt::DownlevelFlags::DEPTH_TEXTURE_AND_BUFFER_COPIES) + { + return Err(TransferError::MissingDownlevelFlags(MissingDownlevelFlags( + wgt::DownlevelFlags::DEPTH_TEXTURE_AND_BUFFER_COPIES, + )) + .into()); + } + cmd_buf .buffer_memory_init_actions .extend(dst_buffer.initialization_status.create_action( diff --git a/wgpu-hal/src/gles/adapter.rs b/wgpu-hal/src/gles/adapter.rs index e599b428df..6f1c3455ce 100644 --- a/wgpu-hal/src/gles/adapter.rs +++ b/wgpu-hal/src/gles/adapter.rs @@ -359,6 +359,10 @@ impl super::Adapter { super::PrivateCapabilities::CAN_DISABLE_DRAW_BUFFER, !cfg!(target_arch = "wasm32"), ); + private_caps.set( + super::PrivateCapabilities::GET_BUFFER_SUB_DATA, + cfg!(target_arch = "wasm32"), + ); let max_texture_size = gl.get_parameter_i32(glow::MAX_TEXTURE_SIZE) as u32; let max_texture_3d_size = gl.get_parameter_i32(glow::MAX_3D_TEXTURE_SIZE) as u32; @@ -706,6 +710,32 @@ impl crate::Adapter for super::Adapter { } } +impl super::AdapterShared { + pub(super) unsafe fn get_buffer_sub_data( + &self, + gl: &glow::Context, + target: u32, + offset: i32, + dst_data: &mut [u8], + ) { + if self + .private_caps + .contains(super::PrivateCapabilities::GET_BUFFER_SUB_DATA) + { + gl.get_buffer_sub_data(target, offset, dst_data); + } else { + log::error!("Fake map"); + let length = dst_data.len(); + let buffer_mapping = + gl.map_buffer_range(target, offset, length as _, glow::MAP_READ_BIT); + + std::ptr::copy_nonoverlapping(buffer_mapping, dst_data.as_mut_ptr(), length); + + gl.unmap_buffer(target); + } + } +} + // SAFE: WASM doesn't have threads #[cfg(target_arch = "wasm32")] unsafe impl Sync for super::Adapter {} diff --git a/wgpu-hal/src/gles/device.rs b/wgpu-hal/src/gles/device.rs index 628eaf0929..29a6155f14 100644 --- a/wgpu-hal/src/gles/device.rs +++ b/wgpu-hal/src/gles/device.rs @@ -457,7 +457,7 @@ impl crate::Device for super::Device { let ptr = if let Some(ref map_read_allocation) = buffer.data { let mut guard = map_read_allocation.lock().unwrap(); let slice = guard.as_mut_slice(); - gl.get_buffer_sub_data(buffer.target, 0, slice); + self.shared.get_buffer_sub_data(gl, buffer.target, 0, slice); slice.as_mut_ptr() } else { gl.map_buffer_range( @@ -478,11 +478,7 @@ impl crate::Device for super::Device { } unsafe fn unmap_buffer(&self, buffer: &super::Buffer) -> Result<(), crate::DeviceError> { if let Some(raw) = buffer.raw { - if !self - .shared - .workarounds - .contains(super::Workarounds::EMULATE_BUFFER_MAP) - { + if buffer.data.is_none() { let gl = &self.shared.context.lock(); gl.bind_buffer(buffer.target, Some(raw)); gl.unmap_buffer(buffer.target); diff --git a/wgpu-hal/src/gles/mod.rs b/wgpu-hal/src/gles/mod.rs index c48225f6d6..d62799814f 100644 --- a/wgpu-hal/src/gles/mod.rs +++ b/wgpu-hal/src/gles/mod.rs @@ -135,6 +135,8 @@ bitflags::bitflags! { const INDEX_BUFFER_ROLE_CHANGE = 1 << 5; /// Indicates that the device supports disabling draw buffers const CAN_DISABLE_DRAW_BUFFER = 1 << 6; + /// Supports `glGetBufferSubData` + const GET_BUFFER_SUB_DATA = 1 << 7; } } diff --git a/wgpu-hal/src/gles/queue.rs b/wgpu-hal/src/gles/queue.rs index 2c9b9978fb..aef7e77721 100644 --- a/wgpu-hal/src/gles/queue.rs +++ b/wgpu-hal/src/gles/queue.rs @@ -274,7 +274,12 @@ impl super::Queue { [copy.dst_offset as usize..copy.dst_offset as usize + size]; gl.bind_buffer(copy_src_target, Some(src)); - gl.get_buffer_sub_data(copy_src_target, copy.src_offset as i32, dst_data); + self.shared.get_buffer_sub_data( + gl, + copy_src_target, + copy.src_offset as i32, + dst_data, + ); } (None, Some(dst)) => { let data = src.data.as_ref().unwrap().lock().unwrap(); diff --git a/wgpu-types/src/lib.rs b/wgpu-types/src/lib.rs index b1bb6180a1..8f0d402040 100644 --- a/wgpu-types/src/lib.rs +++ b/wgpu-types/src/lib.rs @@ -991,6 +991,10 @@ bitflags::bitflags! { /// Supports sample-rate shading. const MULTISAMPLED_SHADING = 1 << 12; + /// Supports copies between depth textures and buffers. + /// + /// GLES/WebGL don't support this. + const DEPTH_TEXTURE_AND_BUFFER_COPIES = 1 << 13; } } diff --git a/wgpu/tests/zero_init_texture_after_discard.rs b/wgpu/tests/zero_init_texture_after_discard.rs index 74c29340e8..ec77e909f0 100644 --- a/wgpu/tests/zero_init_texture_after_discard.rs +++ b/wgpu/tests/zero_init_texture_after_discard.rs @@ -68,38 +68,43 @@ fn discarding_color_target_resets_texture_init_state_check_visible_on_copy_in_sa #[test] fn discarding_depth_target_resets_texture_init_state_check_visible_on_copy_in_same_encoder() { - initialize_test(TestParameters::default(), |ctx| { - for format in [ - wgpu::TextureFormat::Depth32Float, - //wgpu::TextureFormat::Depth24Plus, // Can't copy to or from buffer - //wgpu::TextureFormat::Depth24PlusStencil8, // Can only copy stencil aspect to/from buffer - ] { - let (texture, readback_buffer) = create_white_texture_and_readback_buffer(&ctx, format); - { - let mut encoder = ctx - .device - .create_command_encoder(&wgpu::CommandEncoderDescriptor::default()); - encoder.begin_render_pass(&wgpu::RenderPassDescriptor { - label: Some("Depth Discard"), - color_attachments: &[], - depth_stencil_attachment: Some(wgpu::RenderPassDepthStencilAttachment { - view: &texture.create_view(&wgpu::TextureViewDescriptor::default()), - depth_ops: Some(wgpu::Operations { - load: wgpu::LoadOp::Load, - store: false, // discard! - }), - stencil_ops: Some(wgpu::Operations { - load: wgpu::LoadOp::Load, - store: false, // discard! + initialize_test( + TestParameters::default() + .downlevel_flags(wgpu::DownlevelFlags::DEPTH_TEXTURE_AND_BUFFER_COPIES), + |ctx| { + for format in [ + wgpu::TextureFormat::Depth32Float, + //wgpu::TextureFormat::Depth24Plus, // Can't copy to or from buffer + //wgpu::TextureFormat::Depth24PlusStencil8, // Can only copy stencil aspect to/from buffer + ] { + let (texture, readback_buffer) = + create_white_texture_and_readback_buffer(&ctx, format); + { + let mut encoder = ctx + .device + .create_command_encoder(&wgpu::CommandEncoderDescriptor::default()); + encoder.begin_render_pass(&wgpu::RenderPassDescriptor { + label: Some("Depth Discard"), + color_attachments: &[], + depth_stencil_attachment: Some(wgpu::RenderPassDepthStencilAttachment { + view: &texture.create_view(&wgpu::TextureViewDescriptor::default()), + depth_ops: Some(wgpu::Operations { + load: wgpu::LoadOp::Load, + store: false, // discard! + }), + stencil_ops: Some(wgpu::Operations { + load: wgpu::LoadOp::Load, + store: false, // discard! + }), }), - }), - }); - copy_texture_to_buffer(&mut encoder, &texture, &readback_buffer); - ctx.queue.submit([encoder.finish()]); + }); + copy_texture_to_buffer(&mut encoder, &texture, &readback_buffer); + ctx.queue.submit([encoder.finish()]); + } + assert_buffer_is_zero(&readback_buffer, &ctx.device); } - assert_buffer_is_zero(&readback_buffer, &ctx.device); - } - }); + }, + ); } #[test] From aa0a0faf439e78b8737a52a852fc9ac2760e3836 Mon Sep 17 00:00:00 2001 From: Connor Fitzgerald Date: Thu, 24 Feb 2022 02:32:29 -0500 Subject: [PATCH 02/13] Fill out GLES texture capability table --- wgpu-hal/src/gles/adapter.rs | 90 ++++++++++++++++++++++-------------- 1 file changed, 55 insertions(+), 35 deletions(-) diff --git a/wgpu-hal/src/gles/adapter.rs b/wgpu-hal/src/gles/adapter.rs index 6f1c3455ce..ae76bce77a 100644 --- a/wgpu-hal/src/gles/adapter.rs +++ b/wgpu-hal/src/gles/adapter.rs @@ -601,35 +601,59 @@ impl crate::Adapter for super::Adapter { use crate::TextureFormatCapabilities as Tfc; use wgt::TextureFormat as Tf; - // The storage types are sprinkled based on section - // "TEXTURE IMAGE LOADS AND STORES" of GLES-3.2 spec. - let unfiltered_color = - Tfc::SAMPLED | Tfc::COLOR_ATTACHMENT | Tfc::MULTISAMPLE | Tfc::MULTISAMPLE_RESOLVE; - let filtered_color = unfiltered_color | Tfc::SAMPLED_LINEAR | Tfc::COLOR_ATTACHMENT_BLEND; + // Base types are pulled from the table in the OpenGLES 3.0 spec in section 3.8. + // + // The storage types are based on table 8.26, in section + // "TEXTURE IMAGE LOADS AND STORES" of OpenGLES-3.2 spec. + let empty = Tfc::empty(); + let unfilterable = Tfc::SAMPLED; + let depth = Tfc::SAMPLED | Tfc::DEPTH_STENCIL_ATTACHMENT; + let filterable = unfilterable | Tfc::SAMPLED_LINEAR; + let renderable = + unfilterable | Tfc::COLOR_ATTACHMENT | Tfc::MULTISAMPLE | Tfc::MULTISAMPLE_RESOLVE; + let filterable_renderable = filterable | renderable | Tfc::COLOR_ATTACHMENT_BLEND; + let storage = Tfc::STORAGE | Tfc::STORAGE_READ_WRITE; match format { - Tf::R8Unorm | Tf::R8Snorm => filtered_color, - Tf::R8Uint | Tf::R8Sint | Tf::R16Uint | Tf::R16Sint => unfiltered_color, - Tf::R16Float | Tf::Rg8Unorm | Tf::Rg8Snorm => filtered_color, - Tf::Rg8Uint | Tf::Rg8Sint | Tf::R32Uint | Tf::R32Sint => { - unfiltered_color | Tfc::STORAGE - } - Tf::R16Unorm | Tf::Rg16Unorm | Tf::Rgba16Unorm => filtered_color, - Tf::R16Snorm | Tf::Rg16Snorm | Tf::Rgba16Snorm => filtered_color, - Tf::R32Float => unfiltered_color, - Tf::Rg16Uint | Tf::Rg16Sint => unfiltered_color, - Tf::Rg16Float | Tf::Rgba8Unorm | Tf::Rgba8UnormSrgb => filtered_color | Tfc::STORAGE, - Tf::Bgra8UnormSrgb | Tf::Rgba8Snorm | Tf::Bgra8Unorm => filtered_color, - Tf::Rgba8Uint | Tf::Rgba8Sint => unfiltered_color | Tfc::STORAGE, - Tf::Rgb10a2Unorm | Tf::Rg11b10Float => filtered_color, - Tf::Rg32Uint | Tf::Rg32Sint => unfiltered_color, - Tf::Rg32Float => unfiltered_color | Tfc::STORAGE, - Tf::Rgba16Uint | Tf::Rgba16Sint => unfiltered_color | Tfc::STORAGE, - Tf::Rgba16Float => filtered_color | Tfc::STORAGE, - Tf::Rgba32Uint | Tf::Rgba32Sint => unfiltered_color | Tfc::STORAGE, - Tf::Rgba32Float => unfiltered_color | Tfc::STORAGE, - Tf::Depth32Float => Tfc::SAMPLED | Tfc::DEPTH_STENCIL_ATTACHMENT, - Tf::Depth24Plus => Tfc::SAMPLED | Tfc::DEPTH_STENCIL_ATTACHMENT, - Tf::Depth24PlusStencil8 => Tfc::SAMPLED | Tfc::DEPTH_STENCIL_ATTACHMENT, + Tf::R8Unorm => filterable_renderable, + Tf::R8Snorm => filterable, + Tf::R8Uint => renderable, + Tf::R8Sint => renderable, + Tf::R16Uint => renderable, + Tf::R16Sint => renderable, + Tf::R16Unorm => empty, + Tf::R16Snorm => empty, + Tf::R16Float => filterable, + Tf::Rg8Unorm => filterable_renderable, + Tf::Rg8Snorm => filterable, + Tf::Rg8Uint => renderable, + Tf::Rg8Sint => renderable, + Tf::R32Uint => renderable | storage, + Tf::R32Sint => renderable | storage, + Tf::R32Float => unfilterable | storage, + Tf::Rg16Uint => renderable, + Tf::Rg16Sint => renderable, + Tf::Rg16Unorm => empty, + Tf::Rg16Snorm => empty, + Tf::Rg16Float => filterable, + Tf::Rgba8Unorm | Tf::Rgba8UnormSrgb => filterable_renderable | storage, + Tf::Bgra8Unorm | Tf::Bgra8UnormSrgb => filterable_renderable, + Tf::Rgba8Snorm => filterable, + Tf::Rgba8Uint => renderable | storage, + Tf::Rgba8Sint => renderable | storage, + Tf::Rgb10a2Unorm => filterable_renderable, + Tf::Rg11b10Float => filterable, + Tf::Rg32Uint => renderable, + Tf::Rg32Sint => renderable, + Tf::Rg32Float => unfilterable, + Tf::Rgba16Uint => renderable | storage, + Tf::Rgba16Sint => renderable | storage, + Tf::Rgba16Unorm => empty, + Tf::Rgba16Snorm => empty, + Tf::Rgba16Float => filterable | storage, + Tf::Rgba32Uint => renderable | storage, + Tf::Rgba32Sint => renderable | storage, + Tf::Rgba32Float => unfilterable | storage, + Tf::Depth32Float | Tf::Depth24Plus | Tf::Depth24PlusStencil8 => depth, Tf::Rgb9e5Ufloat | Tf::Bc1RgbaUnorm | Tf::Bc1RgbaUnormSrgb @@ -657,16 +681,12 @@ impl crate::Adapter for super::Adapter { | Tf::EacRg11Snorm | Tf::Astc { block: _, - channel: AstcChannel::Unorm, - } - | Tf::Astc { - block: _, - channel: AstcChannel::UnormSrgb, - } => Tfc::SAMPLED | Tfc::SAMPLED_LINEAR, + channel: AstcChannel::Unorm | AstcChannel::UnormSrgb, + } => filterable, Tf::Astc { block: _, channel: AstcChannel::Hdr, - } => unimplemented!(), + } => empty, } } From c39af7dfd26576425a79e49893ce27c26b2b9df8 Mon Sep 17 00:00:00 2001 From: Connor Fitzgerald Date: Thu, 24 Feb 2022 14:52:17 -0500 Subject: [PATCH 03/13] Mark expectant test failures on ANGLE --- wgpu/examples/shadow/main.rs | 1 + wgpu/examples/skybox/main.rs | 21 ++++++++++++++++++--- wgpu/tests/clear_texture.rs | 6 +++--- 3 files changed, 22 insertions(+), 6 deletions(-) diff --git a/wgpu/examples/shadow/main.rs b/wgpu/examples/shadow/main.rs index b6219f6b71..6e6ce9bb93 100644 --- a/wgpu/examples/shadow/main.rs +++ b/wgpu/examples/shadow/main.rs @@ -859,6 +859,7 @@ fn shadow() { optional_features: wgpu::Features::default(), base_test_parameters: framework::test_common::TestParameters::default() .downlevel_flags(wgpu::DownlevelFlags::COMPARISON_SAMPLERS) + .backend_failure(wgpu::Backends::GL) // https://github.com/gfx-rs/naga/issues/1747 .specific_failure(Some(wgpu::Backends::VULKAN), None, Some("V3D"), false), // rpi4 on VK doesn't work: https://gitlab.freedesktop.org/mesa/mesa/-/issues/3916 tolerance: 2, max_outliers: 500, // bounded by rpi4 diff --git a/wgpu/examples/skybox/main.rs b/wgpu/examples/skybox/main.rs index a1608227cf..643fb04fd1 100644 --- a/wgpu/examples/skybox/main.rs +++ b/wgpu/examples/skybox/main.rs @@ -490,7 +490,12 @@ fn skybox_bc1() { width: 1024, height: 768, optional_features: wgpu::Features::TEXTURE_COMPRESSION_BC, - base_test_parameters: framework::test_common::TestParameters::default(), + base_test_parameters: framework::test_common::TestParameters::default().specific_failure( + Some(wgpu::Backends::GL), + None, + Some("ANGLE"), + true, + ), // https://bugs.chromium.org/p/angleproject/issues/detail?id=7056 tolerance: 5, max_outliers: 10, }); @@ -503,7 +508,12 @@ fn skybox_etc2() { width: 1024, height: 768, optional_features: wgpu::Features::TEXTURE_COMPRESSION_ETC2, - base_test_parameters: framework::test_common::TestParameters::default(), + base_test_parameters: framework::test_common::TestParameters::default().specific_failure( + Some(wgpu::Backends::GL), + None, + Some("ANGLE"), + true, + ), // https://bugs.chromium.org/p/angleproject/issues/detail?id=7056 tolerance: 5, max_outliers: 105, // Bounded by llvmpipe }); @@ -516,7 +526,12 @@ fn skybox_astc() { width: 1024, height: 768, optional_features: wgpu::Features::TEXTURE_COMPRESSION_ASTC_LDR, - base_test_parameters: framework::test_common::TestParameters::default(), + base_test_parameters: framework::test_common::TestParameters::default().specific_failure( + Some(wgpu::Backends::GL), + None, + Some("ANGLE"), + true, + ), // https://bugs.chromium.org/p/angleproject/issues/detail?id=7056 tolerance: 5, max_outliers: 300, // Bounded by rp4 on vk }); diff --git a/wgpu/tests/clear_texture.rs b/wgpu/tests/clear_texture.rs index 788a37b12b..26f0a331c5 100644 --- a/wgpu/tests/clear_texture.rs +++ b/wgpu/tests/clear_texture.rs @@ -315,7 +315,7 @@ fn clear_texture_2d_bc() { initialize_test( TestParameters::default() .features(wgpu::Features::CLEAR_TEXTURE | wgpu::Features::TEXTURE_COMPRESSION_BC) - .specific_failure(Some(wgpu::Backends::GL), None, None, true), + .specific_failure(Some(wgpu::Backends::GL), None, Some("ANGLE"), true), // https://bugs.chromium.org/p/angleproject/issues/detail?id=7056 |ctx| { clear_texture_tests(&ctx, TEXTURE_FORMATS_BC, false, true); }, @@ -327,7 +327,7 @@ fn clear_texture_2d_astc() { initialize_test( TestParameters::default() .features(wgpu::Features::CLEAR_TEXTURE | wgpu::Features::TEXTURE_COMPRESSION_ASTC_LDR) - .specific_failure(Some(wgpu::Backends::GL), None, None, true), + .specific_failure(Some(wgpu::Backends::GL), None, Some("ANGLE"), true), // https://bugs.chromium.org/p/angleproject/issues/detail?id=7056 |ctx| { clear_texture_tests(&ctx, TEXTURE_FORMATS_ASTC, false, true); }, @@ -339,7 +339,7 @@ fn clear_texture_2d_etc2() { initialize_test( TestParameters::default() .features(wgpu::Features::CLEAR_TEXTURE | wgpu::Features::TEXTURE_COMPRESSION_ETC2) - .specific_failure(Some(wgpu::Backends::GL), None, None, true), + .specific_failure(Some(wgpu::Backends::GL), None, Some("ANGLE"), true), // https://bugs.chromium.org/p/angleproject/issues/detail?id=7056 |ctx| { clear_texture_tests(&ctx, TEXTURE_FORMATS_ETC2, false, true); }, From 8fd5940745dafa67a918cddf238e2e39d22845ea Mon Sep 17 00:00:00 2001 From: Connor Fitzgerald Date: Thu, 24 Feb 2022 14:52:51 -0500 Subject: [PATCH 04/13] Re-enable GL tests in CI --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index fed4fd574c..7a9f8489e6 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -66,7 +66,7 @@ jobs: target: x86_64-unknown-linux-gnu tool: clippy kind: local - backends: vulkan # gl + backends: vulkan gl nextest_url: https://get.nexte.st/latest/linux - name: Linux aarch64 From 5a5f2d357b243437a3ea01bbdd1f622ebc02946a Mon Sep 17 00:00:00 2001 From: Connor Fitzgerald Date: Thu, 24 Feb 2022 16:20:53 -0500 Subject: [PATCH 05/13] Implement validation canary --- wgpu-hal/src/dx12/instance.rs | 4 ++-- wgpu-hal/src/gles/egl.rs | 3 ++- wgpu-hal/src/lib.rs | 34 +++++++++++++++++++++++++++++++++ wgpu-hal/src/vulkan/instance.rs | 6 ++++-- wgpu/examples/skybox/main.rs | 6 +++--- wgpu/tests/clear_texture.rs | 6 +++--- wgpu/tests/common/mod.rs | 29 ++++++++++++++++++++-------- 7 files changed, 69 insertions(+), 19 deletions(-) diff --git a/wgpu-hal/src/dx12/instance.rs b/wgpu-hal/src/dx12/instance.rs index e430d48d3d..26f0796509 100644 --- a/wgpu-hal/src/dx12/instance.rs +++ b/wgpu-hal/src/dx12/instance.rs @@ -61,8 +61,8 @@ unsafe extern "system" fn output_debug_string_handler( log::log!(level, "{}", message); if cfg!(debug_assertions) && level == log::Level::Error { - // Panicking behind FFI is UB, so we just exit. - std::process::exit(1); + // Set canary and continue + crate::VALIDATION_CANARY.set(); } excpt::EXCEPTION_CONTINUE_EXECUTION diff --git a/wgpu-hal/src/gles/egl.rs b/wgpu-hal/src/gles/egl.rs index 1c3f545a87..87cb633c30 100644 --- a/wgpu-hal/src/gles/egl.rs +++ b/wgpu-hal/src/gles/egl.rs @@ -272,7 +272,8 @@ fn gl_debug_message_callback(source: u32, gltype: u32, id: u32, severity: u32, m ); if cfg!(debug_assertions) && log_severity == log::Level::Error { - std::process::exit(1); + // Set canary and continue + crate::VALIDATION_CANARY.set(); } } diff --git a/wgpu-hal/src/lib.rs b/wgpu-hal/src/lib.rs index feb7bf7773..d6bd281677 100644 --- a/wgpu-hal/src/lib.rs +++ b/wgpu-hal/src/lib.rs @@ -84,6 +84,7 @@ use std::{ num::{NonZeroU32, NonZeroU8}, ops::{Range, RangeInclusive}, ptr::NonNull, + sync::atomic::AtomicBool, }; use bitflags::bitflags; @@ -1148,6 +1149,39 @@ pub struct ComputePassDescriptor<'a> { pub label: Label<'a>, } +/// Stores if any API validation error has occurred in this process +/// since it was last reset. +/// +/// This is used for internal wgpu testing only and _must not_ be used +/// as a way to check for errors. +/// +/// This works as a static because `cargo nextest` runs all of our +/// tests in separate processes, so each test gets its own canary. +/// +/// This prevents the issue of one validation error terminating the +/// entire process. +pub static VALIDATION_CANARY: ValidationCanary = ValidationCanary { + inner: AtomicBool::new(false), +}; + +/// Flag for internal testing. +pub struct ValidationCanary { + inner: AtomicBool, +} + +impl ValidationCanary { + #[allow(dead_code)] // in some configurations this function is dead + fn set(&self) { + self.inner.store(true, std::sync::atomic::Ordering::SeqCst); + } + + /// Returns true if any API validation error has occurred in this process + /// since the last call to this function. + pub fn get_and_reset(&self) -> bool { + self.inner.swap(false, std::sync::atomic::Ordering::SeqCst) + } +} + #[test] fn test_default_limits() { let limits = wgt::Limits::default(); diff --git a/wgpu-hal/src/vulkan/instance.rs b/wgpu-hal/src/vulkan/instance.rs index 3cc304307a..25b9b32662 100644 --- a/wgpu-hal/src/vulkan/instance.rs +++ b/wgpu-hal/src/vulkan/instance.rs @@ -102,8 +102,10 @@ unsafe extern "system" fn debug_utils_messenger_callback( log::log!(level, "\tobjects: {}", names.join(", ")); } - // uncommenting this is useful for tests - //assert_ne!(level, log::Level::Error); + if cfg!(debug_assertions) && level == log::Level::Error { + // Set canary and continue + crate::VALIDATION_CANARY.set(); + } vk::FALSE } diff --git a/wgpu/examples/skybox/main.rs b/wgpu/examples/skybox/main.rs index 643fb04fd1..0343bd4313 100644 --- a/wgpu/examples/skybox/main.rs +++ b/wgpu/examples/skybox/main.rs @@ -494,7 +494,7 @@ fn skybox_bc1() { Some(wgpu::Backends::GL), None, Some("ANGLE"), - true, + false, ), // https://bugs.chromium.org/p/angleproject/issues/detail?id=7056 tolerance: 5, max_outliers: 10, @@ -512,7 +512,7 @@ fn skybox_etc2() { Some(wgpu::Backends::GL), None, Some("ANGLE"), - true, + false, ), // https://bugs.chromium.org/p/angleproject/issues/detail?id=7056 tolerance: 5, max_outliers: 105, // Bounded by llvmpipe @@ -530,7 +530,7 @@ fn skybox_astc() { Some(wgpu::Backends::GL), None, Some("ANGLE"), - true, + false, ), // https://bugs.chromium.org/p/angleproject/issues/detail?id=7056 tolerance: 5, max_outliers: 300, // Bounded by rp4 on vk diff --git a/wgpu/tests/clear_texture.rs b/wgpu/tests/clear_texture.rs index 26f0a331c5..269c5da62c 100644 --- a/wgpu/tests/clear_texture.rs +++ b/wgpu/tests/clear_texture.rs @@ -315,7 +315,7 @@ fn clear_texture_2d_bc() { initialize_test( TestParameters::default() .features(wgpu::Features::CLEAR_TEXTURE | wgpu::Features::TEXTURE_COMPRESSION_BC) - .specific_failure(Some(wgpu::Backends::GL), None, Some("ANGLE"), true), // https://bugs.chromium.org/p/angleproject/issues/detail?id=7056 + .specific_failure(Some(wgpu::Backends::GL), None, Some("ANGLE"), false), // https://bugs.chromium.org/p/angleproject/issues/detail?id=7056 |ctx| { clear_texture_tests(&ctx, TEXTURE_FORMATS_BC, false, true); }, @@ -327,7 +327,7 @@ fn clear_texture_2d_astc() { initialize_test( TestParameters::default() .features(wgpu::Features::CLEAR_TEXTURE | wgpu::Features::TEXTURE_COMPRESSION_ASTC_LDR) - .specific_failure(Some(wgpu::Backends::GL), None, Some("ANGLE"), true), // https://bugs.chromium.org/p/angleproject/issues/detail?id=7056 + .specific_failure(Some(wgpu::Backends::GL), None, Some("ANGLE"), false), // https://bugs.chromium.org/p/angleproject/issues/detail?id=7056 |ctx| { clear_texture_tests(&ctx, TEXTURE_FORMATS_ASTC, false, true); }, @@ -339,7 +339,7 @@ fn clear_texture_2d_etc2() { initialize_test( TestParameters::default() .features(wgpu::Features::CLEAR_TEXTURE | wgpu::Features::TEXTURE_COMPRESSION_ETC2) - .specific_failure(Some(wgpu::Backends::GL), None, Some("ANGLE"), true), // https://bugs.chromium.org/p/angleproject/issues/detail?id=7056 + .specific_failure(Some(wgpu::Backends::GL), None, Some("ANGLE"), false), // https://bugs.chromium.org/p/angleproject/issues/detail?id=7056 |ctx| { clear_texture_tests(&ctx, TEXTURE_FORMATS_ETC2, false, true); }, diff --git a/wgpu/tests/common/mod.rs b/wgpu/tests/common/mod.rs index 0cf7a6a6f6..a98de71ac6 100644 --- a/wgpu/tests/common/mod.rs +++ b/wgpu/tests/common/mod.rs @@ -221,7 +221,7 @@ pub fn initialize_test(parameters: TestParameters, test_function: impl FnOnce(Te queue, }; - let failure_reason = parameters.failures.iter().find_map(|failure| { + let expected_failure_reason = parameters.failures.iter().find_map(|failure| { let always = failure.backends.is_none() && failure.vendor.is_none() && failure.adapter.is_none(); @@ -261,25 +261,38 @@ pub fn initialize_test(parameters: TestParameters, test_function: impl FnOnce(Te } }); - if let Some((reason, true)) = failure_reason { + if let Some((reason, true)) = expected_failure_reason { println!("EXPECTED TEST FAILURE SKIPPED: {:?}", reason); return; } let panicked = catch_unwind(AssertUnwindSafe(|| test_function(context))).is_err(); + let canary_set = hal::VALIDATION_CANARY.get_and_reset(); - let expect_failure = failure_reason.is_some(); + let failed = panicked || canary_set; - if panicked == expect_failure { + let failure_cause = match (panicked, canary_set) { + (true, true) => "PANIC AND VALIDATION ERROR", + (true, false) => "PANIC", + (false, true) => "VALIDATION ERROR", + (false, false) => "", + }; + + let expect_failure = expected_failure_reason.is_some(); + + if failed == expect_failure { // We got the conditions we expected - if let Some((reason, _)) = failure_reason { + if let Some((expected_reason, _)) = expected_failure_reason { // Print out reason for the failure - println!("GOT EXPECTED TEST FAILURE: {:?}", reason); + println!( + "GOT EXPECTED TEST FAILURE DUE TO {}: {:?}", + failure_cause, expected_reason + ); } - } else if let Some((reason, _)) = failure_reason { + } else if let Some((reason, _)) = expected_failure_reason { // We expected to fail, but things passed panic!("UNEXPECTED TEST PASS: {:?}", reason); } else { - panic!("UNEXPECTED TEST FAILURE") + panic!("UNEXPECTED TEST FAILURE DUE TO {}", failure_cause) } } From 8a28259d8143fd2f6b1de6a37c4f99519e01405b Mon Sep 17 00:00:00 2001 From: Connor Fitzgerald Date: Thu, 24 Feb 2022 16:51:10 -0500 Subject: [PATCH 06/13] Prevent 3D compressed textures --- wgpu-core/src/device/mod.rs | 10 ++++++++- wgpu-core/src/resource.rs | 6 ++++-- wgpu/tests/clear_texture.rs | 42 ++++++++++++++++++------------------- 3 files changed, 33 insertions(+), 25 deletions(-) diff --git a/wgpu-core/src/device/mod.rs b/wgpu-core/src/device/mod.rs index 2699878169..4936d97adc 100644 --- a/wgpu-core/src/device/mod.rs +++ b/wgpu-core/src/device/mod.rs @@ -642,7 +642,7 @@ impl Device { if desc.dimension != wgt::TextureDimension::D2 { // Depth textures can only be 2D if format_desc.sample_type == wgt::TextureSampleType::Depth { - return Err(resource::CreateTextureError::InvalidDepthKind( + return Err(resource::CreateTextureError::InvalidDepthDimension( desc.dimension, desc.format, )); @@ -654,6 +654,14 @@ impl Device { desc.dimension, )); } + + // Compressed textures can only be 2D + if format_desc.is_compressed() { + return Err(resource::CreateTextureError::InvalidCompressedDimension( + desc.dimension, + desc.format, + )); + } } let format_features = self diff --git a/wgpu-core/src/resource.rs b/wgpu-core/src/resource.rs index f970cd1028..3f12aba0d5 100644 --- a/wgpu-core/src/resource.rs +++ b/wgpu-core/src/resource.rs @@ -299,8 +299,10 @@ pub enum CreateTextureError { EmptyUsage, #[error(transparent)] InvalidDimension(#[from] TextureDimensionError), - #[error("Depth texture kind {0:?} of format {0:?} can't be created")] - InvalidDepthKind(wgt::TextureDimension, wgt::TextureFormat), + #[error("Depth texture ({1:?}) can't be created as {0:?}")] + InvalidDepthDimension(wgt::TextureDimension, wgt::TextureFormat), + #[error("Compressed texture ({1:?}) can't be created as {0:?}")] + InvalidCompressedDimension(wgt::TextureDimension, wgt::TextureFormat), #[error( "Texture descriptor mip level count {requested} is invalid, maximum allowed is {maximum}" )] diff --git a/wgpu/tests/clear_texture.rs b/wgpu/tests/clear_texture.rs index 269c5da62c..9a15a41274 100644 --- a/wgpu/tests/clear_texture.rs +++ b/wgpu/tests/clear_texture.rs @@ -270,31 +270,29 @@ fn clear_texture_tests( }, 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, + ); if supports_3d { - // 2D array texture + // volume texture single_texture_clear_test( ctx, format, wgpu::Extent3d { - width: 64, - height: 64, - depth_or_array_layers: 4, + width: 16, + height: 16, + depth_or_array_layers: 16, }, - wgpu::TextureDimension::D2, + wgpu::TextureDimension::D3, ); - // 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, - ); - } } } } @@ -305,7 +303,7 @@ fn clear_texture_2d_uncompressed() { TestParameters::default().features(wgpu::Features::CLEAR_TEXTURE), |ctx| { clear_texture_tests(&ctx, TEXTURE_FORMATS_UNCOMPRESSED, true, true); - clear_texture_tests(&ctx, TEXTURE_FORMATS_DEPTH, false, true); + clear_texture_tests(&ctx, TEXTURE_FORMATS_DEPTH, false, false); }, ) } @@ -317,7 +315,7 @@ fn clear_texture_2d_bc() { .features(wgpu::Features::CLEAR_TEXTURE | wgpu::Features::TEXTURE_COMPRESSION_BC) .specific_failure(Some(wgpu::Backends::GL), None, Some("ANGLE"), false), // https://bugs.chromium.org/p/angleproject/issues/detail?id=7056 |ctx| { - clear_texture_tests(&ctx, TEXTURE_FORMATS_BC, false, true); + clear_texture_tests(&ctx, TEXTURE_FORMATS_BC, false, false); }, ) } @@ -329,7 +327,7 @@ fn clear_texture_2d_astc() { .features(wgpu::Features::CLEAR_TEXTURE | wgpu::Features::TEXTURE_COMPRESSION_ASTC_LDR) .specific_failure(Some(wgpu::Backends::GL), None, Some("ANGLE"), false), // https://bugs.chromium.org/p/angleproject/issues/detail?id=7056 |ctx| { - clear_texture_tests(&ctx, TEXTURE_FORMATS_ASTC, false, true); + clear_texture_tests(&ctx, TEXTURE_FORMATS_ASTC, false, false); }, ) } @@ -341,7 +339,7 @@ fn clear_texture_2d_etc2() { .features(wgpu::Features::CLEAR_TEXTURE | wgpu::Features::TEXTURE_COMPRESSION_ETC2) .specific_failure(Some(wgpu::Backends::GL), None, Some("ANGLE"), false), // https://bugs.chromium.org/p/angleproject/issues/detail?id=7056 |ctx| { - clear_texture_tests(&ctx, TEXTURE_FORMATS_ETC2, false, true); + clear_texture_tests(&ctx, TEXTURE_FORMATS_ETC2, false, false); }, ) } From 339c32c94b1e8bf7ec048678fb11205e0a493e1a Mon Sep 17 00:00:00 2001 From: Connor Fitzgerald Date: Thu, 24 Feb 2022 17:15:04 -0500 Subject: [PATCH 07/13] Make texture format info into an in-code table --- wgpu-types/src/lib.rs | 225 +++++++++++++++--------------------------- 1 file changed, 77 insertions(+), 148 deletions(-) diff --git a/wgpu-types/src/lib.rs b/wgpu-types/src/lib.rs index 8f0d402040..7642dd2b57 100644 --- a/wgpu-types/src/lib.rs +++ b/wgpu-types/src/lib.rs @@ -2012,6 +2012,7 @@ impl TextureFormat { let all_flags = TextureUsages::all(); // See for reference + #[rustfmt::skip] // lets make a nice table let ( required_features, sample_type, @@ -2023,159 +2024,95 @@ impl TextureFormat { components, ) = match self { // Normal 8 bit textures - Self::R8Unorm => ( - native, - float, - linear, - msaa_resolve, - (1, 1), - 1, - attachment, - 1, - ), - Self::R8Snorm => (native, float, linear, msaa, (1, 1), 1, basic, 1), - Self::R8Uint => (native, uint, linear, msaa, (1, 1), 1, attachment, 1), - Self::R8Sint => (native, sint, linear, msaa, (1, 1), 1, attachment, 1), + Self::R8Unorm => ( native, float, linear, msaa_resolve, (1, 1), 1, attachment, 1), + Self::R8Snorm => ( native, float, linear, msaa, (1, 1), 1, basic, 1), + Self::R8Uint => ( native, uint, linear, msaa, (1, 1), 1, attachment, 1), + Self::R8Sint => ( native, sint, linear, msaa, (1, 1), 1, attachment, 1), // Normal 16 bit textures - Self::R16Uint => (native, uint, linear, msaa, (1, 1), 2, attachment, 1), - Self::R16Sint => (native, sint, linear, msaa, (1, 1), 2, attachment, 1), - Self::R16Float => ( - native, - float, - linear, - msaa_resolve, - (1, 1), - 2, - attachment, - 1, - ), - Self::Rg8Unorm => ( - native, - float, - linear, - msaa_resolve, - (1, 1), - 2, - attachment, - 2, - ), - Self::Rg8Snorm => (native, float, linear, msaa, (1, 1), 2, attachment, 2), - Self::Rg8Uint => (native, uint, linear, msaa, (1, 1), 2, attachment, 2), - Self::Rg8Sint => (native, sint, linear, msaa, (1, 1), 2, basic, 2), + Self::R16Uint => ( native, uint, linear, msaa, (1, 1), 2, attachment, 1), + Self::R16Sint => ( native, sint, linear, msaa, (1, 1), 2, attachment, 1), + Self::R16Float => ( native, float, linear, msaa_resolve, (1, 1), 2, attachment, 1), + Self::Rg8Unorm => ( native, float, linear, msaa_resolve, (1, 1), 2, attachment, 2), + Self::Rg8Snorm => ( native, float, linear, msaa, (1, 1), 2, attachment, 2), + Self::Rg8Uint => ( native, uint, linear, msaa, (1, 1), 2, attachment, 2), + Self::Rg8Sint => ( native, sint, linear, msaa, (1, 1), 2, basic, 2), // Normal 32 bit textures - Self::R32Uint => (native, uint, linear, noaa, (1, 1), 4, all_flags, 1), - Self::R32Sint => (native, sint, linear, noaa, (1, 1), 4, all_flags, 1), - Self::R32Float => (native, nearest, linear, msaa, (1, 1), 4, all_flags, 1), - Self::Rg16Uint => (native, uint, linear, msaa, (1, 1), 4, attachment, 2), - Self::Rg16Sint => (native, sint, linear, msaa, (1, 1), 4, attachment, 2), - Self::Rg16Float => ( - native, - float, - linear, - msaa_resolve, - (1, 1), - 4, - attachment, - 2, - ), - Self::Rgba8Unorm => (native, float, linear, msaa_resolve, (1, 1), 4, all_flags, 4), - Self::Rgba8UnormSrgb => ( - native, - float, - corrected, - msaa_resolve, - (1, 1), - 4, - attachment, - 4, - ), - Self::Rgba8Snorm => (native, float, linear, msaa, (1, 1), 4, storage, 4), - Self::Rgba8Uint => (native, uint, linear, msaa, (1, 1), 4, all_flags, 4), - Self::Rgba8Sint => (native, sint, linear, msaa, (1, 1), 4, all_flags, 4), - Self::Bgra8Unorm => ( - native, - float, - linear, - msaa_resolve, - (1, 1), - 4, - attachment, - 4, - ), - Self::Bgra8UnormSrgb => ( - native, - float, - corrected, - msaa_resolve, - (1, 1), - 4, - attachment, - 4, - ), + Self::R32Uint => ( native, uint, linear, noaa, (1, 1), 4, all_flags, 1), + Self::R32Sint => ( native, sint, linear, noaa, (1, 1), 4, all_flags, 1), + Self::R32Float => ( native, nearest, linear, msaa, (1, 1), 4, all_flags, 1), + Self::Rg16Uint => ( native, uint, linear, msaa, (1, 1), 4, attachment, 2), + Self::Rg16Sint => ( native, sint, linear, msaa, (1, 1), 4, attachment, 2), + Self::Rg16Float => ( native, float, linear, msaa_resolve, (1, 1), 4, attachment, 2), + Self::Rgba8Unorm => ( native, float, linear, msaa_resolve, (1, 1), 4, all_flags, 4), + Self::Rgba8UnormSrgb => ( native, float, corrected, msaa_resolve, (1, 1), 4, attachment, 4), + Self::Rgba8Snorm => ( native, float, linear, msaa, (1, 1), 4, storage, 4), + Self::Rgba8Uint => ( native, uint, linear, msaa, (1, 1), 4, all_flags, 4), + Self::Rgba8Sint => ( native, sint, linear, msaa, (1, 1), 4, all_flags, 4), + Self::Bgra8Unorm => ( native, float, linear, msaa_resolve, (1, 1), 4, attachment, 4), + Self::Bgra8UnormSrgb => ( native, float, corrected, msaa_resolve, (1, 1), 4, attachment, 4), // Packed 32 bit textures - Self::Rgb10a2Unorm => ( - native, - float, - linear, - msaa_resolve, - (1, 1), - 4, - attachment, - 4, - ), - Self::Rg11b10Float => (native, float, linear, msaa, (1, 1), 4, basic, 3), - - // Packed 32 bit textures - Self::Rg32Uint => (native, uint, linear, noaa, (1, 1), 8, all_flags, 2), - Self::Rg32Sint => (native, sint, linear, noaa, (1, 1), 8, all_flags, 2), - Self::Rg32Float => (native, nearest, linear, noaa, (1, 1), 8, all_flags, 2), - Self::Rgba16Uint => (native, uint, linear, msaa, (1, 1), 8, all_flags, 4), - Self::Rgba16Sint => (native, sint, linear, msaa, (1, 1), 8, all_flags, 4), - Self::Rgba16Float => (native, float, linear, msaa_resolve, (1, 1), 8, all_flags, 4), - - // Packed 32 bit textures - Self::Rgba32Uint => (native, uint, linear, noaa, (1, 1), 16, all_flags, 4), - Self::Rgba32Sint => (native, sint, linear, noaa, (1, 1), 16, all_flags, 4), - Self::Rgba32Float => (native, nearest, linear, noaa, (1, 1), 16, all_flags, 4), + Self::Rgb10a2Unorm => ( native, float, linear, msaa_resolve, (1, 1), 4, attachment, 4), + Self::Rg11b10Float => ( native, float, linear, msaa, (1, 1), 4, basic, 3), + + // Packed 32 bit textures + Self::Rg32Uint => ( native, uint, linear, noaa, (1, 1), 8, all_flags, 2), + Self::Rg32Sint => ( native, sint, linear, noaa, (1, 1), 8, all_flags, 2), + Self::Rg32Float => ( native, nearest, linear, noaa, (1, 1), 8, all_flags, 2), + Self::Rgba16Uint => ( native, uint, linear, msaa, (1, 1), 8, all_flags, 4), + Self::Rgba16Sint => ( native, sint, linear, msaa, (1, 1), 8, all_flags, 4), + Self::Rgba16Float => ( native, float, linear, msaa_resolve, (1, 1), 8, all_flags, 4), + + // Packed 32 bit textures + Self::Rgba32Uint => ( native, uint, linear, noaa, (1, 1), 16, all_flags, 4), + Self::Rgba32Sint => ( native, sint, linear, noaa, (1, 1), 16, all_flags, 4), + Self::Rgba32Float => ( native, nearest, linear, noaa, (1, 1), 16, all_flags, 4), // Depth-stencil textures - Self::Depth32Float => (native, depth, linear, msaa, (1, 1), 4, attachment, 1), - Self::Depth24Plus => (native, depth, linear, msaa, (1, 1), 4, attachment, 1), - Self::Depth24PlusStencil8 => (native, depth, linear, msaa, (1, 1), 4, attachment, 2), + Self::Depth32Float => ( native, depth, linear, msaa, (1, 1), 4, attachment, 1), + Self::Depth24Plus => ( native, depth, linear, msaa, (1, 1), 4, attachment, 1), + Self::Depth24PlusStencil8 => ( native, depth, linear, msaa, (1, 1), 4, attachment, 2), - // Packed uncompressed - Self::Rgb9e5Ufloat => (native, float, linear, noaa, (1, 1), 4, basic, 3), + // Packed uncompressed + Self::Rgb9e5Ufloat => ( native, float, linear, noaa, (1, 1), 4, basic, 3), + + // Optional normalized 16-bit-per-channel formats + Self::R16Unorm => (norm16bit, float, linear, msaa, (1, 1), 2, storage, 1), + Self::R16Snorm => (norm16bit, float, linear, msaa, (1, 1), 2, storage, 1), + Self::Rg16Unorm => (norm16bit, float, linear, msaa, (1, 1), 4, storage, 2), + Self::Rg16Snorm => (norm16bit, float, linear, msaa, (1, 1), 4, storage, 2), + Self::Rgba16Unorm => (norm16bit, float, linear, msaa, (1, 1), 8, storage, 4), + Self::Rgba16Snorm => (norm16bit, float, linear, msaa, (1, 1), 8, storage, 4), // BCn compressed textures - Self::Bc1RgbaUnorm => (bc, float, linear, noaa, (4, 4), 8, basic, 4), - Self::Bc1RgbaUnormSrgb => (bc, float, corrected, noaa, (4, 4), 8, basic, 4), - Self::Bc2RgbaUnorm => (bc, float, linear, noaa, (4, 4), 16, basic, 4), - Self::Bc2RgbaUnormSrgb => (bc, float, corrected, noaa, (4, 4), 16, basic, 4), - Self::Bc3RgbaUnorm => (bc, float, linear, noaa, (4, 4), 16, basic, 4), - Self::Bc3RgbaUnormSrgb => (bc, float, corrected, noaa, (4, 4), 16, basic, 4), - Self::Bc4RUnorm => (bc, float, linear, noaa, (4, 4), 8, basic, 1), - Self::Bc4RSnorm => (bc, float, linear, noaa, (4, 4), 8, basic, 1), - Self::Bc5RgUnorm => (bc, float, linear, noaa, (4, 4), 16, basic, 2), - Self::Bc5RgSnorm => (bc, float, linear, noaa, (4, 4), 16, basic, 2), - Self::Bc6hRgbUfloat => (bc, float, linear, noaa, (4, 4), 16, basic, 3), - Self::Bc6hRgbSfloat => (bc, float, linear, noaa, (4, 4), 16, basic, 3), - Self::Bc7RgbaUnorm => (bc, float, linear, noaa, (4, 4), 16, basic, 4), - Self::Bc7RgbaUnormSrgb => (bc, float, corrected, noaa, (4, 4), 16, basic, 4), + Self::Bc1RgbaUnorm => ( bc, float, linear, noaa, (4, 4), 8, basic, 4), + Self::Bc1RgbaUnormSrgb => ( bc, float, corrected, noaa, (4, 4), 8, basic, 4), + Self::Bc2RgbaUnorm => ( bc, float, linear, noaa, (4, 4), 16, basic, 4), + Self::Bc2RgbaUnormSrgb => ( bc, float, corrected, noaa, (4, 4), 16, basic, 4), + Self::Bc3RgbaUnorm => ( bc, float, linear, noaa, (4, 4), 16, basic, 4), + Self::Bc3RgbaUnormSrgb => ( bc, float, corrected, noaa, (4, 4), 16, basic, 4), + Self::Bc4RUnorm => ( bc, float, linear, noaa, (4, 4), 8, basic, 1), + Self::Bc4RSnorm => ( bc, float, linear, noaa, (4, 4), 8, basic, 1), + Self::Bc5RgUnorm => ( bc, float, linear, noaa, (4, 4), 16, basic, 2), + Self::Bc5RgSnorm => ( bc, float, linear, noaa, (4, 4), 16, basic, 2), + Self::Bc6hRgbUfloat => ( bc, float, linear, noaa, (4, 4), 16, basic, 3), + Self::Bc6hRgbSfloat => ( bc, float, linear, noaa, (4, 4), 16, basic, 3), + Self::Bc7RgbaUnorm => ( bc, float, linear, noaa, (4, 4), 16, basic, 4), + Self::Bc7RgbaUnormSrgb => ( bc, float, corrected, noaa, (4, 4), 16, basic, 4), // ETC compressed textures - Self::Etc2Rgb8Unorm => (etc2, float, linear, noaa, (4, 4), 8, basic, 3), - Self::Etc2Rgb8UnormSrgb => (etc2, float, corrected, noaa, (4, 4), 8, basic, 3), - Self::Etc2Rgb8A1Unorm => (etc2, float, linear, noaa, (4, 4), 8, basic, 4), - Self::Etc2Rgb8A1UnormSrgb => (etc2, float, corrected, noaa, (4, 4), 8, basic, 4), - Self::Etc2Rgba8Unorm => (etc2, float, linear, noaa, (4, 4), 16, basic, 4), - Self::Etc2Rgba8UnormSrgb => (etc2, float, corrected, noaa, (4, 4), 16, basic, 4), - Self::EacR11Unorm => (etc2, float, linear, noaa, (4, 4), 8, basic, 1), - Self::EacR11Snorm => (etc2, float, linear, noaa, (4, 4), 8, basic, 1), - Self::EacRg11Unorm => (etc2, float, linear, noaa, (4, 4), 16, basic, 2), - Self::EacRg11Snorm => (etc2, float, linear, noaa, (4, 4), 16, basic, 2), + Self::Etc2Rgb8Unorm => ( etc2, float, linear, noaa, (4, 4), 8, basic, 3), + Self::Etc2Rgb8UnormSrgb => ( etc2, float, corrected, noaa, (4, 4), 8, basic, 3), + Self::Etc2Rgb8A1Unorm => ( etc2, float, linear, noaa, (4, 4), 8, basic, 4), + Self::Etc2Rgb8A1UnormSrgb => ( etc2, float, corrected, noaa, (4, 4), 8, basic, 4), + Self::Etc2Rgba8Unorm => ( etc2, float, linear, noaa, (4, 4), 16, basic, 4), + Self::Etc2Rgba8UnormSrgb => ( etc2, float, corrected, noaa, (4, 4), 16, basic, 4), + Self::EacR11Unorm => ( etc2, float, linear, noaa, (4, 4), 8, basic, 1), + Self::EacR11Snorm => ( etc2, float, linear, noaa, (4, 4), 8, basic, 1), + Self::EacRg11Unorm => ( etc2, float, linear, noaa, (4, 4), 16, basic, 2), + Self::EacRg11Snorm => ( etc2, float, linear, noaa, (4, 4), 16, basic, 2), // ASTC compressed textures Self::Astc { block, channel } => { @@ -2202,14 +2139,6 @@ impl TextureFormat { }; (feature, float, color_space, noaa, dimensions, 16, basic, 4) } - - // Optional normalized 16-bit-per-channel formats - Self::R16Unorm => (norm16bit, float, linear, msaa, (1, 1), 2, storage, 1), - Self::R16Snorm => (norm16bit, float, linear, msaa, (1, 1), 2, storage, 1), - Self::Rg16Unorm => (norm16bit, float, linear, msaa, (1, 1), 4, storage, 2), - Self::Rg16Snorm => (norm16bit, float, linear, msaa, (1, 1), 4, storage, 2), - Self::Rgba16Unorm => (norm16bit, float, linear, msaa, (1, 1), 8, storage, 4), - Self::Rgba16Snorm => (norm16bit, float, linear, msaa, (1, 1), 8, storage, 4), }; let mut flags = msaa_flags; From 96bdf32e96599289d619c639e89c88aa3a43bd4f Mon Sep 17 00:00:00 2001 From: Connor Fitzgerald Date: Thu, 24 Feb 2022 17:25:11 -0500 Subject: [PATCH 08/13] Install vulkan sdk on CI --- .github/workflows/ci.yml | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 7a9f8489e6..e02534a9a2 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -152,13 +152,20 @@ jobs: run: | echo "$ANDROID_HOME/ndk-bundle/toolchains/llvm/prebuilt/linux-x86_64/bin" >> $GITHUB_PATH - - name: install llvmpipe and lavapipe + - name: install llvmpipe, lavapipe, and vulkan sdk if: matrix.os == 'ubuntu-20.04' && matrix.target != 'aarch64-linux-android' && matrix.kind == 'local' run: | sudo apt-get update -y -qq + + # llvmpipe/lavapipe sudo add-apt-repository ppa:oibaf/graphics-drivers -y + + # vulkan sdk + wget -qO - https://packages.lunarg.com/lunarg-signing-key-pub.asc | sudo apt-key add - + sudo wget -qO /etc/apt/sources.list.d/lunarg-vulkan-focal.list https://packages.lunarg.com/vulkan/lunarg-vulkan-focal.list + sudo apt-get update - sudo apt install -y libegl1-mesa libgl1-mesa-dri libxcb-xfixes0-dev mesa-vulkan-drivers + sudo apt install -y libegl1-mesa libgl1-mesa-dri libxcb-xfixes0-dev mesa-vulkan-drivers vulkan-sdk # We enable line numbers for panics, but that's it - name: disable debug From 799f030003c2b1dd53b7bca9c544c7dd0114f017 Mon Sep 17 00:00:00 2001 From: Connor Fitzgerald Date: Thu, 24 Feb 2022 23:36:36 -0500 Subject: [PATCH 09/13] Prevent uncaught validation error on water example --- wgpu/examples/water/main.rs | 22 +++++++++++++++++++--- wgpu/examples/water/water.wgsl | 3 ++- 2 files changed, 21 insertions(+), 4 deletions(-) diff --git a/wgpu/examples/water/main.rs b/wgpu/examples/water/main.rs index 0a493eefcf..9209c4b6b1 100644 --- a/wgpu/examples/water/main.rs +++ b/wgpu/examples/water/main.rs @@ -215,8 +215,8 @@ impl Example { | wgpu::TextureUsages::RENDER_ATTACHMENT, }); - let sampler = device.create_sampler(&wgpu::SamplerDescriptor { - label: Some("Texture Sampler"), + let color_sampler = device.create_sampler(&wgpu::SamplerDescriptor { + label: Some("Color Sampler"), address_mode_u: wgpu::AddressMode::ClampToEdge, address_mode_v: wgpu::AddressMode::ClampToEdge, address_mode_w: wgpu::AddressMode::ClampToEdge, @@ -226,6 +226,11 @@ impl Example { ..Default::default() }); + let depth_sampler = device.create_sampler(&wgpu::SamplerDescriptor { + label: Some("Depth Sampler"), + ..Default::default() + }); + let depth_view = draw_depth_buffer.create_view(&wgpu::TextureViewDescriptor::default()); let water_bind_group = device.create_bind_group(&wgpu::BindGroupDescriptor { @@ -247,7 +252,11 @@ impl Example { }, wgpu::BindGroupEntry { binding: 3, - resource: wgpu::BindingResource::Sampler(&sampler), + resource: wgpu::BindingResource::Sampler(&color_sampler), + }, + wgpu::BindGroupEntry { + binding: 4, + resource: wgpu::BindingResource::Sampler(&depth_sampler), }, ], label: Some("Water Bind Group"), @@ -394,6 +403,13 @@ impl framework::Example for Example { ty: wgpu::BindingType::Sampler(wgpu::SamplerBindingType::Filtering), count: None, }, + // Sampler to be able to sample the textures. + wgpu::BindGroupLayoutEntry { + binding: 4, + visibility: wgpu::ShaderStages::FRAGMENT, + ty: wgpu::BindingType::Sampler(wgpu::SamplerBindingType::NonFiltering), + count: None, + }, ], }); diff --git a/wgpu/examples/water/water.wgsl b/wgpu/examples/water/water.wgsl index 80daad7d69..6db139039b 100644 --- a/wgpu/examples/water/water.wgsl +++ b/wgpu/examples/water/water.wgsl @@ -225,6 +225,7 @@ let zFar = 400.0; @group(0) @binding(1) var reflection: texture_2d; @group(0) @binding(2) var terrain_depth_tex: texture_2d; @group(0) @binding(3) var colour_sampler: sampler; +@group(0) @binding(4) var depth_sampler: sampler; fn to_linear_depth(depth: f32) -> f32 { let z_n = 2.0 * depth - 1.0; @@ -238,7 +239,7 @@ fn fs_main(in: VertexOutput) -> @location(0) vec4 { let pixel_depth = to_linear_depth(in.position.z); let normalized_coords = in.position.xy / vec2(uniforms.time_size_width.w, uniforms.viewport_height); - let terrain_depth = to_linear_depth(textureSample(terrain_depth_tex, colour_sampler, normalized_coords).r); + let terrain_depth = to_linear_depth(textureSample(terrain_depth_tex, depth_sampler, normalized_coords).r); let dist = terrain_depth - pixel_depth; let clamped = pow(smoothStep(0.0, 1.5, dist), 4.8); From c87015720b30fa7024a012b2ba86931b3945cec4 Mon Sep 17 00:00:00 2001 From: Connor Fitzgerald Date: Fri, 25 Feb 2022 01:28:21 -0500 Subject: [PATCH 10/13] hal/gles: Fix compressed texture stride calculations --- .github/workflows/ci.yml | 2 +- wgpu-hal/src/gles/queue.rs | 52 ++++++++++++++++++++++---------------- 2 files changed, 31 insertions(+), 23 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index e02534a9a2..dfae111931 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -139,7 +139,7 @@ jobs: - name: caching uses: Swatinem/rust-cache@v1 with: - key: ${{ matrix.target }}-a # suffix for cache busting + key: ${{ matrix.target }}-b # suffix for cache busting - name: download nextest if: matrix.kind == 'local' diff --git a/wgpu-hal/src/gles/queue.rs b/wgpu-hal/src/gles/queue.rs index aef7e77721..31c837cdbb 100644 --- a/wgpu-hal/src/gles/queue.rs +++ b/wgpu-hal/src/gles/queue.rs @@ -463,12 +463,18 @@ impl super::Queue { .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 block_height = format_info.block_dimensions.1 as u32; + let minimum_rows_per_image = (copy.size.height + block_height - 1) + / format_info.block_dimensions.1 as u32; + let rows_per_image = copy + .buffer_layout + .rows_per_image + .map_or(minimum_rows_per_image, |rpi| rpi.get()); let bytes_per_image = bytes_per_row * rows_per_image; + let minimum_bytes_per_image = bytes_per_row * minimum_rows_per_image; + let bytes_in_upload = + (bytes_per_image * (copy.size.depth - 1)) + minimum_bytes_per_image; let offset = copy.buffer_layout.offset as u32; let buffer_data; @@ -477,18 +483,35 @@ impl super::Queue { gl.bind_buffer(glow::PIXEL_UNPACK_BUFFER, Some(buffer)); unbind_unpack_buffer = true; glow::CompressedPixelUnpackData::BufferRange( - offset..offset + bytes_per_image, + offset..offset + bytes_in_upload, ) } None => { buffer_data = src.data.as_ref().unwrap().lock().unwrap(); let src_data = &buffer_data.as_slice() - [(offset as usize)..(offset + bytes_per_image) as usize]; + [(offset as usize)..(offset + bytes_in_upload) as usize]; glow::CompressedPixelUnpackData::Slice(src_data) } }; + log::error!( + "bytes_per_row: {}, \ + minimum_rows_per_image: {}, \ + rows_per_image: {}, \ + bytes_per_image: {}, \ + minimum_bytes_per_image: {}, \ + bytes_in_upload: {}\ + ", + bytes_per_row, + minimum_rows_per_image, + rows_per_image, + bytes_per_image, + minimum_bytes_per_image, + bytes_in_upload + ); match dst_target { - glow::TEXTURE_3D | glow::TEXTURE_2D_ARRAY => { + glow::TEXTURE_3D + | glow::TEXTURE_CUBE_MAP_ARRAY + | glow::TEXTURE_2D_ARRAY => { gl.compressed_tex_sub_image_3d( dst_target, copy.texture_base.mip_level as i32, @@ -526,21 +549,6 @@ impl super::Queue { unpack_data, ); } - glow::TEXTURE_CUBE_MAP_ARRAY => { - //Note: not sure if this is correct! - gl.compressed_tex_sub_image_3d( - dst_target, - copy.texture_base.mip_level as i32, - copy.texture_base.origin.x as i32, - copy.texture_base.origin.y as i32, - copy.texture_base.origin.z as i32, - copy.size.width as i32, - copy.size.height as i32, - copy.size.depth as i32, - format_desc.internal, - unpack_data, - ); - } _ => unreachable!(), } } From 2c9087a0bde729fbd664ba8d4e3d45cacdc743ec Mon Sep 17 00:00:00 2001 From: Connor Fitzgerald Date: Fri, 25 Feb 2022 02:28:29 -0500 Subject: [PATCH 11/13] Expand skybox outlier count due to llvmpipe --- wgpu/examples/skybox/main.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/wgpu/examples/skybox/main.rs b/wgpu/examples/skybox/main.rs index 0343bd4313..53526a0277 100644 --- a/wgpu/examples/skybox/main.rs +++ b/wgpu/examples/skybox/main.rs @@ -497,7 +497,7 @@ fn skybox_bc1() { false, ), // https://bugs.chromium.org/p/angleproject/issues/detail?id=7056 tolerance: 5, - max_outliers: 10, + max_outliers: 105, // Bounded by llvmpipe }); } From 8605899061852b6d87d261a470ff3e3dac6b333a Mon Sep 17 00:00:00 2001 From: Connor Fitzgerald Date: Fri, 25 Feb 2022 15:20:05 -0500 Subject: [PATCH 12/13] Round up clear texture tests to block size --- wgpu/examples/skybox/main.rs | 21 +++------------------ wgpu/tests/clear_texture.rs | 22 +++++++++++++++------- 2 files changed, 18 insertions(+), 25 deletions(-) diff --git a/wgpu/examples/skybox/main.rs b/wgpu/examples/skybox/main.rs index 53526a0277..de2de44a6a 100644 --- a/wgpu/examples/skybox/main.rs +++ b/wgpu/examples/skybox/main.rs @@ -490,12 +490,7 @@ fn skybox_bc1() { width: 1024, height: 768, optional_features: wgpu::Features::TEXTURE_COMPRESSION_BC, - base_test_parameters: framework::test_common::TestParameters::default().specific_failure( - Some(wgpu::Backends::GL), - None, - Some("ANGLE"), - false, - ), // https://bugs.chromium.org/p/angleproject/issues/detail?id=7056 + base_test_parameters: framework::test_common::TestParameters::default(), // https://bugs.chromium.org/p/angleproject/issues/detail?id=7056 tolerance: 5, max_outliers: 105, // Bounded by llvmpipe }); @@ -508,12 +503,7 @@ fn skybox_etc2() { width: 1024, height: 768, optional_features: wgpu::Features::TEXTURE_COMPRESSION_ETC2, - base_test_parameters: framework::test_common::TestParameters::default().specific_failure( - Some(wgpu::Backends::GL), - None, - Some("ANGLE"), - false, - ), // https://bugs.chromium.org/p/angleproject/issues/detail?id=7056 + base_test_parameters: framework::test_common::TestParameters::default(), // https://bugs.chromium.org/p/angleproject/issues/detail?id=7056 tolerance: 5, max_outliers: 105, // Bounded by llvmpipe }); @@ -526,12 +516,7 @@ fn skybox_astc() { width: 1024, height: 768, optional_features: wgpu::Features::TEXTURE_COMPRESSION_ASTC_LDR, - base_test_parameters: framework::test_common::TestParameters::default().specific_failure( - Some(wgpu::Backends::GL), - None, - Some("ANGLE"), - false, - ), // https://bugs.chromium.org/p/angleproject/issues/detail?id=7056 + base_test_parameters: framework::test_common::TestParameters::default(), // https://bugs.chromium.org/p/angleproject/issues/detail?id=7056 tolerance: 5, max_outliers: 300, // Bounded by rp4 on vk }); diff --git a/wgpu/tests/clear_texture.rs b/wgpu/tests/clear_texture.rs index 9a15a41274..380d19c40a 100644 --- a/wgpu/tests/clear_texture.rs +++ b/wgpu/tests/clear_texture.rs @@ -239,6 +239,10 @@ fn single_texture_clear_test( // TODO: Read back and check zeroness? } +fn round_up(value: u32, alignment: u32) -> u32 { + ((value + alignment - 1) / alignment) * alignment +} + fn clear_texture_tests( ctx: &TestingContext, formats: &[wgpu::TextureFormat], @@ -246,13 +250,17 @@ fn clear_texture_tests( supports_3d: bool, ) { for &format in formats { + let desc = format.describe(); + let rounded_width = round_up(64, desc.block_dimensions.0 as u32); + let rounded_height = round_up(64, desc.block_dimensions.1 as u32); + // 1D texture if supports_1d { single_texture_clear_test( ctx, format, wgpu::Extent3d { - width: 64, + width: rounded_width, height: 1, depth_or_array_layers: 1, }, @@ -264,8 +272,8 @@ fn clear_texture_tests( ctx, format, wgpu::Extent3d { - width: 64, - height: 64, + width: rounded_width, + height: rounded_height, depth_or_array_layers: 1, }, wgpu::TextureDimension::D2, @@ -275,8 +283,8 @@ fn clear_texture_tests( ctx, format, wgpu::Extent3d { - width: 64, - height: 64, + width: rounded_width, + height: rounded_height, depth_or_array_layers: 4, }, wgpu::TextureDimension::D2, @@ -287,8 +295,8 @@ fn clear_texture_tests( ctx, format, wgpu::Extent3d { - width: 16, - height: 16, + width: rounded_width, + height: rounded_height, depth_or_array_layers: 16, }, wgpu::TextureDimension::D3, From 7fe016f748d023b8bd6c9c9fb23777388f2bfa9a Mon Sep 17 00:00:00 2001 From: Connor Fitzgerald Date: Fri, 25 Feb 2022 16:46:03 -0500 Subject: [PATCH 13/13] Update test status readme --- README.md | 29 ++++++++++++++++------------- 1 file changed, 16 insertions(+), 13 deletions(-) diff --git a/README.md b/README.md index 1280a93c8b..0d79b0983b 100644 --- a/README.md +++ b/README.md @@ -116,40 +116,43 @@ When running the CTS, use the variables `DENO_WEBGPU_ADAPTER_NAME`, `DENO_WEBGPU We have multiple methods of testing, each of which tests different qualities about wgpu. We automatically run our tests on CI if possible. The current state of CI testing: -| Backend/Platform | Status | -| ---------------- | ---------------------------------------------------------------------- | -| DX12/Windows 10 | :heavy_check_mark: (over WARP) | -| DX11/Windows 10 | :construction: (over WARP) | -| Metal/MacOS | :x: (no CPU runner) | -| Vulkan/Linux | :ok: ([cts hangs](https://github.com/gfx-rs/wgpu/issues/1974)) | -| GLES/Linux | :x: ([egl fails init](https://github.com/gfx-rs/wgpu/issues/1551)) | +| Backend/Platform | Tests | CTS | Notes | +| ---------------- | -------------------|---------------------|-------------------------------------- | +| DX12/Windows 10 | :heavy_check_mark: | :heavy_check_mark: | using WARP | +| DX11/Windows 10 | :construction: | — | using WARP | +| Metal/MacOS | — | — | metal requires GPU | +| Vulkan/Linux | :heavy_check_mark: | :x: | using lavapipe, [cts hangs][cts-hang] | +| GLES/Linux | :heavy_check_mark: | — | using llvmpipe | + +[cts-hang]: https://github.com/gfx-rs/wgpu/issues/1974 ### Core Test Infrastructure -All framework based examples have image comparison tested against their screenshot. +We use a tool called [`cargo nextest`](https://github.com/nextest-rs/nextest) to run our tests. +To install it, run `cargo install cargo-nextest`. To run the test suite on the default device: ``` -cargo test --no-fail-fast +cargo nextest run --no-fail-fast ``` -There's logic which can automatically run the tests once for each adapter on your system. +`wgpu-info` can run the tests once for each adapter on your system. ``` -cargo run --bin wgpu-info -- cargo test --no-fail-fast +cargo run --bin wgpu-info -- cargo nextest run --no-fail-fast ``` Then to run an example's image comparison tests, run: ``` -cargo test --example --no-fail-fast +cargo nextest run --example --no-fail-fast ``` Or run a part of the integration test suite: ``` -cargo test -p wgpu -- +cargo nextest run -p wgpu -- ``` If you are a user and want a way to help contribute to wgpu, we always need more help writing test cases.