author | Andy Leiserson <aleiserson@mozilla.com> |
Sat, 19 Jul 2025 16:44:54 +0000 (11 hours ago) | |
changeset 797257 | 246e16bb06c941d6f64d807d43c807bfba04ae86 |
parent 797256 | b85e0ca703bb39bca3fc21f999bfebde54b414f8 |
push id | 42974 |
push user | csabou@mozilla.com |
push date | Sat, 19 Jul 2025 20:32:25 +0000 (7 hours ago) |
treeherder | mozilla-central@246e16bb06c9 [default view] [failures only] |
perfherder | [talos] [build metrics] [platform microbench] (compared to previous push) |
git commit | 47d731cc857a8a983e03643bda5e0abde5747a12 |
reviewers | webgpu-reviewers, supply-chain-reviewers, teoxoy |
bugs | 1976958 |
milestone | 142.0a1 |
first release with | nightly linux32
246e16bb06c9
/
142.0a1
/
20250719203225
/
files
nightly linux64
246e16bb06c9
/
142.0a1
/
20250719203225
/
files
nightly mac
246e16bb06c9
/
142.0a1
/
20250719203225
/
files
nightly win32
246e16bb06c9
/
142.0a1
/
20250719203225
/
files
nightly win64
246e16bb06c9
/
142.0a1
/
20250719203225
/
files
|
last release without | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
releases | nightly linux32
142.0a1
/
20250719203225
/
pushlog to previous
nightly linux64
142.0a1
/
20250719203225
/
pushlog to previous
nightly mac
142.0a1
/
20250719203225
/
pushlog to previous
nightly win32
142.0a1
/
20250719203225
/
pushlog to previous
nightly win64
142.0a1
/
20250719203225
/
pushlog to previous
|
--- a/.cargo/config.toml.in +++ b/.cargo/config.toml.in @@ -30,19 +30,19 @@ git = "https://github.com/beurdouche/nss rev = "e48a946811ffd64abc78de3ee284957d8d1c0d63" replace-with = "vendored-sources" [source."git+https://github.com/franziskuskiefer/cose-rust?rev=43c22248d136c8b38fe42ea709d08da6355cf04b"] git = "https://github.com/franziskuskiefer/cose-rust" rev = "43c22248d136c8b38fe42ea709d08da6355cf04b" replace-with = "vendored-sources" -[source."git+https://github.com/gfx-rs/wgpu?rev=12591e42715badafef264609cb29d4a8e0b90847"] +[source."git+https://github.com/gfx-rs/wgpu?rev=b83c9cfd578837a6163d980130249c245a9c5f8a"] git = "https://github.com/gfx-rs/wgpu" -rev = "12591e42715badafef264609cb29d4a8e0b90847" +rev = "b83c9cfd578837a6163d980130249c245a9c5f8a" replace-with = "vendored-sources" [source."git+https://github.com/glandium/rust-objc?rev=4de89f5aa9851ceca4d40e7ac1e2759410c04324"] git = "https://github.com/glandium/rust-objc" rev = "4de89f5aa9851ceca4d40e7ac1e2759410c04324" replace-with = "vendored-sources" [source."git+https://github.com/hsivonen/any_all_workaround?rev=7fb1b7034c9f172aade21ee1c8554e8d8a48af80"]
--- a/Cargo.lock +++ b/Cargo.lock @@ -4632,18 +4632,18 @@ dependencies = [ [[package]] name = "murmurhash3" version = "0.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a2983372caf4480544083767bf2d27defafe32af49ab4df3a0b7fc90793a3664" [[package]] name = "naga" -version = "25.0.0" -source = "git+https://github.com/gfx-rs/wgpu?rev=12591e42715badafef264609cb29d4a8e0b90847#12591e42715badafef264609cb29d4a8e0b90847" +version = "26.0.0" +source = "git+https://github.com/gfx-rs/wgpu?rev=b83c9cfd578837a6163d980130249c245a9c5f8a#b83c9cfd578837a6163d980130249c245a9c5f8a" dependencies = [ "arrayvec", "bit-set", "bitflags 2.9.0", "cfg-if", "cfg_aliases", "codespan-reporting", "half 2.5.0", @@ -7600,18 +7600,18 @@ version = "5.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "998d2c24ec099a87daf9467808859f9d82b61f1d9c9701251aea037f514eae0e" dependencies = [ "nom", ] [[package]] name = "wgpu-core" -version = "25.0.0" -source = "git+https://github.com/gfx-rs/wgpu?rev=12591e42715badafef264609cb29d4a8e0b90847#12591e42715badafef264609cb29d4a8e0b90847" +version = "26.0.0" +source = "git+https://github.com/gfx-rs/wgpu?rev=b83c9cfd578837a6163d980130249c245a9c5f8a#b83c9cfd578837a6163d980130249c245a9c5f8a" dependencies = [ "arrayvec", "bit-set", "bit-vec", "bitflags 2.9.0", "bytemuck", "cfg_aliases", "document-features", @@ -7630,34 +7630,34 @@ dependencies = [ "wgpu-core-deps-apple", "wgpu-core-deps-windows-linux-android", "wgpu-hal", "wgpu-types", ] [[package]] name = "wgpu-core-deps-apple" -version = "25.0.0" -source = "git+https://github.com/gfx-rs/wgpu?rev=12591e42715badafef264609cb29d4a8e0b90847#12591e42715badafef264609cb29d4a8e0b90847" +version = "26.0.0" +source = "git+https://github.com/gfx-rs/wgpu?rev=b83c9cfd578837a6163d980130249c245a9c5f8a#b83c9cfd578837a6163d980130249c245a9c5f8a" dependencies = [ "wgpu-hal", ] [[package]] name = "wgpu-core-deps-windows-linux-android" -version = "25.0.0" -source = "git+https://github.com/gfx-rs/wgpu?rev=12591e42715badafef264609cb29d4a8e0b90847#12591e42715badafef264609cb29d4a8e0b90847" +version = "26.0.0" +source = "git+https://github.com/gfx-rs/wgpu?rev=b83c9cfd578837a6163d980130249c245a9c5f8a#b83c9cfd578837a6163d980130249c245a9c5f8a" dependencies = [ "wgpu-hal", ] [[package]] name = "wgpu-hal" -version = "25.0.0" -source = "git+https://github.com/gfx-rs/wgpu?rev=12591e42715badafef264609cb29d4a8e0b90847#12591e42715badafef264609cb29d4a8e0b90847" +version = "26.0.0" +source = "git+https://github.com/gfx-rs/wgpu?rev=b83c9cfd578837a6163d980130249c245a9c5f8a#b83c9cfd578837a6163d980130249c245a9c5f8a" dependencies = [ "android_system_properties", "arrayvec", "ash", "bit-set", "bitflags 2.9.0", "block", "bytemuck", @@ -7683,18 +7683,18 @@ dependencies = [ "thiserror 2.0.9", "wgpu-types", "windows", "windows-core", ] [[package]] name = "wgpu-types" -version = "25.0.0" -source = "git+https://github.com/gfx-rs/wgpu?rev=12591e42715badafef264609cb29d4a8e0b90847#12591e42715badafef264609cb29d4a8e0b90847" +version = "26.0.0" +source = "git+https://github.com/gfx-rs/wgpu?rev=b83c9cfd578837a6163d980130249c245a9c5f8a#b83c9cfd578837a6163d980130249c245a9c5f8a" dependencies = [ "bitflags 2.9.0", "bytemuck", "js-sys", "log", "serde", "thiserror 2.0.9", "web-sys",
--- a/gfx/wgpu_bindings/Cargo.toml +++ b/gfx/wgpu_bindings/Cargo.toml @@ -12,58 +12,58 @@ publish = false [lib] [features] default = [] [dependencies.wgc] package = "wgpu-core" git = "https://github.com/gfx-rs/wgpu" -rev = "12591e42715badafef264609cb29d4a8e0b90847" +rev = "b83c9cfd578837a6163d980130249c245a9c5f8a" # TODO: remove the replay feature on the next update containing https://github.com/gfx-rs/wgpu/pull/5182 features = [ "serde", "replay", "trace", "strict_asserts", "wgsl", "api_log_info", ] # We want the wgpu-core Metal backend on macOS and iOS. # (We should consider also enabling "vulkan" for Vulkan Portability.) [target.'cfg(any(target_os = "macos", target_os = "ios"))'.dependencies.wgc] package = "wgpu-core" git = "https://github.com/gfx-rs/wgpu" -rev = "12591e42715badafef264609cb29d4a8e0b90847" +rev = "b83c9cfd578837a6163d980130249c245a9c5f8a" features = ["metal"] # We want the wgpu-core Direct3D backends on Windows. [target.'cfg(windows)'.dependencies.wgc] package = "wgpu-core" git = "https://github.com/gfx-rs/wgpu" -rev = "12591e42715badafef264609cb29d4a8e0b90847" +rev = "b83c9cfd578837a6163d980130249c245a9c5f8a" features = ["dx12"] # We want the wgpu-core Vulkan backend on Linux and Windows. [target.'cfg(any(windows, all(unix, not(any(target_os = "macos", target_os = "ios")))))'.dependencies.wgc] package = "wgpu-core" git = "https://github.com/gfx-rs/wgpu" -rev = "12591e42715badafef264609cb29d4a8e0b90847" +rev = "b83c9cfd578837a6163d980130249c245a9c5f8a" features = ["vulkan"] [dependencies.wgt] package = "wgpu-types" git = "https://github.com/gfx-rs/wgpu" -rev = "12591e42715badafef264609cb29d4a8e0b90847" +rev = "b83c9cfd578837a6163d980130249c245a9c5f8a" [dependencies.wgh] package = "wgpu-hal" git = "https://github.com/gfx-rs/wgpu" -rev = "12591e42715badafef264609cb29d4a8e0b90847" +rev = "b83c9cfd578837a6163d980130249c245a9c5f8a" features = ["device_lost_panic", "internal_error_panic"] [target.'cfg(windows)'.dependencies] windows = { version = "0.58", default-features = false, features = [ "Win32_Graphics_Direct3D12", ] } [target.'cfg(target_os = "macos")'.dependencies]
--- a/gfx/wgpu_bindings/moz.yaml +++ b/gfx/wgpu_bindings/moz.yaml @@ -3,18 +3,18 @@ schema: 1 bugzilla: product: Core component: "Graphics: WebGPU" origin: name: wgpu description: A cross-platform pure-Rust graphics API, modeled on the WebGPU standard url: https://github.com/gfx-rs/wgpu - release: 12591e42715badafef264609cb29d4a8e0b90847 (2025-07-07T02:56:42Z). - revision: 12591e42715badafef264609cb29d4a8e0b90847 + release: b83c9cfd578837a6163d980130249c245a9c5f8a (2025-07-10T18:43:26Z). + revision: b83c9cfd578837a6163d980130249c245a9c5f8a license: ['MIT', 'Apache-2.0'] updatebot: maintainer-phab: "#webgpu-reviewers" maintainer-bz: jimb@mozilla.com try-preset: webgpu tasks: - type: vendoring
--- a/gfx/wgpu_bindings/src/server.rs +++ b/gfx/wgpu_bindings/src/server.rs @@ -57,16 +57,23 @@ const MAX_TEXTURE_EXTENT: u32 = std::i16 // the sum of these limits multiplied by the number of shader stages fits // maxBindingsPerBindGroup (1000). This restriction is arbitrary and is likely to // change eventually. See github.com/gpuweb/gpuweb/pull/4484 // For now it's impractical for users to have very large numbers of bindings so this // limit should not be too restrictive until we add support for a bindless API. // Then we may have to ignore the spec or get it changed. const MAX_BINDINGS_PER_RESOURCE_TYPE: u32 = 64; +#[cfg(any(target_os = "windows", target_os = "linux", target_os = "macos"))] +fn emit_critical_invalid_note(what: &'static str) { + // SAFETY: We ensure that the pointer provided is not null. + let msg = CString::new(format!("{what} is invalid")).unwrap(); + unsafe { gfx_critical_note(msg.as_ptr()) } +} + fn restrict_limits(limits: wgt::Limits) -> wgt::Limits { wgt::Limits { max_buffer_size: limits.max_buffer_size.min(MAX_BUFFER_SIZE), max_texture_dimension_1d: limits.max_texture_dimension_1d.min(MAX_TEXTURE_EXTENT), max_texture_dimension_2d: limits.max_texture_dimension_2d.min(MAX_TEXTURE_EXTENT), max_texture_dimension_3d: limits.max_texture_dimension_3d.min(MAX_TEXTURE_EXTENT), max_sampled_textures_per_shader_stage: limits .max_sampled_textures_per_shader_stage @@ -261,47 +268,44 @@ fn support_use_shared_texture_in_swap_ch let support = if backend != wgt::Backend::Vulkan { log::info!(concat!( "WebGPU: disabling SharedTexture swapchain: \n", "wgpu backend is not Vulkan" )); false } else { unsafe { - global.adapter_as_hal::<wgc::api::Vulkan, _, bool>(self_id, |hal_adapter| { - let hal_adapter = match hal_adapter { - None => { - let msg = c"Vulkan adapter is invalid"; - gfx_critical_note(msg.as_ptr()); - return false; - } - Some(hal_adapter) => hal_adapter, - }; - - let capabilities = hal_adapter.physical_device_capabilities(); - static REQUIRED: &[&'static std::ffi::CStr] = &[ - khr::external_memory_fd::NAME, - ash::ext::external_memory_dma_buf::NAME, - ash::ext::image_drm_format_modifier::NAME, - khr::external_semaphore_fd::NAME, - ]; - REQUIRED.iter().all(|extension| { - let supported = capabilities.supports_extension(extension); - if !supported { - log::info!( - concat!( - "WebGPU: disabling SharedTexture swapchain: \n", - "Vulkan extension not supported: {:?}", - ), - extension.to_string_lossy() - ); - } - supported - }) - }) + match global.adapter_as_hal::<wgc::api::Vulkan>(self_id) { + None => { + emit_critical_invalid_note("Vulkan adapter"); + false + } + Some(hal_adapter) => { + let capabilities = hal_adapter.physical_device_capabilities(); + static REQUIRED: &[&'static std::ffi::CStr] = &[ + khr::external_memory_fd::NAME, + ash::ext::external_memory_dma_buf::NAME, + ash::ext::image_drm_format_modifier::NAME, + khr::external_semaphore_fd::NAME, + ]; + REQUIRED.iter().all(|extension| { + let supported = capabilities.supports_extension(extension); + if !supported { + log::info!( + concat!( + "WebGPU: disabling SharedTexture swapchain: \n", + "Vulkan extension not supported: {:?}", + ), + extension.to_string_lossy() + ); + } + supported + }) + } + } } }; return support; } #[cfg(target_os = "macos")] { if backend != wgt::Backend::Metal { @@ -373,144 +377,125 @@ unsafe fn adapter_request_device( } // TODO: in https://github.com/gfx-rs/wgpu/pull/3626/files#diff-033343814319f5a6bd781494692ea626f06f6c3acc0753a12c867b53a646c34eR97 // which introduced the queue id parameter, the queue id is also the device id. I don't know how applicable this is to // other situations (this one in particular). #[cfg(target_os = "linux")] { - let support_dma_buf = - global.adapter_as_hal::<wgc::api::Vulkan, _, bool>(self_id, |hal_adapter| { - let hal_adapter = match hal_adapter { - None => { - let msg = c"Vulkan adapter is invalid"; - gfx_critical_note(msg.as_ptr()); - return false; - } - Some(hal_adapter) => hal_adapter, + let hal_adapter = global.adapter_as_hal::<wgc::api::Vulkan>(self_id); + + let support_dma_buf = hal_adapter.as_ref().is_some_and(|hal_adapter| { + let capabilities = hal_adapter.physical_device_capabilities(); + + capabilities.supports_extension(khr::external_memory_fd::NAME) + && capabilities.supports_extension(ash::ext::external_memory_dma_buf::NAME) + && capabilities.supports_extension(ash::ext::image_drm_format_modifier::NAME) + && capabilities.supports_extension(khr::external_semaphore_fd::NAME) + }); + + match (hal_adapter, support_dma_buf) { + (None, _) => { + emit_critical_invalid_note("Vulkan adapter"); + } + (Some(_), false) => {} + (Some(hal_adapter), true) => { + let mut enabled_extensions = + hal_adapter.required_device_extensions(desc.required_features); + enabled_extensions.push(khr::external_memory_fd::NAME); + enabled_extensions.push(ash::ext::external_memory_dma_buf::NAME); + enabled_extensions.push(ash::ext::image_drm_format_modifier::NAME); + enabled_extensions.push(khr::external_semaphore_fd::NAME); + + let mut enabled_phd_features = hal_adapter + .physical_device_features(&enabled_extensions, desc.required_features); + + let raw_instance = hal_adapter.shared_instance().raw_instance(); + let raw_physical_device = hal_adapter.raw_physical_device(); + + let queue_family_index = raw_instance + .get_physical_device_queue_family_properties(raw_physical_device) + .into_iter() + .enumerate() + .find_map(|(queue_family_index, info)| { + if info.queue_flags.contains(vk::QueueFlags::GRAPHICS) { + Some(queue_family_index as u32) + } else { + None + } + }); + + let Some(queue_family_index) = queue_family_index else { + let msg = c"Vulkan device has no graphics queue"; + gfx_critical_note(msg.as_ptr()); + return Some(format!("Internal Error: Failed to create ash::Device")); }; - let capabilities = hal_adapter.physical_device_capabilities(); - - capabilities.supports_extension(khr::external_memory_fd::NAME) - && capabilities.supports_extension(ash::ext::external_memory_dma_buf::NAME) - && capabilities.supports_extension(ash::ext::image_drm_format_modifier::NAME) - && capabilities.supports_extension(khr::external_semaphore_fd::NAME) - }); + let family_info = vk::DeviceQueueCreateInfo::default() + .queue_family_index(queue_family_index) + .queue_priorities(&[1.0]); + let family_infos = [family_info]; - if support_dma_buf { - let hal_device = global - .adapter_as_hal::<wgc::api::Vulkan, _, Option<wgh::OpenDevice<wgh::api::Vulkan>>>( - self_id, - |hal_adapter| { - let hal_adapter = match hal_adapter { - None => { - let msg = c"Vulkan adapter is invalid"; - gfx_critical_note(msg.as_ptr()); - return None; - } - Some(hal_adapter) => hal_adapter, - }; + let str_pointers = enabled_extensions + .iter() + .map(|&s| { + // Safe because `enabled_extensions` entries have static lifetime. + s.as_ptr() + }) + .collect::<Vec<_>>(); - let mut enabled_extensions = - hal_adapter.required_device_extensions(desc.required_features); - enabled_extensions.push(khr::external_memory_fd::NAME); - enabled_extensions.push(ash::ext::external_memory_dma_buf::NAME); - enabled_extensions.push(ash::ext::image_drm_format_modifier::NAME); - enabled_extensions.push(khr::external_semaphore_fd::NAME); - - let mut enabled_phd_features = hal_adapter - .physical_device_features(&enabled_extensions, desc.required_features); - - let raw_instance = hal_adapter.shared_instance().raw_instance(); - let raw_physical_device = hal_adapter.raw_physical_device(); + let pre_info = vk::DeviceCreateInfo::default() + .queue_create_infos(&family_infos) + .enabled_extension_names(&str_pointers); + let info = enabled_phd_features.add_to_device_create(pre_info); - let queue_family_index = raw_instance - .get_physical_device_queue_family_properties(raw_physical_device) - .into_iter() - .enumerate() - .find_map(|(queue_family_index, info)| { - if info.queue_flags.contains(vk::QueueFlags::GRAPHICS) { - Some(queue_family_index as u32) - } else { - None - } - }); - - let queue_family_index = match queue_family_index { - None => { - let msg = c"Vulkan device has no graphics queue"; - gfx_critical_note(msg.as_ptr()); - return None; - } - Some(queue_family_index) => queue_family_index, - }; + let raw_device = + match raw_instance.create_device(raw_physical_device, &info, None) { + Err(err) => { + let msg = + CString::new(format!("create_device() failed: {:?}", err)) + .unwrap(); + gfx_critical_note(msg.as_ptr()); + return Some(format!("Internal Error: Failed to create ash::Device")); + } + Ok(raw_device) => raw_device, + }; - let family_info = vk::DeviceQueueCreateInfo::default() - .queue_family_index(queue_family_index) - .queue_priorities(&[1.0]); - let family_infos = [family_info]; - - let str_pointers = enabled_extensions - .iter() - .map(|&s| { - // Safe because `enabled_extensions` entries have static lifetime. - s.as_ptr() - }) - .collect::<Vec<_>>(); - - let pre_info = vk::DeviceCreateInfo::default() - .queue_create_infos(&family_infos) - .enabled_extension_names(&str_pointers); - let info = enabled_phd_features.add_to_device_create(pre_info); - - let raw_device = - match raw_instance.create_device(raw_physical_device, &info, None) { - Err(err) => { - let msg = - CString::new(format!("create_device() failed: {:?}", err)) - .unwrap(); - gfx_critical_note(msg.as_ptr()); - return None; - } - Ok(raw_device) => raw_device, - }; + let hal_device = match hal_adapter.device_from_raw( + raw_device, + None, + &enabled_extensions, + desc.required_features, + &desc.memory_hints, + family_info.queue_family_index, + 0, + ) { + Err(err) => { + let msg = + CString::new(format!("device_from_raw() failed: {:?}", err)) + .unwrap(); + gfx_critical_note(msg.as_ptr()); + return Some(format!("Internal Error: Failed to create ash::Device")); + } + Ok(hal_device) => hal_device, + }; - let hal_device = hal_adapter.device_from_raw( - raw_device, - None, - &enabled_extensions, - desc.required_features, - &desc.memory_hints, - family_info.queue_family_index, - 0, - ); - Some(hal_device.unwrap()) - }, + let res = global.create_device_from_hal( + self_id, + hal_device.into(), + &desc, + Some(new_device_id), + Some(new_queue_id), ); - - let hal_device = match hal_device { - None => { - return Some(format!("Internal Error: Failed to create ash::Device")); + if let Err(err) = res { + return Some(format!("{err}")); } - Some(hal_device) => hal_device, - }; - - let res = global.create_device_from_hal( - self_id, - hal_device.into(), - &desc, - Some(new_device_id), - Some(new_queue_id), - ); - if let Err(err) = res { - return Some(format!("{err}")); + return None; } - return None; } } let res = global.adapter_request_device(self_id, &desc, Some(new_device_id), Some(new_queue_id)); if let Err(err) = res { return Some(format!("{err}")); } else { @@ -773,51 +758,31 @@ pub extern "C" fn wgpu_server_buffer_unm #[allow(unused_variables)] #[no_mangle] pub extern "C" fn wgpu_server_get_device_fence_handle( global: &Global, device_id: id::DeviceId, ) -> *mut c_void { #[cfg(target_os = "windows")] - { - let dx12_device = unsafe { - global.device_as_hal::<wgc::api::Dx12, _, Option<Direct3D12::ID3D12Device>>( - device_id, - |hal_device| hal_device.map(|device| device.raw_device().clone()), - ) - }; - let dx12_device = match dx12_device { - Some(device) => device, - None => { - return ptr::null_mut(); - } + unsafe { + let Some(dx12_device) = global.device_as_hal::<wgc::api::Dx12>(device_id) + .map(|device| device.raw_device().clone()) else { + return ptr::null_mut(); }; - let dx12_fence = unsafe { - global.device_fence_as_hal::<wgc::api::Dx12, _, Option<Direct3D12::ID3D12Fence>>( - device_id, - |hal_fence| hal_fence.map(|fence| fence.raw_fence().clone()), - ) - }; - let dx12_fence = match dx12_fence { - Some(fence) => fence, - None => { - return ptr::null_mut(); - } + let Some(dx12_fence) = global.device_fence_as_hal::<wgc::api::Dx12>(device_id) + .map(|fence| fence.raw_fence().clone()) else { + return ptr::null_mut(); }; - let res = unsafe { - dx12_device.CreateSharedHandle(&dx12_fence, None, Foundation::GENERIC_ALL.0, None) - }; - - return match res { + match dx12_device.CreateSharedHandle(&dx12_fence, None, Foundation::GENERIC_ALL.0, None) { Ok(handle) => handle.0, Err(_) => ptr::null_mut(), - }; + } } #[cfg(not(target_os = "windows"))] ptr::null_mut() } #[derive(Debug)] #[repr(C)] pub struct DMABufInfo { @@ -839,279 +804,252 @@ pub struct VkImageHandle { pub modifier: u64, pub layouts: Vec<vk::SubresourceLayout>, } #[cfg(target_os = "linux")] impl VkImageHandle { fn destroy(&self, global: &Global, device_id: id::DeviceId) { unsafe { - global.device_as_hal::<wgc::api::Vulkan, _, ()>(device_id, |hal_device| { - let hal_device = match hal_device { - None => { - return; - } - Some(hal_device) => hal_device, - }; - let device = hal_device.raw_device(); + let Some(hal_device) = global.device_as_hal::<wgc::api::Vulkan>(device_id) else { + return; + }; - (device.fp_v1_0().destroy_image)(self.device, self.image, ptr::null()); - (device.fp_v1_0().free_memory)(self.device, self.memory, ptr::null()); - }) + let device = hal_device.raw_device(); + + (device.fp_v1_0().destroy_image)(self.device, self.image, ptr::null()); + (device.fp_v1_0().free_memory)(self.device, self.memory, ptr::null()); }; } } #[no_mangle] #[cfg(target_os = "linux")] pub extern "C" fn wgpu_vkimage_create_with_dma_buf( global: &Global, device_id: id::DeviceId, width: u32, height: u32, out_memory_size: *mut u64, ) -> *mut VkImageHandle { - let image_handle = unsafe { - global.device_as_hal::<wgc::api::Vulkan, _, Option<VkImageHandle>>( - device_id, - |hal_device| { - let hal_device = match hal_device { - None => { - let msg = c"Vulkan device is invalid"; - gfx_critical_note(msg.as_ptr()); - return None; - } - Some(hal_device) => hal_device, - }; - - let device = hal_device.raw_device(); - let physical_device = hal_device.raw_physical_device(); - let instance = hal_device.shared_instance().raw_instance(); - - let count = { - let mut drm_format_modifier_props_list = - vk::DrmFormatModifierPropertiesListEXT::default(); - let mut format_properties_2 = vk::FormatProperties2::default() - .push_next(&mut drm_format_modifier_props_list); + unsafe { + let Some(hal_device) = global.device_as_hal::<wgc::api::Vulkan>(device_id) else { + emit_critical_invalid_note("Vulkan device"); + return ptr::null_mut(); + }; - instance.get_physical_device_format_properties2( - physical_device, - vk::Format::R8G8B8A8_UNORM, - &mut format_properties_2, - ); - drm_format_modifier_props_list.drm_format_modifier_count - }; - - if count == 0 { - let msg = c"get_physical_device_format_properties2() failed"; - gfx_critical_note(msg.as_ptr()); - return None; - } - - let mut modifier_props = - vec![vk::DrmFormatModifierPropertiesEXT::default(); count as usize]; - - let mut drm_format_modifier_props_list = - vk::DrmFormatModifierPropertiesListEXT::default() - .drm_format_modifier_properties(&mut modifier_props); - let mut format_properties_2 = - vk::FormatProperties2::default().push_next(&mut drm_format_modifier_props_list); - - instance.get_physical_device_format_properties2( - physical_device, - vk::Format::R8G8B8A8_UNORM, - &mut format_properties_2, - ); + let device = hal_device.raw_device(); + let physical_device = hal_device.raw_physical_device(); + let instance = hal_device.shared_instance().raw_instance(); - let mut usage_flags = vk::ImageUsageFlags::empty(); - usage_flags |= vk::ImageUsageFlags::COLOR_ATTACHMENT; - - modifier_props.retain(|modifier_prop| { - let support = is_dmabuf_supported( - instance, - physical_device, - vk::Format::R8G8B8A8_UNORM, - modifier_prop.drm_format_modifier, - usage_flags, - ); - support - }); - - if modifier_props.is_empty() { - let msg = c"format not supported for dmabuf import"; - gfx_critical_note(msg.as_ptr()); - return None; - } - - let modifiers: Vec<u64> = modifier_props - .iter() - .map(|modifier_prop| modifier_prop.drm_format_modifier) - .collect(); - - let mut modifier_list = vk::ImageDrmFormatModifierListCreateInfoEXT::default() - .drm_format_modifiers(&modifiers); + let count = { + let mut drm_format_modifier_props_list = + vk::DrmFormatModifierPropertiesListEXT::default(); + let mut format_properties_2 = vk::FormatProperties2::default() + .push_next(&mut drm_format_modifier_props_list); - let extent = vk::Extent3D { - width, - height, - depth: 1, - }; - - let mut external_image_create_info = vk::ExternalMemoryImageCreateInfo::default() - .handle_types(vk::ExternalMemoryHandleTypeFlags::DMA_BUF_EXT); - - let mut export_memory_alloc_info = vk::ExportMemoryAllocateInfo::default() - .handle_types(vk::ExternalMemoryHandleTypeFlags::DMA_BUF_EXT); - - let flags = vk::ImageCreateFlags::empty(); + instance.get_physical_device_format_properties2( + physical_device, + vk::Format::R8G8B8A8_UNORM, + &mut format_properties_2, + ); + drm_format_modifier_props_list.drm_format_modifier_count + }; - let vk_info = vk::ImageCreateInfo::default() - .flags(flags) - .image_type(vk::ImageType::TYPE_2D) - .format(vk::Format::R8G8B8A8_UNORM) - .extent(extent) - .mip_levels(1) - .array_layers(1) - .samples(vk::SampleCountFlags::TYPE_1) - .tiling(vk::ImageTiling::DRM_FORMAT_MODIFIER_EXT) - .usage(usage_flags) - .sharing_mode(vk::SharingMode::EXCLUSIVE) - .initial_layout(vk::ImageLayout::UNDEFINED) - .push_next(&mut modifier_list) - .push_next(&mut external_image_create_info); + if count == 0 { + let msg = c"get_physical_device_format_properties2() failed"; + gfx_critical_note(msg.as_ptr()); + return ptr::null_mut(); + } - let image = match device.create_image(&vk_info, None) { - Err(err) => { - let msg = - CString::new(format!("create_image() failed: {:?}", err)).unwrap(); - gfx_critical_note(msg.as_ptr()); - return None; - } - Ok(image) => image, - }; - - let mut image_modifier_properties = - vk::ImageDrmFormatModifierPropertiesEXT::default(); - let image_drm_format_modifier = - ash::ext::image_drm_format_modifier::Device::new(instance, device); - let ret = image_drm_format_modifier.get_image_drm_format_modifier_properties( - image, - &mut image_modifier_properties, - ); - if ret.is_err() { - let msg = CString::new(format!( - "get_image_drm_format_modifier_properties() failed: {:?}", - ret - )) - .unwrap(); - gfx_critical_note(msg.as_ptr()); - return None; - } - - let memory_req = device.get_image_memory_requirements(image); + let mut modifier_props = + vec![vk::DrmFormatModifierPropertiesEXT::default(); count as usize]; - let mem_properties = - instance.get_physical_device_memory_properties(physical_device); - - let index = mem_properties - .memory_types - .iter() - .enumerate() - .position(|(i, t)| { - ((1 << i) & memory_req.memory_type_bits) != 0 - && t.property_flags - .contains(vk::MemoryPropertyFlags::DEVICE_LOCAL) - }); + let mut drm_format_modifier_props_list = + vk::DrmFormatModifierPropertiesListEXT::default() + .drm_format_modifier_properties(&mut modifier_props); + let mut format_properties_2 = + vk::FormatProperties2::default().push_next(&mut drm_format_modifier_props_list); - let index = match index { - None => { - let msg = c"Failed to get DEVICE_LOCAL memory index"; - gfx_critical_note(msg.as_ptr()); - return None; - } - Some(index) => index, - }; - - let mut dedicated_memory_info = - vk::MemoryDedicatedAllocateInfo::default().image(image); - - let memory_allocate_info = vk::MemoryAllocateInfo::default() - .allocation_size(memory_req.size) - .memory_type_index(index as u32) - .push_next(&mut dedicated_memory_info) - .push_next(&mut export_memory_alloc_info); + instance.get_physical_device_format_properties2( + physical_device, + vk::Format::R8G8B8A8_UNORM, + &mut format_properties_2, + ); - let memory = match device.allocate_memory(&memory_allocate_info, None) { - Err(err) => { - let msg = - CString::new(format!("allocate_memory() failed: {:?}", err)).unwrap(); - gfx_critical_note(msg.as_ptr()); - return None; - } - Ok(memory) => memory, - }; - - let result = device.bind_image_memory(image, memory, /* offset */ 0); - if result.is_err() { - let msg = - CString::new(format!("bind_image_memory() failed: {:?}", result)).unwrap(); - gfx_critical_note(msg.as_ptr()); - return None; - } - - *out_memory_size = memory_req.size; + let mut usage_flags = vk::ImageUsageFlags::empty(); + usage_flags |= vk::ImageUsageFlags::COLOR_ATTACHMENT; - let modifier_prop = modifier_props.iter().find(|prop| { - prop.drm_format_modifier == image_modifier_properties.drm_format_modifier - }); - let modifier_prop = match modifier_prop { - None => { - let msg = c"failed to find modifier_prop"; - gfx_critical_note(msg.as_ptr()); - return None; - } - Some(modifier_prop) => modifier_prop, - }; - - let plane_count = modifier_prop.drm_format_modifier_plane_count; + modifier_props.retain(|modifier_prop| { + let support = is_dmabuf_supported( + instance, + physical_device, + vk::Format::R8G8B8A8_UNORM, + modifier_prop.drm_format_modifier, + usage_flags, + ); + support + }); - let mut layouts = Vec::new(); - for i in 0..plane_count { - let flag = match i { - 0 => vk::ImageAspectFlags::PLANE_0, - 1 => vk::ImageAspectFlags::PLANE_1, - 2 => vk::ImageAspectFlags::PLANE_2, - _ => unreachable!(), - }; - let subresource = vk::ImageSubresource::default().aspect_mask(flag); - let layout = device.get_image_subresource_layout(image, subresource); - layouts.push(layout); - } - - Some(VkImageHandle { - device: device.handle(), - image, - memory, - memory_size: memory_req.size, - memory_type_index: index as u32, - modifier: image_modifier_properties.drm_format_modifier, - layouts, - }) - }, - ) - }; - - let image_handle = match image_handle { - None => { + if modifier_props.is_empty() { + let msg = c"format not supported for dmabuf import"; + gfx_critical_note(msg.as_ptr()); return ptr::null_mut(); } - Some(image_handle) => image_handle, - }; + + let modifiers: Vec<u64> = modifier_props + .iter() + .map(|modifier_prop| modifier_prop.drm_format_modifier) + .collect(); + + let mut modifier_list = vk::ImageDrmFormatModifierListCreateInfoEXT::default() + .drm_format_modifiers(&modifiers); + + let extent = vk::Extent3D { + width, + height, + depth: 1, + }; + + let mut external_image_create_info = vk::ExternalMemoryImageCreateInfo::default() + .handle_types(vk::ExternalMemoryHandleTypeFlags::DMA_BUF_EXT); + + let mut export_memory_alloc_info = vk::ExportMemoryAllocateInfo::default() + .handle_types(vk::ExternalMemoryHandleTypeFlags::DMA_BUF_EXT); + + let flags = vk::ImageCreateFlags::empty(); + + let vk_info = vk::ImageCreateInfo::default() + .flags(flags) + .image_type(vk::ImageType::TYPE_2D) + .format(vk::Format::R8G8B8A8_UNORM) + .extent(extent) + .mip_levels(1) + .array_layers(1) + .samples(vk::SampleCountFlags::TYPE_1) + .tiling(vk::ImageTiling::DRM_FORMAT_MODIFIER_EXT) + .usage(usage_flags) + .sharing_mode(vk::SharingMode::EXCLUSIVE) + .initial_layout(vk::ImageLayout::UNDEFINED) + .push_next(&mut modifier_list) + .push_next(&mut external_image_create_info); + + let image = match device.create_image(&vk_info, None) { + Err(err) => { + let msg = + CString::new(format!("create_image() failed: {:?}", err)).unwrap(); + gfx_critical_note(msg.as_ptr()); + return ptr::null_mut(); + } + Ok(image) => image, + }; + + let mut image_modifier_properties = + vk::ImageDrmFormatModifierPropertiesEXT::default(); + let image_drm_format_modifier = + ash::ext::image_drm_format_modifier::Device::new(instance, device); + let ret = image_drm_format_modifier.get_image_drm_format_modifier_properties( + image, + &mut image_modifier_properties, + ); + if ret.is_err() { + let msg = CString::new(format!( + "get_image_drm_format_modifier_properties() failed: {:?}", + ret + )) + .unwrap(); + gfx_critical_note(msg.as_ptr()); + return ptr::null_mut(); + } + + let memory_req = device.get_image_memory_requirements(image); + + let mem_properties = + instance.get_physical_device_memory_properties(physical_device); - Box::into_raw(Box::new(image_handle)) + let index = mem_properties + .memory_types + .iter() + .enumerate() + .position(|(i, t)| { + ((1 << i) & memory_req.memory_type_bits) != 0 + && t.property_flags + .contains(vk::MemoryPropertyFlags::DEVICE_LOCAL) + }); + + let Some(index) = index else { + let msg = c"Failed to get DEVICE_LOCAL memory index"; + gfx_critical_note(msg.as_ptr()); + return ptr::null_mut(); + }; + + let mut dedicated_memory_info = + vk::MemoryDedicatedAllocateInfo::default().image(image); + + let memory_allocate_info = vk::MemoryAllocateInfo::default() + .allocation_size(memory_req.size) + .memory_type_index(index as u32) + .push_next(&mut dedicated_memory_info) + .push_next(&mut export_memory_alloc_info); + + let memory = match device.allocate_memory(&memory_allocate_info, None) { + Err(err) => { + let msg = + CString::new(format!("allocate_memory() failed: {:?}", err)).unwrap(); + gfx_critical_note(msg.as_ptr()); + return ptr::null_mut(); + } + Ok(memory) => memory, + }; + + let result = device.bind_image_memory(image, memory, /* offset */ 0); + if result.is_err() { + let msg = CString::new(format!("bind_image_memory() failed: {:?}", result)).unwrap(); + gfx_critical_note(msg.as_ptr()); + return ptr::null_mut(); + } + + *out_memory_size = memory_req.size; + + let modifier_prop = modifier_props.iter().find(|prop| { + prop.drm_format_modifier == image_modifier_properties.drm_format_modifier + }); + let Some(modifier_prop) = modifier_prop else { + let msg = c"failed to find modifier_prop"; + gfx_critical_note(msg.as_ptr()); + return ptr::null_mut(); + }; + + let plane_count = modifier_prop.drm_format_modifier_plane_count; + + let mut layouts = Vec::new(); + for i in 0..plane_count { + let flag = match i { + 0 => vk::ImageAspectFlags::PLANE_0, + 1 => vk::ImageAspectFlags::PLANE_1, + 2 => vk::ImageAspectFlags::PLANE_2, + _ => unreachable!(), + }; + let subresource = vk::ImageSubresource::default().aspect_mask(flag); + let layout = device.get_image_subresource_layout(image, subresource); + layouts.push(layout); + } + + let image_handle = VkImageHandle { + device: device.handle(), + image, + memory, + memory_size: memory_req.size, + memory_type_index: index as u32, + modifier: image_modifier_properties.drm_format_modifier, + layouts, + }; + + Box::into_raw(Box::new(image_handle)) + } } #[no_mangle] #[cfg(target_os = "linux")] pub unsafe extern "C" fn wgpu_vkimage_destroy( global: &Global, device_id: id::DeviceId, handle: &VkImageHandle, @@ -1128,40 +1066,31 @@ pub unsafe extern "C" fn wgpu_vkimage_de #[no_mangle] #[cfg(target_os = "linux")] pub extern "C" fn wgpu_vkimage_get_file_descriptor( global: &Global, device_id: id::DeviceId, handle: &VkImageHandle, ) -> i32 { unsafe { - global.device_as_hal::<wgc::api::Vulkan, _, i32>(device_id, |hal_device| { - let hal_device = match hal_device { - None => { - let msg = c"Vulkan device is invalid"; - gfx_critical_note(msg.as_ptr()); - return -1; - } - Some(hal_device) => hal_device, - }; + let Some(hal_device) = global.device_as_hal::<wgc::api::Vulkan>(device_id) else { + emit_critical_invalid_note("Vulkan device"); + return -1; + }; + + let device = hal_device.raw_device(); + let instance = hal_device.shared_instance().raw_instance(); - let device = hal_device.raw_device(); - let instance = hal_device.shared_instance().raw_instance(); - - let get_fd_info = vk::MemoryGetFdInfoKHR::default() - .memory(handle.memory) - .handle_type(vk::ExternalMemoryHandleTypeFlags::DMA_BUF_EXT); + let get_fd_info = vk::MemoryGetFdInfoKHR::default() + .memory(handle.memory) + .handle_type(vk::ExternalMemoryHandleTypeFlags::DMA_BUF_EXT); - let loader = khr::external_memory_fd::Device::new(instance, device); + let loader = khr::external_memory_fd::Device::new(instance, device); - return match loader.get_memory_fd(&get_fd_info) { - Err(..) => -1, - Ok(fd) => fd, - }; - }) + loader.get_memory_fd(&get_fd_info).unwrap_or(-1) } } #[no_mangle] #[cfg(target_os = "linux")] pub extern "C" fn wgpu_vkimage_get_dma_buf_info(handle: &VkImageHandle) -> DMABufInfo { let mut offsets: [u64; 3] = [0; 3]; let mut strides: [u64; 3] = [0; 3]; @@ -1190,20 +1119,18 @@ pub struct MetalSharedEventHandle; #[allow(unused_variables)] pub extern "C" fn wgpu_server_get_device_fence_metal_shared_event( global: &Global, device_id: id::DeviceId, ) -> *mut MetalSharedEventHandle { #[cfg(target_os = "macos")] { let shared_event = unsafe { - global.device_fence_as_hal::<wgc::api::Metal, _, Option<metal::SharedEvent>>( - device_id, - |hal_fence| hal_fence.map(|fence| fence.raw_shared_event().unwrap().clone()), - ) + global.device_fence_as_hal::<wgc::api::Metal>(device_id) + .map(|fence| fence.raw_shared_event().unwrap().clone()) }; let shared_event = match shared_event { Some(shared_event) => shared_event, None => { return ptr::null_mut(); } }; return Box::into_raw(Box::new(MetalSharedEventHandle(shared_event))); @@ -1473,36 +1400,26 @@ impl Global { fn create_texture_with_shared_texture_d3d11( &self, device_id: id::DeviceId, texture_id: id::TextureId, desc: &wgc::resource::TextureDescriptor, swap_chain_id: Option<SwapChainId>, ) -> bool { let dx12_device = unsafe { - self.device_as_hal::<wgc::api::Dx12, _, Option<Direct3D12::ID3D12Device>>( - device_id, - |hal_device| { - if hal_device.is_none() { - return None; - } - hal_device.map(|hal_device| hal_device.raw_device().clone()) - }, - ) + match self.device_as_hal::<wgc::api::Dx12>(device_id) + .map(|hal_device| hal_device.raw_device().clone()) { + None => { + emit_critical_invalid_note("dx12 device"); + return false; + } + Some(dx12_device) => dx12_device, + } }; - if dx12_device.is_none() { - let msg = c"dx12 device is none"; - unsafe { - gfx_critical_note(msg.as_ptr()); - } - return false; - } - - let dx12_device = dx12_device.unwrap(); let ret = unsafe { wgpu_server_ensure_shared_texture_for_swap_chain( self.webgpu_parent, swap_chain_id.unwrap(), device_id, texture_id, desc.size.width, desc.size.height, @@ -1566,216 +1483,186 @@ impl Global { #[cfg(target_os = "linux")] fn create_texture_with_shared_texture_dmabuf( &self, device_id: id::DeviceId, texture_id: id::TextureId, desc: &wgc::resource::TextureDescriptor, swap_chain_id: Option<SwapChainId>, ) -> bool { - let ret = unsafe { - wgpu_server_ensure_shared_texture_for_swap_chain( + unsafe { + let ret = wgpu_server_ensure_shared_texture_for_swap_chain( self.webgpu_parent, swap_chain_id.unwrap(), device_id, texture_id, desc.size.width, desc.size.height, desc.format, desc.usage, - ) - }; - if ret != true { - let msg = c"Failed to create shared texture"; - unsafe { + ); + if ret != true { + let msg = c"Failed to create shared texture"; gfx_critical_note(msg.as_ptr()); - } - return false; - } - - let handle = unsafe { wgpu_server_get_vk_image_handle(self.webgpu_parent, texture_id) }; - if handle.is_null() { - let msg = c"Failed to get VkImageHandle"; - unsafe { - gfx_critical_note(msg.as_ptr()); - } - return false; - } - - let vk_image_wrapper = unsafe { &*handle }; - - let fd = unsafe { wgpu_server_get_dma_buf_fd(self.webgpu_parent, texture_id) }; - if fd < 0 { - let msg = c"Failed to get DMABuf fd"; - unsafe { - gfx_critical_note(msg.as_ptr()); + return false; } - return false; - } - - // Ensure to close file descriptor - let owned_fd = unsafe { OwnedFd::from_raw_fd(fd as RawFd) }; - - let image_holder = unsafe { - self.device_as_hal::<wgc::api::Vulkan, _, Option<VkImageHolder>>( - device_id, - |hal_device| { - let hal_device = match hal_device { - None => { - let msg = c"Vulkan device is invalid"; - gfx_critical_note(msg.as_ptr()); - return None; - } - Some(hal_device) => hal_device, - }; - - let device = hal_device.raw_device(); - - let extent = vk::Extent3D { - width: desc.size.width, - height: desc.size.height, - depth: 1, - }; - let mut usage_flags = vk::ImageUsageFlags::empty(); - usage_flags |= vk::ImageUsageFlags::COLOR_ATTACHMENT; - - let mut external_image_create_info = - vk::ExternalMemoryImageCreateInfo::default() - .handle_types(vk::ExternalMemoryHandleTypeFlags::DMA_BUF_EXT); - let vk_info = vk::ImageCreateInfo::default() - .flags(vk::ImageCreateFlags::ALIAS) - .image_type(vk::ImageType::TYPE_2D) - .format(vk::Format::R8G8B8A8_UNORM) - .extent(extent) - .mip_levels(1) - .array_layers(1) - .samples(vk::SampleCountFlags::TYPE_1) - .tiling(vk::ImageTiling::OPTIMAL) - .usage(usage_flags) - .sharing_mode(vk::SharingMode::EXCLUSIVE) - .initial_layout(vk::ImageLayout::UNDEFINED) - .push_next(&mut external_image_create_info); - - let image = match device.create_image(&vk_info, None) { - Err(err) => { - let msg = - CString::new(format!("create_image() failed: {:?}", err)).unwrap(); - gfx_critical_note(msg.as_ptr()); - return None; - } - Ok(image) => image, - }; - - let memory_req = device.get_image_memory_requirements(image); - if memory_req.size > vk_image_wrapper.memory_size { - let msg = c"Invalid memory size"; - gfx_critical_note(msg.as_ptr()); - return None; - } - - let mut dedicated_memory_info = - vk::MemoryDedicatedAllocateInfo::default().image(image); - - let mut import_memory_fd_info = vk::ImportMemoryFdInfoKHR::default() - .handle_type(vk::ExternalMemoryHandleTypeFlags::DMA_BUF_EXT) - .fd(owned_fd.into_raw_fd()); + let handle = wgpu_server_get_vk_image_handle(self.webgpu_parent, texture_id); + if handle.is_null() { + let msg = c"Failed to get VkImageHandle"; + gfx_critical_note(msg.as_ptr()); + return false; + } - let memory_allocate_info = vk::MemoryAllocateInfo::default() - .allocation_size(vk_image_wrapper.memory_size) - .memory_type_index(vk_image_wrapper.memory_type_index) - .push_next(&mut dedicated_memory_info) - .push_next(&mut import_memory_fd_info); - - let memory = match device.allocate_memory(&memory_allocate_info, None) { - Err(err) => { - let msg = CString::new(format!("allocate_memory() failed: {:?}", err)) - .unwrap(); - gfx_critical_note(msg.as_ptr()); - return None; - } - Ok(memory) => memory, - }; + let vk_image_wrapper = &*handle; - let result = device.bind_image_memory(image, memory, /* offset */ 0); - if result.is_err() { - let msg = CString::new(format!("bind_image_memory() failed: {:?}", result)) - .unwrap(); - gfx_critical_note(msg.as_ptr()); - return None; - } - - Some(VkImageHolder { - device: device.handle(), - image, - memory, - fn_destroy_image: device.fp_v1_0().destroy_image, - fn_free_memory: device.fp_v1_0().free_memory, - }) - }, - ) - }; - - let image_holder = match image_holder { - None => { - let msg = c"Failed to get vk::Image"; - unsafe { - gfx_critical_note(msg.as_ptr()); - } + let fd = wgpu_server_get_dma_buf_fd(self.webgpu_parent, texture_id); + if fd < 0 { + let msg = c"Failed to get DMABuf fd"; + gfx_critical_note(msg.as_ptr()); return false; } - Some(image_holder) => image_holder, - }; + + // Ensure to close file descriptor + let owned_fd = OwnedFd::from_raw_fd(fd as RawFd); + + let Some(hal_device) = self.device_as_hal::<wgc::api::Vulkan>(device_id) else { + emit_critical_invalid_note("Vulkan device"); + return false; + }; + + let device = hal_device.raw_device(); + + let extent = vk::Extent3D { + width: desc.size.width, + height: desc.size.height, + depth: 1, + }; + let mut usage_flags = vk::ImageUsageFlags::empty(); + usage_flags |= vk::ImageUsageFlags::COLOR_ATTACHMENT; + + let mut external_image_create_info = + vk::ExternalMemoryImageCreateInfo::default() + .handle_types(vk::ExternalMemoryHandleTypeFlags::DMA_BUF_EXT); + + let vk_info = vk::ImageCreateInfo::default() + .flags(vk::ImageCreateFlags::ALIAS) + .image_type(vk::ImageType::TYPE_2D) + .format(vk::Format::R8G8B8A8_UNORM) + .extent(extent) + .mip_levels(1) + .array_layers(1) + .samples(vk::SampleCountFlags::TYPE_1) + .tiling(vk::ImageTiling::OPTIMAL) + .usage(usage_flags) + .sharing_mode(vk::SharingMode::EXCLUSIVE) + .initial_layout(vk::ImageLayout::UNDEFINED) + .push_next(&mut external_image_create_info); + + let image = match device.create_image(&vk_info, None) { + Err(err) => { + let msg = + CString::new(format!("Failed to get vk::Image: create_image() failed: {:?}", err)).unwrap(); + gfx_critical_note(msg.as_ptr()); + return false; + } + Ok(image) => image, + }; + + let memory_req = device.get_image_memory_requirements(image); + if memory_req.size > vk_image_wrapper.memory_size { + let msg = c"Invalid memory size"; + gfx_critical_note(msg.as_ptr()); + return false; + } - let hal_desc = wgh::TextureDescriptor { - label: None, - size: desc.size, - mip_level_count: desc.mip_level_count, - sample_count: desc.sample_count, - dimension: desc.dimension, - format: desc.format, - usage: wgt::TextureUses::COPY_DST | wgt::TextureUses::COLOR_TARGET, - memory_flags: wgh::MemoryFlags::empty(), - view_formats: vec![], - }; + let mut dedicated_memory_info = + vk::MemoryDedicatedAllocateInfo::default().image(image); + + let mut import_memory_fd_info = vk::ImportMemoryFdInfoKHR::default() + .handle_type(vk::ExternalMemoryHandleTypeFlags::DMA_BUF_EXT) + .fd(owned_fd.into_raw_fd()); + + let memory_allocate_info = vk::MemoryAllocateInfo::default() + .allocation_size(vk_image_wrapper.memory_size) + .memory_type_index(vk_image_wrapper.memory_type_index) + .push_next(&mut dedicated_memory_info) + .push_next(&mut import_memory_fd_info); + + let memory = match device.allocate_memory(&memory_allocate_info, None) { + Err(err) => { + let msg = CString::new(format!("Failed to get vk::Image: allocate_memory() failed: {:?}", err)) + .unwrap(); + gfx_critical_note(msg.as_ptr()); + return false; + } + Ok(memory) => memory, + }; - let image = image_holder.image; + match device.bind_image_memory(image, memory, /* offset */ 0) { + Ok(()) => {} + Err(err) => { + let msg = CString::new(format!("Failed to get vk::Image: bind_image_memory() failed: {:?}", err)) + .unwrap(); + gfx_critical_note(msg.as_ptr()); + return false; + } + } - let hal_texture = unsafe { - <wgh::api::Vulkan as wgh::Api>::Device::texture_from_raw( + let image_holder = VkImageHolder { + device: device.handle(), + image, + memory, + fn_destroy_image: device.fp_v1_0().destroy_image, + fn_free_memory: device.fp_v1_0().free_memory, + }; + + let hal_desc = wgh::TextureDescriptor { + label: None, + size: desc.size, + mip_level_count: desc.mip_level_count, + sample_count: desc.sample_count, + dimension: desc.dimension, + format: desc.format, + usage: wgt::TextureUses::COPY_DST | wgt::TextureUses::COLOR_TARGET, + memory_flags: wgh::MemoryFlags::empty(), + view_formats: vec![], + }; + + let image = image_holder.image; + + let hal_texture = <wgh::api::Vulkan as wgh::Api>::Device::texture_from_raw( image, &hal_desc, Some(Box::new(move || { image_holder.destroy(); })), - ) - }; + ); - let (_, error) = unsafe { - self.create_texture_from_hal(Box::new(hal_texture), device_id, &desc, Some(texture_id)) - }; - if let Some(err) = error { - let msg = CString::new(format!("create_texture_from_hal() failed: {:?}", err)).unwrap(); - unsafe { + let (_, error) = self.create_texture_from_hal(Box::new(hal_texture), device_id, &desc, Some(texture_id)); + if let Some(err) = error { + let msg = CString::new(format!("create_texture_from_hal() failed: {:?}", err)).unwrap(); gfx_critical_note(msg.as_ptr()); + return false; } - return false; + + true } - - true } #[cfg(target_os = "macos")] fn create_texture_with_shared_texture_iosurface( &self, device_id: id::DeviceId, texture_id: id::TextureId, desc: &wgc::resource::TextureDescriptor, swap_chain_id: Option<SwapChainId>, ) -> bool { + use metal::foreign_types::ForeignType as _; + let ret = unsafe { wgpu_server_ensure_shared_texture_for_swap_chain( self.webgpu_parent, swap_chain_id.unwrap(), device_id, texture_id, desc.size.width, desc.size.height, @@ -1800,70 +1687,58 @@ impl Global { } return false; } let io_surface = io_surface::lookup(io_surface_id); let desc_ref = &desc; - let raw = unsafe { - self.device_as_hal::<wgc::api::Metal, _, Option<metal::Texture>>( - device_id, - |hal_device| { - let hal_device = match hal_device { - None => { - let msg = c"metal device is invalid"; - gfx_critical_note(msg.as_ptr()); - return None; - } - Some(hal_device) => hal_device, - }; + let raw_texture: metal::Texture = unsafe { + let Some(hal_device) = self.device_as_hal::<wgc::api::Metal>(device_id) else { + emit_critical_invalid_note("metal device"); + return false; + }; - use metal::foreign_types::ForeignType as _; - let device = hal_device.raw_device(); + let device = hal_device.raw_device(); - objc::rc::autoreleasepool(|| { - let descriptor = metal::TextureDescriptor::new(); - let usage = metal::MTLTextureUsage::RenderTarget - | metal::MTLTextureUsage::ShaderRead - | metal::MTLTextureUsage::PixelFormatView; + objc::rc::autoreleasepool(|| { + let descriptor = metal::TextureDescriptor::new(); + let usage = metal::MTLTextureUsage::RenderTarget + | metal::MTLTextureUsage::ShaderRead + | metal::MTLTextureUsage::PixelFormatView; - descriptor.set_texture_type(metal::MTLTextureType::D2); - descriptor.set_width(desc_ref.size.width as u64); - descriptor.set_height(desc_ref.size.height as u64); - descriptor.set_mipmap_level_count(desc_ref.mip_level_count as u64); - descriptor.set_pixel_format(metal::MTLPixelFormat::BGRA8Unorm); - descriptor.set_usage(usage); - descriptor.set_storage_mode(metal::MTLStorageMode::Private); - - let raw_device = device.lock(); - let raw_texture: metal::Texture = msg_send![*raw_device, newTextureWithDescriptor: descriptor - iosurface:io_surface.obj - plane:0]; + descriptor.set_texture_type(metal::MTLTextureType::D2); + descriptor.set_width(desc_ref.size.width as u64); + descriptor.set_height(desc_ref.size.height as u64); + descriptor.set_mipmap_level_count(desc_ref.mip_level_count as u64); + descriptor.set_pixel_format(metal::MTLPixelFormat::BGRA8Unorm); + descriptor.set_usage(usage); + descriptor.set_storage_mode(metal::MTLStorageMode::Private); - if raw_texture.as_ptr().is_null() { - let msg = c"Failed to create metal::Texture for swap chain"; - gfx_critical_note(msg.as_ptr()); - return None; - } + let raw_device = device.lock(); + msg_send![*raw_device, newTextureWithDescriptor: descriptor iosurface:io_surface.obj plane:0] + }) + }; - if let Some(label) = &desc_ref.label { - raw_texture.set_label(&label); - } + if raw_texture.as_ptr().is_null() { + let msg = c"Failed to create metal::Texture for swap chain"; + unsafe { + gfx_critical_note(msg.as_ptr()); + } + return false; + } - Some(raw_texture) - }) - }, - ) - }; + if let Some(label) = &desc_ref.label { + raw_texture.set_label(&label); + } let hal_texture = unsafe { <wgh::api::Metal as wgh::Api>::Device::texture_from_raw( - raw.unwrap(), + raw_texture, wgt::TextureFormat::Bgra8Unorm, metal::MTLTextureType::D2, 1, 1, wgh::CopyExtent { width: desc.size.width, height: desc.size.height, depth: 1, @@ -2958,86 +2833,76 @@ pub struct SubmittedWorkDoneClosure { unsafe impl Send for SubmittedWorkDoneClosure {} #[derive(Debug)] #[cfg(target_os = "linux")] pub struct VkSemaphoreHandle { pub semaphore: vk::Semaphore, } -#[allow(dead_code)] -fn emit_critical_invalid_note_if_none<T>(what: &'static str, t: Option<T>) -> Option<T> { - if t.is_none() { - // SAFETY: We ensure that the pointer provided is not null. - let msg = CString::new(format!("{what} is invalid")).unwrap(); - unsafe { gfx_critical_note(msg.as_ptr()) } - } - t -} - #[no_mangle] #[cfg(target_os = "linux")] pub extern "C" fn wgpu_vksemaphore_create_signal_semaphore( global: &Global, queue_id: id::QueueId, ) -> *mut VkSemaphoreHandle { let semaphore_handle = unsafe { - global.queue_as_hal::<wgc::api::Vulkan, _, Option<VkSemaphoreHandle>>( - queue_id, - |hal_queue| { - let hal_queue = emit_critical_invalid_note_if_none("Vulkan queue", hal_queue)?; - let device = hal_queue.raw_device(); + let Some(hal_queue) = global.queue_as_hal::<wgc::api::Vulkan>(queue_id) else { + emit_critical_invalid_note("Vulkan queue"); + return ptr::null_mut(); + }; + let device = hal_queue.raw_device(); - let mut export_semaphore_create_info = vk::ExportSemaphoreCreateInfo::default() - .handle_types(vk::ExternalSemaphoreHandleTypeFlags::OPAQUE_FD); - let create_info = - vk::SemaphoreCreateInfo::default().push_next(&mut export_semaphore_create_info); - let semaphore = match device.create_semaphore(&create_info, None) { - Err(err) => { - let msg = - CString::new(format!("create_semaphore() failed: {:?}", err)).unwrap(); - gfx_critical_note(msg.as_ptr()); - return None; - } - Ok(semaphore) => semaphore, - }; + let mut export_semaphore_create_info = vk::ExportSemaphoreCreateInfo::default() + .handle_types(vk::ExternalSemaphoreHandleTypeFlags::OPAQUE_FD); + let create_info = + vk::SemaphoreCreateInfo::default().push_next(&mut export_semaphore_create_info); + let semaphore = match device.create_semaphore(&create_info, None) { + Err(err) => { + let msg = + CString::new(format!("create_semaphore() failed: {:?}", err)).unwrap(); + gfx_critical_note(msg.as_ptr()); + return ptr::null_mut(); + } + Ok(semaphore) => semaphore, + }; - hal_queue.add_signal_semaphore(semaphore, None); + hal_queue.add_signal_semaphore(semaphore, None); - Some(VkSemaphoreHandle { semaphore }) - }, - ) + VkSemaphoreHandle { semaphore } }; - match semaphore_handle { - None => ptr::null_mut(), - Some(semaphore_handle) => Box::into_raw(Box::new(semaphore_handle)), - } + Box::into_raw(Box::new(semaphore_handle)) } #[no_mangle] #[cfg(target_os = "linux")] pub unsafe extern "C" fn wgpu_vksemaphore_get_file_descriptor( global: &Global, device_id: id::DeviceId, handle: &VkSemaphoreHandle, ) -> i32 { let file_descriptor = unsafe { - global.device_as_hal::<wgc::api::Vulkan, _, Option<i32>>(device_id, |hal_device| { - let hal_device = emit_critical_invalid_note_if_none("Vulkan device", hal_device)?; - let device = hal_device.raw_device(); - let instance = hal_device.shared_instance().raw_instance(); + match global.device_as_hal::<wgc::api::Vulkan>(device_id) { + None => { + emit_critical_invalid_note("Vulkan device"); + None + } + Some(hal_device) => { + let device = hal_device.raw_device(); + let instance = hal_device.shared_instance().raw_instance(); - let external_semaphore_fd = khr::external_semaphore_fd::Device::new(instance, device); - let get_fd_info = vk::SemaphoreGetFdInfoKHR::default() - .semaphore(handle.semaphore) - .handle_type(vk::ExternalSemaphoreHandleTypeFlags::OPAQUE_FD); + let external_semaphore_fd = khr::external_semaphore_fd::Device::new(instance, device); + let get_fd_info = vk::SemaphoreGetFdInfoKHR::default() + .semaphore(handle.semaphore) + .handle_type(vk::ExternalSemaphoreHandleTypeFlags::OPAQUE_FD); - external_semaphore_fd.get_semaphore_fd(&get_fd_info).ok() - }) + external_semaphore_fd.get_semaphore_fd(&get_fd_info).ok() + } + } }; // From [Wikipedia](https://en.wikipedia.org/wiki/File_descriptor): // // > File descriptors typically have non-negative integer values, with negative values // > being reserved to indicate "no value" or error conditions. file_descriptor.unwrap_or(-1) } @@ -3045,27 +2910,22 @@ pub unsafe extern "C" fn wgpu_vksemaphor #[no_mangle] #[cfg(target_os = "linux")] pub unsafe extern "C" fn wgpu_vksemaphore_destroy( global: &Global, device_id: id::DeviceId, handle: &VkSemaphoreHandle, ) { unsafe { - global.device_as_hal::<wgc::api::Vulkan, _, ()>(device_id, |hal_device| { - let hal_device = emit_critical_invalid_note_if_none("Vulkan device", hal_device); - let hal_device = match hal_device { - None => { - return; - } - Some(hal_device) => hal_device, - }; - let device = hal_device.raw_device(); - device.destroy_semaphore(handle.semaphore, None); - }) + let Some(hal_device) = global.device_as_hal::<wgc::api::Vulkan>(device_id) else { + emit_critical_invalid_note("Vulkan device"); + return; + }; + let device = hal_device.raw_device(); + device.destroy_semaphore(handle.semaphore, None); }; } #[no_mangle] #[cfg(target_os = "linux")] pub unsafe extern "C" fn wgpu_vksemaphore_delete(handle: *mut VkSemaphoreHandle) { let _ = Box::from_raw(handle); }
--- a/supply-chain/audits.toml +++ b/supply-chain/audits.toml @@ -4029,16 +4029,22 @@ criteria = "safe-to-deploy" delta = "25.0.0 -> 25.0.0@git:12591e42715badafef264609cb29d4a8e0b90847" importable = false [[audits.naga]] who = "Erich Gubler <erichdongubler@gmail.com>" criteria = "safe-to-deploy" delta = "25.0.0 -> 26.0.0" +[[audits.naga]] +who = "Andy Leiserson <aleiserson@mozilla.com>" +criteria = "safe-to-deploy" +delta = "26.0.0 -> 26.0.0@git:b83c9cfd578837a6163d980130249c245a9c5f8a" +importable = false + [[audits.net2]] who = "Mike Hommey <mh+mozilla@glandium.org>" criteria = "safe-to-run" delta = "0.2.37 -> 0.2.38" [[audits.new_debug_unreachable]] who = "Bobby Holley <bobbyholley@gmail.com>" criteria = "safe-to-deploy" @@ -6425,16 +6431,22 @@ criteria = "safe-to-deploy" delta = "25.0.0 -> 25.0.0@git:12591e42715badafef264609cb29d4a8e0b90847" importable = false [[audits.wgpu-core]] who = "Erich Gubler <erichdongubler@gmail.com>" criteria = "safe-to-deploy" delta = "25.0.0 -> 26.0.0" +[[audits.wgpu-core]] +who = "Andy Leiserson <aleiserson@mozilla.com>" +criteria = "safe-to-deploy" +delta = "26.0.0 -> 26.0.0@git:b83c9cfd578837a6163d980130249c245a9c5f8a" +importable = false + [[audits.wgpu-core-deps-apple]] who = "Erich Gubler <erichdongubler@gmail.com>" criteria = "safe-to-deploy" version = "25.0.0" [[audits.wgpu-core-deps-apple]] who = [ "Teodor Tanasoaia <ttanasoaia@mozilla.com>", @@ -6446,16 +6458,22 @@ criteria = "safe-to-deploy" delta = "25.0.0 -> 25.0.0@git:12591e42715badafef264609cb29d4a8e0b90847" importable = false [[audits.wgpu-core-deps-apple]] who = "Erich Gubler <erichdongubler@gmail.com>" criteria = "safe-to-deploy" delta = "25.0.0 -> 26.0.0" +[[audits.wgpu-core-deps-apple]] +who = "Andy Leiserson <aleiserson@mozilla.com>" +criteria = "safe-to-deploy" +delta = "26.0.0 -> 26.0.0@git:b83c9cfd578837a6163d980130249c245a9c5f8a" +importable = false + [[audits.wgpu-core-deps-windows-linux-android]] who = "Erich Gubler <erichdongubler@gmail.com>" criteria = "safe-to-deploy" version = "25.0.0" [[audits.wgpu-core-deps-windows-linux-android]] who = [ "Teodor Tanasoaia <ttanasoaia@mozilla.com>", @@ -6467,16 +6485,22 @@ criteria = "safe-to-deploy" delta = "25.0.0 -> 25.0.0@git:12591e42715badafef264609cb29d4a8e0b90847" importable = false [[audits.wgpu-core-deps-windows-linux-android]] who = "Erich Gubler <erichdongubler@gmail.com>" criteria = "safe-to-deploy" delta = "25.0.0 -> 26.0.0" +[[audits.wgpu-core-deps-windows-linux-android]] +who = "Andy Leiserson <aleiserson@mozilla.com>" +criteria = "safe-to-deploy" +delta = "26.0.0 -> 26.0.0@git:b83c9cfd578837a6163d980130249c245a9c5f8a" +importable = false + [[audits.wgpu-hal]] who = "Dzmitry Malyshau <kvark@fastmail.com>" criteria = "safe-to-deploy" version = "0.12.0" notes = """ This crate, up through the indicated version, was written or reviewed by Dzmitry Malyshau while he was a Mozilla employee. Dzmitry left Mozilla at the beginning of February 2022. This audit statement was @@ -6566,16 +6590,22 @@ criteria = "safe-to-deploy" delta = "25.0.0 -> 25.0.0@git:12591e42715badafef264609cb29d4a8e0b90847" importable = false [[audits.wgpu-hal]] who = "Erich Gubler <erichdongubler@gmail.com>" criteria = "safe-to-deploy" delta = "25.0.0 -> 26.0.0" +[[audits.wgpu-hal]] +who = "Andy Leiserson <aleiserson@mozilla.com>" +criteria = "safe-to-deploy" +delta = "26.0.0 -> 26.0.0@git:b83c9cfd578837a6163d980130249c245a9c5f8a" +importable = false + [[audits.wgpu-types]] who = "Dzmitry Malyshau <kvark@fastmail.com>" criteria = "safe-to-deploy" version = "0.12.0" notes = """ This crate, up through the indicated version, was written or reviewed by Dzmitry Malyshau while he was a Mozilla employee. Dzmitry left Mozilla at the beginning of February 2022. This audit statement was @@ -6660,16 +6690,22 @@ criteria = "safe-to-deploy" delta = "25.0.0 -> 25.0.0@git:12591e42715badafef264609cb29d4a8e0b90847" importable = false [[audits.wgpu-types]] who = "Erich Gubler <erichdongubler@gmail.com>" criteria = "safe-to-deploy" delta = "25.0.0 -> 26.0.0" +[[audits.wgpu-types]] +who = "Andy Leiserson <aleiserson@mozilla.com>" +criteria = "safe-to-deploy" +delta = "26.0.0 -> 26.0.0@git:b83c9cfd578837a6163d980130249c245a9c5f8a" +importable = false + [[audits.whatsys]] who = "Bobby Holley <bobbyholley@gmail.com>" criteria = "safe-to-deploy" version = "0.1.2" notes = """ Contains platform-specific FFI code for apple, mac, and windows. The windows code also contains a small C file compiled at build-time. I audited all of it and it looks correct.
--- a/testing/web-platform/mozilla/meta/webgpu/cts/webgpu/api/validation/encoding/cmds/render/setIndexBuffer/cts.https.html.ini +++ b/testing/web-platform/mozilla/meta/webgpu/cts/webgpu/api/validation/encoding/cmds/render/setIndexBuffer/cts.https.html.ini @@ -12,17 +12,9 @@ [cts.https.html?q=webgpu:api,validation,encoding,cmds,render,setIndexBuffer:offset_alignment:*] implementation-status: backlog [:] expected: FAIL [cts.https.html?q=webgpu:api,validation,encoding,cmds,render,setIndexBuffer:offset_and_size_oob:*] - implementation-status: backlog - expected: - if os == "linux" and debug: CRASH - if os == "mac" and debug: CRASH [:] - expected: - if os == "win": FAIL - if os == "linux" and not debug: FAIL - if os == "mac" and not debug: FAIL
--- a/testing/web-platform/mozilla/meta/webgpu/cts/webgpu/api/validation/encoding/cmds/render/setVertexBuffer/cts.https.html.ini +++ b/testing/web-platform/mozilla/meta/webgpu/cts/webgpu/api/validation/encoding/cmds/render/setVertexBuffer/cts.https.html.ini @@ -1,24 +1,16 @@ [cts.https.html?q=webgpu:api,validation,encoding,cmds,render,setVertexBuffer:offset_alignment:*] implementation-status: backlog [:] expected: FAIL [cts.https.html?q=webgpu:api,validation,encoding,cmds,render,setVertexBuffer:offset_and_size_oob:*] - implementation-status: backlog - expected: - if os == "linux" and debug: CRASH - if os == "mac" and debug: CRASH [:] - expected: - if os == "win": FAIL - if os == "linux" and not debug: FAIL - if os == "mac" and not debug: FAIL [cts.https.html?q=webgpu:api,validation,encoding,cmds,render,setVertexBuffer:slot:*] [:] [cts.https.html?q=webgpu:api,validation,encoding,cmds,render,setVertexBuffer:vertex_buffer,device_mismatch:*] [:]
--- a/testing/web-platform/mozilla/meta/webgpu/cts/webgpu/api/validation/encoding/cmds/setBindGroup/cts.https.html.ini +++ b/testing/web-platform/mozilla/meta/webgpu/cts/webgpu/api/validation/encoding/cmds/setBindGroup/cts.https.html.ini @@ -171,18 +171,17 @@ [cts.https.html?q=webgpu:api,validation,encoding,cmds,setBindGroup:state_and_binding_index:*] implementation-status: backlog expected: if os == "linux": [OK, CRASH] [:encoderType="compute%20pass";state="destroyed";resourceType="buffer"] expected: FAIL [:encoderType="compute%20pass";state="destroyed";resourceType="texture"] - expected: - if os == "win" and debug: [PASS, FAIL] + expected: FAIL [:encoderType="compute%20pass";state="invalid";resourceType="buffer"] expected: if os == "win" and debug: [PASS, FAIL] [:encoderType="compute%20pass";state="invalid";resourceType="texture"] expected: if os == "win" and debug: [PASS, FAIL] @@ -194,18 +193,17 @@ [:encoderType="compute%20pass";state="valid";resourceType="texture"] expected: if os == "win" and debug: [PASS, FAIL] [:encoderType="render%20bundle";state="destroyed";resourceType="buffer"] expected: FAIL [:encoderType="render%20bundle";state="destroyed";resourceType="texture"] - expected: - if os == "win" and debug: [PASS, FAIL] + expected: FAIL [:encoderType="render%20bundle";state="invalid";resourceType="buffer"] expected: if os == "win" and debug: [PASS, FAIL] [:encoderType="render%20bundle";state="invalid";resourceType="texture"] expected: if os == "win" and debug: [PASS, FAIL] @@ -217,18 +215,17 @@ [:encoderType="render%20bundle";state="valid";resourceType="texture"] expected: if os == "win" and debug: [PASS, FAIL] [:encoderType="render%20pass";state="destroyed";resourceType="buffer"] expected: FAIL [:encoderType="render%20pass";state="destroyed";resourceType="texture"] - expected: - if os == "win" and debug: [PASS, FAIL] + expected: FAIL [:encoderType="render%20pass";state="invalid";resourceType="buffer"] expected: if os == "win" and debug: [PASS, FAIL] [:encoderType="render%20pass";state="invalid";resourceType="texture"] expected: if os == "win" and debug: [PASS, FAIL]
--- a/testing/web-platform/mozilla/meta/webgpu/cts/webgpu/api/validation/image_copy/layout_related/cts.https.html.ini +++ b/testing/web-platform/mozilla/meta/webgpu/cts/webgpu/api/validation/image_copy/layout_related/cts.https.html.ini @@ -1685,32 +1685,21 @@ [:method="WriteTexture";dimension="2d";size=[4,4,3\]] expected: FAIL [:method="WriteTexture";dimension="3d";size=[4,4,3\]] expected: FAIL [cts.https.html?q=webgpu:api,validation,image_copy,layout_related:copy_end_overflows_u64:*] - implementation-status: - if debug: backlog - expected: - if os == "linux" and debug: CRASH - if os == "mac" and debug: CRASH [:method="CopyB2T"] - expected: - if os == "win" and debug: FAIL [:method="CopyT2B"] - expected: - if os == "win" and debug: FAIL [:method="WriteTexture"] - expected: - if os == "win" and debug: FAIL [cts.https.html?q=webgpu:api,validation,image_copy,layout_related:offset_alignment:*] [:method="CopyB2T";format="astc-10x10-unorm";dimension="2d"] [:method="CopyB2T";format="astc-10x10-unorm";dimension="3d"] [:method="CopyB2T";format="astc-10x10-unorm-srgb";dimension="2d"]
--- a/third_party/rust/naga/.cargo-checksum.json +++ b/third_party/rust/naga/.cargo-checksum.json @@ -1,1 +1,1 @@ -{"files":{".cargo/config.toml":"7248ed3bed246d755d7bf9e5d7842d74b5c270ba6c29ad907872b55a67707ee0","CHANGELOG.md":"e60105d413f857e37dae165f819c47491d0a595183d3c9146b259d811b98b14f","Cargo.toml":"3eed95bdea8c5d544ed14d6cea7d1997a66f4f0f3d8a085162b3dc591258e564","README.md":"9550cbc1a518ad0f624aabe12c342c72f670705cb4a6878c0c87d172f1dacea0","build.rs":"e9098f486e87d91710c07d40f1b32716e5debfe94a0b5e53e37075b0ee997eec","src/arena/handle.rs":"897b2b0eebe0d9ae6a65bf2e8c210c8391924da06ef4c9e2a1225ad622400b6c","src/arena/handle_set.rs":"5c2a0bcf41d85c8173ac68b2d439552e79d0c3c0fe1ff3b1e1a48f0c83a4d48f","src/arena/handlevec.rs":"999de9d55d01213789072a63ad4ae9b4635e6653984d38db8b308d42bb1e7be3","src/arena/mod.rs":"e305d0521233791e181b4b6e7de70175a6bc730811063ea066c3bd3b73d12979","src/arena/range.rs":"b783969dfe32b4937593d871aa5190d561bdd79b6f615da53cb54346e300b9e2","src/arena/unique_arena.rs":"ddd6c404c9b7d7d1aa041af1a8c3d451ef6e71339d408eac22f10d25d33d5b18","src/back/continue_forward.rs":"8194d238763caa6d5601ec3af56ba39a471c39945f43152b58d582092c99aefa","src/back/dot/mod.rs":"214622a55414393f205a7e71a5aa2bd535e76fde71b612845f251ca57bd32539","src/back/glsl/features.rs":"5975ad4ae9c2e78f795f9d2532d03fe425ce910a146f6fe8863f95a4f029b280","src/back/glsl/keywords.rs":"4cfbcf931f8b234f10b7cd807839764945cd6ece71910735d9bae362690aceed","src/back/glsl/mod.rs":"19c02133c489e35f8e7a93eceb8a2b28a31a008dfc284102bfc7a9ff66e7e90d","src/back/hlsl/conv.rs":"3e1a78203e8c4efb75986db962cec150c7b2d99f7e48b400e702233de70e8aab","src/back/hlsl/help.rs":"67786bb73f4809769d8e5f97a401f576a89803f7c95a92e59088271ccb84d9d6","src/back/hlsl/keywords.rs":"af1c16b81f14f3ae04e3911701cf0782fcaf54ad9427a13e5fdc4dd0ca441e5f","src/back/hlsl/mod.rs":"e644011ea83a6dd194e417a640deb395160d7af4460d30c1359145b3d6dacc5e","src/back/hlsl/ray.rs":"259db3bc8fd5b8ec343fb8620c7cef50048cbea2b9db1f17dc8813ff848269df","src/back/hlsl/storage.rs":"7443cea2abb6ce8d0c0c9bfe805b37b5600bd28618de44ba1ebd8e4e38eac92f","src/back/hlsl/writer.rs":"4fdaa36c745269e5759737dbb6907e5bb304b0baec8e72bd6770d979afd4a9ef","src/back/mod.rs":"1489e44272b0fbe58e6e5042fcb6299525c00ce42a811944c6f94935379e52d7","src/back/msl/keywords.rs":"f1f080b02d98a36ccde81a3b77ae12651272dffc4043ddaebd6937673154ba2b","src/back/msl/mod.rs":"f980ddf9cfaf0f7e0249a9580216cafe76405047cd949210bfbfb29ee64e1cfb","src/back/msl/sampler.rs":"9be8805063258b0ff6b6db2e6856d59326caa18f6f64eaf413c5abfcbd1ad341","src/back/msl/writer.rs":"1c6c3662d20c60261b4bc0550adca55f6e14c7164eb9456252e1ea54e40dd949","src/back/pipeline_constants.rs":"c2244d7e47a52c01ead61b4b6c7b3d0f29263ca308aca70f213137a0938c9aa4","src/back/spv/block.rs":"d005284f0fb17b4bf3e3b7323183e903bfae7e86956419b9602891ed950eaa45","src/back/spv/helpers.rs":"37ef7388b1e97edb2682b93f1f0eceb71039ecd54923d91346d974b29322077c","src/back/spv/image.rs":"e22cb4c56e29d049a512a7fe43d6ad2c059a17e06531ae84b3c9446ac27c35f6","src/back/spv/index.rs":"5f0561a83011bcf482575d209c549ce08fce85b9dd95f179f6e8c2b112e0c8e5","src/back/spv/instructions.rs":"556f1f30ae11c3e01910c354a36ba314280932e3a2928584b06eb0812a2cb81a","src/back/spv/layout.rs":"28ba27739d7c9fa4b9e363ffc112cdc39c5e8ec4236d71a7260039d1bd8321d7","src/back/spv/mod.rs":"ba6228b2addde92d6671410df87970cb31baa06818f507930f278a6307d58140","src/back/spv/ray.rs":"a31fd66e9497ffd19437bdab53427705b7f28f555ab215c8f0a4c2156283413e","src/back/spv/recyclable.rs":"8ea397d4d8d3f2cd5fbc8e0be94d136c2d6e0f0e8a4b5eb567dcc1be104c9ae5","src/back/spv/selection.rs":"aea4bb4da7c0fa4e907b8f1e185433a48f2f0eb7ded97fdd3225beb3f6c1f249","src/back/spv/subgroup.rs":"68fc3e3153022a0a8bddec20ad9221820678f02921878318e571d5aa2ca13cee","src/back/spv/writer.rs":"3e2fa86bdc1a8117512ac20eaf208124cefd77b6ef451c2d4e2da74ffa684fb9","src/back/wgsl/mod.rs":"1b04d66e8dba609513d43431d1f0ee9a209fbfd8453862d6e8a7aa41f8910997","src/back/wgsl/polyfill/inverse/inverse_2x2_f16.wgsl":"9e7635d04724822931c805a8b35e76d6d294d447e4ea8d57b308ce45609bf736","src/back/wgsl/polyfill/inverse/inverse_2x2_f32.wgsl":"340d491abde07f93996391796db65a5f88402663eaf6b9d2d894d11cb8cf8b6d","src/back/wgsl/polyfill/inverse/inverse_3x3_f16.wgsl":"4f13a1a4b3e1b51f0f992d13c55cf854a80917554a4d13c997819fa1fe776ba4","src/back/wgsl/polyfill/inverse/inverse_3x3_f32.wgsl":"9b16d2f4b9e433c8e03a0cb46ab48508f3bf7e185ce1b4e26106c47e81a677cb","src/back/wgsl/polyfill/inverse/inverse_4x4_f16.wgsl":"86d39d1db5d03995b404950279db7f1698ad9622982aa319fdedb7532673235b","src/back/wgsl/polyfill/inverse/inverse_4x4_f32.wgsl":"dc510525ac2dce66389a8c4bf8b2f31f0dedd9e6debdbe4ffd939a0a7fc533d3","src/back/wgsl/polyfill/mod.rs":"f4ab3c9b9cdc36d16dab00d0f7f07d6e6beda0e27a36053e9b5ffeeb7ca18edc","src/back/wgsl/writer.rs":"36aa1d68def860e9befd9c694d841fc5c0680f98cba61c33989cfea6eb705771","src/common/diagnostic_debug.rs":"8c73fe605e5b6162d0485e264287ac50c061cf581743feebbffe1474d1d3516d","src/common/diagnostic_display.rs":"46f1ff8a32179703ef0bcdb704db9f6e6e8b4eaad6cadf94577eeab3d8a16cd1","src/common/mod.rs":"289231637b08407fbe2cc976a1bab4eac4c9e66042c6618aff3af44baaff3e26","src/common/predeclared.rs":"a5f42d55f2e13d8f5a8213d4a881e9155c3994c4054d43edcf7bd7bb7c868ccf","src/common/wgsl/diagnostics.rs":"4fec985b4c5cc6dfae4dd78bd7c850adc88a1761d7b6691de0355ea49300e532","src/common/wgsl/mod.rs":"d944915ff692c96aecca67737bccc2d5d9eb68f475166a2744f29a025f4a4c93","src/common/wgsl/to_wgsl.rs":"c506579e7f124643a35373705a870318500e000a6a752be58666bcbb3c08fc1f","src/common/wgsl/types.rs":"9ccdd6676437ac7e282a508403eb24742dea654b380d6419ffe5aac9cd699996","src/compact/expressions.rs":"1bd4426d06afda9ba226a495406e8239a8d87bbbf8a89b6fab4a78c9bd6880cf","src/compact/functions.rs":"f9598be11b9bbdd63a2c42348b8a25422f477287b92b331ac7ebd7ba4d44d879","src/compact/handle_set_map.rs":"f282349ba0d1e35a873f6ee9ff9086ae061d3dd8e31f2a291c443bd0e7e1ebfd","src/compact/mod.rs":"03ceafe4140713c279168bcd20b17c9bb9f880d406806fd63ca2065de9950f0f","src/compact/statements.rs":"85b2faf6a4caaebc0372e773ca3be2904db5bb0e691ac7ea845720ef0864a22b","src/compact/types.rs":"a955ce5e336afa8d26f750c14d4a6638dcee6b0b5e0fcd7c446d8f88a35d8277","src/diagnostic_filter.rs":"5e3d14a774974148b7d2918617ba3e2c3a07493e0f90485a7de9db86e05a7cd0","src/error.rs":"b7f570cc9e334e2b5a1aec499b4742457eba6f2f6673de4e80c8f5499eb16793","src/front/atomic_upgrade.rs":"86ce9f9628d92a1a09802cb534bb4310236b83f2799c921b81c687f009c589be","src/front/glsl/ast.rs":"15a4f7c56aa44529373c7aa2a266d1582b7775833de6adc6b8f5bfd54d85a669","src/front/glsl/builtins.rs":"5514238a48529d2bb953a032d13014c00adfe6c497e13ac33d27a5f17ae1fc63","src/front/glsl/context.rs":"14fd933c79f49f4fb4ccabdc24ad31745777806f7464f111a4f7782662612a4b","src/front/glsl/error.rs":"4f0836fbab8dcdad0603d4e3164d17b48f5d7498b829665ed0c9c48c3fb0b410","src/front/glsl/functions.rs":"28aa0fa2e048a296df0f342d482ee5e02510ae39bfa96fb400a5892cfff71cf9","src/front/glsl/lex.rs":"24706628b600b5ce435cef464c84196ac5d58013122a97e7b59d509cc25f85a2","src/front/glsl/mod.rs":"f4f1cce6911935b305c415afe3c15f84c7824a3bb828a5d15e6f9ae4b0316df0","src/front/glsl/offset.rs":"66bd524a2d17dc44f431430dcbbb74a771fdab43c9581e88bb1123e6cfec516b","src/front/glsl/parser.rs":"6a13b4737f53b09d5bbc0add01f8fc1b2633b7957f0318374edfe0b903939912","src/front/glsl/parser/declarations.rs":"9949649fba43636d03eaf7f7560d3bb3743b19c7204fb95859283ee84b5dd239","src/front/glsl/parser/expressions.rs":"e056fbdde3bc7c8473acbd485aecd14120d3dbefbabd813ddbc5cfedaf605889","src/front/glsl/parser/functions.rs":"302e24e06190aff555131c33f9a80b15df6a0390d6c776f888a44d5ef7df697e","src/front/glsl/parser/types.rs":"ee242048a65cd3709e16b70a3882e9296e615327480f2ad779e3d2523778181f","src/front/glsl/parser_tests.rs":"6834f0d595f4077266054e5da43e4f1b60e5c6780611ab0f530d9964cc62fad3","src/front/glsl/token.rs":"83780c0c1954ef216896c9d8a48e412b357783e00ccd4909a7a249935c742629","src/front/glsl/types.rs":"286395d82707a09d28b4c1a8bade917822478e53d8eb277ceec5fa9e71649ba2","src/front/glsl/variables.rs":"75d3e203a07befd011f5693ab8f2789e4f06821badb4974043cc4ee10bd5c6c9","src/front/interpolator.rs":"4d6c6639c01fba78ffb8d0af298094cc2d6bb33f8054dad4379fd9fe3af5a4c8","src/front/mod.rs":"74762e4375fd5c1d2b425a80d40bf5771fa06ad9eb6838ffed7cdfcc1b909a06","src/front/spv/convert.rs":"16b8281fc1ae75dc62a02893db2c5b6d8994166e78b3b6b8cac7a01e0da4eae2","src/front/spv/error.rs":"ac484fca63ed6aa83a9e2527de049f0afaa6d92aa132e4e9aee4cf60f0bdd471","src/front/spv/function.rs":"c929cdc1a4b83fff75d9dcd1404c243142d288efbbe0ec5afef20e9602635142","src/front/spv/image.rs":"368ec748dd0e35ea855f5d69ebb8b6df5e9445d986cd7ad858a7c85d2af520d7","src/front/spv/mod.rs":"46301fb6946e0740ae4ea36888c09846e53ac067f52f8c58eaaf43d9b61d6bc0","src/front/spv/null.rs":"ee20287365e025e8bcc91f29df930ff8b63cb6d7f26db0b1789d54de614a7353","src/front/type_gen.rs":"d7abef5dfc9e18ae549ebb87bd61f5c9cd1007bde3cf280745dbadb48667a248","src/front/wgsl/error.rs":"ded41f78cd926b50eb31113da82cbeae15c47e390b17692f39404ab346ae1d21","src/front/wgsl/index.rs":"1db1bee7074a3fe9668d2c2ba0bd5053d6443f4ea19a56e4cccf2aa2bc8a33c9","src/front/wgsl/lower/construction.rs":"24e0eb2181974651ab9d13497cceaa126ee816c38848e9dbbd88f1e7b5f5c53c","src/front/wgsl/lower/conversion.rs":"d4a66519b38caa208b011846cdc3459e8a0b6bae8027235692b30188ae88e110","src/front/wgsl/lower/mod.rs":"0c941c094880f1df02d7f552583692dfd2214fece0244ab97f0e2f7cb4ef1736","src/front/wgsl/mod.rs":"b7b407ad94e91d32135643350b4549b3320a3ebdbfd22292218ae35aec95c5bc","src/front/wgsl/parse/ast.rs":"ca893c1cfbd76df5d4faaa43baad988c59129dd1f756b1637e7e329600c42ac5","src/front/wgsl/parse/conv.rs":"a03db6fc5c7c04eb84ea3b9338c96ee0574ad5b59defd80b9ea6bdc1df279643","src/front/wgsl/parse/directive.rs":"c96f33cef2c1d8a374fe1b3827538f7db33d6b7811a6e0914d29de80b8963257","src/front/wgsl/parse/directive/enable_extension.rs":"21de0a5b3146764de193b78e823cc5a925fdff3301eb277dafd0c31b55d86aeb","src/front/wgsl/parse/directive/language_extension.rs":"f82ae1c1f1d82e9e27e336b6a6975e21c7c08e5f1700f28f8d351b7f03a1621c","src/front/wgsl/parse/lexer.rs":"2194d38da1dc803ffb850202023350a07b6a3b80af68857d772c76ea49bc6344","src/front/wgsl/parse/mod.rs":"dcb58fb3746ceff5fc74637b77b57ef7d4883405c12ef43e032970475f3eeec9","src/front/wgsl/parse/number.rs":"7af92c71031e4c4258e9d8d323f7ee99a2fd4be3b6975ab9b8b53b95431845d9","src/front/wgsl/tests.rs":"a50bd5d6d218fc0be8876d1f9db7936ff593d93805c5e85754ae6bf277beae32","src/ir/block.rs":"b562a83a4fa53002d2ca21b4553ed8e2fa77f61e687f24fd4bbd90f1597b2a9d","src/ir/mod.rs":"a94b9fcd19ea4cab1dba48b420c1851d872802646101e56aa3e1621c0d4ec473","src/keywords/mod.rs":"47a6fde012bf7d1e70f0fac7762f6a8e7dca6b9bbb99e2cada773c61527cfbfe","src/keywords/wgsl.rs":"291811eef2a56f625c460b33a5a459d685e4eca2d9f30e24816bcc72a5e4705f","src/lib.rs":"81a21310e6db0d30efa8f679e65167706deef9cbb03c2006dfac1989f1ed140b","src/non_max_u32.rs":"b2d81efda0e1e5ace9e2fad990a7adf628f1dec63273b069c93d5423eb78350d","src/path_like.rs":"2740c65fc61e490b24066cdefc8ae2822650bd0c9323f83054e18005a28dfc48","src/proc/constant_evaluator.rs":"abc75112f5ffde7893ab71c8c0082198f24df98780d3ccbc34d6c5deb87fb0e4","src/proc/emitter.rs":"39ac886c651e2ad33c06a676a7e4826a0e93de0af660c01e8e4b1f7406742f88","src/proc/index.rs":"f1defc37588bb9ef8c097db8f7ebe4898a9aa182d8009d3c2e76b38b4144fb91","src/proc/layouter.rs":"bf50fed8cf4b15400218fa1cf897f04925795939b09c9ce658eb8bc7559a5705","src/proc/mod.rs":"8b79b860f32f27568b9e2a45845424deb89960bbcd32ef46e168bc4ab995457c","src/proc/namer.rs":"d706e30b34f3d2b3e292174acfce229a2579dbffc986ee81e5bb6219bf8bb76f","src/proc/overloads/any_overload_set.rs":"877cd637d979abc08caa021dabb9821a79fc9109eb97024a230bcfac82830388","src/proc/overloads/constructor_set.rs":"b702f866ac1472bcc075bd0bede450388123b5899431934fd60a29865498c68b","src/proc/overloads/list.rs":"7cfbf66a3619fdd66f9acf652d56cd2a9451f7905c5d4637cdb9f77f4ef2af51","src/proc/overloads/mathfunction.rs":"d5801d64d1a6fd10e0da30a7c0ac7368954654e5f3d0b022fa806ff9a2ab61b8","src/proc/overloads/mod.rs":"0e96479cbd0ec9fa8200a5e88c16a22ee7ed2021ecf6f80a7e4ded69cad5239f","src/proc/overloads/one_bits_iter.rs":"6b98769fdec777d311248084f13958c5cca44659d0928603ece8618387ea58b2","src/proc/overloads/regular.rs":"e272f1973c881f17ef23a0509edc0a1184b20778b1f03bdb33a4d6b15c4a25e1","src/proc/overloads/rule.rs":"b7f87d5ca0cffdaa8ee0db0110918f5a726359fd8a72bc638d8ce27a4b0ae3b2","src/proc/overloads/scalar_set.rs":"3729bc754dbf29a2337379ecb46568fdc3149a48074a354244da91e3d9cb5cef","src/proc/overloads/utils.rs":"4b5e02f20611bd24c6849e1f2c01aad4b271388407e8eb866d5a34983538ef8f","src/proc/terminator.rs":"61df2289408be24f69b6c23da469ca3f63f913568f8c314427c3571b826632dd","src/proc/type_methods.rs":"f1b73b2507377d04ee873ace7971e1b4bc90ff520d3534df1cd29de56035366a","src/proc/typifier.rs":"3bea9c55fb9d6141072c6a17b6fc9d990de4bd5209bf5ea3eb3a5d72466aa2c4","src/racy_lock.rs":"b5b6e081c9519648a61225710b656b53dd695ae65a1cd9ca927946340b2a6e70","src/span.rs":"666a413531c2eb44ab5a42a84349d25f5747f52337268afeb1714c7740d94961","src/valid/analyzer.rs":"9e0479bee5d2ac15704f69d8852400cd1bcd35bc01c056cb9a510db6dec63a39","src/valid/compose.rs":"44f01ed290d49b9ffc5651c2edaf9a7aa3b969828790a732da39a908b54aee24","src/valid/expression.rs":"469df8f97ead6e7b21f14a68c95bcc008f178661f095eccb8f6123461ee5fd6a","src/valid/function.rs":"8e2891789df255e0b8472e9b5e092ded0171f17d1e953b18c8f7c6eea135237c","src/valid/handles.rs":"59f96f672f57e253006f330a3b9a540564dfb462a543e5cad6d20231de29538f","src/valid/interface.rs":"0bb4025647600237b78d4e7188f88af44bb66fcd77db987ae88baf73161ea8fe","src/valid/mod.rs":"b262c3c31affe6a645ad87aa4c396c987c5ed173a1f038247d6607572b1c8b82","src/valid/type.rs":"0947af787fcbd40ac74dc6fb35c1973879cbd548d1cb815eb0907c0a7bf7c362"},"package":null} \ No newline at end of file +{"files":{".cargo/config.toml":"7248ed3bed246d755d7bf9e5d7842d74b5c270ba6c29ad907872b55a67707ee0","CHANGELOG.md":"e60105d413f857e37dae165f819c47491d0a595183d3c9146b259d811b98b14f","Cargo.toml":"29cc03bac7a55b4e0bb3ae20ed22e44c3711deaba835b025177086247aca668c","README.md":"9550cbc1a518ad0f624aabe12c342c72f670705cb4a6878c0c87d172f1dacea0","build.rs":"e9098f486e87d91710c07d40f1b32716e5debfe94a0b5e53e37075b0ee997eec","src/arena/handle.rs":"897b2b0eebe0d9ae6a65bf2e8c210c8391924da06ef4c9e2a1225ad622400b6c","src/arena/handle_set.rs":"5c2a0bcf41d85c8173ac68b2d439552e79d0c3c0fe1ff3b1e1a48f0c83a4d48f","src/arena/handlevec.rs":"999de9d55d01213789072a63ad4ae9b4635e6653984d38db8b308d42bb1e7be3","src/arena/mod.rs":"e305d0521233791e181b4b6e7de70175a6bc730811063ea066c3bd3b73d12979","src/arena/range.rs":"b783969dfe32b4937593d871aa5190d561bdd79b6f615da53cb54346e300b9e2","src/arena/unique_arena.rs":"ddd6c404c9b7d7d1aa041af1a8c3d451ef6e71339d408eac22f10d25d33d5b18","src/back/continue_forward.rs":"8194d238763caa6d5601ec3af56ba39a471c39945f43152b58d582092c99aefa","src/back/dot/mod.rs":"214622a55414393f205a7e71a5aa2bd535e76fde71b612845f251ca57bd32539","src/back/glsl/features.rs":"5975ad4ae9c2e78f795f9d2532d03fe425ce910a146f6fe8863f95a4f029b280","src/back/glsl/keywords.rs":"4cfbcf931f8b234f10b7cd807839764945cd6ece71910735d9bae362690aceed","src/back/glsl/mod.rs":"19c02133c489e35f8e7a93eceb8a2b28a31a008dfc284102bfc7a9ff66e7e90d","src/back/hlsl/conv.rs":"3e1a78203e8c4efb75986db962cec150c7b2d99f7e48b400e702233de70e8aab","src/back/hlsl/help.rs":"67786bb73f4809769d8e5f97a401f576a89803f7c95a92e59088271ccb84d9d6","src/back/hlsl/keywords.rs":"af1c16b81f14f3ae04e3911701cf0782fcaf54ad9427a13e5fdc4dd0ca441e5f","src/back/hlsl/mod.rs":"e644011ea83a6dd194e417a640deb395160d7af4460d30c1359145b3d6dacc5e","src/back/hlsl/ray.rs":"259db3bc8fd5b8ec343fb8620c7cef50048cbea2b9db1f17dc8813ff848269df","src/back/hlsl/storage.rs":"7443cea2abb6ce8d0c0c9bfe805b37b5600bd28618de44ba1ebd8e4e38eac92f","src/back/hlsl/writer.rs":"4fdaa36c745269e5759737dbb6907e5bb304b0baec8e72bd6770d979afd4a9ef","src/back/mod.rs":"1489e44272b0fbe58e6e5042fcb6299525c00ce42a811944c6f94935379e52d7","src/back/msl/keywords.rs":"f1f080b02d98a36ccde81a3b77ae12651272dffc4043ddaebd6937673154ba2b","src/back/msl/mod.rs":"f980ddf9cfaf0f7e0249a9580216cafe76405047cd949210bfbfb29ee64e1cfb","src/back/msl/sampler.rs":"9be8805063258b0ff6b6db2e6856d59326caa18f6f64eaf413c5abfcbd1ad341","src/back/msl/writer.rs":"1c6c3662d20c60261b4bc0550adca55f6e14c7164eb9456252e1ea54e40dd949","src/back/pipeline_constants.rs":"c2244d7e47a52c01ead61b4b6c7b3d0f29263ca308aca70f213137a0938c9aa4","src/back/spv/block.rs":"d005284f0fb17b4bf3e3b7323183e903bfae7e86956419b9602891ed950eaa45","src/back/spv/helpers.rs":"37ef7388b1e97edb2682b93f1f0eceb71039ecd54923d91346d974b29322077c","src/back/spv/image.rs":"e22cb4c56e29d049a512a7fe43d6ad2c059a17e06531ae84b3c9446ac27c35f6","src/back/spv/index.rs":"5f0561a83011bcf482575d209c549ce08fce85b9dd95f179f6e8c2b112e0c8e5","src/back/spv/instructions.rs":"556f1f30ae11c3e01910c354a36ba314280932e3a2928584b06eb0812a2cb81a","src/back/spv/layout.rs":"28ba27739d7c9fa4b9e363ffc112cdc39c5e8ec4236d71a7260039d1bd8321d7","src/back/spv/mod.rs":"ba6228b2addde92d6671410df87970cb31baa06818f507930f278a6307d58140","src/back/spv/ray.rs":"a31fd66e9497ffd19437bdab53427705b7f28f555ab215c8f0a4c2156283413e","src/back/spv/recyclable.rs":"8ea397d4d8d3f2cd5fbc8e0be94d136c2d6e0f0e8a4b5eb567dcc1be104c9ae5","src/back/spv/selection.rs":"aea4bb4da7c0fa4e907b8f1e185433a48f2f0eb7ded97fdd3225beb3f6c1f249","src/back/spv/subgroup.rs":"68fc3e3153022a0a8bddec20ad9221820678f02921878318e571d5aa2ca13cee","src/back/spv/writer.rs":"3e2fa86bdc1a8117512ac20eaf208124cefd77b6ef451c2d4e2da74ffa684fb9","src/back/wgsl/mod.rs":"1b04d66e8dba609513d43431d1f0ee9a209fbfd8453862d6e8a7aa41f8910997","src/back/wgsl/polyfill/inverse/inverse_2x2_f16.wgsl":"9e7635d04724822931c805a8b35e76d6d294d447e4ea8d57b308ce45609bf736","src/back/wgsl/polyfill/inverse/inverse_2x2_f32.wgsl":"340d491abde07f93996391796db65a5f88402663eaf6b9d2d894d11cb8cf8b6d","src/back/wgsl/polyfill/inverse/inverse_3x3_f16.wgsl":"4f13a1a4b3e1b51f0f992d13c55cf854a80917554a4d13c997819fa1fe776ba4","src/back/wgsl/polyfill/inverse/inverse_3x3_f32.wgsl":"9b16d2f4b9e433c8e03a0cb46ab48508f3bf7e185ce1b4e26106c47e81a677cb","src/back/wgsl/polyfill/inverse/inverse_4x4_f16.wgsl":"86d39d1db5d03995b404950279db7f1698ad9622982aa319fdedb7532673235b","src/back/wgsl/polyfill/inverse/inverse_4x4_f32.wgsl":"dc510525ac2dce66389a8c4bf8b2f31f0dedd9e6debdbe4ffd939a0a7fc533d3","src/back/wgsl/polyfill/mod.rs":"f4ab3c9b9cdc36d16dab00d0f7f07d6e6beda0e27a36053e9b5ffeeb7ca18edc","src/back/wgsl/writer.rs":"36aa1d68def860e9befd9c694d841fc5c0680f98cba61c33989cfea6eb705771","src/common/diagnostic_debug.rs":"8c73fe605e5b6162d0485e264287ac50c061cf581743feebbffe1474d1d3516d","src/common/diagnostic_display.rs":"46f1ff8a32179703ef0bcdb704db9f6e6e8b4eaad6cadf94577eeab3d8a16cd1","src/common/mod.rs":"289231637b08407fbe2cc976a1bab4eac4c9e66042c6618aff3af44baaff3e26","src/common/predeclared.rs":"a5f42d55f2e13d8f5a8213d4a881e9155c3994c4054d43edcf7bd7bb7c868ccf","src/common/wgsl/diagnostics.rs":"4fec985b4c5cc6dfae4dd78bd7c850adc88a1761d7b6691de0355ea49300e532","src/common/wgsl/mod.rs":"d944915ff692c96aecca67737bccc2d5d9eb68f475166a2744f29a025f4a4c93","src/common/wgsl/to_wgsl.rs":"c506579e7f124643a35373705a870318500e000a6a752be58666bcbb3c08fc1f","src/common/wgsl/types.rs":"9ccdd6676437ac7e282a508403eb24742dea654b380d6419ffe5aac9cd699996","src/compact/expressions.rs":"1bd4426d06afda9ba226a495406e8239a8d87bbbf8a89b6fab4a78c9bd6880cf","src/compact/functions.rs":"f9598be11b9bbdd63a2c42348b8a25422f477287b92b331ac7ebd7ba4d44d879","src/compact/handle_set_map.rs":"f282349ba0d1e35a873f6ee9ff9086ae061d3dd8e31f2a291c443bd0e7e1ebfd","src/compact/mod.rs":"03ceafe4140713c279168bcd20b17c9bb9f880d406806fd63ca2065de9950f0f","src/compact/statements.rs":"85b2faf6a4caaebc0372e773ca3be2904db5bb0e691ac7ea845720ef0864a22b","src/compact/types.rs":"a955ce5e336afa8d26f750c14d4a6638dcee6b0b5e0fcd7c446d8f88a35d8277","src/diagnostic_filter.rs":"5e3d14a774974148b7d2918617ba3e2c3a07493e0f90485a7de9db86e05a7cd0","src/error.rs":"b7f570cc9e334e2b5a1aec499b4742457eba6f2f6673de4e80c8f5499eb16793","src/front/atomic_upgrade.rs":"86ce9f9628d92a1a09802cb534bb4310236b83f2799c921b81c687f009c589be","src/front/glsl/ast.rs":"15a4f7c56aa44529373c7aa2a266d1582b7775833de6adc6b8f5bfd54d85a669","src/front/glsl/builtins.rs":"5514238a48529d2bb953a032d13014c00adfe6c497e13ac33d27a5f17ae1fc63","src/front/glsl/context.rs":"14fd933c79f49f4fb4ccabdc24ad31745777806f7464f111a4f7782662612a4b","src/front/glsl/error.rs":"4f0836fbab8dcdad0603d4e3164d17b48f5d7498b829665ed0c9c48c3fb0b410","src/front/glsl/functions.rs":"28aa0fa2e048a296df0f342d482ee5e02510ae39bfa96fb400a5892cfff71cf9","src/front/glsl/lex.rs":"24706628b600b5ce435cef464c84196ac5d58013122a97e7b59d509cc25f85a2","src/front/glsl/mod.rs":"f4f1cce6911935b305c415afe3c15f84c7824a3bb828a5d15e6f9ae4b0316df0","src/front/glsl/offset.rs":"66bd524a2d17dc44f431430dcbbb74a771fdab43c9581e88bb1123e6cfec516b","src/front/glsl/parser.rs":"6a13b4737f53b09d5bbc0add01f8fc1b2633b7957f0318374edfe0b903939912","src/front/glsl/parser/declarations.rs":"9949649fba43636d03eaf7f7560d3bb3743b19c7204fb95859283ee84b5dd239","src/front/glsl/parser/expressions.rs":"e056fbdde3bc7c8473acbd485aecd14120d3dbefbabd813ddbc5cfedaf605889","src/front/glsl/parser/functions.rs":"302e24e06190aff555131c33f9a80b15df6a0390d6c776f888a44d5ef7df697e","src/front/glsl/parser/types.rs":"ee242048a65cd3709e16b70a3882e9296e615327480f2ad779e3d2523778181f","src/front/glsl/parser_tests.rs":"6834f0d595f4077266054e5da43e4f1b60e5c6780611ab0f530d9964cc62fad3","src/front/glsl/token.rs":"83780c0c1954ef216896c9d8a48e412b357783e00ccd4909a7a249935c742629","src/front/glsl/types.rs":"286395d82707a09d28b4c1a8bade917822478e53d8eb277ceec5fa9e71649ba2","src/front/glsl/variables.rs":"75d3e203a07befd011f5693ab8f2789e4f06821badb4974043cc4ee10bd5c6c9","src/front/interpolator.rs":"4d6c6639c01fba78ffb8d0af298094cc2d6bb33f8054dad4379fd9fe3af5a4c8","src/front/mod.rs":"74762e4375fd5c1d2b425a80d40bf5771fa06ad9eb6838ffed7cdfcc1b909a06","src/front/spv/convert.rs":"16b8281fc1ae75dc62a02893db2c5b6d8994166e78b3b6b8cac7a01e0da4eae2","src/front/spv/error.rs":"ac484fca63ed6aa83a9e2527de049f0afaa6d92aa132e4e9aee4cf60f0bdd471","src/front/spv/function.rs":"c929cdc1a4b83fff75d9dcd1404c243142d288efbbe0ec5afef20e9602635142","src/front/spv/image.rs":"368ec748dd0e35ea855f5d69ebb8b6df5e9445d986cd7ad858a7c85d2af520d7","src/front/spv/mod.rs":"46301fb6946e0740ae4ea36888c09846e53ac067f52f8c58eaaf43d9b61d6bc0","src/front/spv/null.rs":"ee20287365e025e8bcc91f29df930ff8b63cb6d7f26db0b1789d54de614a7353","src/front/type_gen.rs":"d7abef5dfc9e18ae549ebb87bd61f5c9cd1007bde3cf280745dbadb48667a248","src/front/wgsl/error.rs":"ded41f78cd926b50eb31113da82cbeae15c47e390b17692f39404ab346ae1d21","src/front/wgsl/index.rs":"1db1bee7074a3fe9668d2c2ba0bd5053d6443f4ea19a56e4cccf2aa2bc8a33c9","src/front/wgsl/lower/construction.rs":"24e0eb2181974651ab9d13497cceaa126ee816c38848e9dbbd88f1e7b5f5c53c","src/front/wgsl/lower/conversion.rs":"d4a66519b38caa208b011846cdc3459e8a0b6bae8027235692b30188ae88e110","src/front/wgsl/lower/mod.rs":"0c941c094880f1df02d7f552583692dfd2214fece0244ab97f0e2f7cb4ef1736","src/front/wgsl/mod.rs":"b7b407ad94e91d32135643350b4549b3320a3ebdbfd22292218ae35aec95c5bc","src/front/wgsl/parse/ast.rs":"ca893c1cfbd76df5d4faaa43baad988c59129dd1f756b1637e7e329600c42ac5","src/front/wgsl/parse/conv.rs":"a03db6fc5c7c04eb84ea3b9338c96ee0574ad5b59defd80b9ea6bdc1df279643","src/front/wgsl/parse/directive.rs":"c96f33cef2c1d8a374fe1b3827538f7db33d6b7811a6e0914d29de80b8963257","src/front/wgsl/parse/directive/enable_extension.rs":"21de0a5b3146764de193b78e823cc5a925fdff3301eb277dafd0c31b55d86aeb","src/front/wgsl/parse/directive/language_extension.rs":"f82ae1c1f1d82e9e27e336b6a6975e21c7c08e5f1700f28f8d351b7f03a1621c","src/front/wgsl/parse/lexer.rs":"2194d38da1dc803ffb850202023350a07b6a3b80af68857d772c76ea49bc6344","src/front/wgsl/parse/mod.rs":"dcb58fb3746ceff5fc74637b77b57ef7d4883405c12ef43e032970475f3eeec9","src/front/wgsl/parse/number.rs":"7af92c71031e4c4258e9d8d323f7ee99a2fd4be3b6975ab9b8b53b95431845d9","src/front/wgsl/tests.rs":"a50bd5d6d218fc0be8876d1f9db7936ff593d93805c5e85754ae6bf277beae32","src/ir/block.rs":"b562a83a4fa53002d2ca21b4553ed8e2fa77f61e687f24fd4bbd90f1597b2a9d","src/ir/mod.rs":"a94b9fcd19ea4cab1dba48b420c1851d872802646101e56aa3e1621c0d4ec473","src/keywords/mod.rs":"47a6fde012bf7d1e70f0fac7762f6a8e7dca6b9bbb99e2cada773c61527cfbfe","src/keywords/wgsl.rs":"291811eef2a56f625c460b33a5a459d685e4eca2d9f30e24816bcc72a5e4705f","src/lib.rs":"81a21310e6db0d30efa8f679e65167706deef9cbb03c2006dfac1989f1ed140b","src/non_max_u32.rs":"b2d81efda0e1e5ace9e2fad990a7adf628f1dec63273b069c93d5423eb78350d","src/path_like.rs":"2740c65fc61e490b24066cdefc8ae2822650bd0c9323f83054e18005a28dfc48","src/proc/constant_evaluator.rs":"abc75112f5ffde7893ab71c8c0082198f24df98780d3ccbc34d6c5deb87fb0e4","src/proc/emitter.rs":"39ac886c651e2ad33c06a676a7e4826a0e93de0af660c01e8e4b1f7406742f88","src/proc/index.rs":"f1defc37588bb9ef8c097db8f7ebe4898a9aa182d8009d3c2e76b38b4144fb91","src/proc/layouter.rs":"bf50fed8cf4b15400218fa1cf897f04925795939b09c9ce658eb8bc7559a5705","src/proc/mod.rs":"8b79b860f32f27568b9e2a45845424deb89960bbcd32ef46e168bc4ab995457c","src/proc/namer.rs":"d706e30b34f3d2b3e292174acfce229a2579dbffc986ee81e5bb6219bf8bb76f","src/proc/overloads/any_overload_set.rs":"877cd637d979abc08caa021dabb9821a79fc9109eb97024a230bcfac82830388","src/proc/overloads/constructor_set.rs":"b702f866ac1472bcc075bd0bede450388123b5899431934fd60a29865498c68b","src/proc/overloads/list.rs":"7cfbf66a3619fdd66f9acf652d56cd2a9451f7905c5d4637cdb9f77f4ef2af51","src/proc/overloads/mathfunction.rs":"d5801d64d1a6fd10e0da30a7c0ac7368954654e5f3d0b022fa806ff9a2ab61b8","src/proc/overloads/mod.rs":"0e96479cbd0ec9fa8200a5e88c16a22ee7ed2021ecf6f80a7e4ded69cad5239f","src/proc/overloads/one_bits_iter.rs":"6b98769fdec777d311248084f13958c5cca44659d0928603ece8618387ea58b2","src/proc/overloads/regular.rs":"e272f1973c881f17ef23a0509edc0a1184b20778b1f03bdb33a4d6b15c4a25e1","src/proc/overloads/rule.rs":"b7f87d5ca0cffdaa8ee0db0110918f5a726359fd8a72bc638d8ce27a4b0ae3b2","src/proc/overloads/scalar_set.rs":"3729bc754dbf29a2337379ecb46568fdc3149a48074a354244da91e3d9cb5cef","src/proc/overloads/utils.rs":"4b5e02f20611bd24c6849e1f2c01aad4b271388407e8eb866d5a34983538ef8f","src/proc/terminator.rs":"61df2289408be24f69b6c23da469ca3f63f913568f8c314427c3571b826632dd","src/proc/type_methods.rs":"f1b73b2507377d04ee873ace7971e1b4bc90ff520d3534df1cd29de56035366a","src/proc/typifier.rs":"3bea9c55fb9d6141072c6a17b6fc9d990de4bd5209bf5ea3eb3a5d72466aa2c4","src/racy_lock.rs":"b5b6e081c9519648a61225710b656b53dd695ae65a1cd9ca927946340b2a6e70","src/span.rs":"666a413531c2eb44ab5a42a84349d25f5747f52337268afeb1714c7740d94961","src/valid/analyzer.rs":"9e0479bee5d2ac15704f69d8852400cd1bcd35bc01c056cb9a510db6dec63a39","src/valid/compose.rs":"44f01ed290d49b9ffc5651c2edaf9a7aa3b969828790a732da39a908b54aee24","src/valid/expression.rs":"469df8f97ead6e7b21f14a68c95bcc008f178661f095eccb8f6123461ee5fd6a","src/valid/function.rs":"8e2891789df255e0b8472e9b5e092ded0171f17d1e953b18c8f7c6eea135237c","src/valid/handles.rs":"59f96f672f57e253006f330a3b9a540564dfb462a543e5cad6d20231de29538f","src/valid/interface.rs":"0bb4025647600237b78d4e7188f88af44bb66fcd77db987ae88baf73161ea8fe","src/valid/mod.rs":"b262c3c31affe6a645ad87aa4c396c987c5ed173a1f038247d6607572b1c8b82","src/valid/type.rs":"0947af787fcbd40ac74dc6fb35c1973879cbd548d1cb815eb0907c0a7bf7c362"},"package":null} \ No newline at end of file
--- a/third_party/rust/naga/Cargo.toml +++ b/third_party/rust/naga/Cargo.toml @@ -8,17 +8,17 @@ # If you are reading this file be aware that the original Cargo.toml # will likely look very different (and much more reasonable). # See Cargo.toml.orig for the original contents. [package] edition = "2021" rust-version = "1.82.0" name = "naga" -version = "25.0.0" +version = "26.0.0" authors = ["gfx-rs developers"] build = "build.rs" exclude = [ "bin/**/*", "tests/**/*", "Cargo.lock", "target/**/*", ]
--- a/third_party/rust/wgpu-core-deps-apple/.cargo-checksum.json +++ b/third_party/rust/wgpu-core-deps-apple/.cargo-checksum.json @@ -1,1 +1,1 @@ -{"files":{"Cargo.toml":"6731a9da7b46084fa1c5cb6d8d55026c10a84b11a9d61dfed9275b5528fab0ad","README.md":"729fdd16cb87ad318ed2bfc70593363aa324c804c825ffea7c42670dff681255","src/lib.rs":"54ef7b7d746c6b26b0ee65552cc969d69c6204d0d38b3678c40bffbfbc5a146c"},"package":null} \ No newline at end of file +{"files":{"Cargo.toml":"7a8c769f2eb7ea6b5a24f430264b36c878413198a87a8b9faa65002d7be95f96","README.md":"729fdd16cb87ad318ed2bfc70593363aa324c804c825ffea7c42670dff681255","src/lib.rs":"54ef7b7d746c6b26b0ee65552cc969d69c6204d0d38b3678c40bffbfbc5a146c"},"package":null} \ No newline at end of file
--- a/third_party/rust/wgpu-core-deps-apple/Cargo.toml +++ b/third_party/rust/wgpu-core-deps-apple/Cargo.toml @@ -8,17 +8,17 @@ # If you are reading this file be aware that the original Cargo.toml # will likely look very different (and much more reasonable). # See Cargo.toml.orig for the original contents. [package] edition = "2021" rust-version = "1.76" name = "wgpu-core-deps-apple" -version = "25.0.0" +version = "26.0.0" authors = ["gfx-rs developers"] build = false autolib = false autobins = false autoexamples = false autotests = false autobenches = false description = "Feature unification helper crate for Apple platforms" @@ -39,10 +39,10 @@ vulkan-portability = [ "wgpu-hal/renderdoc", ] [lib] name = "wgpu_core_deps_apple" path = "src/lib.rs" [target.'cfg(target_vendor = "apple")'.dependencies.wgpu-hal] -version = "25.0.0" +version = "26.0.0" path = "../../../wgpu-hal"
--- a/third_party/rust/wgpu-core-deps-windows-linux-android/.cargo-checksum.json +++ b/third_party/rust/wgpu-core-deps-windows-linux-android/.cargo-checksum.json @@ -1,1 +1,1 @@ -{"files":{"Cargo.toml":"0b0dd61a2bcfaf314f95e1ccc01b1c27bb2d984fbf02f87429e2fd7125aa6b32","README.md":"38086a02e134ac959bd061f1161c141a848a1b05a6bf31874035908217ad3eed","src/lib.rs":"a99034037e9c9ddf912f44c05b98af2c11e0ed0d09bb7cb69577826f46062ab9"},"package":null} \ No newline at end of file +{"files":{"Cargo.toml":"41aec5999e044b23c0f31729cfb447099f4be9d943d52d659b25fdd7609448db","README.md":"38086a02e134ac959bd061f1161c141a848a1b05a6bf31874035908217ad3eed","src/lib.rs":"a99034037e9c9ddf912f44c05b98af2c11e0ed0d09bb7cb69577826f46062ab9"},"package":null} \ No newline at end of file
--- a/third_party/rust/wgpu-core-deps-windows-linux-android/Cargo.toml +++ b/third_party/rust/wgpu-core-deps-windows-linux-android/Cargo.toml @@ -8,17 +8,17 @@ # If you are reading this file be aware that the original Cargo.toml # will likely look very different (and much more reasonable). # See Cargo.toml.orig for the original contents. [package] edition = "2021" rust-version = "1.76" name = "wgpu-core-deps-windows-linux-android" -version = "25.0.0" +version = "26.0.0" authors = ["gfx-rs developers"] build = false autolib = false autobins = false autoexamples = false autotests = false autobenches = false description = "Feature unification helper crate for the Windows/Linux/Android platforms" @@ -34,10 +34,10 @@ gles = ["wgpu-hal/gles"] renderdoc = ["wgpu-hal/renderdoc"] vulkan = ["wgpu-hal/vulkan"] [lib] name = "wgpu_core_deps_windows_linux_android" path = "src/lib.rs" [target.'cfg(any(windows, target_os = "linux", target_os = "android"))'.dependencies.wgpu-hal] -version = "25.0.0" +version = "26.0.0" path = "../../../wgpu-hal"
--- a/third_party/rust/wgpu-core/.cargo-checksum.json +++ b/third_party/rust/wgpu-core/.cargo-checksum.json @@ -1,1 +1,1 @@ -{"files":{"Cargo.toml":"76e5f69ff2a959493c3621810bea2db96e67cc6894d99acfd76d85108eb2f360","LICENSE.APACHE":"a6cba85bc92e0cff7a450b1d873c0eaa2e9fc96bf472df0247a26bec77bf3ff9","LICENSE.MIT":"c7fea58d1cfe49634cd92e54fc10a9d871f4b275321a4cd8c09e449122caaeb4","build.rs":"c67295643e006849b11d2d4bf64142e6485280e19887523785c3c03cb5fe1f32","src/binding_model.rs":"1e6a73574e602ec8b4ff57ba11fa6c62b8431ceceda4f5508c2048240236e12e","src/command/allocator.rs":"386cb6e60bd332a881dbbe57ff66a0fa83f35e3ee924559f1689418ac6c7273a","src/command/bind.rs":"c88aa87bf3052fe0993b79ff047339fac4557ead85973f4a37bf236fba401222","src/command/bundle.rs":"59dd5714d3b553339864f9c9f5fcfc8a6a7816a4ba9b59aa459b5ea7f3edfcd3","src/command/clear.rs":"7e03fa2b2516e4f930599b5fa72f326805c18ee004bed04ad74e317c007c4c42","src/command/compute.rs":"43796e32cc5cb3b2cbd6f310fa6eccb1c6291a3c65b67007cfd690f06fb686b3","src/command/compute_command.rs":"18aa0b8e389a5d345243b876b1abbacfc998a19d23069e092183fa7be10fa0ab","src/command/draw.rs":"304a308ac77cab1f6904d77516047497ede7f18562e0800a8cc918ae1d314d05","src/command/memory_init.rs":"f25554cff06f96e37afd81153a351e9d8482c855318b86b4db29231926d265b5","src/command/mod.rs":"a750bb0a17c60407df4f3604995db40d20353564e077984ea865284a560c4ec3","src/command/pass.rs":"23f17526798dff6e352359e166c6734e34c16c0087f60a9c1c9951d2442fb4cc","src/command/query.rs":"189d9949f0431ad0c3826936651959b7c4219fb3fe4eacb2122ffb2f7a9ce124","src/command/ray_tracing.rs":"ebc6fe1bd6b8fc86b9cc0bb74666b638416d3709b220d3a8b5cc00d1c791a3a7","src/command/render.rs":"34378658b994cf1d727d9078d7e5b4b35a2621153faf8c44db7ec8b7cdbbdad6","src/command/render_command.rs":"209242e9ab30e23044840f89efed62e4d0dbadf832fcaf5a861d2487af4358ad","src/command/timestamp_writes.rs":"da06fb07b8d0917be3e7fb9212d0ffc6b16526e1c1df617213ef354c3e1fb446","src/command/transfer.rs":"5917c1c1371acb6045517ad0b828e1810762ea60cf8df2569d1faf8fecf36c6b","src/command/transition_resources.rs":"b591797bb75f937bce6d5bffc60b54bbcdb78111ea8d140f4a8c17d80958f226","src/conv.rs":"02722149d21bcdba6ee5101b3c0625a9de8ef607523a0eebb1f4088e82b3608b","src/device/bgl.rs":"fcb1d53b692970912781748379df675268981c97352872abf2e7bb0b1ebdd533","src/device/global.rs":"298d32daa32f67b5c6c47739d4173033c4930eb4b51281e595eefe70f9816dfc","src/device/life.rs":"c14c34512f24a511febbe4f3ef092e2c8ad43e5bdd5c29b7e965b19827b80b52","src/device/mod.rs":"b1949bf0f98ebe0604f7c342acb88022a6749ea94e92731e18f832b824f915ec","src/device/queue.rs":"202acc9a5192e78e4c28dac46d3ba879c60f9ad56917708370d28478d153b3e8","src/device/ray_tracing.rs":"237fc05b6258c102037a0ec13942727375f088bfdbde078e7360bfa49e44a041","src/device/resource.rs":"269ad0cab4ae709e8abc6d05426ba1865b57ea48d3b1b221cb179f3a6cec1bf2","src/device/trace.rs":"48316a9360ba795ce024f4e93fb1751ca0fa4210a93c6255ebc9a6d9a0f15e72","src/error.rs":"4f07a0b09b30b2d6cbc855d0091d724000f492018af3b41e80befbeccf2a6f4e","src/global.rs":"7bb7dc795d01607fd5d6f4477b55255c71fe4b1f8621a004b0a4305d6641fc20","src/hal_api.rs":"7962c119456602e9c2ba958712660532290cabe0b8c4c67ef7595de73cdf8b57","src/hash_utils.rs":"9f57a627fe3f00659391670141df62f68d67922c7b186f2a9a5958ab16fb576f","src/hub.rs":"ce0a14d5a3314df318bbc7c4d8c40ea2b3197dbddb2227e828ceb5127db7d37d","src/id.rs":"207f262558388147b484c51cf07d2554c26a3e19243058939e63a7f8e5c7ea75","src/identity.rs":"0a92302fc5b483ea1a8750b1672971af1cf2abfd4c0325bb02488b43e85073e2","src/indirect_validation/dispatch.rs":"1d732bb0e0716c6e5505871ea0dcc9de128fb9c9e2813769f359088d8f1573f9","src/indirect_validation/draw.rs":"a2f6d25318e0a679ce12f9ef439e96867ffb1ef57119810f78dd59e5a4804150","src/indirect_validation/mod.rs":"79466e4f9a59386e833958b3537beed6ffb6a7ee62aaabcf35382c2683998e43","src/indirect_validation/utils.rs":"e6a3b636dd71ff6b01d5abd5a589a0136fb30aa1d517a43f45cf2e5ad54da245","src/indirect_validation/validate_draw.wgsl":"fa7bba5f28c6c181f2d55ecfe386a5e5cd276bcb3c36aa7f963f43c535a9bf9a","src/init_tracker/buffer.rs":"6167a400ab271ba857f1c507e60a46fbd318c185aff87eecf7eb05f7f09b6963","src/init_tracker/mod.rs":"3895c4a2284631b6d6247c0d96c5fc9cfd024d358e09cad8752b2505700138a3","src/init_tracker/texture.rs":"ffdc67d4be23bcd48b22945de94ac0ea8ee571f91eb6d00323b9afe6fa91eef3","src/instance.rs":"80d8ab62ebad5c7093c1afa3345b09e480fa0e2d7ad0170a8f3b782d359f8e90","src/lib.rs":"5686a1fd2149f1ef352e5f5bacd3322d7721040cc5fed5b67f45163cf5730736","src/lock/mod.rs":"7343aa3ee73a0e6d41f0c28c658f22a2af0ff3e558a2c3437764ebc038816c0f","src/lock/observing.rs":"21c4749dad50cdbed159d8cc44ffd87e83620bb9fabc715773ac7f88afe1b276","src/lock/rank.rs":"238e6a97c58ee1a804863c8011bb257864301170344d18596bdaab09f3f74b54","src/lock/ranked.rs":"7f44776bc7d71a25e23c97ab80e2fdab3576bb3f912bc8a0b4fcc28a64ef5c6e","src/lock/vanilla.rs":"3a772dfc1f8d8d4047669962beaa15542f771d2dcbe4e1755cd2cfed5cbacca0","src/pipeline.rs":"3f81da8f824feb62a8c7e22811d409e14507945c3bab795878d41b9989f7c0e6","src/pipeline_cache.rs":"256bf8df58d8ab904afddc132349d03e4f659b6bd6882bc8df582dcfd05ae3d5","src/pool.rs":"e11bfdc73a66321d26715465fa74657dcd26a9b856b80b8369b4aac2132a4295","src/present.rs":"d0ab0b3ab29f3e49828a595ed432f0281bf569b5eafb0bb996f49bcfab86d2c0","src/ray_tracing.rs":"6e33799815e98d0dc7e98902e6b9c9c928bc50aaab27f343379989a13cc728f9","src/registry.rs":"779d8c277193537edd2b883b72cdcc07161b7231c8d2c80be726bd800cd327b6","src/resource.rs":"6410c784d2b4f292f296d1cdf6ad4a58541bdf3702489f8071cfc50f59537636","src/scratch.rs":"05f2032fa6d6f589c2507f4028755769b9524029e5ad59cc500cab7940e40d42","src/snatch.rs":"d75583fa0504b60554b14a865e1b1062b6b1dea7d99903cf09d03608f3a78a4c","src/storage.rs":"8a4d20e85c3ac135316dcb0dab41ec4d335d86d34959d4392ec07f592125f0d3","src/timestamp_normalization/common.wgsl":"9f65aef0526ff9dde945fae70cef064ad961b0aee4291759ae82974cd2ead0a7","src/timestamp_normalization/mod.rs":"a1aab50a03ae283e86db0885ad00239278da8b3a40647f2d93fa15b2f23e51dc","src/timestamp_normalization/timestamp_normalization.wgsl":"4b2202b965e4c67482d03a546ac38c72a602d79ed9a60e6f7217393c49afad49","src/track/blas.rs":"18c7b5b89a60ab49bbc0f4f8b85a24502c1d968714ef4c586095e119848d902a","src/track/buffer.rs":"1ab5310367606fc74f0791733ea5ba2e09acc92ff7f4f4773f66bcfb3138c52f","src/track/metadata.rs":"04b8bcf8ded7c7c805d9336cfc874da9d8de7d12d99f7525f0540780a1dffc45","src/track/mod.rs":"93348b15d04f2680507e9dde66df2c70d82ebcaae170b0dfb203a72482ff4bda","src/track/range.rs":"2688b05a0c6e8510ff6ba3a9623e8b83f433a05ba743129928c56c93d9a9c233","src/track/stateless.rs":"3db699f5f48a319fa07fb16cdf51e1623d6ecac7a476467ee366e014ea665b89","src/track/texture.rs":"fbd5f3cde5161404048131dbea014806cfc210ab1497bfd638f0064969c004f9","src/validation.rs":"256f8ff5e579af4f1319997a2ca9e110f806ecf0d9b5534a2c5b4bd4f0c10776","src/weak_vec.rs":"a4193add5912b91226a3155cc613365b7fafdf2e7929d21d68bc19d149696e85"},"package":null} \ No newline at end of file +{"files":{"Cargo.toml":"2612ad61671a56b139c5c92fd152e633e47550b945ba1a727af71af65e7ad87f","LICENSE.APACHE":"a6cba85bc92e0cff7a450b1d873c0eaa2e9fc96bf472df0247a26bec77bf3ff9","LICENSE.MIT":"c7fea58d1cfe49634cd92e54fc10a9d871f4b275321a4cd8c09e449122caaeb4","build.rs":"c67295643e006849b11d2d4bf64142e6485280e19887523785c3c03cb5fe1f32","src/as_hal.rs":"c3fa229dc0c65b1480951c53994afba580a595d13ecdad04095a83081ff4fe57","src/binding_model.rs":"f5f669f6ba53ce0940bacbbaa6100661a43e3d957d8ebc1906aad20608676abf","src/command/allocator.rs":"386cb6e60bd332a881dbbe57ff66a0fa83f35e3ee924559f1689418ac6c7273a","src/command/bind.rs":"c88aa87bf3052fe0993b79ff047339fac4557ead85973f4a37bf236fba401222","src/command/bundle.rs":"27eb1565c32f5486dd9dc87e0ba63e3fd9f3211e6e4a66a998071e0171a28fdf","src/command/clear.rs":"388a5dd1c7dfcf82053e61c74c52228346261191c9061c17f52285ec2fa51443","src/command/compute.rs":"5680142897313eacb4becc6f0c3cddc29dfc3ef7f6e3d5084c8ef6d5adf78230","src/command/compute_command.rs":"18aa0b8e389a5d345243b876b1abbacfc998a19d23069e092183fa7be10fa0ab","src/command/draw.rs":"97e61b057fdea79d68490604aadf7ccfa24381712405f21aba09d6ddc0f03f24","src/command/memory_init.rs":"2a7a8c27c48c2e4f4d40d09784d06d1cd22ea8793e71dbafb369efa430a05417","src/command/mod.rs":"01e1998b74e9a590235ea57f8249f96aa9b6cd7226069e46ed79e1db132b165e","src/command/pass.rs":"23f17526798dff6e352359e166c6734e34c16c0087f60a9c1c9951d2442fb4cc","src/command/query.rs":"8e88b65266169430c8a8e0b9ea39c5b36b161c8c6dccb6b574e4056a2e6d004e","src/command/ray_tracing.rs":"ad2581fbb13ab487b8a82bf875c31a1af7b3ef000e3b3b4b9f8dd528d5b29caa","src/command/render.rs":"7e439909996382b3539a8653c726ac405ea503b3436114b893139cb21c53c130","src/command/render_command.rs":"e6eaabb59d04c2c0c46e2f008d20eb01ff1a59e0d25abd6240ac49a23f8ce30a","src/command/timestamp_writes.rs":"da06fb07b8d0917be3e7fb9212d0ffc6b16526e1c1df617213ef354c3e1fb446","src/command/transfer.rs":"775941b4ddc25834fa8f27b41b3974d9e8a647bb099078812128153a90ef1a02","src/command/transition_resources.rs":"b591797bb75f937bce6d5bffc60b54bbcdb78111ea8d140f4a8c17d80958f226","src/conv.rs":"02722149d21bcdba6ee5101b3c0625a9de8ef607523a0eebb1f4088e82b3608b","src/device/bgl.rs":"fcb1d53b692970912781748379df675268981c97352872abf2e7bb0b1ebdd533","src/device/global.rs":"373d802bc24f28807dc171454c1729fa1fd0dbfb1f09044469e70bf9c7aac80b","src/device/life.rs":"c14c34512f24a511febbe4f3ef092e2c8ad43e5bdd5c29b7e965b19827b80b52","src/device/mod.rs":"3007e78178ba5b5b9b40ec75799c1576347789235b7ce68943b1ea869395e77d","src/device/queue.rs":"2caec9f5fe7db12bd9ab9047ebfd216a7c57ab83833e21071c8914c7bb385583","src/device/ray_tracing.rs":"237fc05b6258c102037a0ec13942727375f088bfdbde078e7360bfa49e44a041","src/device/resource.rs":"ad8f58dacfd22aeeb33604800a431bce7c2d1f0666f582ca487c62c01c7e67ad","src/device/trace.rs":"48316a9360ba795ce024f4e93fb1751ca0fa4210a93c6255ebc9a6d9a0f15e72","src/error.rs":"4f07a0b09b30b2d6cbc855d0091d724000f492018af3b41e80befbeccf2a6f4e","src/global.rs":"7bb7dc795d01607fd5d6f4477b55255c71fe4b1f8621a004b0a4305d6641fc20","src/hal_api.rs":"7962c119456602e9c2ba958712660532290cabe0b8c4c67ef7595de73cdf8b57","src/hash_utils.rs":"9f57a627fe3f00659391670141df62f68d67922c7b186f2a9a5958ab16fb576f","src/hub.rs":"ce0a14d5a3314df318bbc7c4d8c40ea2b3197dbddb2227e828ceb5127db7d37d","src/id.rs":"207f262558388147b484c51cf07d2554c26a3e19243058939e63a7f8e5c7ea75","src/identity.rs":"0a92302fc5b483ea1a8750b1672971af1cf2abfd4c0325bb02488b43e85073e2","src/indirect_validation/dispatch.rs":"8530817d6a062158c6426b51a1a6fb7da945b41c71c41e9a72ad832fad70c2ae","src/indirect_validation/draw.rs":"83a89798f7511e1ecfa3d489c2ba9ec558da9d2ac96bbf2717ebc5c4084f14d6","src/indirect_validation/mod.rs":"79466e4f9a59386e833958b3537beed6ffb6a7ee62aaabcf35382c2683998e43","src/indirect_validation/utils.rs":"e6a3b636dd71ff6b01d5abd5a589a0136fb30aa1d517a43f45cf2e5ad54da245","src/indirect_validation/validate_draw.wgsl":"fa7bba5f28c6c181f2d55ecfe386a5e5cd276bcb3c36aa7f963f43c535a9bf9a","src/init_tracker/buffer.rs":"6167a400ab271ba857f1c507e60a46fbd318c185aff87eecf7eb05f7f09b6963","src/init_tracker/mod.rs":"3895c4a2284631b6d6247c0d96c5fc9cfd024d358e09cad8752b2505700138a3","src/init_tracker/texture.rs":"ffdc67d4be23bcd48b22945de94ac0ea8ee571f91eb6d00323b9afe6fa91eef3","src/instance.rs":"80d8ab62ebad5c7093c1afa3345b09e480fa0e2d7ad0170a8f3b782d359f8e90","src/lib.rs":"578fce1910bf5a305baac6df171c94119ee71bf0b311d09478411fc27bfd0010","src/lock/mod.rs":"8d3ae3f8d004d7f7d8a3aefe9f30b35669cb8e2409f5fba27b1fcb116b2429c4","src/lock/observing.rs":"154134e93283a39327155b83fe7bf63df3c0f5cd9bbc0641081a4a5cf27851b5","src/lock/rank.rs":"238e6a97c58ee1a804863c8011bb257864301170344d18596bdaab09f3f74b54","src/lock/ranked.rs":"82809ea117b802bbb6f9ce2afebb5b0ab193c5a96491e881c55d4082f2681c61","src/lock/vanilla.rs":"a2907c56c847cb37cc0d38a7790c3849f4d81034d0f85162195805be60398eae","src/pipeline.rs":"2abb5aacdb603a1fdba247db47c55c55d57c174d22b5f8b82a0bc29e17ad1ad6","src/pipeline_cache.rs":"256bf8df58d8ab904afddc132349d03e4f659b6bd6882bc8df582dcfd05ae3d5","src/pool.rs":"e11bfdc73a66321d26715465fa74657dcd26a9b856b80b8369b4aac2132a4295","src/present.rs":"d0ab0b3ab29f3e49828a595ed432f0281bf569b5eafb0bb996f49bcfab86d2c0","src/ray_tracing.rs":"6e33799815e98d0dc7e98902e6b9c9c928bc50aaab27f343379989a13cc728f9","src/registry.rs":"779d8c277193537edd2b883b72cdcc07161b7231c8d2c80be726bd800cd327b6","src/resource.rs":"800112a9a711eb6b57b29f5a54bfa41769561a1e69f103b3541200a852421317","src/scratch.rs":"05f2032fa6d6f589c2507f4028755769b9524029e5ad59cc500cab7940e40d42","src/snatch.rs":"a0de237e327c9b30e4729440784c9e44b0725715d881b9762594dc3f8e61e32d","src/storage.rs":"8a4d20e85c3ac135316dcb0dab41ec4d335d86d34959d4392ec07f592125f0d3","src/timestamp_normalization/common.wgsl":"9f65aef0526ff9dde945fae70cef064ad961b0aee4291759ae82974cd2ead0a7","src/timestamp_normalization/mod.rs":"037b0ea1573065cef19d290a692d0cc7546e16c84b3a7cf4b510a4a7e02b2db4","src/timestamp_normalization/timestamp_normalization.wgsl":"4b2202b965e4c67482d03a546ac38c72a602d79ed9a60e6f7217393c49afad49","src/track/blas.rs":"18c7b5b89a60ab49bbc0f4f8b85a24502c1d968714ef4c586095e119848d902a","src/track/buffer.rs":"1ab5310367606fc74f0791733ea5ba2e09acc92ff7f4f4773f66bcfb3138c52f","src/track/metadata.rs":"04b8bcf8ded7c7c805d9336cfc874da9d8de7d12d99f7525f0540780a1dffc45","src/track/mod.rs":"57a2aeda7ed8dc25f3fa13d70f1fb66b123f0e59c29a89c7529d573e3501f5b5","src/track/range.rs":"2688b05a0c6e8510ff6ba3a9623e8b83f433a05ba743129928c56c93d9a9c233","src/track/stateless.rs":"3db699f5f48a319fa07fb16cdf51e1623d6ecac7a476467ee366e014ea665b89","src/track/texture.rs":"754c54f3051c8c780f3904c8c9213fc91ea1838ee14301731dd069a98c8c6695","src/validation.rs":"256f8ff5e579af4f1319997a2ca9e110f806ecf0d9b5534a2c5b4bd4f0c10776","src/weak_vec.rs":"a4193add5912b91226a3155cc613365b7fafdf2e7929d21d68bc19d149696e85"},"package":null} \ No newline at end of file
--- a/third_party/rust/wgpu-core/Cargo.toml +++ b/third_party/rust/wgpu-core/Cargo.toml @@ -8,17 +8,17 @@ # If you are reading this file be aware that the original Cargo.toml # will likely look very different (and much more reasonable). # See Cargo.toml.orig for the original contents. [package] edition = "2021" rust-version = "1.82.0" name = "wgpu-core" -version = "25.0.0" +version = "26.0.0" authors = ["gfx-rs developers"] build = "build.rs" autolib = false autobins = false autoexamples = false autotests = false autobenches = false description = "Core implementation logic of wgpu, the cross-platform, safe, pure-rust graphics API" @@ -144,29 +144,29 @@ default-features = false [dependencies.indexmap] version = "2.7" default-features = false [dependencies.log] version = "0.4.21" [dependencies.naga] -version = "25.0.0" +version = "26.0.0" path = "../naga" [dependencies.once_cell] version = "1.21" features = ["std"] default-features = false [dependencies.parking_lot] version = "0.12.3" [dependencies.profiling] -version = "1" +version = "1.0.1" default-features = false [dependencies.raw-window-handle] version = "0.6.2" optional = true default-features = false [dependencies.ron] @@ -189,47 +189,47 @@ default-features = false [dependencies.smallvec] version = "1.9" [dependencies.thiserror] version = "2.0.3" default-features = false [dependencies.wgpu-hal] -version = "25.0.0" +version = "26.0.0" path = "../wgpu-hal" [dependencies.wgpu-types] -version = "25.0.0" +version = "26.0.0" path = "../wgpu-types" default-features = false [build-dependencies.cfg_aliases] version = "0.2.1" [target.'cfg(all(target_arch = "wasm32", not(target_os = "emscripten")))'.dependencies.wgpu-core-deps-wasm] -version = "25.0.0" +version = "26.0.0" path = "platform-deps/wasm" optional = true [target.'cfg(any(windows, target_os = "linux", target_os = "android"))'.dependencies.wgpu-core-deps-windows-linux-android] -version = "25.0.0" +version = "26.0.0" path = "platform-deps/windows-linux-android" optional = true [target.'cfg(not(target_has_atomic = "64"))'.dependencies.portable-atomic] version = "1.8" optional = true [target.'cfg(target_os = "emscripten")'.dependencies.wgpu-core-deps-emscripten] -version = "25.0.0" +version = "26.0.0" path = "platform-deps/emscripten" optional = true [target.'cfg(target_vendor = "apple")'.dependencies.wgpu-core-deps-apple] -version = "25.0.0" +version = "26.0.0" path = "platform-deps/apple" optional = true [lints.rust.unexpected_cfgs] level = "warn" priority = 0 check-cfg = ["cfg(wgpu_validate_locks)"]
new file mode 100644 --- /dev/null +++ b/third_party/rust/wgpu-core/src/as_hal.rs @@ -0,0 +1,408 @@ +use core::{mem::ManuallyDrop, ops::Deref}; + +use alloc::sync::Arc; +use hal::DynResource; + +use crate::{ + device::Device, + global::Global, + hal_api::HalApi, + id::{ + AdapterId, BlasId, BufferId, CommandEncoderId, DeviceId, QueueId, SurfaceId, TextureId, + TextureViewId, TlasId, + }, + lock::{RankData, RwLockReadGuard}, + resource::RawResourceAccess, + snatch::SnatchGuard, +}; + +/// A guard which holds alive a wgpu-core resource and dereferences to the Hal type. +struct SimpleResourceGuard<Resource, HalType> { + _guard: Resource, + ptr: *const HalType, +} + +impl<Resource, HalType> SimpleResourceGuard<Resource, HalType> { + /// Creates a new guard from a resource, using a callback to derive the Hal type. + pub fn new<C>(guard: Resource, callback: C) -> Option<Self> + where + C: Fn(&Resource) -> Option<&HalType>, + { + // Derive the hal type from the resource and coerce it to a pointer. + let ptr: *const HalType = callback(&guard)?; + + Some(Self { _guard: guard, ptr }) + } +} + +impl<Resource, HalType> Deref for SimpleResourceGuard<Resource, HalType> { + type Target = HalType; + + fn deref(&self) -> &Self::Target { + // SAFETY: The pointer is guaranteed to be valid as the original resource is + // still alive and this guard cannot be used with snatchable resources. + unsafe { &*self.ptr } + } +} + +unsafe impl<Resource, HalType> Send for SimpleResourceGuard<Resource, HalType> +where + Resource: Send, + HalType: Send, +{ +} +unsafe impl<Resource, HalType> Sync for SimpleResourceGuard<Resource, HalType> +where + Resource: Sync, + HalType: Sync, +{ +} + +/// A guard which holds alive a snatchable wgpu-core resource and dereferences to the Hal type. +struct SnatchableResourceGuard<Resource, HalType> +where + Resource: RawResourceAccess, +{ + resource: Arc<Resource>, + snatch_lock_rank_data: ManuallyDrop<RankData>, + ptr: *const HalType, +} + +impl<Resource, HalType> SnatchableResourceGuard<Resource, HalType> +where + Resource: RawResourceAccess, + HalType: 'static, +{ + /// Creates a new guard from a snatchable resource. + /// + /// Returns `None` if: + /// - The resource is not of the expected Hal type. + /// - The resource has been destroyed. + pub fn new(resource: Arc<Resource>) -> Option<Self> { + // Grab the snatchable lock. + let snatch_guard = resource.device().snatchable_lock.read(); + + // Get the raw resource and downcast it to the expected Hal type. + let underlying = resource + .raw(&snatch_guard)? + .as_any() + .downcast_ref::<HalType>()?; + + // Cast the raw resource to a pointer to get rid of the lifetime + // connecting us to the snatch guard. + let ptr: *const HalType = underlying; + + // SAFETY: At this point all panicking or divergance has already happened, + // so we can safely forget the snatch guard without causing the lock to be left open. + let snatch_lock_rank_data = SnatchGuard::forget(snatch_guard); + + // SAFETY: We only construct this guard while the snatchable lock is held, + // as the `drop` implementation of this guard will unsafely release the lock. + Some(Self { + resource, + snatch_lock_rank_data: ManuallyDrop::new(snatch_lock_rank_data), + ptr, + }) + } +} + +impl<Resource, HalType> Deref for SnatchableResourceGuard<Resource, HalType> +where + Resource: RawResourceAccess, +{ + type Target = HalType; + + fn deref(&self) -> &Self::Target { + // SAFETY: The pointer is guaranteed to be valid as the original resource is + // still alive and the snatchable lock is still being held due to the forgotten + // snatch guard. + unsafe { &*self.ptr } + } +} + +impl<Resource, HalType> Drop for SnatchableResourceGuard<Resource, HalType> +where + Resource: RawResourceAccess, +{ + fn drop(&mut self) { + // SAFETY: + // - We are not going to access the rank data anymore. + let data = unsafe { ManuallyDrop::take(&mut self.snatch_lock_rank_data) }; + + // SAFETY: + // - The pointer is no longer going to be accessed. + // - The snatchable lock is being held because this type was not created + // until after the snatchable lock was forgotten. + unsafe { + self.resource + .device() + .snatchable_lock + .force_unlock_read(data) + }; + } +} + +unsafe impl<Resource, HalType> Send for SnatchableResourceGuard<Resource, HalType> +where + Resource: RawResourceAccess + Send, + HalType: Send, +{ +} +unsafe impl<Resource, HalType> Sync for SnatchableResourceGuard<Resource, HalType> +where + Resource: RawResourceAccess + Sync, + HalType: Sync, +{ +} + +/// A guard which holds alive a device and the device's fence lock, dereferencing to the Hal type. +struct FenceGuard<Fence> { + device: Arc<Device>, + fence_lock_rank_data: ManuallyDrop<RankData>, + ptr: *const Fence, +} + +impl<Fence> FenceGuard<Fence> +where + Fence: 'static, +{ + /// Creates a new guard over a device's fence. + /// + /// Returns `None` if: + /// - The device's fence is not of the expected Hal type. + pub fn new(device: Arc<Device>) -> Option<Self> { + // Grab the fence lock. + let fence_guard = device.fence.read(); + + // Get the raw fence and downcast it to the expected Hal type, coercing it to a pointer + // to get rid of the lifetime connecting us to the fence guard. + let ptr: *const Fence = fence_guard.as_any().downcast_ref::<Fence>()?; + + // SAFETY: At this point all panicking or divergance has already happened, + // so we can safely forget the fence guard without causing the lock to be left open. + let fence_lock_rank_data = RwLockReadGuard::forget(fence_guard); + + // SAFETY: We only construct this guard while the fence lock is held, + // as the `drop` implementation of this guard will unsafely release the lock. + Some(Self { + device, + fence_lock_rank_data: ManuallyDrop::new(fence_lock_rank_data), + ptr, + }) + } +} + +impl<Fence> Deref for FenceGuard<Fence> { + type Target = Fence; + + fn deref(&self) -> &Self::Target { + // SAFETY: The pointer is guaranteed to be valid as the original device's fence + // is still alive and the fence lock is still being held due to the forgotten + // fence guard. + unsafe { &*self.ptr } + } +} + +impl<Fence> Drop for FenceGuard<Fence> { + fn drop(&mut self) { + // SAFETY: + // - We are not going to access the rank data anymore. + let data = unsafe { ManuallyDrop::take(&mut self.fence_lock_rank_data) }; + + // SAFETY: + // - The pointer is no longer going to be accessed. + // - The fence lock is being held because this type was not created + // until after the fence lock was forgotten. + unsafe { + self.device.fence.force_unlock_read(data); + }; + } +} + +unsafe impl<Fence> Send for FenceGuard<Fence> where Fence: Send {} +unsafe impl<Fence> Sync for FenceGuard<Fence> where Fence: Sync {} + +impl Global { + /// # Safety + /// + /// - The raw buffer handle must not be manually destroyed + pub unsafe fn buffer_as_hal<A: HalApi>( + &self, + id: BufferId, + ) -> Option<impl Deref<Target = A::Buffer>> { + profiling::scope!("Buffer::as_hal"); + + let hub = &self.hub; + + let buffer = hub.buffers.get(id).get().ok()?; + + SnatchableResourceGuard::new(buffer) + } + + /// # Safety + /// + /// - The raw texture handle must not be manually destroyed + pub unsafe fn texture_as_hal<A: HalApi>( + &self, + id: TextureId, + ) -> Option<impl Deref<Target = A::Texture>> { + profiling::scope!("Texture::as_hal"); + + let hub = &self.hub; + + let texture = hub.textures.get(id).get().ok()?; + + SnatchableResourceGuard::new(texture) + } + + /// # Safety + /// + /// - The raw texture view handle must not be manually destroyed + pub unsafe fn texture_view_as_hal<A: HalApi>( + &self, + id: TextureViewId, + ) -> Option<impl Deref<Target = A::TextureView>> { + profiling::scope!("TextureView::as_hal"); + + let hub = &self.hub; + + let view = hub.texture_views.get(id).get().ok()?; + + SnatchableResourceGuard::new(view) + } + + /// # Safety + /// + /// - The raw adapter handle must not be manually destroyed + pub unsafe fn adapter_as_hal<A: HalApi>( + &self, + id: AdapterId, + ) -> Option<impl Deref<Target = A::Adapter>> { + profiling::scope!("Adapter::as_hal"); + + let hub = &self.hub; + let adapter = hub.adapters.get(id); + + SimpleResourceGuard::new(adapter, move |adapter| { + adapter.raw.adapter.as_any().downcast_ref() + }) + } + + /// # Safety + /// + /// - The raw device handle must not be manually destroyed + pub unsafe fn device_as_hal<A: HalApi>( + &self, + id: DeviceId, + ) -> Option<impl Deref<Target = A::Device>> { + profiling::scope!("Device::as_hal"); + + let device = self.hub.devices.get(id); + + SimpleResourceGuard::new(device, move |device| device.raw().as_any().downcast_ref()) + } + + /// # Safety + /// + /// - The raw fence handle must not be manually destroyed + pub unsafe fn device_fence_as_hal<A: HalApi>( + &self, + id: DeviceId, + ) -> Option<impl Deref<Target = A::Fence>> { + profiling::scope!("Device::fence_as_hal"); + + let device = self.hub.devices.get(id); + + FenceGuard::new(device) + } + + /// # Safety + /// - The raw surface handle must not be manually destroyed + pub unsafe fn surface_as_hal<A: HalApi>( + &self, + id: SurfaceId, + ) -> Option<impl Deref<Target = A::Surface>> { + profiling::scope!("Surface::as_hal"); + + let surface = self.surfaces.get(id); + + SimpleResourceGuard::new(surface, move |surface| { + surface.raw(A::VARIANT)?.as_any().downcast_ref() + }) + } + + /// # Safety + /// + /// - The raw command encoder handle must not be manually destroyed + pub unsafe fn command_encoder_as_hal_mut< + A: HalApi, + F: FnOnce(Option<&mut A::CommandEncoder>) -> R, + R, + >( + &self, + id: CommandEncoderId, + hal_command_encoder_callback: F, + ) -> R { + profiling::scope!("CommandEncoder::as_hal"); + + let hub = &self.hub; + + let cmd_buf = hub.command_buffers.get(id.into_command_buffer_id()); + let mut cmd_buf_data = cmd_buf.data.lock(); + cmd_buf_data.record_as_hal_mut(|opt_cmd_buf| -> R { + hal_command_encoder_callback(opt_cmd_buf.and_then(|cmd_buf| { + cmd_buf + .encoder + .open() + .ok() + .and_then(|encoder| encoder.as_any_mut().downcast_mut()) + })) + }) + } + + /// # Safety + /// + /// - The raw queue handle must not be manually destroyed + pub unsafe fn queue_as_hal<A: HalApi>( + &self, + id: QueueId, + ) -> Option<impl Deref<Target = A::Queue>> { + profiling::scope!("Queue::as_hal"); + + let queue = self.hub.queues.get(id); + + SimpleResourceGuard::new(queue, move |queue| queue.raw().as_any().downcast_ref()) + } + + /// # Safety + /// + /// - The raw blas handle must not be manually destroyed + pub unsafe fn blas_as_hal<A: HalApi>( + &self, + id: BlasId, + ) -> Option<impl Deref<Target = A::AccelerationStructure>> { + profiling::scope!("Blas::as_hal"); + + let hub = &self.hub; + + let blas = hub.blas_s.get(id).get().ok()?; + + SnatchableResourceGuard::new(blas) + } + + /// # Safety + /// + /// - The raw tlas handle must not be manually destroyed + pub unsafe fn tlas_as_hal<A: HalApi>( + &self, + id: TlasId, + ) -> Option<impl Deref<Target = A::AccelerationStructure>> { + profiling::scope!("Tlas::as_hal"); + + let hub = &self.hub; + + let tlas = hub.tlas_s.get(id).get().ok()?; + + SnatchableResourceGuard::new(tlas) + } +}
--- a/third_party/rust/wgpu-core/src/binding_model.rs +++ b/third_party/rust/wgpu-core/src/binding_model.rs @@ -21,17 +21,18 @@ use crate::{ device::{ bgl, Device, DeviceError, MissingDownlevelFlags, MissingFeatures, SHADER_STAGE_COUNT, }, id::{BindGroupLayoutId, BufferId, SamplerId, TextureViewId, TlasId}, init_tracker::{BufferInitTrackerAction, TextureInitTrackerAction}, pipeline::{ComputePipeline, RenderPipeline}, resource::{ Buffer, DestroyedResourceError, InvalidResourceError, Labeled, MissingBufferUsageError, - MissingTextureUsageError, ResourceErrorIdent, Sampler, TextureView, Tlas, TrackingData, + MissingTextureUsageError, RawResourceAccess, ResourceErrorIdent, Sampler, TextureView, + Tlas, TrackingData, }, resource_log, snatch::{SnatchGuard, Snatchable}, track::{BindGroupStates, ResourceUsageCompatibilityError}, Label, }; #[derive(Clone, Debug, Error)] @@ -89,41 +90,68 @@ impl WebGpuError for CreateBindGroupLayo | Self::InvalidBindingIndex { .. } | Self::InvalidVisibility(_) | Self::ContainsBothBindingArrayAndDynamicOffsetArray | Self::ContainsBothBindingArrayAndUniformBuffer => ErrorType::Validation, } } } -//TODO: refactor this to move out `enum BindingError`. +#[derive(Clone, Debug, Error)] +#[non_exhaustive] +pub enum BindingError { + #[error(transparent)] + DestroyedResource(#[from] DestroyedResourceError), + #[error("Buffer {buffer}: Binding with size {binding_size} at offset {offset} would overflow buffer size of {buffer_size}")] + BindingRangeTooLarge { + buffer: ResourceErrorIdent, + offset: wgt::BufferAddress, + binding_size: u64, + buffer_size: u64, + }, + #[error("Buffer {buffer}: Binding offset {offset} is greater than buffer size {buffer_size}")] + BindingOffsetTooLarge { + buffer: ResourceErrorIdent, + offset: wgt::BufferAddress, + buffer_size: u64, + }, +} +impl WebGpuError for BindingError { + fn webgpu_error_type(&self) -> ErrorType { + match self { + Self::DestroyedResource(e) => e.webgpu_error_type(), + Self::BindingRangeTooLarge { .. } | Self::BindingOffsetTooLarge { .. } => { + ErrorType::Validation + } + } + } +} + +// TODO: there may be additional variants here that can be extracted into +// `BindingError`. #[derive(Clone, Debug, Error)] #[non_exhaustive] pub enum CreateBindGroupError { #[error(transparent)] Device(#[from] DeviceError), #[error(transparent)] DestroyedResource(#[from] DestroyedResourceError), + #[error(transparent)] + BindingError(#[from] BindingError), #[error( "Binding count declared with at most {expected} items, but {actual} items were provided" )] BindingArrayPartialLengthMismatch { actual: usize, expected: usize }, #[error( "Binding count declared with exactly {expected} items, but {actual} items were provided" )] BindingArrayLengthMismatch { actual: usize, expected: usize }, #[error("Array binding provided zero elements")] BindingArrayZeroLength, - #[error("The bound range {range:?} of {buffer} overflows its size ({size})")] - BindingRangeTooLarge { - buffer: ResourceErrorIdent, - range: Range<wgt::BufferAddress>, - size: u64, - }, #[error("Binding size {actual} of {buffer} is less than minimum {min}")] BindingSizeTooSmall { buffer: ResourceErrorIdent, actual: u64, min: u64, }, #[error("{0} binding size is zero")] BindingZeroSize(ResourceErrorIdent), @@ -228,24 +256,24 @@ pub enum CreateBindGroupError { InvalidResource(#[from] InvalidResourceError), } impl WebGpuError for CreateBindGroupError { fn webgpu_error_type(&self) -> ErrorType { let e: &dyn WebGpuError = match self { Self::Device(e) => e, Self::DestroyedResource(e) => e, + Self::BindingError(e) => e, Self::MissingBufferUsage(e) => e, Self::MissingTextureUsage(e) => e, Self::ResourceUsageCompatibility(e) => e, Self::InvalidResource(e) => e, Self::BindingArrayPartialLengthMismatch { .. } | Self::BindingArrayLengthMismatch { .. } | Self::BindingArrayZeroLength - | Self::BindingRangeTooLarge { .. } | Self::BindingSizeTooSmall { .. } | Self::BindingsNumMismatch { .. } | Self::BindingZeroSize(_) | Self::DuplicateBinding(_) | Self::MissingBindingDeclaration(_) | Self::SingleBindingExpected | Self::UnalignedBufferOffset(_, _, _) | Self::BufferRangeTooLarge { .. }
--- a/third_party/rust/wgpu-core/src/command/bundle.rs +++ b/third_party/rust/wgpu-core/src/command/bundle.rs @@ -88,16 +88,17 @@ use core::{ convert::Infallible, num::{NonZeroU32, NonZeroU64}, ops::Range, }; use arrayvec::ArrayVec; use thiserror::Error; +use wgpu_hal::ShouldBeNonZeroExt; use wgt::error::{ErrorType, WebGpuError}; use crate::{ binding_model::{BindError, BindGroup, PipelineLayout}, command::{ BasePass, BindGroupStateChange, ColorAttachmentError, DrawError, MapPassErr, PassErrorScope, RenderCommandError, StateChange, }, @@ -106,17 +107,17 @@ use crate::{ SHADER_STAGE_COUNT, }, hub::Hub, id, init_tracker::{BufferInitTrackerAction, MemoryInitKind, TextureInitTrackerAction}, pipeline::{PipelineFlags, RenderPipeline, VertexStep}, resource::{ Buffer, DestroyedResourceError, Fallible, InvalidResourceError, Labeled, ParentDevice, - TrackingData, + RawResourceAccess, TrackingData, }, resource_log, snatch::SnatchGuard, track::RenderBundleScope, Label, LabelHelpers, }; use super::{ @@ -597,16 +598,17 @@ fn set_pipeline( state.invalidate_bind_groups(&pipeline_state, &pipeline.layout); state.pipeline = Some(pipeline_state); state.trackers.render_pipelines.insert_single(pipeline); Ok(()) } +// This function is duplicative of `render::set_index_buffer`. fn set_index_buffer( state: &mut State, buffer_guard: &crate::storage::Storage<Fallible<Buffer>>, buffer_id: id::Id<id::markers::Buffer>, index_format: wgt::IndexFormat, offset: u64, size: Option<NonZeroU64>, ) -> Result<(), RenderBundleErrorInner> { @@ -615,31 +617,30 @@ fn set_index_buffer( state .trackers .buffers .merge_single(&buffer, wgt::BufferUses::INDEX)?; buffer.same_device(&state.device)?; buffer.check_usage(wgt::BufferUsages::INDEX)?; - let end = match size { - Some(s) => offset + s.get(), - None => buffer.size, - }; + let end = offset + buffer.resolve_binding_size(offset, size)?; + state .buffer_memory_init_actions .extend(buffer.initialization_status.read().create_action( &buffer, - offset..end, + offset..end.get(), MemoryInitKind::NeedsInitializedMemory, )); - state.set_index_buffer(buffer, index_format, offset..end); + state.set_index_buffer(buffer, index_format, offset..end.get()); Ok(()) } +// This function is duplicative of `render::set_vertex_buffer`. fn set_vertex_buffer( state: &mut State, buffer_guard: &crate::storage::Storage<Fallible<Buffer>>, slot: u32, buffer_id: id::Id<id::markers::Buffer>, offset: u64, size: Option<NonZeroU64>, ) -> Result<(), RenderBundleErrorInner> { @@ -657,28 +658,26 @@ fn set_vertex_buffer( state .trackers .buffers .merge_single(&buffer, wgt::BufferUses::VERTEX)?; buffer.same_device(&state.device)?; buffer.check_usage(wgt::BufferUsages::VERTEX)?; - let end = match size { - Some(s) => offset + s.get(), - None => buffer.size, - }; + let end = offset + buffer.resolve_binding_size(offset, size)?; + state .buffer_memory_init_actions .extend(buffer.initialization_status.read().create_action( &buffer, - offset..end, + offset..end.get(), MemoryInitKind::NeedsInitializedMemory, )); - state.vertex[slot as usize] = Some(VertexState::new(buffer, offset..end)); + state.vertex[slot as usize] = Some(VertexState::new(buffer, offset..end.get())); Ok(()) } fn set_push_constant( state: &mut State, stages: wgt::ShaderStages, offset: u32, size_bytes: u32, @@ -960,35 +959,31 @@ impl RenderBundle { } Cmd::SetIndexBuffer { buffer, index_format, offset, size, } => { let buffer = buffer.try_raw(snatch_guard)?; - let bb = hal::BufferBinding { - buffer, - offset: *offset, - size: *size, - }; + // SAFETY: The binding size was checked against the buffer size + // in `set_index_buffer` and again in `IndexState::flush`. + let bb = hal::BufferBinding::new_unchecked(buffer, *offset, *size); unsafe { raw.set_index_buffer(bb, *index_format) }; } Cmd::SetVertexBuffer { slot, buffer, offset, size, } => { let buffer = buffer.try_raw(snatch_guard)?; - let bb = hal::BufferBinding { - buffer, - offset: *offset, - size: *size, - }; + // SAFETY: The binding size was checked against the buffer size + // in `set_vertex_buffer` and again in `VertexState::flush`. + let bb = hal::BufferBinding::new_unchecked(buffer, *offset, *size); unsafe { raw.set_vertex_buffer(*slot, bb) }; } Cmd::SetPushConstant { stages, offset, size_bytes, values_offset, } => { @@ -1126,16 +1121,19 @@ crate::impl_parent_device!(RenderBundle) crate::impl_storage_item!(RenderBundle); crate::impl_trackable!(RenderBundle); /// A render bundle's current index buffer state. /// /// [`RenderBundleEncoder::finish`] records the currently set index buffer here, /// and calls [`State::flush_index`] before any indexed draw command to produce /// a `SetIndexBuffer` command if one is necessary. +/// +/// Binding ranges must be validated against the size of the buffer before +/// being stored in `IndexState`. #[derive(Debug)] struct IndexState { buffer: Arc<Buffer>, format: wgt::IndexFormat, range: Range<wgt::BufferAddress>, is_dirty: bool, } @@ -1147,66 +1145,87 @@ impl IndexState { let bytes_per_index = self.format.byte_size() as u64; (self.range.end - self.range.start) / bytes_per_index } /// Generate a `SetIndexBuffer` command to prepare for an indexed draw /// command, if needed. fn flush(&mut self) -> Option<ArcRenderCommand> { + // This was all checked before, but let's check again just in case. + let binding_size = self + .range + .end + .checked_sub(self.range.start) + .filter(|_| self.range.end <= self.buffer.size) + .expect("index range must be contained in buffer"); + if self.is_dirty { self.is_dirty = false; Some(ArcRenderCommand::SetIndexBuffer { buffer: self.buffer.clone(), index_format: self.format, offset: self.range.start, - size: wgt::BufferSize::new(self.range.end - self.range.start), + size: NonZeroU64::new(binding_size), }) } else { None } } } /// The state of a single vertex buffer slot during render bundle encoding. /// /// [`RenderBundleEncoder::finish`] uses this to drop redundant /// `SetVertexBuffer` commands from the final [`RenderBundle`]. It /// records one vertex buffer slot's state changes here, and then /// calls this type's [`flush`] method just before any draw command to /// produce a `SetVertexBuffer` commands if one is necessary. /// +/// Binding ranges must be validated against the size of the buffer before +/// being stored in `VertexState`. +/// /// [`flush`]: IndexState::flush #[derive(Debug)] struct VertexState { buffer: Arc<Buffer>, range: Range<wgt::BufferAddress>, is_dirty: bool, } impl VertexState { + /// Create a new `VertexState`. + /// + /// The `range` must be contained within `buffer`. fn new(buffer: Arc<Buffer>, range: Range<wgt::BufferAddress>) -> Self { Self { buffer, range, is_dirty: true, } } /// Generate a `SetVertexBuffer` command for this slot, if necessary. /// /// `slot` is the index of the vertex buffer slot that `self` tracks. fn flush(&mut self, slot: u32) -> Option<ArcRenderCommand> { + let binding_size = self + .range + .end + .checked_sub(self.range.start) + .filter(|_| self.range.end <= self.buffer.size) + .expect("vertex range must be contained in buffer"); + if self.is_dirty { self.is_dirty = false; Some(ArcRenderCommand::SetVertexBuffer { slot, buffer: self.buffer.clone(), offset: self.range.start, - size: wgt::BufferSize::new(self.range.end - self.range.start), + size: NonZeroU64::new(binding_size), }) } else { None } } } /// A bind group that has been set at a particular index during render bundle encoding.
--- a/third_party/rust/wgpu-core/src/command/clear.rs +++ b/third_party/rust/wgpu-core/src/command/clear.rs @@ -8,17 +8,17 @@ use crate::{ command::EncoderStateError, device::DeviceError, get_lowest_common_denom, global::Global, id::{BufferId, CommandEncoderId, TextureId}, init_tracker::{MemoryInitKind, TextureInitRange}, resource::{ DestroyedResourceError, InvalidResourceError, Labeled, MissingBufferUsageError, - ParentDevice, ResourceErrorIdent, Texture, TextureClearMode, + ParentDevice, RawResourceAccess, ResourceErrorIdent, Texture, TextureClearMode, }, snatch::SnatchGuard, track::TextureTrackerSetSingle, }; use thiserror::Error; use wgt::{ error::{ErrorType, WebGpuError},
--- a/third_party/rust/wgpu-core/src/command/compute.rs +++ b/third_party/rust/wgpu-core/src/command/compute.rs @@ -2,19 +2,19 @@ use thiserror::Error; use wgt::{ error::{ErrorType, WebGpuError}, BufferAddress, DynamicOffset, }; use alloc::{borrow::Cow, boxed::Box, sync::Arc, vec::Vec}; use core::{fmt, str}; -use crate::binding_model::BindError; use crate::command::{pass, EncoderStateError, PassStateError, TimestampWritesError}; use crate::resource::DestroyedResourceError; +use crate::{binding_model::BindError, resource::RawResourceAccess}; use crate::{ binding_model::{LateMinBufferBindingSizeMismatch, PushConstantUploadError}, command::{ bind::{Binder, BinderError}, compute_command::ArcComputeCommand, end_pipeline_statistics_query, memory_init::{fixup_discarded_surfaces, SurfacesInDiscardState}, pass_base, pass_try, validate_and_begin_pipeline_statistics_query, ArcPassTimestampWrites, @@ -487,17 +487,17 @@ impl Global { self.compute_pass_end(&mut compute_pass).unwrap(); } pub fn compute_pass_end(&self, pass: &mut ComputePass) -> Result<(), EncoderStateError> { let pass_scope = PassErrorScope::Pass; profiling::scope!( "CommandEncoder::run_compute_pass {}", - base.label.as_deref().unwrap_or("") + pass.base.label.as_deref().unwrap_or("") ); let cmd_buf = pass.parent.take().ok_or(EncoderStateError::Ended)?; let mut cmd_buf_data = cmd_buf.data.lock(); if let Some(err) = pass.base.error.take() { if matches!( err,
--- a/third_party/rust/wgpu-core/src/command/draw.rs +++ b/third_party/rust/wgpu-core/src/command/draw.rs @@ -2,17 +2,17 @@ use alloc::boxed::Box; use thiserror::Error; use wgt::error::{ErrorType, WebGpuError}; use super::bind::BinderError; use crate::command::pass; use crate::{ - binding_model::{LateMinBufferBindingSizeMismatch, PushConstantUploadError}, + binding_model::{BindingError, LateMinBufferBindingSizeMismatch, PushConstantUploadError}, resource::{ DestroyedResourceError, MissingBufferUsageError, MissingTextureUsageError, ResourceErrorIdent, }, track::ResourceUsageCompatibilityError, }; /// Error validating a draw call. @@ -84,16 +84,18 @@ pub enum RenderCommandError { #[error(transparent)] DestroyedResource(#[from] DestroyedResourceError), #[error(transparent)] MissingBufferUsage(#[from] MissingBufferUsageError), #[error(transparent)] MissingTextureUsage(#[from] MissingTextureUsageError), #[error(transparent)] PushConstants(#[from] PushConstantUploadError), + #[error(transparent)] + BindingError(#[from] BindingError), #[error("Viewport size {{ w: {w}, h: {h} }} greater than device's requested `max_texture_dimension_2d` limit {max}, or less than zero")] InvalidViewportRectSize { w: f32, h: f32, max: u32 }, #[error("Viewport has invalid rect {rect:?} for device's requested `max_texture_dimension_2d` limit; Origin less than -2 * `max_texture_dimension_2d` ({min}), or rect extends past 2 * `max_texture_dimension_2d` - 1 ({max})")] InvalidViewportRectPosition { rect: Rect<f32>, min: f32, max: f32 }, #[error("Viewport minDepth {0} and/or maxDepth {1} are not in [0, 1]")] InvalidViewportDepth(f32, f32), #[error("Scissor {0:?} is not contained in the render target {1:?}")] InvalidScissorRect(Rect<u32>, wgt::Extent3d), @@ -105,16 +107,17 @@ impl WebGpuError for RenderCommandError fn webgpu_error_type(&self) -> ErrorType { let e: &dyn WebGpuError = match self { Self::IncompatiblePipelineTargets(e) => e, Self::ResourceUsageCompatibility(e) => e, Self::DestroyedResource(e) => e, Self::MissingBufferUsage(e) => e, Self::MissingTextureUsage(e) => e, Self::PushConstants(e) => e, + Self::BindingError(e) => e, Self::BindGroupIndexOutOfRange { .. } | Self::VertexBufferIndexOutOfRange { .. } | Self::IncompatibleDepthAccess(..) | Self::IncompatibleStencilAccess(..) | Self::InvalidViewportRectSize { .. } | Self::InvalidViewportRectPosition { .. } | Self::InvalidViewportDepth(..)
--- a/third_party/rust/wgpu-core/src/command/memory_init.rs +++ b/third_party/rust/wgpu-core/src/command/memory_init.rs @@ -4,17 +4,17 @@ use alloc::{ }; use core::ops::Range; use hashbrown::hash_map::Entry; use crate::{ device::Device, init_tracker::*, - resource::{DestroyedResourceError, ParentDevice, Texture, Trackable}, + resource::{DestroyedResourceError, ParentDevice, RawResourceAccess, Texture, Trackable}, snatch::SnatchGuard, track::{DeviceTracker, TextureTracker}, FastHashMap, }; use super::{clear::clear_texture, BakedCommands, ClearError}; /// Surface that was discarded by `StoreOp::Discard` of a preceding renderpass.
--- a/third_party/rust/wgpu-core/src/command/mod.rs +++ b/third_party/rust/wgpu-core/src/command/mod.rs @@ -26,16 +26,17 @@ pub use self::{ }; pub(crate) use allocator::CommandAllocator; pub(crate) use timestamp_writes::ArcPassTimestampWrites; pub use timestamp_writes::PassTimestampWrites; use self::memory_init::CommandBufferTextureMemoryActions; +use crate::binding_model::BindingError; use crate::command::transition_resources::TransitionResourcesError; use crate::device::queue::TempResource; use crate::device::{Device, DeviceError, MissingFeatures}; use crate::lock::{rank, Mutex}; use crate::snatch::SnatchGuard; use crate::init_tracker::BufferInitTrackerAction; use crate::ray_tracing::{AsAction, BuildAccelerationStructureError}; @@ -1055,16 +1056,28 @@ impl CommandEncoderError { | Self::ComputePass(ComputePassError { inner: ComputePassErrorInner::DestroyedResource(_), .. }) | Self::RenderPass(RenderPassError { inner: RenderPassErrorInner::DestroyedResource(_), .. }) + | Self::RenderPass(RenderPassError { + inner: RenderPassErrorInner::RenderCommand( + RenderCommandError::DestroyedResource(_) + ), + .. + }) + | Self::RenderPass(RenderPassError { + inner: RenderPassErrorInner::RenderCommand(RenderCommandError::BindingError( + BindingError::DestroyedResource(_) + )), + .. + }) ) } } impl WebGpuError for CommandEncoderError { fn webgpu_error_type(&self) -> ErrorType { let e: &dyn WebGpuError = match self { Self::Device(e) => e,
--- a/third_party/rust/wgpu-core/src/command/query.rs +++ b/third_party/rust/wgpu-core/src/command/query.rs @@ -6,17 +6,17 @@ use crate::device::trace::Command as Tra use crate::{ command::{CommandBuffer, EncoderStateError}, device::{DeviceError, MissingFeatures}, global::Global, id, init_tracker::MemoryInitKind, resource::{ DestroyedResourceError, InvalidResourceError, MissingBufferUsageError, ParentDevice, - QuerySet, Trackable, + QuerySet, RawResourceAccess, Trackable, }, track::{StatelessTracker, TrackerIndex}, FastHashMap, }; use thiserror::Error; use wgt::{ error::{ErrorType, WebGpuError}, BufferAddress,
--- a/third_party/rust/wgpu-core/src/command/ray_tracing.rs +++ b/third_party/rust/wgpu-core/src/command/ray_tracing.rs @@ -2,38 +2,36 @@ use alloc::{boxed::Box, sync::Arc, vec:: use core::{ cmp::max, num::NonZeroU64, ops::{Deref, Range}, }; use wgt::{math::align_to, BufferUsages, BufferUses, Features}; -use crate::lock::RwLockWriteGuard; use crate::ray_tracing::{AsAction, AsBuild, TlasBuild, ValidateAsActionsError}; use crate::{ command::CommandBufferMutable, device::queue::TempResource, global::Global, hub::Hub, id::CommandEncoderId, init_tracker::MemoryInitKind, ray_tracing::{ BlasBuildEntry, BlasGeometries, BlasTriangleGeometry, BuildAccelerationStructureError, TlasInstance, TlasPackage, TraceBlasBuildEntry, TraceBlasGeometries, TraceBlasTriangleGeometry, TraceTlasInstance, TraceTlasPackage, }, - resource::{ - AccelerationStructure, Blas, BlasCompactState, Buffer, Labeled, StagingBuffer, Tlas, - }, + resource::{Blas, BlasCompactState, Buffer, Labeled, StagingBuffer, Tlas}, scratch::ScratchBuffer, snatch::SnatchGuard, track::PendingTransition, }; use crate::{command::EncoderStateError, device::resource::CommandIndices}; +use crate::{lock::RwLockWriteGuard, resource::RawResourceAccess}; use crate::id::{BlasId, TlasId}; struct TriangleBufferStore<'a> { vertex_buffer: Arc<Buffer>, vertex_transition: Option<PendingTransition<BufferUses>>, index_buffer_transition: Option<(Arc<Buffer>, Option<PendingTransition<BufferUses>>)>, transform_buffer_transition: Option<(Arc<Buffer>, Option<PendingTransition<BufferUses>>)>,
--- a/third_party/rust/wgpu-core/src/command/render.rs +++ b/third_party/rust/wgpu-core/src/command/render.rs @@ -10,16 +10,17 @@ use wgt::{ }; use crate::command::{ pass, pass_base, pass_try, validate_and_begin_occlusion_query, validate_and_begin_pipeline_statistics_query, EncoderStateError, PassStateError, TimestampWritesError, }; use crate::pipeline::{RenderPipeline, VertexStep}; +use crate::resource::RawResourceAccess; use crate::resource::{InvalidResourceError, ResourceErrorIdent}; use crate::snatch::SnatchGuard; use crate::{ api_log, command::{ bind::Binder, end_occlusion_query, end_pipeline_statistics_query, memory_init::{fixup_discarded_surfaces, SurfacesInDiscardState}, @@ -1798,17 +1799,17 @@ impl Global { self.render_pass_end(&mut render_pass).unwrap(); } pub fn render_pass_end(&self, pass: &mut RenderPass) -> Result<(), EncoderStateError> { let pass_scope = PassErrorScope::Pass; profiling::scope!( "CommandEncoder::run_render_pass {}", - base.label.as_deref().unwrap_or("") + pass.base.label.as_deref().unwrap_or("") ); let cmd_buf = pass.parent.take().ok_or(EncoderStateError::Ended)?; let mut cmd_buf_data = cmd_buf.data.lock(); if let Some(err) = pass.base.error.take() { if matches!( err, @@ -2317,16 +2318,17 @@ fn set_pipeline( || {}, )?; // Update vertex buffer limits. state.vertex.update_limits(&pipeline.vertex_steps); Ok(()) } +// This function is duplicative of `bundle::set_index_buffer`. fn set_index_buffer( state: &mut State, cmd_buf: &Arc<CommandBuffer>, buffer: Arc<crate::resource::Buffer>, index_format: IndexFormat, offset: u64, size: Option<BufferSize>, ) -> Result<(), RenderPassErrorInner> { @@ -2336,43 +2338,38 @@ fn set_index_buffer( .general .scope .buffers .merge_single(&buffer, wgt::BufferUses::INDEX)?; buffer.same_device_as(cmd_buf.as_ref())?; buffer.check_usage(BufferUsages::INDEX)?; - let buf_raw = buffer.try_raw(state.general.snatch_guard)?; - - let end = match size { - Some(s) => offset + s.get(), - None => buffer.size, - }; + + let (binding, resolved_size) = buffer + .binding(offset, size, state.general.snatch_guard) + .map_err(RenderCommandError::from)?; + let end = offset + resolved_size; state.index.update_buffer(offset..end, index_format); state.general.buffer_memory_init_actions.extend( buffer.initialization_status.read().create_action( &buffer, offset..end, MemoryInitKind::NeedsInitializedMemory, ), ); - let bb = hal::BufferBinding { - buffer: buf_raw, - offset, - size, - }; unsafe { - hal::DynCommandEncoder::set_index_buffer(state.general.raw_encoder, bb, index_format); + hal::DynCommandEncoder::set_index_buffer(state.general.raw_encoder, binding, index_format); } Ok(()) } +// This function is duplicative of `render::set_vertex_buffer`. fn set_vertex_buffer( state: &mut State, cmd_buf: &Arc<CommandBuffer>, slot: u32, buffer: Arc<crate::resource::Buffer>, offset: u64, size: Option<BufferSize>, ) -> Result<(), RenderPassErrorInner> { @@ -2394,40 +2391,32 @@ fn set_vertex_buffer( return Err(RenderCommandError::VertexBufferIndexOutOfRange { index: slot, max: max_vertex_buffers, } .into()); } buffer.check_usage(BufferUsages::VERTEX)?; - let buf_raw = buffer.try_raw(state.general.snatch_guard)?; - - //TODO: where are we checking that the offset is in bound? - let buffer_size = match size { - Some(s) => s.get(), - None => buffer.size - offset, - }; + + let (binding, buffer_size) = buffer + .binding(offset, size, state.general.snatch_guard) + .map_err(RenderCommandError::from)?; state.vertex.buffer_sizes[slot as usize] = Some(buffer_size); state.general.buffer_memory_init_actions.extend( buffer.initialization_status.read().create_action( &buffer, offset..(offset + buffer_size), MemoryInitKind::NeedsInitializedMemory, ), ); - let bb = hal::BufferBinding { - buffer: buf_raw, - offset, - size, - }; unsafe { - hal::DynCommandEncoder::set_vertex_buffer(state.general.raw_encoder, slot, bb); + hal::DynCommandEncoder::set_vertex_buffer(state.general.raw_encoder, slot, binding); } if let Some(pipeline) = state.pipeline.as_ref() { state.vertex.update_limits(&pipeline.vertex_steps); } Ok(()) } fn set_blend_constant(state: &mut State, color: &Color) {
--- a/third_party/rust/wgpu-core/src/command/render_command.rs +++ b/third_party/rust/wgpu-core/src/command/render_command.rs @@ -387,16 +387,27 @@ impl RenderCommand { }) }) .collect::<Result<Vec<_>, RenderPassError>>()?; Ok(resolved_commands) } } /// Equivalent to `RenderCommand` with the Ids resolved into resource Arcs. +/// +/// In a render pass, commands are stored in this format between when they are +/// added to the pass, and when the pass is `end()`ed and the commands are +/// replayed to the HAL encoder. Validation occurs when the pass is ended, which +/// means that parameters stored in an `ArcRenderCommand` for a pass operation +/// have generally not been validated. +/// +/// In a render bundle, commands are stored in this format between when the bundle +/// is `finish()`ed and when the bundle is executed. Validation occurs when the +/// bundle is finished, which means that parameters stored in an `ArcRenderCommand` +/// for a render bundle operation must have been validated. #[doc(hidden)] #[derive(Clone, Debug)] pub enum ArcRenderCommand { SetBindGroup { index: u32, num_dynamic_offsets: usize, bind_group: Option<Arc<BindGroup>>, },
--- a/third_party/rust/wgpu-core/src/command/transfer.rs +++ b/third_party/rust/wgpu-core/src/command/transfer.rs @@ -1,33 +1,34 @@ use alloc::{sync::Arc, vec::Vec}; use arrayvec::ArrayVec; use thiserror::Error; use wgt::{ error::{ErrorType, WebGpuError}, - BufferAddress, BufferUsages, Extent3d, TextureSelector, TextureUsages, + BufferAddress, BufferTextureCopyInfoError, BufferUsages, Extent3d, TextureSelector, + TextureUsages, }; #[cfg(feature = "trace")] use crate::device::trace::Command as TraceCommand; use crate::{ api_log, command::{clear_texture, CommandEncoderError, EncoderStateError}, conv, device::{Device, MissingDownlevelFlags}, global::Global, id::{BufferId, CommandEncoderId, TextureId}, init_tracker::{ has_copy_partial_init_tracker_coverage, MemoryInitKind, TextureInitRange, TextureInitTrackerAction, }, resource::{ - MissingBufferUsageError, MissingTextureUsageError, ParentDevice, Texture, - TextureErrorDimension, + MissingBufferUsageError, MissingTextureUsageError, ParentDevice, RawResourceAccess, + Texture, TextureErrorDimension, }, snatch::SnatchGuard, }; use super::{ClearError, CommandBufferMutable}; pub type TexelCopyBufferInfo = wgt::TexelCopyBufferInfo<BufferId>; pub type TexelCopyTextureInfo = wgt::TexelCopyTextureInfo<TextureId>; @@ -90,16 +91,18 @@ pub enum TransferError { #[error("Number of bytes per row needs to be specified since more than one row is copied")] UnspecifiedBytesPerRow, #[error("Number of rows per image needs to be specified since more than one image is copied")] UnspecifiedRowsPerImage, #[error("Number of bytes per row is less than the number of bytes in a complete row")] InvalidBytesPerRow, #[error("Number of rows per image is invalid")] InvalidRowsPerImage, + #[error("Overflow while computing the size of the copy")] + SizeOverflow, #[error("Copy source aspects must refer to all aspects of the source texture format")] CopySrcMissingAspects, #[error( "Copy destination aspects must refer to all aspects of the destination texture format" )] CopyDstMissingAspects, #[error("Copy aspect must refer to a single aspect of texture format")] CopyAspectNotOne, @@ -159,16 +162,17 @@ impl WebGpuError for TransferError { | Self::UnalignedCopyHeight | Self::UnalignedCopyOriginX | Self::UnalignedCopyOriginY | Self::UnalignedBytesPerRow | Self::UnspecifiedBytesPerRow | Self::UnspecifiedRowsPerImage | Self::InvalidBytesPerRow | Self::InvalidRowsPerImage + | Self::SizeOverflow | Self::CopySrcMissingAspects | Self::CopyDstMissingAspects | Self::CopyAspectNotOne | Self::CopyFromForbiddenTextureFormat { .. } | Self::CopyToForbiddenTextureFormat { .. } | Self::ExternalCopyToForbiddenTextureFormat(..) | Self::TextureFormatsNotCopyCompatible { .. } | Self::MissingDownlevelFlags(..) @@ -176,16 +180,28 @@ impl WebGpuError for TransferError { | Self::SampleCountNotEqual { .. } | Self::InvalidMipLevel { .. } | Self::SameSourceDestinationBuffer => return ErrorType::Validation, }; e.webgpu_error_type() } } +impl From<BufferTextureCopyInfoError> for TransferError { + fn from(value: BufferTextureCopyInfoError) -> Self { + match value { + BufferTextureCopyInfoError::InvalidBytesPerRow => Self::InvalidBytesPerRow, + BufferTextureCopyInfoError::InvalidRowsPerImage => Self::InvalidRowsPerImage, + BufferTextureCopyInfoError::ImageStrideOverflow + | BufferTextureCopyInfoError::ImageBytesOverflow(_) + | BufferTextureCopyInfoError::ArraySizeOverflow(_) => Self::SizeOverflow, + } + } +} + pub(crate) fn extract_texture_selector<T>( copy_texture: &wgt::TexelCopyTextureInfo<T>, copy_size: &Extent3d, texture: &Texture, ) -> Result<(TextureSelector, hal::TextureCopyBase), TransferError> { let format = texture.desc.format; let copy_aspect = hal::FormatAspects::new(format, copy_texture.aspect); if copy_aspect.is_empty() { @@ -249,53 +265,47 @@ pub(crate) fn validate_linear_texture_da block_size_bytes, block_width_texels, block_height_texels, width_blocks: _, height_blocks, - row_bytes_dense, + row_bytes_dense: _, row_stride_bytes, image_stride_rows: _, image_stride_bytes, image_rows_dense: _, image_bytes_dense: _, bytes_in_copy, - } = layout.get_buffer_texture_copy_info(format, aspect, copy_size); + } = layout.get_buffer_texture_copy_info(format, aspect, copy_size)?; if copy_width % block_width_texels != 0 { return Err(TransferError::UnalignedCopyWidth); } if copy_height % block_height_texels != 0 { return Err(TransferError::UnalignedCopyHeight); } let requires_multiple_rows = depth_or_array_layers > 1 || height_blocks > 1; let requires_multiple_images = depth_or_array_layers > 1; - if let Some(raw_bytes_per_row) = layout.bytes_per_row { - let raw_bytes_per_row = raw_bytes_per_row as BufferAddress; - if raw_bytes_per_row < row_bytes_dense { - return Err(TransferError::InvalidBytesPerRow); - } - } else if requires_multiple_rows { + // `get_buffer_texture_copy_info()` already proceeded with defaults if these + // were not specified, and ensured that the values satisfy the minima if + // they were, but now we enforce the WebGPU requirement that they be + // specified any time they apply. + if layout.bytes_per_row.is_none() && requires_multiple_rows { return Err(TransferError::UnspecifiedBytesPerRow); } - if let Some(raw_rows_per_image) = layout.rows_per_image { - let raw_rows_per_image = raw_rows_per_image as BufferAddress; - if raw_rows_per_image < height_blocks { - return Err(TransferError::InvalidRowsPerImage); - } - } else if requires_multiple_images { + if layout.rows_per_image.is_none() && requires_multiple_images { return Err(TransferError::UnspecifiedRowsPerImage); }; if need_copy_aligned_rows { let bytes_per_row_alignment = wgt::COPY_BYTES_PER_ROW_ALIGNMENT as BufferAddress; let mut offset_alignment = block_size_bytes; if format.is_depth_stencil_format() {
--- a/third_party/rust/wgpu-core/src/device/global.rs +++ b/third_party/rust/wgpu-core/src/device/global.rs @@ -202,16 +202,18 @@ impl Global { #[cfg(feature = "replay")] pub fn device_set_buffer_data( &self, buffer_id: id::BufferId, offset: BufferAddress, data: &[u8], ) -> BufferAccessResult { + use crate::resource::RawResourceAccess; + let hub = &self.hub; let buffer = hub.buffers.get(buffer_id).get()?; let device = &buffer.device; device.check_is_valid()?; buffer.check_usage(wgt::BufferUsages::MAP_WRITE)?; @@ -378,16 +380,17 @@ impl Global { (id, Some(error)) } /// # Safety /// /// - `hal_buffer` must be created from `device_id` corresponding raw handle. /// - `hal_buffer` must be created respecting `desc` /// - `hal_buffer` must be initialized + /// - `hal_buffer` must not have zero size. pub unsafe fn create_buffer_from_hal<A: HalApi>( &self, hal_buffer: A::Buffer, device_id: DeviceId, desc: &resource::BufferDescriptor, id_in: Option<id::BufferId>, ) -> (id::BufferId, Option<CreateBufferError>) { profiling::scope!("Device::create_buffer"); @@ -399,17 +402,17 @@ impl Global { // NB: Any change done through the raw buffer handle will not be // recorded in the replay #[cfg(feature = "trace")] if let Some(trace) = device.trace.lock().as_mut() { trace.add(trace::Action::CreateBuffer(fid.id(), desc.clone())); } - let (buffer, err) = device.create_buffer_from_hal(Box::new(hal_buffer), desc); + let (buffer, err) = unsafe { device.create_buffer_from_hal(Box::new(hal_buffer), desc) }; let id = fid.assign(buffer); api_log!("Device::create_buffer -> {id:?}"); (id, err) } pub fn texture_destroy(&self, texture_id: id::TextureId) {
--- a/third_party/rust/wgpu-core/src/device/mod.rs +++ b/third_party/rust/wgpu-core/src/device/mod.rs @@ -3,17 +3,17 @@ use core::{fmt, num::NonZeroU32}; use crate::{ binding_model, hub::Hub, id::{BindGroupLayoutId, PipelineLayoutId}, ray_tracing::BlasCompactReadyPendingClosure, resource::{ Buffer, BufferAccessError, BufferAccessResult, BufferMapOperation, Labeled, - ResourceErrorIdent, + RawResourceAccess, ResourceErrorIdent, }, snatch::SnatchGuard, Label, DOWNLEVEL_ERROR_MESSAGE, }; use arrayvec::ArrayVec; use smallvec::SmallVec; use thiserror::Error;
--- a/third_party/rust/wgpu-core/src/device/queue.rs +++ b/third_party/rust/wgpu-core/src/device/queue.rs @@ -9,17 +9,16 @@ use core::{ use smallvec::SmallVec; use thiserror::Error; use wgt::{ error::{ErrorType, WebGpuError}, AccelerationStructureFlags, }; use super::{life::LifetimeTracker, Device}; -use crate::device::resource::CommandIndices; #[cfg(feature = "trace")] use crate::device::trace::Action; use crate::{ api_log, command::{ extract_texture_selector, validate_linear_texture_data, validate_texture_copy_range, ClearError, CommandAllocator, CommandBuffer, CommandEncoderError, CopySide, TexelCopyTextureInfo, TransferError, @@ -28,27 +27,28 @@ use crate::{ device::{DeviceError, WaitIdleError}, get_lowest_common_denom, global::Global, id::{self, BlasId, QueueId}, init_tracker::{has_copy_partial_init_tracker_coverage, TextureInitRange}, lock::{rank, Mutex, MutexGuard, RwLock, RwLockWriteGuard}, ray_tracing::{BlasCompactReadyPendingClosure, CompactBlasError}, resource::{ - AccelerationStructure, Blas, BlasCompactState, Buffer, BufferAccessError, BufferMapState, - DestroyedBuffer, DestroyedResourceError, DestroyedTexture, Fallible, FlushedStagingBuffer, + Blas, BlasCompactState, Buffer, BufferAccessError, BufferMapState, DestroyedBuffer, + DestroyedResourceError, DestroyedTexture, Fallible, FlushedStagingBuffer, InvalidResourceError, Labeled, ParentDevice, ResourceErrorIdent, StagingBuffer, Texture, TextureInner, Trackable, TrackingData, }, resource_log, scratch::ScratchBuffer, snatch::{SnatchGuard, Snatchable}, track::{self, Tracker, TrackerIndex}, FastHashMap, SubmissionIndex, }; +use crate::{device::resource::CommandIndices, resource::RawResourceAccess}; pub struct Queue { raw: Box<dyn hal::DynQueue>, pub(crate) pending_writes: Mutex<PendingWrites>, life_tracker: Mutex<LifetimeTracker>, // The device needs to be dropped last (`Device.zero_buffer` might be referenced by the encoder in pending writes). pub(crate) device: Arc<Device>, }
--- a/third_party/rust/wgpu-core/src/device/resource.rs +++ b/third_party/rust/wgpu-core/src/device/resource.rs @@ -6,16 +6,17 @@ use alloc::{ vec::Vec, }; use core::{ fmt, mem::{self, ManuallyDrop}, num::NonZeroU32, sync::atomic::{AtomicBool, Ordering}, }; +use hal::ShouldBeNonZeroExt; use arrayvec::ArrayVec; use bitflags::Flags; use smallvec::SmallVec; use wgt::{ math::align_to, DeviceLostReason, TextureFormat, TextureSampleType, TextureSelector, TextureViewDimension, }; @@ -35,17 +36,17 @@ use crate::{ BufferInitTracker, BufferInitTrackerAction, MemoryInitKind, TextureInitRange, TextureInitTrackerAction, }, instance::{Adapter, RequestDeviceError}, lock::{rank, Mutex, RwLock}, pipeline, pool::ResourcePool, resource::{ - self, AccelerationStructure, Buffer, Fallible, Labeled, ParentDevice, QuerySet, Sampler, + self, Buffer, Fallible, Labeled, ParentDevice, QuerySet, RawResourceAccess, Sampler, StagingBuffer, Texture, TextureView, TextureViewNotRenderableReason, Tlas, TrackingData, }, resource_log, snatch::{SnatchGuard, SnatchLock, Snatchable}, timestamp_normalization::TIMESTAMP_NORMALIZATION_BUFFER_USES, track::{BindGroupStates, DeviceTracker, TrackerIndexAllocators, UsageScope, UsageScopePool}, validation::{self, validate_color_attachment_bytes_per_sample}, weak_vec::WeakVec, @@ -697,28 +698,29 @@ impl Device { label: desc.label.to_hal(self.instance_flags), size: aligned_size, usage, memory_flags: hal::MemoryFlags::empty(), }; let buffer = unsafe { self.raw().create_buffer(&hal_desc) } .map_err(|e| self.handle_hal_error_with_nonfatal_oom(e))?; - let timestamp_normalization_bind_group = Snatchable::new( + let timestamp_normalization_bind_group = Snatchable::new(unsafe { + // SAFETY: The size passed here must not overflow the buffer. self.timestamp_normalizer .get() .unwrap() .create_normalization_bind_group( self, &*buffer, desc.label.as_deref(), - desc.size, + wgt::BufferSize::new(hal_desc.size).unwrap(), desc.usage, - )?, - ); + ) + }?); let indirect_validation_bind_groups = self.create_indirect_validation_bind_groups(buffer.as_ref(), desc.size, desc.usage)?; let buffer = Buffer { raw: Snatchable::new(buffer), device: self.clone(), usage: desc.usage, @@ -804,38 +806,46 @@ impl Device { self.trackers .lock() .textures .insert_single(&texture, wgt::TextureUses::UNINITIALIZED); Ok(texture) } - pub(crate) fn create_buffer_from_hal( + /// # Safety + /// + /// - `hal_buffer` must have been created on this device. + /// - `hal_buffer` must have been created respecting `desc` (in particular, the size). + /// - `hal_buffer` must be initialized. + /// - `hal_buffer` must not have zero size. + pub(crate) unsafe fn create_buffer_from_hal( self: &Arc<Self>, hal_buffer: Box<dyn hal::DynBuffer>, desc: &resource::BufferDescriptor, ) -> (Fallible<Buffer>, Option<resource::CreateBufferError>) { - let timestamp_normalization_bind_group = match self - .timestamp_normalizer - .get() - .unwrap() - .create_normalization_bind_group( - self, - &*hal_buffer, - desc.label.as_deref(), - desc.size, - desc.usage, - ) { - Ok(bg) => Snatchable::new(bg), - Err(e) => { - return ( - Fallible::Invalid(Arc::new(desc.label.to_string())), - Some(e.into()), - ) + let timestamp_normalization_bind_group = unsafe { + match self + .timestamp_normalizer + .get() + .unwrap() + .create_normalization_bind_group( + self, + &*hal_buffer, + desc.label.as_deref(), + wgt::BufferSize::new(desc.size).unwrap(), + desc.usage, + ) { + Ok(bg) => Snatchable::new(bg), + Err(e) => { + return ( + Fallible::Invalid(Arc::new(desc.label.to_string())), + Some(e.into()), + ) + } } }; let indirect_validation_bind_groups = match self.create_indirect_validation_bind_groups( hal_buffer.as_ref(), desc.size, desc.usage, ) { @@ -2182,41 +2192,19 @@ impl Device { let buffer = &bb.buffer; used.buffers.insert_single(buffer.clone(), internal_use); buffer.same_device(self)?; buffer.check_usage(pub_usage)?; - let raw_buffer = buffer.try_raw(snatch_guard)?; - - let (bind_size, bind_end) = match bb.size { - Some(size) => { - let end = bb.offset + size.get(); - if end > buffer.size { - return Err(Error::BindingRangeTooLarge { - buffer: buffer.error_ident(), - range: bb.offset..end, - size: buffer.size, - }); - } - (size.get(), end) - } - None => { - if buffer.size < bb.offset { - return Err(Error::BindingRangeTooLarge { - buffer: buffer.error_ident(), - range: bb.offset..bb.offset, - size: buffer.size, - }); - } - (buffer.size - bb.offset, buffer.size) - } - }; + + let (bb, bind_size) = buffer.binding(bb.offset, bb.size, snatch_guard)?; + let bind_end = bb.offset + bind_size; if bind_size > range_limit as u64 { return Err(Error::BufferRangeTooLarge { binding, given: bind_size as u32, limit: range_limit, }); } @@ -2260,21 +2248,17 @@ impl Device { let visible_size = align_to(bind_size, bounds_check_alignment); used_buffer_ranges.extend(buffer.initialization_status.read().create_action( buffer, bb.offset..bb.offset + visible_size, MemoryInitKind::NeedsInitializedMemory, )); - Ok(hal::BufferBinding { - buffer: raw_buffer, - offset: bb.offset, - size: bb.size, - }) + Ok(bb) } fn create_sampler_binding<'a>( &self, used: &mut BindGroupStates, binding: u32, decl: &wgt::BindGroupLayoutEntry, sampler: &'a Arc<Sampler>,
--- a/third_party/rust/wgpu-core/src/indirect_validation/dispatch.rs +++ b/third_party/rust/wgpu-core/src/indirect_validation/dispatch.rs @@ -227,21 +227,22 @@ impl Dispatch { let dst_bind_group_desc = hal::BindGroupDescriptor { label: None, layout: dst_bind_group_layout.as_ref(), entries: &[hal::BindGroupEntry { binding: 0, resource_index: 0, count: 1, }], - buffers: &[hal::BufferBinding { - buffer: dst_buffer.as_ref(), - offset: 0, - size: Some(DST_BUFFER_SIZE), - }], + // SAFETY: We just created the buffer with this size. + buffers: &[hal::BufferBinding::new_unchecked( + dst_buffer.as_ref(), + 0, + Some(DST_BUFFER_SIZE), + )], samplers: &[], textures: &[], acceleration_structures: &[], }; let dst_bind_group = unsafe { device .create_bind_group(&dst_bind_group_desc) .map_err(DeviceError::from_hal) @@ -273,21 +274,18 @@ impl Dispatch { let hal_desc = hal::BindGroupDescriptor { label: None, layout: self.src_bind_group_layout.as_ref(), entries: &[hal::BindGroupEntry { binding: 0, resource_index: 0, count: 1, }], - buffers: &[hal::BufferBinding { - buffer, - offset: 0, - size: Some(binding_size), - }], + // SAFETY: We calculated the binding size to fit within the buffer. + buffers: &[hal::BufferBinding::new_unchecked(buffer, 0, binding_size)], samplers: &[], textures: &[], acceleration_structures: &[], }; unsafe { device .create_bind_group(&hal_desc) .map(Some)
--- a/third_party/rust/wgpu-core/src/indirect_validation/draw.rs +++ b/third_party/rust/wgpu-core/src/indirect_validation/draw.rs @@ -130,21 +130,18 @@ impl Draw { let hal_desc = hal::BindGroupDescriptor { label: None, layout: self.src_bind_group_layout.as_ref(), entries: &[hal::BindGroupEntry { binding: 0, resource_index: 0, count: 1, }], - buffers: &[hal::BufferBinding { - buffer, - offset: 0, - size: Some(binding_size), - }], + // SAFETY: We calculated the binding size to fit within the buffer. + buffers: &[hal::BufferBinding::new_unchecked(buffer, 0, binding_size)], samplers: &[], textures: &[], acceleration_structures: &[], }; unsafe { device .create_bind_group(&hal_desc) .map(Some) @@ -679,21 +676,22 @@ fn create_buffer_and_bind_group( let bind_group_desc = hal::BindGroupDescriptor { label: None, layout: bind_group_layout, entries: &[hal::BindGroupEntry { binding: 0, resource_index: 0, count: 1, }], - buffers: &[hal::BufferBinding { - buffer: buffer.as_ref(), - offset: 0, - size: Some(BUFFER_SIZE), - }], + // SAFETY: We just created the buffer with this size. + buffers: &[hal::BufferBinding::new_unchecked( + buffer.as_ref(), + 0, + BUFFER_SIZE, + )], samplers: &[], textures: &[], acceleration_structures: &[], }; let bind_group = unsafe { device.create_bind_group(&bind_group_desc) }?; Ok(BufferPoolEntry { buffer, bind_group }) }
--- a/third_party/rust/wgpu-core/src/lib.rs +++ b/third_party/rust/wgpu-core/src/lib.rs @@ -60,16 +60,17 @@ #![cfg_attr(not(send_sync), allow(clippy::arc_with_non_send_sync))] extern crate alloc; #[cfg(feature = "std")] extern crate std; extern crate wgpu_hal as hal; extern crate wgpu_types as wgt; +mod as_hal; pub mod binding_model; pub mod command; mod conv; pub mod device; pub mod error; pub mod global; pub mod hal_api; mod hash_utils;
--- a/third_party/rust/wgpu-core/src/lock/mod.rs +++ b/third_party/rust/wgpu-core/src/lock/mod.rs @@ -47,9 +47,9 @@ mod vanilla; use ranked as chosen; #[cfg(feature = "observe_locks")] use observing as chosen; #[cfg(not(any(wgpu_validate_locks, feature = "observe_locks")))] use vanilla as chosen; -pub use chosen::{Mutex, MutexGuard, RwLock, RwLockReadGuard, RwLockWriteGuard}; +pub use chosen::{Mutex, MutexGuard, RankData, RwLock, RwLockReadGuard, RwLockWriteGuard};
--- a/third_party/rust/wgpu-core/src/lock/observing.rs +++ b/third_party/rust/wgpu-core/src/lock/observing.rs @@ -33,16 +33,18 @@ use core::{cell::RefCell, panic::Locatio use std::{ fs::File, path::{Path, PathBuf}, }; use super::rank::{LockRank, LockRankSet}; use crate::FastHashSet; +pub type RankData = Option<HeldLock>; + /// A `Mutex` instrumented for lock acquisition order observation. /// /// This is just a wrapper around a [`parking_lot::Mutex`], along with /// its rank in the `wgpu_core` lock ordering. /// /// For details, see [the module documentation][self]. pub struct Mutex<T> { inner: parking_lot::Mutex<T>, @@ -155,16 +157,37 @@ impl<T> RwLock<T> { #[track_caller] pub fn write(&self) -> RwLockWriteGuard<T> { let saved = acquire(self.rank, Location::caller()); RwLockWriteGuard { inner: self.inner.write(), _state: LockStateGuard { saved }, } } + + /// Force an read-unlock operation on this lock. + /// + /// Safety: + /// - A read lock must be held which is not held by a guard. + pub unsafe fn force_unlock_read(&self, data: RankData) { + release(data); + unsafe { self.inner.force_unlock_read() }; + } +} + +impl<'a, T> RwLockReadGuard<'a, T> { + // Forget the read guard, leaving the lock in a locked state with no guard. + // + // Equivalent to std::mem::forget, but preserves the information about the lock + // rank. + pub fn forget(this: Self) -> RankData { + core::mem::forget(this.inner); + + this._state.saved + } } impl<'a, T> RwLockWriteGuard<'a, T> { pub fn downgrade(this: Self) -> RwLockReadGuard<'a, T> { RwLockReadGuard { inner: parking_lot::RwLockWriteGuard::downgrade(this.inner), _state: this._state, } @@ -311,17 +334,17 @@ enum ThreadState { Enabled { held_lock: Option<HeldLock>, log: ObservationLog, }, } /// Information about a currently held lock. #[derive(Debug, Copy, Clone)] -struct HeldLock { +pub struct HeldLock { /// The lock's rank. rank: LockRank, /// Where we acquired the lock. location: &'static Location<'static>, } /// A log to which we can write observations of lock activity.
--- a/third_party/rust/wgpu-core/src/lock/ranked.rs +++ b/third_party/rust/wgpu-core/src/lock/ranked.rs @@ -54,16 +54,18 @@ //! dependent on any particular interleaving of execution. //! //! [`lock::rank`]: crate::lock::rank use core::{cell::Cell, fmt, ops, panic::Location}; use super::rank::LockRank; +pub use LockState as RankData; + /// A `Mutex` instrumented for deadlock prevention. /// /// This is just a wrapper around a [`parking_lot::Mutex`], along with /// its rank in the `wgpu_core` lock ordering. /// /// For details, see [the module documentation][self]. pub struct Mutex<T> { inner: parking_lot::Mutex<T>, @@ -82,17 +84,17 @@ pub struct MutexGuard<'a, T> { } std::thread_local! { static LOCK_STATE: Cell<LockState> = const { Cell::new(LockState::INITIAL) }; } /// Per-thread state for the deadlock checker. #[derive(Debug, Copy, Clone)] -struct LockState { +pub struct LockState { /// The last lock we acquired, and where. last_acquired: Option<(LockRank, &'static Location<'static>)>, /// The number of locks currently held. /// /// This is used to enforce stack-like lock acquisition and release. depth: u32, } @@ -265,16 +267,37 @@ impl<T> RwLock<T> { #[track_caller] pub fn write(&self) -> RwLockWriteGuard<T> { let saved = acquire(self.rank, Location::caller()); RwLockWriteGuard { inner: self.inner.write(), saved: LockStateGuard(saved), } } + + /// Force an read-unlock operation on this lock. + /// + /// Safety: + /// - A read lock must be held which is not held by a guard. + pub unsafe fn force_unlock_read(&self, data: RankData) { + release(data); + unsafe { self.inner.force_unlock_read() }; + } +} + +impl<'a, T> RwLockReadGuard<'a, T> { + // Forget the read guard, leaving the lock in a locked state with no guard. + // + // Equivalent to std::mem::forget, but preserves the information about the lock + // rank. + pub fn forget(this: Self) -> RankData { + core::mem::forget(this.inner); + + this.saved.0 + } } impl<'a, T> RwLockWriteGuard<'a, T> { pub fn downgrade(this: Self) -> RwLockReadGuard<'a, T> { RwLockReadGuard { inner: parking_lot::RwLockWriteGuard::downgrade(this.inner), saved: this.saved, }
--- a/third_party/rust/wgpu-core/src/lock/vanilla.rs +++ b/third_party/rust/wgpu-core/src/lock/vanilla.rs @@ -1,15 +1,19 @@ //! Plain, uninstrumented wrappers around [`parking_lot`] lock types. //! //! These definitions are used when no particular lock instrumentation //! Cargo feature is selected. use core::{fmt, ops}; +use crate::lock::rank::LockRank; + +pub struct RankData; + /// A plain wrapper around [`parking_lot::Mutex`]. /// /// This is just like [`parking_lot::Mutex`], except that our [`new`] /// method takes a rank, indicating where the new mutex should sit in /// `wgpu-core`'s lock ordering. The rank is ignored. /// /// See the [`lock`] module documentation for other wrappers. /// @@ -18,17 +22,17 @@ use core::{fmt, ops}; pub struct Mutex<T>(parking_lot::Mutex<T>); /// A guard produced by locking [`Mutex`]. /// /// This is just a wrapper around a [`parking_lot::MutexGuard`]. pub struct MutexGuard<'a, T>(parking_lot::MutexGuard<'a, T>); impl<T> Mutex<T> { - pub fn new(_rank: super::rank::LockRank, value: T) -> Mutex<T> { + pub fn new(_rank: LockRank, value: T) -> Mutex<T> { Mutex(parking_lot::Mutex::new(value)) } pub fn lock(&self) -> MutexGuard<T> { MutexGuard(self.0.lock()) } pub fn into_inner(self) -> T { @@ -74,27 +78,47 @@ pub struct RwLock<T>(parking_lot::RwLock pub struct RwLockReadGuard<'a, T>(parking_lot::RwLockReadGuard<'a, T>); /// A write guard produced by locking [`RwLock`] as a writer. /// /// This is just a wrapper around a [`parking_lot::RwLockWriteGuard`]. pub struct RwLockWriteGuard<'a, T>(parking_lot::RwLockWriteGuard<'a, T>); impl<T> RwLock<T> { - pub fn new(_rank: super::rank::LockRank, value: T) -> RwLock<T> { + pub fn new(_rank: LockRank, value: T) -> RwLock<T> { RwLock(parking_lot::RwLock::new(value)) } pub fn read(&self) -> RwLockReadGuard<T> { RwLockReadGuard(self.0.read()) } pub fn write(&self) -> RwLockWriteGuard<T> { RwLockWriteGuard(self.0.write()) } + + /// Force an read-unlock operation on this lock. + /// + /// Safety: + /// - A read lock must be held which is not held by a guard. + pub unsafe fn force_unlock_read(&self, _data: RankData) { + unsafe { self.0.force_unlock_read() }; + } +} + +impl<'a, T> RwLockReadGuard<'a, T> { + // Forget the read guard, leaving the lock in a locked state with no guard. + // + // Equivalent to std::mem::forget, but preserves the information about the lock + // rank. + pub fn forget(this: Self) -> RankData { + core::mem::forget(this.0); + + RankData + } } impl<'a, T> RwLockWriteGuard<'a, T> { pub fn downgrade(this: Self) -> RwLockReadGuard<'a, T> { RwLockReadGuard(parking_lot::RwLockWriteGuard::downgrade(this.0)) } }
--- a/third_party/rust/wgpu-core/src/pipeline.rs +++ b/third_party/rust/wgpu-core/src/pipeline.rs @@ -366,16 +366,27 @@ pub struct VertexBufferLayout<'a> { /// The stride, in bytes, between elements of this buffer. pub array_stride: wgt::BufferAddress, /// How often this vertex buffer is "stepped" forward. pub step_mode: wgt::VertexStepMode, /// The list of attributes which comprise a single vertex. pub attributes: Cow<'a, [wgt::VertexAttribute]>, } +/// A null vertex buffer layout that may be placed in unused slots. +impl Default for VertexBufferLayout<'_> { + fn default() -> Self { + Self { + array_stride: Default::default(), + step_mode: Default::default(), + attributes: Cow::Borrowed(&[]), + } + } +} + /// Describes the vertex process in a render pipeline. #[derive(Clone, Debug)] #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub struct VertexState<'a, SM = ShaderModuleId> { /// The compiled vertex stage and its entry point. pub stage: ProgrammableStageDescriptor<'a, SM>, /// The format of any vertex buffers used with this pipeline. pub buffers: Cow<'a, [VertexBufferLayout<'a>]>,
--- a/third_party/rust/wgpu-core/src/resource.rs +++ b/third_party/rust/wgpu-core/src/resource.rs @@ -12,40 +12,32 @@ use thiserror::Error; use wgt::{ error::{ErrorType, WebGpuError}, TextureSelector, }; #[cfg(feature = "trace")] use crate::device::trace; use crate::{ - binding_model::BindGroup, + binding_model::{BindGroup, BindingError}, device::{ queue, resource::DeferredDestroy, BufferMapPendingClosure, Device, DeviceError, DeviceMismatch, HostMap, MissingDownlevelFlags, MissingFeatures, }, - global::Global, - hal_api::HalApi, - id::{ - AdapterId, BufferId, CommandEncoderId, DeviceId, QueueId, SurfaceId, TextureId, - TextureViewId, - }, init_tracker::{BufferInitTracker, TextureInitTracker}, lock::{rank, Mutex, RwLock}, ray_tracing::{BlasCompactReadyPendingClosure, BlasPrepareCompactError}, resource_log, snatch::{SnatchGuard, Snatchable}, timestamp_normalization::TimestampNormalizationBindGroup, track::{SharedTrackerIndexAllocator, TrackerIndex}, weak_vec::WeakVec, Label, LabelHelpers, SubmissionIndex, }; -use crate::id::{BlasId, TlasId}; - /// Information about the wgpu-core resource. /// /// Each type representing a `wgpu-core` resource, like [`Device`], /// [`Buffer`], etc., contains a `ResourceInfo` which contains /// its latest submission index and label. /// /// A resource may need to be retained for any of several reasons: /// and any lifetime logic will be handled by `Arc<Resource>` refcount @@ -138,16 +130,39 @@ macro_rules! impl_parent_device { impl $crate::resource::ParentDevice for $ty { fn device(&self) -> &Arc<Device> { &self.device } } }; } +/// Allow access to the hal resource as guarded by the `SnatchGuard`. +pub trait RawResourceAccess: ParentDevice { + type DynResource: hal::DynResource + ?Sized; + + /// Get access to the raw resource if it is not destroyed. + /// + /// Returns `None` if the resource has been destroyed. This method + /// does not allocate in either case. + fn raw<'a>(&'a self, guard: &'a SnatchGuard) -> Option<&'a Self::DynResource>; + + /// Get access to the raw resource if it is not destroyed. + /// + /// Returns a full error if the resource has been destroyed. This + /// method allocates a label in the error case. + fn try_raw<'a>( + &'a self, + guard: &'a SnatchGuard, + ) -> Result<&'a Self::DynResource, DestroyedResourceError> { + self.raw(guard) + .ok_or_else(|| DestroyedResourceError(self.error_ident())) + } +} + pub trait ResourceType { const TYPE: &'static str; } #[macro_export] macro_rules! impl_resource_type { ($ty:ident) => { impl $crate::resource::ResourceType for $ty { @@ -438,31 +453,25 @@ impl Drop for Buffer { resource_log!("Destroy raw {}", self.error_ident()); unsafe { self.device.raw().destroy_buffer(raw); } } } } -impl Buffer { - pub(crate) fn raw<'a>(&'a self, guard: &'a SnatchGuard) -> Option<&'a dyn hal::DynBuffer> { +impl RawResourceAccess for Buffer { + type DynResource = dyn hal::DynBuffer; + + fn raw<'a>(&'a self, guard: &'a SnatchGuard) -> Option<&'a Self::DynResource> { self.raw.get(guard).map(|b| b.as_ref()) } +} - pub(crate) fn try_raw<'a>( - &'a self, - guard: &'a SnatchGuard, - ) -> Result<&'a dyn hal::DynBuffer, DestroyedResourceError> { - self.raw - .get(guard) - .map(|raw| raw.as_ref()) - .ok_or_else(|| DestroyedResourceError(self.error_ident())) - } - +impl Buffer { pub(crate) fn check_destroyed( &self, guard: &SnatchGuard, ) -> Result<(), DestroyedResourceError> { self.raw .get(guard) .map(|_| ()) .ok_or_else(|| DestroyedResourceError(self.error_ident())) @@ -480,16 +489,92 @@ impl Buffer { Err(MissingBufferUsageError { res: self.error_ident(), actual: self.usage, expected, }) } } + /// Resolve the size of a binding for buffer with `offset` and `size`. + /// + /// If `size` is `None`, then the remainder of the buffer starting from + /// `offset` is used. + /// + /// If the binding would overflow the buffer, then an error is returned. + /// + /// Zero-size bindings are permitted here for historical reasons. Although + /// zero-size bindings are permitted by WebGPU, they are not permitted by + /// some backends. See [`Buffer::binding`] and + /// [#3170](https://github.com/gfx-rs/wgpu/issues/3170). + pub fn resolve_binding_size( + &self, + offset: wgt::BufferAddress, + binding_size: Option<wgt::BufferSize>, + ) -> Result<u64, BindingError> { + let buffer_size = self.size; + + match binding_size { + Some(binding_size) => match offset.checked_add(binding_size.get()) { + Some(end) if end <= buffer_size => Ok(binding_size.get()), + _ => Err(BindingError::BindingRangeTooLarge { + buffer: self.error_ident(), + offset, + binding_size: binding_size.get(), + buffer_size, + }), + }, + None => { + buffer_size + .checked_sub(offset) + .ok_or_else(|| BindingError::BindingOffsetTooLarge { + buffer: self.error_ident(), + offset, + buffer_size, + }) + } + } + } + + /// Create a new [`hal::BufferBinding`] for the buffer with `offset` and + /// `binding_size`. + /// + /// If `binding_size` is `None`, then the remainder of the buffer starting + /// from `offset` is used. + /// + /// If the binding would overflow the buffer, then an error is returned. + /// + /// A zero-size binding at the end of the buffer is permitted here for historical reasons. Although + /// zero-size bindings are permitted by WebGPU, they are not permitted by + /// some backends. The zero-size binding need to be quashed or remapped to a + /// non-zero size, either universally in wgpu-core, or in specific backends + /// that do not support them. See + /// [#3170](https://github.com/gfx-rs/wgpu/issues/3170). + /// + /// Although it seems like it would be simpler and safer to use the resolved + /// size in the returned [`hal::BufferBinding`], doing this (and removing + /// redundant logic in backends to resolve the implicit size) was observed + /// to cause problems in certain CTS tests, so an implicit size + /// specification is preserved in the output. + pub fn binding<'a>( + &'a self, + offset: wgt::BufferAddress, + binding_size: Option<wgt::BufferSize>, + snatch_guard: &'a SnatchGuard, + ) -> Result<(hal::BufferBinding<'a, dyn hal::DynBuffer>, u64), BindingError> { + let buf_raw = self.try_raw(snatch_guard)?; + let resolved_size = self.resolve_binding_size(offset, binding_size)?; + // SAFETY: The offset and size passed to hal::BufferBinding::new_unchecked must + // define a binding contained within the buffer. + Ok(( + hal::BufferBinding::new_unchecked(buf_raw, offset, binding_size), + resolved_size, + )) + } + /// Returns the mapping callback in case of error so that the callback can be fired outside /// of the locks that are held in this function. pub(crate) fn map_async( self: &Arc<Self>, offset: wgt::BufferAddress, size: Option<wgt::BufferAddress>, op: BufferMapOperation, ) -> Result<SubmissionIndex, (BufferMapOperation, BufferAccessError)> { @@ -642,33 +727,33 @@ impl Buffer { Ok(()) }; Some((pending_mapping.op, status)) } // Note: This must not be called while holding a lock. pub(crate) fn unmap( self: &Arc<Self>, - #[cfg(feature = "trace")] buffer_id: BufferId, + #[cfg(feature = "trace")] buffer_id: crate::id::BufferId, ) -> Result<(), BufferAccessError> { if let Some((mut operation, status)) = self.unmap_inner( #[cfg(feature = "trace")] buffer_id, )? { if let Some(callback) = operation.callback.take() { callback(status); } } Ok(()) } fn unmap_inner( self: &Arc<Self>, - #[cfg(feature = "trace")] buffer_id: BufferId, + #[cfg(feature = "trace")] buffer_id: crate::id::BufferId, ) -> Result<Option<BufferMapPendingClosure>, BufferAccessError> { let device = &self.device; let snatch_guard = device.snatchable_lock.read(); let raw_buf = self.try_raw(&snatch_guard)?; match mem::replace(&mut *self.map_state.lock(), BufferMapState::Idle) { BufferMapState::Init { staging_buffer } => { #[cfg(feature = "trace")] if let Some(ref mut trace) = *device.trace.lock() { @@ -910,19 +995,19 @@ unsafe impl Sync for StagingBuffer {} /// used with [`queue_write_staging_buffer`]. They are also used internally by /// operations like [`queue_write_texture`] that need to upload data to the GPU, /// but that don't belong to any particular wgpu command buffer. /// /// Used `StagingBuffer`s are accumulated in [`Device::pending_writes`], to be /// freed once their associated operation's queue submission has finished /// execution. /// -/// [`queue_create_staging_buffer`]: Global::queue_create_staging_buffer -/// [`queue_write_staging_buffer`]: Global::queue_write_staging_buffer -/// [`queue_write_texture`]: Global::queue_write_texture +/// [`queue_create_staging_buffer`]: crate::global::Global::queue_create_staging_buffer +/// [`queue_write_staging_buffer`]: crate::global::Global::queue_write_staging_buffer +/// [`queue_write_texture`]: crate::global::Global::queue_write_texture /// [`Device::pending_writes`]: crate::device::Device #[derive(Debug)] pub struct StagingBuffer { raw: Box<dyn hal::DynBuffer>, device: Arc<Device>, pub(crate) size: wgt::BufferSize, is_coherent: bool, ptr: NonNull<u8>, @@ -1185,43 +1270,34 @@ impl Drop for Texture { resource_log!("Destroy raw {}", self.error_ident()); unsafe { self.device.raw().destroy_texture(raw); } } } } +impl RawResourceAccess for Texture { + type DynResource = dyn hal::DynTexture; + + fn raw<'a>(&'a self, guard: &'a SnatchGuard) -> Option<&'a Self::DynResource> { + self.inner.get(guard).map(|t| t.raw()) + } +} + impl Texture { pub(crate) fn try_inner<'a>( &'a self, guard: &'a SnatchGuard, ) -> Result<&'a TextureInner, DestroyedResourceError> { self.inner .get(guard) .ok_or_else(|| DestroyedResourceError(self.error_ident())) } - pub(crate) fn raw<'a>( - &'a self, - snatch_guard: &'a SnatchGuard, - ) -> Option<&'a dyn hal::DynTexture> { - Some(self.inner.get(snatch_guard)?.raw()) - } - - pub(crate) fn try_raw<'a>( - &'a self, - guard: &'a SnatchGuard, - ) -> Result<&'a dyn hal::DynTexture, DestroyedResourceError> { - self.inner - .get(guard) - .map(|t| t.raw()) - .ok_or_else(|| DestroyedResourceError(self.error_ident())) - } - pub(crate) fn check_destroyed( &self, guard: &SnatchGuard, ) -> Result<(), DestroyedResourceError> { self.inner .get(guard) .map(|_| ()) .ok_or_else(|| DestroyedResourceError(self.error_ident())) @@ -1301,246 +1377,16 @@ impl Texture { if let Some(last_submit_index) = last_submit_index { life_lock.schedule_resource_destruction(temp, last_submit_index); } } } } } -impl Global { - /// # Safety - /// - /// - The raw buffer handle must not be manually destroyed - pub unsafe fn buffer_as_hal<A: HalApi, F: FnOnce(Option<&A::Buffer>) -> R, R>( - &self, - id: BufferId, - hal_buffer_callback: F, - ) -> R { - profiling::scope!("Buffer::as_hal"); - - let hub = &self.hub; - - if let Ok(buffer) = hub.buffers.get(id).get() { - let snatch_guard = buffer.device.snatchable_lock.read(); - let hal_buffer = buffer - .raw(&snatch_guard) - .and_then(|b| b.as_any().downcast_ref()); - hal_buffer_callback(hal_buffer) - } else { - hal_buffer_callback(None) - } - } - - /// # Safety - /// - /// - The raw texture handle must not be manually destroyed - pub unsafe fn texture_as_hal<A: HalApi, F: FnOnce(Option<&A::Texture>) -> R, R>( - &self, - id: TextureId, - hal_texture_callback: F, - ) -> R { - profiling::scope!("Texture::as_hal"); - - let hub = &self.hub; - - if let Ok(texture) = hub.textures.get(id).get() { - let snatch_guard = texture.device.snatchable_lock.read(); - let hal_texture = texture.raw(&snatch_guard); - let hal_texture = hal_texture - .as_ref() - .and_then(|it| it.as_any().downcast_ref()); - hal_texture_callback(hal_texture) - } else { - hal_texture_callback(None) - } - } - - /// # Safety - /// - /// - The raw texture view handle must not be manually destroyed - pub unsafe fn texture_view_as_hal<A: HalApi, F: FnOnce(Option<&A::TextureView>) -> R, R>( - &self, - id: TextureViewId, - hal_texture_view_callback: F, - ) -> R { - profiling::scope!("TextureView::as_hal"); - - let hub = &self.hub; - - if let Ok(texture_view) = hub.texture_views.get(id).get() { - let snatch_guard = texture_view.device.snatchable_lock.read(); - let hal_texture_view = texture_view.raw(&snatch_guard); - let hal_texture_view = hal_texture_view - .as_ref() - .and_then(|it| it.as_any().downcast_ref()); - hal_texture_view_callback(hal_texture_view) - } else { - hal_texture_view_callback(None) - } - } - - /// # Safety - /// - /// - The raw adapter handle must not be manually destroyed - pub unsafe fn adapter_as_hal<A: HalApi, F: FnOnce(Option<&A::Adapter>) -> R, R>( - &self, - id: AdapterId, - hal_adapter_callback: F, - ) -> R { - profiling::scope!("Adapter::as_hal"); - - let hub = &self.hub; - let adapter = hub.adapters.get(id); - let hal_adapter = adapter.raw.adapter.as_any().downcast_ref(); - - hal_adapter_callback(hal_adapter) - } - - /// # Safety - /// - /// - The raw device handle must not be manually destroyed - pub unsafe fn device_as_hal<A: HalApi, F: FnOnce(Option<&A::Device>) -> R, R>( - &self, - id: DeviceId, - hal_device_callback: F, - ) -> R { - profiling::scope!("Device::as_hal"); - - let device = self.hub.devices.get(id); - let hal_device = device.raw().as_any().downcast_ref(); - - hal_device_callback(hal_device) - } - - /// # Safety - /// - /// - The raw fence handle must not be manually destroyed - pub unsafe fn device_fence_as_hal<A: HalApi, F: FnOnce(Option<&A::Fence>) -> R, R>( - &self, - id: DeviceId, - hal_fence_callback: F, - ) -> R { - profiling::scope!("Device::fence_as_hal"); - - let device = self.hub.devices.get(id); - let fence = device.fence.read(); - hal_fence_callback(fence.as_any().downcast_ref()) - } - - /// # Safety - /// - The raw surface handle must not be manually destroyed - pub unsafe fn surface_as_hal<A: HalApi, F: FnOnce(Option<&A::Surface>) -> R, R>( - &self, - id: SurfaceId, - hal_surface_callback: F, - ) -> R { - profiling::scope!("Surface::as_hal"); - - let surface = self.surfaces.get(id); - let hal_surface = surface - .raw(A::VARIANT) - .and_then(|surface| surface.as_any().downcast_ref()); - - hal_surface_callback(hal_surface) - } - - /// # Safety - /// - /// - The raw command encoder handle must not be manually destroyed - pub unsafe fn command_encoder_as_hal_mut< - A: HalApi, - F: FnOnce(Option<&mut A::CommandEncoder>) -> R, - R, - >( - &self, - id: CommandEncoderId, - hal_command_encoder_callback: F, - ) -> R { - profiling::scope!("CommandEncoder::as_hal"); - - let hub = &self.hub; - - let cmd_buf = hub.command_buffers.get(id.into_command_buffer_id()); - let mut cmd_buf_data = cmd_buf.data.lock(); - cmd_buf_data.record_as_hal_mut(|opt_cmd_buf| -> R { - hal_command_encoder_callback(opt_cmd_buf.and_then(|cmd_buf| { - cmd_buf - .encoder - .open() - .ok() - .and_then(|encoder| encoder.as_any_mut().downcast_mut()) - })) - }) - } - - /// # Safety - /// - /// - The raw queue handle must not be manually destroyed - pub unsafe fn queue_as_hal<A: HalApi, F, R>(&self, id: QueueId, hal_queue_callback: F) -> R - where - F: FnOnce(Option<&A::Queue>) -> R, - { - profiling::scope!("Queue::as_hal"); - - let queue = self.hub.queues.get(id); - let hal_queue = queue.raw().as_any().downcast_ref(); - - hal_queue_callback(hal_queue) - } - - /// # Safety - /// - /// - The raw blas handle must not be manually destroyed - pub unsafe fn blas_as_hal<A: HalApi, F: FnOnce(Option<&A::AccelerationStructure>) -> R, R>( - &self, - id: BlasId, - hal_blas_callback: F, - ) -> R { - profiling::scope!("Blas::as_hal"); - - let hub = &self.hub; - - if let Ok(blas) = hub.blas_s.get(id).get() { - let snatch_guard = blas.device.snatchable_lock.read(); - let hal_blas = blas - .try_raw(&snatch_guard) - .ok() - .and_then(|b| b.as_any().downcast_ref()); - hal_blas_callback(hal_blas) - } else { - hal_blas_callback(None) - } - } - - /// # Safety - /// - /// - The raw tlas handle must not be manually destroyed - pub unsafe fn tlas_as_hal<A: HalApi, F: FnOnce(Option<&A::AccelerationStructure>) -> R, R>( - &self, - id: TlasId, - hal_tlas_callback: F, - ) -> R { - profiling::scope!("Blas::as_hal"); - - let hub = &self.hub; - - if let Ok(tlas) = hub.tlas_s.get(id).get() { - let snatch_guard = tlas.device.snatchable_lock.read(); - let hal_tlas = tlas - .try_raw(&snatch_guard) - .ok() - .and_then(|t| t.as_any().downcast_ref()); - hal_tlas_callback(hal_tlas) - } else { - hal_tlas_callback(None) - } - } -} - /// A texture that has been marked as destroyed and is staged for actual deletion soon. #[derive(Debug)] pub struct DestroyedTexture { raw: ManuallyDrop<Box<dyn hal::DynTexture>>, views: WeakVec<TextureView>, clear_mode: TextureClearMode, bind_groups: WeakVec<BindGroup>, device: Arc<Device>, @@ -1803,35 +1649,35 @@ impl Drop for TextureView { resource_log!("Destroy raw {}", self.error_ident()); unsafe { self.device.raw().destroy_texture_view(raw); } } } } -impl TextureView { - pub(crate) fn raw<'a>( - &'a self, - snatch_guard: &'a SnatchGuard, - ) -> Option<&'a dyn hal::DynTextureView> { - self.raw.get(snatch_guard).map(|it| it.as_ref()) +impl RawResourceAccess for TextureView { + type DynResource = dyn hal::DynTextureView; + + fn raw<'a>(&'a self, guard: &'a SnatchGuard) -> Option<&'a Self::DynResource> { + self.raw.get(guard).map(|it| it.as_ref()) } - pub(crate) fn try_raw<'a>( + fn try_raw<'a>( &'a self, guard: &'a SnatchGuard, - ) -> Result<&'a dyn hal::DynTextureView, DestroyedResourceError> { + ) -> Result<&'a Self::DynResource, DestroyedResourceError> { self.parent.check_destroyed(guard)?; - self.raw - .get(guard) - .map(|it| it.as_ref()) + + self.raw(guard) .ok_or_else(|| DestroyedResourceError(self.error_ident())) } +} +impl TextureView { /// Checks that the given texture usage contains the required texture usage, /// returns an error otherwise. pub(crate) fn check_usage( &self, expected: wgt::TextureUsages, ) -> Result<(), MissingTextureUsageError> { if self.desc.usage.contains(expected) { Ok(()) @@ -2121,23 +1967,16 @@ impl QuerySet { pub(crate) fn raw(&self) -> &dyn hal::DynQuerySet { self.raw.as_ref() } } pub type BlasDescriptor<'a> = wgt::CreateBlasDescriptor<Label<'a>>; pub type TlasDescriptor<'a> = wgt::CreateTlasDescriptor<Label<'a>>; -pub(crate) trait AccelerationStructure: Trackable { - fn try_raw<'a>( - &'a self, - guard: &'a SnatchGuard, - ) -> Result<&'a dyn hal::DynAccelerationStructure, DestroyedResourceError>; -} - pub type BlasPrepareCompactResult = Result<(), BlasPrepareCompactError>; #[cfg(send_sync)] pub type BlasCompactCallback = Box<dyn FnOnce(BlasPrepareCompactResult) + Send + 'static>; #[cfg(not(send_sync))] pub type BlasCompactCallback = Box<dyn FnOnce(BlasPrepareCompactResult) + 'static>; pub(crate) struct BlasPendingCompact { @@ -2203,25 +2042,21 @@ impl Drop for Blas { self.device .raw() .destroy_buffer(ManuallyDrop::take(&mut raw)) } } } } -impl AccelerationStructure for Blas { - fn try_raw<'a>( - &'a self, - guard: &'a SnatchGuard, - ) -> Result<&'a dyn hal::DynAccelerationStructure, DestroyedResourceError> { - self.raw - .get(guard) - .map(|raw| raw.as_ref()) - .ok_or_else(|| DestroyedResourceError(self.error_ident())) +impl RawResourceAccess for Blas { + type DynResource = dyn hal::DynAccelerationStructure; + + fn raw<'a>(&'a self, guard: &'a SnatchGuard) -> Option<&'a Self::DynResource> { + self.raw.get(guard).map(|it| it.as_ref()) } } impl Blas { pub(crate) fn prepare_compact_async( self: &Arc<Self>, op: Option<BlasCompactCallback>, ) -> Result<SubmissionIndex, (Option<BlasCompactCallback>, BlasPrepareCompactError)> { @@ -2351,25 +2186,21 @@ impl Drop for Tlas { self.device.raw().destroy_acceleration_structure(structure); } let buffer = ManuallyDrop::take(&mut self.instance_buffer); self.device.raw().destroy_buffer(buffer); } } } -impl AccelerationStructure for Tlas { - fn try_raw<'a>( - &'a self, - guard: &'a SnatchGuard, - ) -> Result<&'a dyn hal::DynAccelerationStructure, DestroyedResourceError> { - self.raw - .get(guard) - .map(|raw| raw.as_ref()) - .ok_or_else(|| DestroyedResourceError(self.error_ident())) +impl RawResourceAccess for Tlas { + type DynResource = dyn hal::DynAccelerationStructure; + + fn raw<'a>(&'a self, guard: &'a SnatchGuard) -> Option<&'a Self::DynResource> { + self.raw.get(guard).map(|raw| raw.as_ref()) } } crate::impl_resource_type!(Tlas); crate::impl_labeled!(Tlas); crate::impl_parent_device!(Tlas); crate::impl_storage_item!(Tlas); crate::impl_trackable!(Tlas);
--- a/third_party/rust/wgpu-core/src/snatch.rs +++ b/third_party/rust/wgpu-core/src/snatch.rs @@ -1,14 +1,14 @@ -use core::{cell::UnsafeCell, fmt}; +use core::{cell::UnsafeCell, fmt, mem::ManuallyDrop}; -use crate::lock::{rank, RwLock, RwLockReadGuard, RwLockWriteGuard}; +use crate::lock::{rank, RankData, RwLock, RwLockReadGuard, RwLockWriteGuard}; /// A guard that provides read access to snatchable data. -pub struct SnatchGuard<'a>(#[expect(dead_code)] RwLockReadGuard<'a, ()>); +pub struct SnatchGuard<'a>(RwLockReadGuard<'a, ()>); /// A guard that allows snatching the snatchable data. pub struct ExclusiveSnatchGuard<'a>(#[expect(dead_code)] RwLockWriteGuard<'a, ()>); /// A value that is mostly immutable but can be "snatched" if we need to destroy /// it early. /// /// In order to safely access the underlying data, the device's global snatchable /// lock must be taken. To guarantee it, methods take a read or write guard of that @@ -153,16 +153,43 @@ impl SnatchLock { /// This should only be called when a resource needs to be snatched. This has /// a high risk of causing lock contention if called concurrently with other /// wgpu work. #[track_caller] pub fn write(&self) -> ExclusiveSnatchGuard { LockTrace::enter("write"); ExclusiveSnatchGuard(self.lock.write()) } + + #[track_caller] + pub unsafe fn force_unlock_read(&self, data: RankData) { + // This is unsafe because it can cause deadlocks if the lock is held. + // It should only be used in very specific cases, like when a resource + // needs to be snatched in a panic handler. + LockTrace::exit(); + unsafe { self.lock.force_unlock_read(data) }; + } +} + +impl SnatchGuard<'_> { + /// Forget the guard, leaving the lock in a locked state with no guard. + /// + /// This is equivalent to `std::mem::forget`, but preserves the information about the lock + /// rank. + pub fn forget(this: Self) -> RankData { + // Cancel the drop implementation of the current guard. + let manually_drop = ManuallyDrop::new(this); + + // As we are unable to destructure out of this guard due to the drop implementation, + // so we manually read the inner value. + // SAFETY: This is safe because we never access the original guard again. + let inner_guard = unsafe { core::ptr::read(&manually_drop.0) }; + + RwLockReadGuard::forget(inner_guard) + } } impl Drop for SnatchGuard<'_> { fn drop(&mut self) { LockTrace::exit(); } }
--- a/third_party/rust/wgpu-core/src/timestamp_normalization/mod.rs +++ b/third_party/rust/wgpu-core/src/timestamp_normalization/mod.rs @@ -237,38 +237,42 @@ impl TimestampNormalizer { temporary_bind_group_layout, pipeline_layout, pipeline, }), }) } } - pub fn create_normalization_bind_group( + /// Create a bind group for normalizing timestamps in `buffer`. + /// + /// This function is unsafe because it does not know that `buffer_size` is + /// the true size of the buffer. + pub unsafe fn create_normalization_bind_group( &self, device: &Device, buffer: &dyn hal::DynBuffer, buffer_label: Option<&str>, - buffer_size: u64, + buffer_size: wgt::BufferSize, buffer_usages: wgt::BufferUsages, ) -> Result<TimestampNormalizationBindGroup, DeviceError> { unsafe { let Some(ref state) = &self.state else { return Ok(TimestampNormalizationBindGroup { raw: None }); }; if !buffer_usages.contains(wgt::BufferUsages::QUERY_RESOLVE) { return Ok(TimestampNormalizationBindGroup { raw: None }); } // If this buffer is large enough that we wouldn't be able to bind the entire thing // at once to normalize the timestamps, we can't use it. We force the buffer to fail // to allocate. The lowest max binding size is 128MB, and query sets must be small // (no more than 4096), so this should never be hit in practice by sane programs. - if buffer_size > device.adapter.limits().max_storage_buffer_binding_size as u64 { + if buffer_size.get() > device.adapter.limits().max_storage_buffer_binding_size as u64 { return Err(DeviceError::OutOfMemory); } let bg_label_alloc; let label = match buffer_label { Some(label) => { bg_label_alloc = alloc::format!("Timestamp normalization bind group ({})", label); @@ -277,21 +281,17 @@ impl TimestampNormalizer { None => "Timestamp normalization bind group", }; let bg = device .raw() .create_bind_group(&hal::BindGroupDescriptor { label: Some(label), layout: &*state.temporary_bind_group_layout, - buffers: &[hal::BufferBinding { - buffer, - offset: 0, - size: None, - }], + buffers: &[hal::BufferBinding::new_unchecked(buffer, 0, buffer_size)], samplers: &[], textures: &[], acceleration_structures: &[], entries: &[hal::BindGroupEntry { binding: 0, resource_index: 0, count: 1, }],
--- a/third_party/rust/wgpu-core/src/track/mod.rs +++ b/third_party/rust/wgpu-core/src/track/mod.rs @@ -101,17 +101,17 @@ mod metadata; mod range; mod stateless; mod texture; use crate::{ binding_model, command, lock::{rank, Mutex}, pipeline, - resource::{self, Labeled, ResourceErrorIdent}, + resource::{self, Labeled, RawResourceAccess, ResourceErrorIdent}, snatch::SnatchGuard, track::blas::BlasTracker, }; use alloc::{sync::Arc, vec::Vec}; use core::{fmt, mem, ops}; use thiserror::Error;
--- a/third_party/rust/wgpu-core/src/track/texture.rs +++ b/third_party/rust/wgpu-core/src/track/texture.rs @@ -15,17 +15,17 @@ //! It cannot leak into transitions, it is invalid to transition into UNKNOWN //! state. //! - `UNINITIALIZED` is used in both simple and complex states to mean the texture //! is known to be in some undefined state. Any transition away from UNINITIALIZED //! will treat the contents as junk. use super::{range::RangedStates, PendingTransition, PendingTransitionList}; use crate::{ - resource::{Texture, TextureInner, TextureView, Trackable}, + resource::{RawResourceAccess, Texture, TextureInner, TextureView, Trackable}, snatch::SnatchGuard, track::{ invalid_resource_state, skip_barrier, ResourceMetadata, ResourceMetadataProvider, ResourceUsageCompatibilityError, ResourceUses, }, }; use hal::TextureBarrier;
--- a/third_party/rust/wgpu-hal/.cargo-checksum.json +++ b/third_party/rust/wgpu-hal/.cargo-checksum.json @@ -1,1 +1,1 @@ -{"files":{"Cargo.toml":"05bb196b5da1be2afc2062b9650421841629cb29ed27997f5a5d0dc414b46692","LICENSE.APACHE":"a6cba85bc92e0cff7a450b1d873c0eaa2e9fc96bf472df0247a26bec77bf3ff9","LICENSE.MIT":"c7fea58d1cfe49634cd92e54fc10a9d871f4b275321a4cd8c09e449122caaeb4","README.md":"cf9e84804a635e4a8a9fefc596be9da6bf7354dde0d105e27d56a12cb20dd8e3","build.rs":"e720cf033fecfdc7e4f34010af2a86340c99b8aaabf69559d32391521e25de6c","examples/halmark/main.rs":"f42ceef4ee26c1e2b5b917e697ae662099550fece8bb715b2076a55413662c6c","examples/halmark/shader.wgsl":"26c256ec36d6f0e9a1647431ca772766bee4382d64eaa718ba7b488dcfb6bcca","examples/raw-gles.em.html":"70fbe68394a1a4522192de1dcfaf7d399f60d7bdf5de70b708f9bb0417427546","examples/raw-gles.rs":"f41b15e898da0047d33c7bed0dd311ca6fade507ba453c238a7babf789480b6c","examples/ray-traced-triangle/main.rs":"ecbd4625050f1be3d61af83f4effffa11b8baaef127ec17a2d3ca0465cb7d967","examples/ray-traced-triangle/shader.wgsl":"cc10caf92746724a71f6dd0dbc3a71e57b37c7d1d83278556805a535c0728a9d","src/auxil/dxgi/conv.rs":"f451fb0c416a637f11542e9b166a48800be50c48925779b06d40a9bc87958d97","src/auxil/dxgi/exception.rs":"4ac0004d0efc88ba7738e166064796400ca1eb9518bd8cc642144401989ec796","src/auxil/dxgi/factory.rs":"1d8cfeb733e34b97d5b879705fc5621ab7b9be578aebb3c3ddadea992effb566","src/auxil/dxgi/mod.rs":"e6c5cc3b73bb97742135d6f35308c42f0822304764978fb8dabb0e848863352a","src/auxil/dxgi/name.rs":"ff942da0da1a497ee4d2be21604f7ba9fae963588105b3d1f63aae1a0c536e82","src/auxil/dxgi/result.rs":"a3b52fd87e512bb94df79c8cadf89a1fbcf7ab0a3a8c7fa1280c2e54cb75d96e","src/auxil/dxgi/time.rs":"b6911800be3873cbe277b2534b3839c6f005f3d9a09341aace4752e207d584a2","src/auxil/mod.rs":"540b9250d9f0e0af709245ce1e284eaca15b27d47550b0ebba2a512da1666c48","src/auxil/renderdoc.rs":"e687710ea0c9e88c9be0e2acd39d136635b835ffb941886b875811b3ec945080","src/dx12/adapter.rs":"965016bde0f374b7ac3bd59e8952590a92a2c404da2c0f52372fd236466b73a5","src/dx12/command.rs":"f11a50b9ada035ed27affcb0e127c63bc62ba8bfae47a9357251b263e1e7f872","src/dx12/conv.rs":"f800cf605bda983828330f73a53d7f47549a17e7263572a356168dd656270c31","src/dx12/descriptor.rs":"e3371d7539c44ffc4c7b958b6d948855200bb3c4e7da9577835cc0bca695807b","src/dx12/device.rs":"9b7c547548aaeb4075d9bfa705758bcadfc0b5f6a0215da0bc234f9ead68b02b","src/dx12/instance.rs":"0c4bd516177ddb3724529aa30751ebde41d6f80e6bf294a23ec621712663cedd","src/dx12/mod.rs":"6156fae97db99b4e90e983533a3c08c85866dec113a412194d9e108641984ba4","src/dx12/sampler.rs":"64464c32452ee63ac49014a03ca3be894ab9b74e11dc853567b5da5f846faae6","src/dx12/shader_compilation.rs":"c901a797c69e08c8c0ec93ea37c5f31084eb21c26c7d703d7031f987f2243509","src/dx12/suballocation.rs":"44f5ab65c1eeb54a53841dc769b749ce7702e32b89a6bd2ddd1a270f63437a50","src/dx12/types.rs":"3fc7619fc09303eb3c936d4ded6889f94ce9e8b9aa62742ce900baa1b1e1cca7","src/dx12/view.rs":"79b3f7331d9795e60f9b53023cbf0df46c3a05b1e8bd5c7bcca8acdd235b124f","src/dynamic/adapter.rs":"e93f7d082a3950c9e8ccff8a631d251c7598b4b25dda9fe6347dadfa3ba07829","src/dynamic/command.rs":"9635dea15d8a885011d2b8b6b9cc5ffe2126cc3f141f47f7aaf46e1f201abea9","src/dynamic/device.rs":"f00305d56cac0636d4cb86cc44ee69c291bfb3d5f6d5e8d745adce9a28a6a1d5","src/dynamic/instance.rs":"7b515c201e1ca24f24439544dbfa1d19ea1412a4f89bd803e009aed13b021e55","src/dynamic/mod.rs":"b02a3c11b22c896cf66ef206f5d4bb4e24988ecadc29972c572baf347f54aa04","src/dynamic/queue.rs":"d76abb4797e90253386d24584f186dbe1909e772560156b2e891fa043cfefbdc","src/dynamic/surface.rs":"4328c2fe86931f50aa00ac3d6982d0879b774eebf7a507903d1b1898c891fb4d","src/gles/adapter.rs":"bf6318ba3b45b277181b69d715184ff06ffe0173ce44872ad90d55098f04a1ab","src/gles/command.rs":"c13d50eeb1a4aaab367a3b4a7fe6c25c8c73377e68d0d8cc43791d1a7202d23b","src/gles/conv.rs":"7f885dd2bc72641d22f8f2e688ebdd857663bfe315f1b5364ea302f99a05adbf","src/gles/device.rs":"07aa761e7a5857fc25caecddc6ed6b0ea970a815feb7343f75cb76bc2196ca01","src/gles/egl.rs":"de77822e37369bb4c41e1efcd92134aa220acf0dd8a251a0d4499dd4d541a547","src/gles/emscripten.rs":"316d2bb6f2a4bb126dbe68a223f7393399080d116b61c39504454acdf4f9cfaf","src/gles/fence.rs":"083cd49747aba6272002aba0b0c37e5768cdbc2a1b8bacd1a244ee905d3f7b0f","src/gles/mod.rs":"897365cdd34914a654532c8d9592cb3a3f460bd50ac2b6ba72106a105c12ac10","src/gles/queue.rs":"f0a75fa2431f84feaf9a2cd0ba156ffa011b0ba671b167066d2f9341bde89109","src/gles/shaders/clear.frag":"9133ed8ed97d3641fbb6b5f5ea894a3554c629ccc1b80a5fc9221d7293aa1954","src/gles/shaders/clear.vert":"a543768725f4121ff2e9e1fb5b00644931e9d6f2f946c0ef01968afb5a135abd","src/gles/shaders/srgb_present.frag":"dd9a43c339a2fa4ccf7f6a1854c6f400cabf271a7d5e9230768e9f39d47f3ff5","src/gles/shaders/srgb_present.vert":"6e85d489403d80b81cc94790730bb53b309dfc5eeede8f1ea3412a660f31d357","src/gles/web.rs":"cb5940bf7b2381811675011b640040274f407a7d1908d0f82c813d6a9d3b00f7","src/gles/wgl.rs":"ed0cee8844447b461ed5340f81eb55bb051ceaac67a5768985318ceac133cbe4","src/lib.rs":"8e6be7b49b9af7c2f19da313f173a19d8cf1ab007469b547318f7e8555b78769","src/metal/adapter.rs":"1b035bf4e69df1575b215cf5a6578afcf729ac26dbae81cf1344fbae5659f65f","src/metal/command.rs":"1ec1a9e0e1ccf298c2c416b96e60827173e6584c9061b8dd582b7789545ce60a","src/metal/conv.rs":"85e8168be334ba24d109575a0a7e91b2ad3459403173e99e5cdd5d977cc5c18f","src/metal/device.rs":"581472ed832c8b0960d61f0a0347dba42b649182a576285367f8198555e63051","src/metal/layer_observer.rs":"8370a6e443d01739b951b8538ee719a03b69fc0cbac92c748db418fbcc8837b5","src/metal/mod.rs":"8721673e6f9e88bca5318ff4286a91e5c441ae607b53940c45bda0d8c053e99d","src/metal/surface.rs":"50c628f0e555f936707e57dbff59bbc9b1b05b10747b8303189b878b6fb28795","src/metal/time.rs":"c32d69f30e846dfcc0e39e01097fb80df63b2bebb6586143bb62494999850246","src/noop/buffer.rs":"b5edc5e2c52287dfbd4f619e36097ac233041eb9ab287b889b6ee477d740fa09","src/noop/command.rs":"3de99a1a260cfea2e6ca2e76797c1923cc26b069b08362c38798ce27cdc75543","src/noop/mod.rs":"c0d0b593e890e028deb88cc02a02c87c61f2049b6371cd0c788d3345b306f9a4","src/validation_canary.rs":"2e8f84e5f85671b3e55ddd410476171c762e34cbea315b37921cbb6ff18bfb4f","src/vulkan/adapter.rs":"4d1f9feb3b7fdfa685038acb3f4ae4967de164ce9a09be519cadd837b7a717d9","src/vulkan/command.rs":"e058758398d4ec6fda1d0274d99b92ae541f4263ee804bcb1c42ca96f8610ac0","src/vulkan/conv.rs":"f416df65d0abceff8518c5ac86c1f88102b66e64403494d795691b56328374da","src/vulkan/device.rs":"2641631d6d20db6c72dbe9a67fbabccc8975f43f9aed1c2be6f7ed8b0cf1a590","src/vulkan/drm.rs":"09eaa92c6a17e219ee856ffc3fe5f9fe1c15063b4c3dbb7cd20bf2f4f9cac2c7","src/vulkan/instance.rs":"e7d3e7abec8ac8aa582f4facc28668f02dfdc8342cca948f359746851a6c6260","src/vulkan/mod.rs":"1de05dec5386cd701decda525512e48316347f87c48aa273c44a63fd510e8241","src/vulkan/sampler.rs":"f65729d6df5cce681b7756b3e48074017f0c7f42da69ca55e26cc723cd14ad59","src/vulkan/semaphore_list.rs":"102266d8e1b9f2ec1decf681bcc9e1a4cbff29533a258f2699fb6c573c434771"},"package":null} \ No newline at end of file +{"files":{"Cargo.toml":"a6f3ec315417a8d74aba436354d64a2f8ec01059a65b179f9877b2a26c2f1eba","LICENSE.APACHE":"a6cba85bc92e0cff7a450b1d873c0eaa2e9fc96bf472df0247a26bec77bf3ff9","LICENSE.MIT":"c7fea58d1cfe49634cd92e54fc10a9d871f4b275321a4cd8c09e449122caaeb4","README.md":"cf9e84804a635e4a8a9fefc596be9da6bf7354dde0d105e27d56a12cb20dd8e3","build.rs":"e720cf033fecfdc7e4f34010af2a86340c99b8aaabf69559d32391521e25de6c","examples/halmark/main.rs":"4cfc7ca7d9ae764aa115549f774659ff524b1a56cced3e737a22efe861e7f12a","examples/halmark/shader.wgsl":"26c256ec36d6f0e9a1647431ca772766bee4382d64eaa718ba7b488dcfb6bcca","examples/raw-gles.em.html":"70fbe68394a1a4522192de1dcfaf7d399f60d7bdf5de70b708f9bb0417427546","examples/raw-gles.rs":"f41b15e898da0047d33c7bed0dd311ca6fade507ba453c238a7babf789480b6c","examples/ray-traced-triangle/main.rs":"ea8765315c464e285a0496fb9ee34d8c40d7b439d2d3ecac4475196eacae6786","examples/ray-traced-triangle/shader.wgsl":"cc10caf92746724a71f6dd0dbc3a71e57b37c7d1d83278556805a535c0728a9d","src/auxil/dxgi/conv.rs":"f451fb0c416a637f11542e9b166a48800be50c48925779b06d40a9bc87958d97","src/auxil/dxgi/exception.rs":"4ac0004d0efc88ba7738e166064796400ca1eb9518bd8cc642144401989ec796","src/auxil/dxgi/factory.rs":"1d8cfeb733e34b97d5b879705fc5621ab7b9be578aebb3c3ddadea992effb566","src/auxil/dxgi/mod.rs":"e6c5cc3b73bb97742135d6f35308c42f0822304764978fb8dabb0e848863352a","src/auxil/dxgi/name.rs":"ff942da0da1a497ee4d2be21604f7ba9fae963588105b3d1f63aae1a0c536e82","src/auxil/dxgi/result.rs":"a3b52fd87e512bb94df79c8cadf89a1fbcf7ab0a3a8c7fa1280c2e54cb75d96e","src/auxil/dxgi/time.rs":"b6911800be3873cbe277b2534b3839c6f005f3d9a09341aace4752e207d584a2","src/auxil/mod.rs":"540b9250d9f0e0af709245ce1e284eaca15b27d47550b0ebba2a512da1666c48","src/auxil/renderdoc.rs":"e687710ea0c9e88c9be0e2acd39d136635b835ffb941886b875811b3ec945080","src/dx12/adapter.rs":"965016bde0f374b7ac3bd59e8952590a92a2c404da2c0f52372fd236466b73a5","src/dx12/command.rs":"bad5f12c670e0d4cae5191ee0ee8cc82f9d90c408bdc648c7e2493881a9992fc","src/dx12/conv.rs":"f800cf605bda983828330f73a53d7f47549a17e7263572a356168dd656270c31","src/dx12/descriptor.rs":"e3371d7539c44ffc4c7b958b6d948855200bb3c4e7da9577835cc0bca695807b","src/dx12/device.rs":"929173beaca41ccd7e8c465a724c5ef8f6da96e5abd0b6fab533da5b761af966","src/dx12/instance.rs":"0c4bd516177ddb3724529aa30751ebde41d6f80e6bf294a23ec621712663cedd","src/dx12/mod.rs":"6156fae97db99b4e90e983533a3c08c85866dec113a412194d9e108641984ba4","src/dx12/sampler.rs":"64464c32452ee63ac49014a03ca3be894ab9b74e11dc853567b5da5f846faae6","src/dx12/shader_compilation.rs":"c901a797c69e08c8c0ec93ea37c5f31084eb21c26c7d703d7031f987f2243509","src/dx12/suballocation.rs":"44f5ab65c1eeb54a53841dc769b749ce7702e32b89a6bd2ddd1a270f63437a50","src/dx12/types.rs":"3fc7619fc09303eb3c936d4ded6889f94ce9e8b9aa62742ce900baa1b1e1cca7","src/dx12/view.rs":"79b3f7331d9795e60f9b53023cbf0df46c3a05b1e8bd5c7bcca8acdd235b124f","src/dynamic/adapter.rs":"e93f7d082a3950c9e8ccff8a631d251c7598b4b25dda9fe6347dadfa3ba07829","src/dynamic/command.rs":"9635dea15d8a885011d2b8b6b9cc5ffe2126cc3f141f47f7aaf46e1f201abea9","src/dynamic/device.rs":"f00305d56cac0636d4cb86cc44ee69c291bfb3d5f6d5e8d745adce9a28a6a1d5","src/dynamic/instance.rs":"7b515c201e1ca24f24439544dbfa1d19ea1412a4f89bd803e009aed13b021e55","src/dynamic/mod.rs":"b02a3c11b22c896cf66ef206f5d4bb4e24988ecadc29972c572baf347f54aa04","src/dynamic/queue.rs":"d76abb4797e90253386d24584f186dbe1909e772560156b2e891fa043cfefbdc","src/dynamic/surface.rs":"4328c2fe86931f50aa00ac3d6982d0879b774eebf7a507903d1b1898c891fb4d","src/gles/adapter.rs":"bf6318ba3b45b277181b69d715184ff06ffe0173ce44872ad90d55098f04a1ab","src/gles/command.rs":"c13d50eeb1a4aaab367a3b4a7fe6c25c8c73377e68d0d8cc43791d1a7202d23b","src/gles/conv.rs":"7f885dd2bc72641d22f8f2e688ebdd857663bfe315f1b5364ea302f99a05adbf","src/gles/device.rs":"07aa761e7a5857fc25caecddc6ed6b0ea970a815feb7343f75cb76bc2196ca01","src/gles/egl.rs":"de77822e37369bb4c41e1efcd92134aa220acf0dd8a251a0d4499dd4d541a547","src/gles/emscripten.rs":"316d2bb6f2a4bb126dbe68a223f7393399080d116b61c39504454acdf4f9cfaf","src/gles/fence.rs":"083cd49747aba6272002aba0b0c37e5768cdbc2a1b8bacd1a244ee905d3f7b0f","src/gles/mod.rs":"897365cdd34914a654532c8d9592cb3a3f460bd50ac2b6ba72106a105c12ac10","src/gles/queue.rs":"f0a75fa2431f84feaf9a2cd0ba156ffa011b0ba671b167066d2f9341bde89109","src/gles/shaders/clear.frag":"9133ed8ed97d3641fbb6b5f5ea894a3554c629ccc1b80a5fc9221d7293aa1954","src/gles/shaders/clear.vert":"a543768725f4121ff2e9e1fb5b00644931e9d6f2f946c0ef01968afb5a135abd","src/gles/shaders/srgb_present.frag":"dd9a43c339a2fa4ccf7f6a1854c6f400cabf271a7d5e9230768e9f39d47f3ff5","src/gles/shaders/srgb_present.vert":"6e85d489403d80b81cc94790730bb53b309dfc5eeede8f1ea3412a660f31d357","src/gles/web.rs":"cb5940bf7b2381811675011b640040274f407a7d1908d0f82c813d6a9d3b00f7","src/gles/wgl.rs":"ed0cee8844447b461ed5340f81eb55bb051ceaac67a5768985318ceac133cbe4","src/lib.rs":"012043474fbf7875224f2464e3202b73302a146da180dfaab259297e0c52ffdd","src/metal/adapter.rs":"1b035bf4e69df1575b215cf5a6578afcf729ac26dbae81cf1344fbae5659f65f","src/metal/command.rs":"1ec1a9e0e1ccf298c2c416b96e60827173e6584c9061b8dd582b7789545ce60a","src/metal/conv.rs":"85e8168be334ba24d109575a0a7e91b2ad3459403173e99e5cdd5d977cc5c18f","src/metal/device.rs":"581472ed832c8b0960d61f0a0347dba42b649182a576285367f8198555e63051","src/metal/layer_observer.rs":"8370a6e443d01739b951b8538ee719a03b69fc0cbac92c748db418fbcc8837b5","src/metal/mod.rs":"8721673e6f9e88bca5318ff4286a91e5c441ae607b53940c45bda0d8c053e99d","src/metal/surface.rs":"50c628f0e555f936707e57dbff59bbc9b1b05b10747b8303189b878b6fb28795","src/metal/time.rs":"c32d69f30e846dfcc0e39e01097fb80df63b2bebb6586143bb62494999850246","src/noop/buffer.rs":"b5edc5e2c52287dfbd4f619e36097ac233041eb9ab287b889b6ee477d740fa09","src/noop/command.rs":"3de99a1a260cfea2e6ca2e76797c1923cc26b069b08362c38798ce27cdc75543","src/noop/mod.rs":"c0d0b593e890e028deb88cc02a02c87c61f2049b6371cd0c788d3345b306f9a4","src/validation_canary.rs":"2e8f84e5f85671b3e55ddd410476171c762e34cbea315b37921cbb6ff18bfb4f","src/vulkan/adapter.rs":"4d1f9feb3b7fdfa685038acb3f4ae4967de164ce9a09be519cadd837b7a717d9","src/vulkan/command.rs":"e058758398d4ec6fda1d0274d99b92ae541f4263ee804bcb1c42ca96f8610ac0","src/vulkan/conv.rs":"f416df65d0abceff8518c5ac86c1f88102b66e64403494d795691b56328374da","src/vulkan/device.rs":"c31564d96f047c2cd4b583749b1d62bf9bd37f5e4c490c03a6f0498d9b743357","src/vulkan/drm.rs":"09eaa92c6a17e219ee856ffc3fe5f9fe1c15063b4c3dbb7cd20bf2f4f9cac2c7","src/vulkan/instance.rs":"e7d3e7abec8ac8aa582f4facc28668f02dfdc8342cca948f359746851a6c6260","src/vulkan/mod.rs":"22b74c1d6abd542b2790067dd6e80473efa03ec94d4ef9cb4e7ee4498def80a3","src/vulkan/sampler.rs":"f65729d6df5cce681b7756b3e48074017f0c7f42da69ca55e26cc723cd14ad59","src/vulkan/semaphore_list.rs":"102266d8e1b9f2ec1decf681bcc9e1a4cbff29533a258f2699fb6c573c434771"},"package":null} \ No newline at end of file
--- a/third_party/rust/wgpu-hal/Cargo.toml +++ b/third_party/rust/wgpu-hal/Cargo.toml @@ -8,17 +8,17 @@ # If you are reading this file be aware that the original Cargo.toml # will likely look very different (and much more reasonable). # See Cargo.toml.orig for the original contents. [package] edition = "2021" rust-version = "1.82.0" name = "wgpu-hal" -version = "25.0.0" +version = "26.0.0" authors = ["gfx-rs developers"] build = "build.rs" autolib = false autobins = false autoexamples = false autotests = false autobenches = false description = "Hardware abstraction layer for wgpu, the cross-platform, safe, pure-rust graphics API" @@ -197,30 +197,30 @@ features = [ optional = true default-features = false [dependencies.log] version = "0.4.21" optional = true [dependencies.naga] -version = "25.0.0" +version = "26.0.0" path = "../naga" [dependencies.ordered-float] version = ">=3, <=5.0" optional = true default-features = false [dependencies.parking_lot] version = "0.12.3" optional = true [dependencies.profiling] -version = "1" +version = "1.0.1" optional = true default-features = false [dependencies.raw-window-handle] version = "0.6.2" default-features = false [dependencies.rustc-hash] @@ -228,29 +228,29 @@ version = "1.1" optional = true default-features = false [dependencies.thiserror] version = "2.0.3" default-features = false [dependencies.wgpu-types] -version = "25.0.0" +version = "26.0.0" path = "../wgpu-types" default-features = false [dev-dependencies.env_logger] version = "0.11" default-features = false [dev-dependencies.glam] version = "0.30" [dev-dependencies.naga] -version = "25.0.0" +version = "26.0.0" path = "../naga" features = [ "wgsl-in", "termcolor", ] [dev-dependencies.winit] version = "0.29"
--- a/third_party/rust/wgpu-hal/examples/halmark/main.rs +++ b/third_party/rust/wgpu-hal/examples/halmark/main.rs @@ -9,17 +9,19 @@ use raw_window_handle::{HasDisplayHandle use winit::{ event::{ElementState, Event, KeyEvent, WindowEvent}, event_loop::ControlFlow, keyboard::{Key, NamedKey}, }; use std::{ borrow::{Borrow, Cow}, - iter, ptr, + iter, + num::NonZeroU64, + ptr, time::Instant, }; const MAX_BUNNIES: usize = 1 << 20; const BUNNY_SIZE: f32 = 0.15 * 256.0; const GRAVITY: f32 = -9.8 * 100.0; const MAX_VELOCITY: f32 = 750.0; const DESIRED_MAX_LATENCY: u32 = 2; @@ -440,21 +442,22 @@ impl<A: hal::Api> Example<A> { format: texture_desc.format, dimension: wgpu_types::TextureViewDimension::D2, usage: wgpu_types::TextureUses::RESOURCE, range: wgpu_types::ImageSubresourceRange::default(), }; let texture_view = unsafe { device.create_texture_view(&texture, &view_desc).unwrap() }; let global_group = { - let global_buffer_binding = hal::BufferBinding { - buffer: &global_buffer, - offset: 0, - size: None, - }; + // SAFETY: This is the same size that was specified for buffer creation. + let global_buffer_binding = hal::BufferBinding::new_unchecked( + &global_buffer, + 0, + NonZeroU64::new(global_buffer_desc.size), + ); let texture_binding = hal::TextureBinding { view: &texture_view, usage: wgpu_types::TextureUses::RESOURCE, }; let global_group_desc = hal::BindGroupDescriptor { label: Some("global"), layout: &global_group_layout, buffers: &[global_buffer_binding], @@ -478,21 +481,22 @@ impl<A: hal::Api> Example<A> { count: 1, }, ], }; unsafe { device.create_bind_group(&global_group_desc).unwrap() } }; let local_group = { - let local_buffer_binding = hal::BufferBinding { - buffer: &local_buffer, - offset: 0, - size: wgpu_types::BufferSize::new(size_of::<Locals>() as _), - }; + // SAFETY: The size must fit within the buffer. + let local_buffer_binding = hal::BufferBinding::new_unchecked( + &local_buffer, + 0, + wgpu_types::BufferSize::new(size_of::<Locals>() as _), + ); let local_group_desc = hal::BindGroupDescriptor { label: Some("local"), layout: &local_group_layout, buffers: &[local_buffer_binding], samplers: &[], textures: &[], acceleration_structures: &[], entries: &[hal::BindGroupEntry {
--- a/third_party/rust/wgpu-hal/examples/ray-traced-triangle/main.rs +++ b/third_party/rust/wgpu-hal/examples/ray-traced-triangle/main.rs @@ -598,20 +598,23 @@ impl<A: hal::Api> Example<A> { format: texture_desc.format, dimension: wgpu_types::TextureViewDimension::D2, usage: wgpu_types::TextureUses::STORAGE_READ_WRITE | wgpu_types::TextureUses::COPY_SRC, range: wgpu_types::ImageSubresourceRange::default(), }; let texture_view = unsafe { device.create_texture_view(&texture, &view_desc).unwrap() }; let bind_group = { - let buffer_binding = hal::BufferBinding { - buffer: &uniform_buffer, - offset: 0, - size: None, + let buffer_binding = unsafe { + // SAFETY: The size matches the buffer allocation. + hal::BufferBinding::new_unchecked( + &uniform_buffer, + 0, + wgpu_types::BufferSize::new_unchecked(uniforms_size as u64), + ) }; let texture_binding = hal::TextureBinding { view: &texture_view, usage: wgpu_types::TextureUses::STORAGE_READ_WRITE, }; let group_desc = hal::BindGroupDescriptor { label: Some("bind group"), layout: &bgl,
--- a/third_party/rust/wgpu-hal/src/dx12/command.rs +++ b/third_party/rust/wgpu-hal/src/dx12/command.rs @@ -1131,30 +1131,30 @@ impl crate::CommandEncoder for super::Co unsafe fn set_index_buffer<'a>( &mut self, binding: crate::BufferBinding<'a, super::Buffer>, format: wgt::IndexFormat, ) { let ibv = Direct3D12::D3D12_INDEX_BUFFER_VIEW { BufferLocation: binding.resolve_address(), - SizeInBytes: binding.resolve_size() as u32, + SizeInBytes: binding.resolve_size().try_into().unwrap(), Format: auxil::dxgi::conv::map_index_format(format), }; unsafe { self.list.as_ref().unwrap().IASetIndexBuffer(Some(&ibv)) } } unsafe fn set_vertex_buffer<'a>( &mut self, index: u32, binding: crate::BufferBinding<'a, super::Buffer>, ) { let vb = &mut self.pass.vertex_buffers[index as usize]; vb.BufferLocation = binding.resolve_address(); - vb.SizeInBytes = binding.resolve_size() as u32; + vb.SizeInBytes = binding.resolve_size().try_into().unwrap(); self.pass.dirty_vertex_buffers |= 1 << index; } unsafe fn set_viewport(&mut self, rect: &crate::Rect<f32>, depth_range: Range<f32>) { let raw_vp = Direct3D12::D3D12_VIEWPORT { TopLeftX: rect.x, TopLeftY: rect.y, Width: rect.w,
--- a/third_party/rust/wgpu-hal/src/dx12/device.rs +++ b/third_party/rust/wgpu-hal/src/dx12/device.rs @@ -1437,17 +1437,17 @@ impl crate::Device for super::Device { ty, has_dynamic_offset, .. } => { let start = entry.resource_index as usize; let end = start + entry.count as usize; for data in &desc.buffers[start..end] { let gpu_address = data.resolve_address(); - let mut size = data.resolve_size() as u32; + let mut size = data.resolve_size().try_into().unwrap(); if has_dynamic_offset { match ty { wgt::BufferBindingType::Uniform => { dynamic_buffers.push(super::DynamicBuffer::Uniform( Direct3D12::D3D12_GPU_DESCRIPTOR_HANDLE { ptr: data.resolve_address(), },
--- a/third_party/rust/wgpu-hal/src/lib.rs +++ b/third_party/rust/wgpu-hal/src/lib.rs @@ -292,17 +292,17 @@ pub use dynamic::{ #[allow(unused)] use alloc::boxed::Box; use alloc::{borrow::Cow, string::String, vec::Vec}; use core::{ borrow::Borrow, error::Error, fmt, - num::NonZeroU32, + num::{NonZeroU32, NonZeroU64}, ops::{Range, RangeInclusive}, ptr::NonNull, }; use bitflags::bitflags; use thiserror::Error; use wgt::WasmNotSendSync; @@ -1963,21 +1963,28 @@ pub struct PipelineLayoutDescriptor<'a, pub bind_group_layouts: &'a [&'a B], pub push_constant_ranges: &'a [wgt::PushConstantRange], } /// A region of a buffer made visible to shaders via a [`BindGroup`]. /// /// [`BindGroup`]: Api::BindGroup /// +/// ## Construction +/// +/// The recommended way to construct a `BufferBinding` is using the `binding` +/// method on a wgpu-core `Buffer`, which will validate the binding size +/// against the buffer size. A `new_unchecked` constructor is also provided for +/// cases where direct construction is necessary. +/// /// ## Accessible region /// /// `wgpu_hal` guarantees that shaders compiled with /// [`ShaderModuleDescriptor::runtime_checks`] set to `true` cannot read or -/// write data via this binding outside the *accessible region* of [`buffer`]: +/// write data via this binding outside the *accessible region* of a buffer: /// /// - The accessible region starts at [`offset`]. /// /// - For [`Storage`] bindings, the size of the accessible region is [`size`], /// which must be a multiple of 4. /// /// - For [`Uniform`] bindings, the size of the accessible region is [`size`] /// rounded up to the next multiple of @@ -1987,58 +1994,128 @@ pub struct PipelineLayoutDescriptor<'a, /// [out-of-bounds accesses][woob], as WGSL allows them to return values from /// elsewhere in the buffer. But this guarantee is necessary anyway, to permit /// `wgpu-core` to avoid clearing uninitialized regions of buffers that will /// never be read by the application before they are overwritten. This /// optimization consults bind group buffer binding regions to determine which /// parts of which buffers shaders might observe. This optimization is only /// sound if shader access is bounds-checked. /// -/// [`buffer`]: BufferBinding::buffer +/// ## Zero-length bindings +/// +/// Some back ends cannot tolerate zero-length regions; for example, see +/// [VUID-VkDescriptorBufferInfo-offset-00340][340] and +/// [VUID-VkDescriptorBufferInfo-range-00341][341], or the +/// documentation for GLES's [glBindBufferRange][bbr]. This documentation +/// previously stated that a `BufferBinding` must have `offset` strictly less +/// than the size of the buffer, but this restriction was not honored elsewhere +/// in the code, so has been removed. However, it remains the case that +/// some backends do not support zero-length bindings, so additional +/// logic is needed somewhere to handle this properly. See +/// [#3170](https://github.com/gfx-rs/wgpu/issues/3170). +/// /// [`offset`]: BufferBinding::offset /// [`size`]: BufferBinding::size /// [`Storage`]: wgt::BufferBindingType::Storage /// [`Uniform`]: wgt::BufferBindingType::Uniform +/// [340]: https://registry.khronos.org/vulkan/specs/1.3-extensions/html/vkspec.html#VUID-VkDescriptorBufferInfo-offset-00340 +/// [341]: https://registry.khronos.org/vulkan/specs/1.3-extensions/html/vkspec.html#VUID-VkDescriptorBufferInfo-range-00341 +/// [bbr]: https://registry.khronos.org/OpenGL-Refpages/es3.0/html/glBindBufferRange.xhtml /// [woob]: https://gpuweb.github.io/gpuweb/wgsl/#out-of-bounds-access-sec #[derive(Debug)] pub struct BufferBinding<'a, B: DynBuffer + ?Sized> { /// The buffer being bound. - pub buffer: &'a B, + /// + /// This is not fully `pub` to prevent direct construction of + /// `BufferBinding`s, while still allowing public read access to the `offset` + /// and `size` properties. + pub(crate) buffer: &'a B, /// The offset at which the bound region starts. /// - /// This must be less than the size of the buffer. Some back ends - /// cannot tolerate zero-length regions; for example, see - /// [VUID-VkDescriptorBufferInfo-offset-00340][340] and - /// [VUID-VkDescriptorBufferInfo-range-00341][341], or the - /// documentation for GLES's [glBindBufferRange][bbr]. - /// - /// [340]: https://registry.khronos.org/vulkan/specs/1.3-extensions/html/vkspec.html#VUID-VkDescriptorBufferInfo-offset-00340 - /// [341]: https://registry.khronos.org/vulkan/specs/1.3-extensions/html/vkspec.html#VUID-VkDescriptorBufferInfo-range-00341 - /// [bbr]: https://registry.khronos.org/OpenGL-Refpages/es3.0/html/glBindBufferRange.xhtml + /// This must be less or equal to the size of the buffer. pub offset: wgt::BufferAddress, /// The size of the region bound, in bytes. /// /// If `None`, the region extends from `offset` to the end of the /// buffer. Given the restrictions on `offset`, this means that /// the size is always greater than zero. pub size: Option<wgt::BufferSize>, } -impl<'a, T: DynBuffer + ?Sized> Clone for BufferBinding<'a, T> { +// We must implement this manually because `B` is not necessarily `Clone`. +impl<B: DynBuffer + ?Sized> Clone for BufferBinding<'_, B> { fn clone(&self) -> Self { BufferBinding { buffer: self.buffer, offset: self.offset, size: self.size, } } } +/// Temporary convenience trait to let us call `.get()` on `u64`s in code that +/// really wants to be using `NonZeroU64`. +/// TODO(<https://github.com/gfx-rs/wgpu/issues/3170>): remove this +pub trait ShouldBeNonZeroExt { + fn get(&self) -> u64; +} + +impl ShouldBeNonZeroExt for NonZeroU64 { + fn get(&self) -> u64 { + NonZeroU64::get(*self) + } +} + +impl ShouldBeNonZeroExt for u64 { + fn get(&self) -> u64 { + *self + } +} + +impl ShouldBeNonZeroExt for Option<NonZeroU64> { + fn get(&self) -> u64 { + match *self { + Some(non_zero) => non_zero.get(), + None => 0, + } + } +} + +impl<'a, B: DynBuffer + ?Sized> BufferBinding<'a, B> { + /// Construct a `BufferBinding` with the given contents. + /// + /// When possible, use the `binding` method on a wgpu-core `Buffer` instead + /// of this method. `Buffer::binding` validates the size of the binding + /// against the size of the buffer. + /// + /// It is more difficult to provide a validating constructor here, due to + /// not having direct access to the size of a `DynBuffer`. + /// + /// SAFETY: The caller is responsible for ensuring that a binding of `size` + /// bytes starting at `offset` is contained within the buffer. + /// + /// The `S` type parameter is a temporary convenience to allow callers to + /// pass a zero size. When the zero-size binding issue is resolved, the + /// argument should just match the type of the member. + /// TODO(<https://github.com/gfx-rs/wgpu/issues/3170>): remove the parameter + pub fn new_unchecked<S: Into<Option<NonZeroU64>>>( + buffer: &'a B, + offset: wgt::BufferAddress, + size: S, + ) -> Self { + Self { + buffer, + offset, + size: size.into(), + } + } +} + #[derive(Debug)] pub struct TextureBinding<'a, T: DynTextureView + ?Sized> { pub view: &'a T, pub usage: wgt::TextureUses, } impl<'a, T: DynTextureView + ?Sized> Clone for TextureBinding<'a, T> { fn clone(&self) -> Self {
--- a/third_party/rust/wgpu-hal/src/vulkan/device.rs +++ b/third_party/rust/wgpu-hal/src/vulkan/device.rs @@ -803,27 +803,16 @@ impl super::Device { drop_guard: None, external_memory: Some(memory), block: None, format: desc.format, copy_size: image.copy_size, }) } - /// # Safety - /// - /// - `vk_buffer`'s memory must be managed by the caller - /// - Externally imported buffers can't be mapped by `wgpu` - pub unsafe fn buffer_from_raw(vk_buffer: vk::Buffer) -> super::Buffer { - super::Buffer { - raw: vk_buffer, - block: None, - } - } - fn create_shader_module_impl( &self, spv: &[u32], ) -> Result<vk::ShaderModule, crate::DeviceError> { let vk_info = vk::ShaderModuleCreateInfo::default() .flags(vk::ShaderModuleCreateFlags::empty()) .code(spv); @@ -1148,25 +1137,32 @@ impl crate::Device for super::Device { unsafe { self.shared.set_object_name(raw, label) }; } self.counters.buffer_memory.add(block.size() as isize); self.counters.buffers.add(1); Ok(super::Buffer { raw, - block: Some(Mutex::new(block)), + block: Some(Mutex::new(super::BufferMemoryBacking::Managed(block))), }) } unsafe fn destroy_buffer(&self, buffer: super::Buffer) { unsafe { self.shared.raw.destroy_buffer(buffer.raw, None) }; if let Some(block) = buffer.block { let block = block.into_inner(); self.counters.buffer_memory.sub(block.size() as isize); - unsafe { self.mem_allocator.lock().dealloc(&*self.shared, block) }; + match block { + super::BufferMemoryBacking::Managed(block) => unsafe { + self.mem_allocator.lock().dealloc(&*self.shared, block) + }, + super::BufferMemoryBacking::VulkanMemory { memory, .. } => unsafe { + self.shared.raw.free_memory(memory, None); + }, + } } self.counters.buffers.sub(1); } unsafe fn add_raw_buffer(&self, _buffer: &super::Buffer) { self.counters.buffers.add(1); } @@ -1174,28 +1170,37 @@ impl crate::Device for super::Device { unsafe fn map_buffer( &self, buffer: &super::Buffer, range: crate::MemoryRange, ) -> Result<crate::BufferMapping, crate::DeviceError> { if let Some(ref block) = buffer.block { let size = range.end - range.start; let mut block = block.lock(); - let ptr = unsafe { block.map(&*self.shared, range.start, size as usize)? }; - let is_coherent = block - .props() - .contains(gpu_alloc::MemoryPropertyFlags::HOST_COHERENT); - Ok(crate::BufferMapping { ptr, is_coherent }) + if let super::BufferMemoryBacking::Managed(ref mut block) = *block { + let ptr = unsafe { block.map(&*self.shared, range.start, size as usize)? }; + let is_coherent = block + .props() + .contains(gpu_alloc::MemoryPropertyFlags::HOST_COHERENT); + Ok(crate::BufferMapping { ptr, is_coherent }) + } else { + crate::hal_usage_error("tried to map externally created buffer") + } } else { crate::hal_usage_error("tried to map external buffer") } } unsafe fn unmap_buffer(&self, buffer: &super::Buffer) { if let Some(ref block) = buffer.block { - unsafe { block.lock().unmap(&*self.shared) }; + match &mut *block.lock() { + super::BufferMemoryBacking::Managed(block) => unsafe { block.unmap(&*self.shared) }, + super::BufferMemoryBacking::VulkanMemory { .. } => { + crate::hal_usage_error("tried to unmap externally created buffer") + } + }; } else { crate::hal_usage_error("tried to unmap external buffer") } } unsafe fn flush_mapped_ranges<I>(&self, buffer: &super::Buffer, ranges: I) where I: Iterator<Item = crate::MemoryRange>,
--- a/third_party/rust/wgpu-hal/src/vulkan/mod.rs +++ b/third_party/rust/wgpu-hal/src/vulkan/mod.rs @@ -771,21 +771,80 @@ impl Queue { } } impl Drop for Queue { fn drop(&mut self) { unsafe { self.relay_semaphores.lock().destroy(&self.device.raw) }; } } - +#[derive(Debug)] +enum BufferMemoryBacking { + Managed(gpu_alloc::MemoryBlock<vk::DeviceMemory>), + VulkanMemory { + memory: vk::DeviceMemory, + offset: u64, + size: u64, + }, +} +impl BufferMemoryBacking { + fn memory(&self) -> &vk::DeviceMemory { + match self { + Self::Managed(m) => m.memory(), + Self::VulkanMemory { memory, .. } => memory, + } + } + fn offset(&self) -> u64 { + match self { + Self::Managed(m) => m.offset(), + Self::VulkanMemory { offset, .. } => *offset, + } + } + fn size(&self) -> u64 { + match self { + Self::Managed(m) => m.size(), + Self::VulkanMemory { size, .. } => *size, + } + } +} #[derive(Debug)] pub struct Buffer { raw: vk::Buffer, - block: Option<Mutex<gpu_alloc::MemoryBlock<vk::DeviceMemory>>>, + block: Option<Mutex<BufferMemoryBacking>>, +} +impl Buffer { + /// # Safety + /// + /// - `vk_buffer`'s memory must be managed by the caller + /// - Externally imported buffers can't be mapped by `wgpu` + pub unsafe fn from_raw(vk_buffer: vk::Buffer) -> Self { + Self { + raw: vk_buffer, + block: None, + } + } + /// # Safety + /// - We will use this buffer and the buffer's backing memory range as if we have exclusive ownership over it, until the wgpu resource is dropped and the wgpu-hal object is cleaned up + /// - Externally imported buffers can't be mapped by `wgpu` + /// - `offset` and `size` must be valid with the allocation of `memory` + pub unsafe fn from_raw_managed( + vk_buffer: vk::Buffer, + memory: vk::DeviceMemory, + offset: u64, + size: u64, + ) -> Self { + Self { + raw: vk_buffer, + block: Some(Mutex::new(BufferMemoryBacking::VulkanMemory { + memory, + offset, + size, + })), + } + } } impl crate::DynBuffer for Buffer {} #[derive(Debug)] pub struct AccelerationStructure { raw: vk::AccelerationStructureKHR, buffer: vk::Buffer,
--- a/third_party/rust/wgpu-types/.cargo-checksum.json +++ b/third_party/rust/wgpu-types/.cargo-checksum.json @@ -1,1 +1,1 @@ -{"files":{"Cargo.toml":"8202270e283ceac9e9ea19937413a5bbc2f7380a9aa87710fb0bc3e06a991a73","LICENSE.APACHE":"a6cba85bc92e0cff7a450b1d873c0eaa2e9fc96bf472df0247a26bec77bf3ff9","LICENSE.MIT":"c7fea58d1cfe49634cd92e54fc10a9d871f4b275321a4cd8c09e449122caaeb4","src/assertions.rs":"e4d2d40bc1e870a59637f4b9574743e19565a62f6dbcc21cb18a76b666b796eb","src/cast_utils.rs":"33f03a57ccbedef2699f2305bec584c623db1fd28bfdf584d1260da4fbecd529","src/counters.rs":"e2a1c69126bdb6a35f74d5062e89e242eb955014d95c2b9e6e1b03f7b4b5bd98","src/env.rs":"26ffc91867625784159bcf391881187aa92cf92b81b1f40959ce1b96ae6d554d","src/error.rs":"0109e6209cf152abbfd0cee85dd934fb24f2304bf6adad6fb684b77f151fb158","src/features.rs":"be6930dfba6465fb84f43ac41d3e62f49a2be607ade17904dd7e49f69caef678","src/instance.rs":"984b152b4653142516b82bc5c3b8bb5e112603d19cf09aa38ede2ca5eb91d706","src/lib.rs":"05a1bdb8141d98f7b9294f89ad522a86cfef78d564507cf96d44e28d3adba5b1","src/math.rs":"3046121800bded318b7d219aea401907e7d3bba3b998df6745a71e76f0734de2","src/transfers.rs":"66fbca652e04751f7912d1b75f009d1f6ad83d41ed6c624ca7f7c34b26b480b3"},"package":null} \ No newline at end of file +{"files":{"Cargo.toml":"1c4e4f9ab000d2ff511c6e9f2bccfc1469ac9c5d7b40798b2422a67910e3118a","LICENSE.APACHE":"a6cba85bc92e0cff7a450b1d873c0eaa2e9fc96bf472df0247a26bec77bf3ff9","LICENSE.MIT":"c7fea58d1cfe49634cd92e54fc10a9d871f4b275321a4cd8c09e449122caaeb4","src/assertions.rs":"e4d2d40bc1e870a59637f4b9574743e19565a62f6dbcc21cb18a76b666b796eb","src/cast_utils.rs":"33f03a57ccbedef2699f2305bec584c623db1fd28bfdf584d1260da4fbecd529","src/counters.rs":"e2a1c69126bdb6a35f74d5062e89e242eb955014d95c2b9e6e1b03f7b4b5bd98","src/env.rs":"26ffc91867625784159bcf391881187aa92cf92b81b1f40959ce1b96ae6d554d","src/error.rs":"0109e6209cf152abbfd0cee85dd934fb24f2304bf6adad6fb684b77f151fb158","src/features.rs":"be6930dfba6465fb84f43ac41d3e62f49a2be607ade17904dd7e49f69caef678","src/instance.rs":"984b152b4653142516b82bc5c3b8bb5e112603d19cf09aa38ede2ca5eb91d706","src/lib.rs":"05a1bdb8141d98f7b9294f89ad522a86cfef78d564507cf96d44e28d3adba5b1","src/math.rs":"3046121800bded318b7d219aea401907e7d3bba3b998df6745a71e76f0734de2","src/transfers.rs":"25f47e9cbc5887f849f5eb4d8952d89de6377df40f480ebbea61c58d2e0e7fc6"},"package":null} \ No newline at end of file
--- a/third_party/rust/wgpu-types/Cargo.toml +++ b/third_party/rust/wgpu-types/Cargo.toml @@ -8,17 +8,17 @@ # If you are reading this file be aware that the original Cargo.toml # will likely look very different (and much more reasonable). # See Cargo.toml.orig for the original contents. [package] edition = "2021" rust-version = "1.82.0" name = "wgpu-types" -version = "25.0.0" +version = "26.0.0" authors = ["gfx-rs developers"] build = false autolib = false autobins = false autoexamples = false autotests = false autobenches = false description = "Common types and utilities for wgpu, the cross-platform, safe, pure-rust graphics API"
--- a/third_party/rust/wgpu-types/src/transfers.rs +++ b/third_party/rust/wgpu-types/src/transfers.rs @@ -1,52 +1,87 @@ use crate::{BufferAddress, Extent3d, TexelCopyBufferLayout, TextureAspect, TextureFormat}; impl TexelCopyBufferLayout { /// Extract a variety of information about the given copy operation. + /// + /// Returns an error if the size of the copy overflows a `u64`, or if the arguments are + /// not valid in conjunction with the `bytes_per_row` or `rows_per_image` parameters in + /// `self`. + /// + /// This is public for use by `wgpu-core` and `wgpu-hal`, it is not a stable API. + /// + /// Although WebGPU requires that `bytes_per_row` and `rows_per_image` be specified in + /// cases where they apply, we are more lenient here (although it's not clear if that is + /// necessary). Our caller, `validate_linear_texture_data`, enforces this and other + /// WebGPU requirements on the copy parameters that we do not check here. + #[doc(hidden)] #[inline(always)] pub fn get_buffer_texture_copy_info( &self, format: TextureFormat, aspect: TextureAspect, copy_size: &Extent3d, - ) -> BufferTextureCopyInfo { - // Convert all inputs to BufferAddress (u64) to avoid some of the overflow issues - // Note: u64 is not always enough to prevent overflow, especially when multiplying - // something with a potentially large depth value, so it is preferable to validate - // the copy size before calling this function (for example via `validate_texture_copy_range`). - let copy_width = copy_size.width as BufferAddress; - let copy_height = copy_size.height as BufferAddress; - let depth_or_array_layers = copy_size.depth_or_array_layers as BufferAddress; + ) -> Result<BufferTextureCopyInfo, Error> { + let copy_width = BufferAddress::from(copy_size.width); + let copy_height = BufferAddress::from(copy_size.height); + let depth_or_array_layers = BufferAddress::from(copy_size.depth_or_array_layers); - let block_size_bytes = format.block_copy_size(Some(aspect)).unwrap() as BufferAddress; + let block_size_bytes = BufferAddress::from(format.block_copy_size(Some(aspect)).unwrap()); let (block_width, block_height) = format.block_dimensions(); - let block_width_texels = block_width as BufferAddress; - let block_height_texels = block_height as BufferAddress; + let block_width_texels = BufferAddress::from(block_width); + let block_height_texels = BufferAddress::from(block_height); let width_blocks = copy_width.div_ceil(block_width_texels); let height_blocks = copy_height.div_ceil(block_height_texels); + // The spec calls this bytesInLastRow. let row_bytes_dense = width_blocks * block_size_bytes; - - let row_stride_bytes = self.bytes_per_row.map_or(row_bytes_dense, u64::from); - let image_stride_rows = self.rows_per_image.map_or(height_blocks, u64::from); - - let image_stride_bytes = row_stride_bytes * image_stride_rows; + let row_stride_bytes = match self.bytes_per_row.map(BufferAddress::from) { + Some(bytes_per_row) if bytes_per_row >= row_bytes_dense => bytes_per_row, + Some(_) => return Err(Error::InvalidBytesPerRow), + None => row_bytes_dense, + }; let image_rows_dense = height_blocks; - let image_bytes_dense = - image_rows_dense.saturating_sub(1) * row_stride_bytes + row_bytes_dense; + let image_stride_rows = match self.rows_per_image.map(BufferAddress::from) { + Some(rows_per_image) if rows_per_image >= image_rows_dense => rows_per_image, + Some(_) => return Err(Error::InvalidRowsPerImage), + None => image_rows_dense, + }; + + let image_bytes_dense = match image_rows_dense.checked_sub(1) { + Some(rows_minus_one) => rows_minus_one + .checked_mul(row_stride_bytes) + .ok_or(Error::ImageBytesOverflow(false))? + .checked_add(row_bytes_dense) + .ok_or(Error::ImageBytesOverflow(true))?, + None => 0, + }; - let mut bytes_in_copy = image_stride_bytes * depth_or_array_layers.saturating_sub(1); - if height_blocks > 0 { - bytes_in_copy += row_stride_bytes * (height_blocks - 1) + row_bytes_dense; - } + // It is possible that `image_stride_bytes` overflows, but the actual + // copy size does not, when the copy only has a single layer and + // `image_size_bytes` is not used. We don't worry about handling this + // gracefully because WebGPU texture size limits should keep things out + // of this realm entirely. + let image_stride_bytes = row_stride_bytes + .checked_mul(image_stride_rows) + .ok_or(Error::ImageStrideOverflow)?; - BufferTextureCopyInfo { + let bytes_in_copy = if depth_or_array_layers <= 1 { + depth_or_array_layers * image_bytes_dense + } else { + (depth_or_array_layers - 1) + .checked_mul(image_stride_bytes) + .ok_or(Error::ArraySizeOverflow(false))? + .checked_add(image_bytes_dense) + .ok_or(Error::ArraySizeOverflow(true))? + }; + + Ok(BufferTextureCopyInfo { copy_width, copy_height, depth_or_array_layers, offset: self.offset, block_size_bytes, block_width_texels, @@ -60,17 +95,17 @@ impl TexelCopyBufferLayout { image_stride_rows, image_stride_bytes, image_rows_dense, image_bytes_dense, bytes_in_copy, - } + }) } } /// Information about a copy between a buffer and a texture. /// /// Mostly used for internal calculations, but useful nonetheless. /// Generated by [`TexelCopyBufferLayout::get_buffer_texture_copy_info`]. #[derive(Debug, Clone, Copy, PartialEq, Eq)] @@ -122,35 +157,78 @@ pub struct BufferTextureCopyInfo { pub image_bytes_dense: u64, /// The total number of bytes in the copy region. /// /// This includes all padding except the padding after the last row in the copy. pub bytes_in_copy: u64, } +/// Errors that can occur while populating `BufferTextureCopyInfo`. +// +// We use the additional detail provided by these errors (over wgpu-core's +// `TransferError`) to improve the reliability of the tests in this module. It +// doesn't seem worth plumbing them upwards, because at the API level it +// shouldn't be possible to exceed them without exceeding the WebGPU limits on +// texture dimension. But the WebGPU limits are not currently enforced, so we +// have to do something here to protect against overflows. +// +// Even when the WebGPU limits are enforced, it may still be useful to keep the +// checks here as a failsafe if the correctness of the primary limit enforcement +// is not immediately apparent. +#[derive(Clone, Copy, Debug, Eq, PartialEq)] +pub enum BufferTextureCopyInfoError { + /// The `bytes_per_row` is too small for the texture width. + InvalidBytesPerRow, + /// The `rows_per_image` is too small for the texture height. + InvalidRowsPerImage, + /// The image stride overflows a `u64`. + ImageStrideOverflow, + /// The last-layer byte size overflows a `u64`. + /// + /// The bool value indicates whether the multiplication (false) or the + /// addition (true) overflowed. + ImageBytesOverflow(bool), + /// The total size of the copy overflows a `u64`. + /// + /// The bool value indicates whether the multiplication (false) or the + /// addition (true) overflowed. + ArraySizeOverflow(bool), +} +type Error = BufferTextureCopyInfoError; + #[cfg(test)] mod tests { use super::*; + #[derive(Clone)] struct LTDTest { layout: TexelCopyBufferLayout, format: TextureFormat, aspect: TextureAspect, copy_size: Extent3d, expected_result: BufferTextureCopyInfo, + // Normally a Result<BufferTextureCopyInfo, Error> would be make sense, + // but since the existing tests were written to mutate + // `LTDTest.expected_result`, keeping this separate avoids a bunch of + // `unwrap`s. + expected_error: Option<Error>, } impl LTDTest { #[track_caller] fn run(&self) { let linear_texture_data = self.layout .get_buffer_texture_copy_info(self.format, self.aspect, &self.copy_size); - assert_eq!(linear_texture_data, self.expected_result); + let expected = match self.expected_error { + Some(err) => Err(err), + None => Ok(self.expected_result), + }; + assert_eq!(linear_texture_data, expected); } } #[test] fn linear_texture_data_1d_copy() { let mut test = LTDTest { layout: TexelCopyBufferLayout { offset: 0, @@ -177,16 +255,17 @@ mod tests { row_bytes_dense: 16, row_stride_bytes: 16, image_stride_rows: 1, image_stride_bytes: 16, image_rows_dense: 1, image_bytes_dense: 16, bytes_in_copy: 16, }, + expected_error: None, }; test.run(); // Changing bytes_per_row should only change the bytes_per_row, not the bytes_in_copy // as that is only affected by the last row size. test.layout.bytes_per_row = Some(32); test.expected_result.row_stride_bytes = 32; @@ -206,17 +285,17 @@ mod tests { test.layout.offset = 4; test.expected_result.offset = 4; test.run(); } #[test] fn linear_texture_data_2d_3d_copy() { - let mut test = LTDTest { + let template = LTDTest { layout: TexelCopyBufferLayout { offset: 0, bytes_per_row: None, rows_per_image: None, }, format: TextureFormat::Rgba8Unorm, aspect: TextureAspect::All, copy_size: Extent3d { @@ -237,32 +316,93 @@ mod tests { row_bytes_dense: 4 * 7, row_stride_bytes: 4 * 7, image_stride_rows: 12, image_stride_bytes: 4 * 7 * 12, image_rows_dense: 12, image_bytes_dense: 4 * 7 * 12, bytes_in_copy: 4 * 7 * 12, }, + expected_error: None, }; + let mut test = template.clone(); test.run(); // Changing bytes_per_row changes a number of other properties. test.layout.bytes_per_row = Some(48); test.expected_result.row_stride_bytes = 48; test.expected_result.image_stride_bytes = 48 * 12; test.expected_result.image_bytes_dense = 48 * 11 + (4 * 7); test.expected_result.bytes_in_copy = 48 * 11 + (4 * 7); + test.run(); // Making this a 3D copy only changes the depth_or_array_layers and the bytes_in_copy. test.copy_size.depth_or_array_layers = 4; test.expected_result.depth_or_array_layers = 4; test.expected_result.bytes_in_copy = 48 * 12 * 3 + 48 * 11 + (4 * 7); // 4 layers + test.run(); + // Changing rows_per_image + test.layout.rows_per_image = Some(20); + test.expected_result.image_stride_rows = 20; + test.expected_result.image_stride_bytes = 20 * test.expected_result.row_stride_bytes; + test.expected_result.bytes_in_copy = 48 * 20 * 3 + 48 * 11 + (4 * 7); // 4 layers + test.run(); + + // Invalid because the row stride is too small. + let mut test = template.clone(); + test.layout.bytes_per_row = Some(20); + test.expected_error = Some(Error::InvalidBytesPerRow); + test.run(); + + // Invalid because the image stride is too small. + let mut test = template.clone(); + test.layout.rows_per_image = Some(8); + test.expected_error = Some(Error::InvalidRowsPerImage); + test.run(); + + // Invalid because width * height * texel_size_bytes overflows. + let mut test = template.clone(); + test.copy_size.width = u32::MAX; + test.copy_size.height = u32::MAX; + test.expected_error = Some(Error::ImageBytesOverflow(false)); + test.run(); + + // Invalid because the addition of row_bytes_dense overflows. + // (But the product rows_minus_one * row_stride_bytes does not overflow.) + let mut test = template.clone(); + test.copy_size.width = 0x8000_0000; + test.copy_size.height = 0x8000_0000; + test.expected_error = Some(Error::ImageBytesOverflow(true)); + test.run(); + + // Invalid because image_stride_bytes overflows. + let mut test = template.clone(); + test.copy_size.width = 0x8000_0000; + test.layout.rows_per_image = Some(0x8000_0000); + test.expected_result.image_stride_rows = 0x8000_0000; + test.expected_error = Some(Error::ImageStrideOverflow); + test.run(); + + // Invalid because (layers - 1) * image_stride_bytes overflows. + let mut test = template.clone(); + test.copy_size.depth_or_array_layers = 0x8000_0000; + test.copy_size.width = 0x1_0000; + test.copy_size.height = 0x1_0000; + test.expected_error = Some(Error::ArraySizeOverflow(false)); + test.run(); + + // Invalid because the total size of the copy overflows (but the product + // (layers - 1) * image_stride_bytes does not overflow). + let mut test = template.clone(); + test.copy_size.depth_or_array_layers = 0x3fff_8001; + test.copy_size.width = 0x1_0001; + test.copy_size.height = 0x1_0001; + test.expected_error = Some(Error::ArraySizeOverflow(true)); test.run(); } #[test] fn linear_texture_data_2d_3d_compressed_copy() { let mut test = LTDTest { layout: TexelCopyBufferLayout { offset: 0, @@ -289,16 +429,17 @@ mod tests { row_bytes_dense: 8 * 2, // block size * width_blocks row_stride_bytes: 8 * 2, image_stride_rows: 4, image_stride_bytes: 8 * 2 * 4, // block size * width_blocks * height_blocks image_rows_dense: 4, image_bytes_dense: 8 * 2 * 4, bytes_in_copy: 8 * 2 * 4, }, + expected_error: None, }; test.run(); // Changing bytes_per_row. test.layout.bytes_per_row = Some(48); test.expected_result.row_stride_bytes = 48; test.expected_result.image_stride_bytes = 48 * 4;