mirror of
https://github.com/gfx-rs/wgpu.git
synced 2024-11-25 08:13:27 +00:00
[core, hal, types] Clarify wgpu_hal
's bounds check promises.
In `wgpu_hal`: - Document that `wgpu_hal` guarantees that shaders will not access buffer contents beyond the bindgroups' bound regions, rounded up to some adapter-specific alignment. Introduce the term "accessible region" for the portion of the buffer that shaders can actually get at. - Document that all bets are off if you disable bounds checks with `ShaderModuleDescriptor::runtime_checks`. - Provide this alignment in `wgpu_hal::Alignments`. Update all backends appropriately. - In the Vulkan backend, use Naga to inject bounds checks on buffer accesses unless `robustBufferAccess2` is available; `robustBufferAccess` is not sufficient. Retrieve `VK_EXT_robustness2`'s properties, as needed to discover the alignment above. In `wgpu_core`: - Use buffer bindings' accessible regions to determine which parts of the buffer need to be initialized. In `wgpu_types`: - Document some of the possible effects of using `ShaderBoundsChecks::unchecked`. Fixes #1813.
This commit is contained in:
parent
de7765bd28
commit
ee35b0e586
@ -96,6 +96,7 @@ By @teoxoy [#6134](https://github.com/gfx-rs/wgpu/pull/6134).
|
|||||||
- Fix crash when dropping the surface after the device. By @wumpf in [#6052](https://github.com/gfx-rs/wgpu/pull/6052)
|
- Fix crash when dropping the surface after the device. By @wumpf in [#6052](https://github.com/gfx-rs/wgpu/pull/6052)
|
||||||
- Fix error message that is thrown in create_render_pass to no longer say `compute_pass`. By @matthew-wong1 [#6041](https://github.com/gfx-rs/wgpu/pull/6041)
|
- Fix error message that is thrown in create_render_pass to no longer say `compute_pass`. By @matthew-wong1 [#6041](https://github.com/gfx-rs/wgpu/pull/6041)
|
||||||
- Add `VideoFrame` to `ExternalImageSource` enum. By @jprochazk in [#6170](https://github.com/gfx-rs/wgpu/pull/6170)
|
- Add `VideoFrame` to `ExternalImageSource` enum. By @jprochazk in [#6170](https://github.com/gfx-rs/wgpu/pull/6170)
|
||||||
|
- Document `wgpu_hal` bounds-checking promises, and adapt `wgpu_core`'s lazy initialization logic to the slightly weaker-than-expected guarantees. By @jimblandy in [#6201](https://github.com/gfx-rs/wgpu/pull/6201)
|
||||||
|
|
||||||
#### GLES / OpenGL
|
#### GLES / OpenGL
|
||||||
|
|
||||||
|
@ -884,6 +884,16 @@ pub(crate) fn buffer_binding_type_alignment(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub(crate) fn buffer_binding_type_bounds_check_alignment(
|
||||||
|
alignments: &hal::Alignments,
|
||||||
|
binding_type: wgt::BufferBindingType,
|
||||||
|
) -> wgt::BufferAddress {
|
||||||
|
match binding_type {
|
||||||
|
wgt::BufferBindingType::Uniform => alignments.uniform_bounds_check_alignment.get(),
|
||||||
|
wgt::BufferBindingType::Storage { .. } => wgt::COPY_BUFFER_ALIGNMENT,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct BindGroup {
|
pub struct BindGroup {
|
||||||
pub(crate) raw: Snatchable<Box<dyn hal::DynBindGroup>>,
|
pub(crate) raw: Snatchable<Box<dyn hal::DynBindGroup>>,
|
||||||
|
@ -39,7 +39,9 @@ use once_cell::sync::OnceCell;
|
|||||||
|
|
||||||
use smallvec::SmallVec;
|
use smallvec::SmallVec;
|
||||||
use thiserror::Error;
|
use thiserror::Error;
|
||||||
use wgt::{DeviceLostReason, TextureFormat, TextureSampleType, TextureViewDimension};
|
use wgt::{
|
||||||
|
math::align_to, DeviceLostReason, TextureFormat, TextureSampleType, TextureViewDimension,
|
||||||
|
};
|
||||||
|
|
||||||
use std::{
|
use std::{
|
||||||
borrow::Cow,
|
borrow::Cow,
|
||||||
@ -2004,10 +2006,21 @@ impl Device {
|
|||||||
late_buffer_binding_sizes.insert(binding, late_size);
|
late_buffer_binding_sizes.insert(binding, late_size);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// This was checked against the device's alignment requirements above,
|
||||||
|
// which should always be a multiple of `COPY_BUFFER_ALIGNMENT`.
|
||||||
assert_eq!(bb.offset % wgt::COPY_BUFFER_ALIGNMENT, 0);
|
assert_eq!(bb.offset % wgt::COPY_BUFFER_ALIGNMENT, 0);
|
||||||
|
|
||||||
|
// `wgpu_hal` only restricts shader access to bound buffer regions with
|
||||||
|
// a certain resolution. For the sake of lazy initialization, round up
|
||||||
|
// the size of the bound range to reflect how much of the buffer is
|
||||||
|
// actually going to be visible to the shader.
|
||||||
|
let bounds_check_alignment =
|
||||||
|
binding_model::buffer_binding_type_bounds_check_alignment(&self.alignments, binding_ty);
|
||||||
|
let visible_size = align_to(bind_size, bounds_check_alignment);
|
||||||
|
|
||||||
used_buffer_ranges.extend(buffer.initialization_status.read().create_action(
|
used_buffer_ranges.extend(buffer.initialization_status.read().create_action(
|
||||||
buffer,
|
buffer,
|
||||||
bb.offset..bb.offset + bind_size,
|
bb.offset..bb.offset + visible_size,
|
||||||
MemoryInitKind::NeedsInitializedMemory,
|
MemoryInitKind::NeedsInitializedMemory,
|
||||||
));
|
));
|
||||||
|
|
||||||
|
@ -519,6 +519,9 @@ impl super::Adapter {
|
|||||||
Direct3D12::D3D12_TEXTURE_DATA_PITCH_ALIGNMENT as u64,
|
Direct3D12::D3D12_TEXTURE_DATA_PITCH_ALIGNMENT as u64,
|
||||||
)
|
)
|
||||||
.unwrap(),
|
.unwrap(),
|
||||||
|
// Direct3D correctly bounds-checks all array accesses:
|
||||||
|
// https://microsoft.github.io/DirectX-Specs/d3d/archive/D3D11_3_FunctionalSpec.htm#18.6.8.2%20Device%20Memory%20Reads
|
||||||
|
uniform_bounds_check_alignment: wgt::BufferSize::new(1).unwrap(),
|
||||||
},
|
},
|
||||||
downlevel,
|
downlevel,
|
||||||
},
|
},
|
||||||
|
@ -841,6 +841,16 @@ impl super::Adapter {
|
|||||||
alignments: crate::Alignments {
|
alignments: crate::Alignments {
|
||||||
buffer_copy_offset: wgt::BufferSize::new(4).unwrap(),
|
buffer_copy_offset: wgt::BufferSize::new(4).unwrap(),
|
||||||
buffer_copy_pitch: wgt::BufferSize::new(4).unwrap(),
|
buffer_copy_pitch: wgt::BufferSize::new(4).unwrap(),
|
||||||
|
// #6151: `wgpu_hal::gles` doesn't ask Naga to inject bounds
|
||||||
|
// checks in GLSL, and it doesn't request extensions like
|
||||||
|
// `KHR_robust_buffer_access_behavior` that would provide
|
||||||
|
// them, so we can't really implement the checks promised by
|
||||||
|
// [`crate::BufferBinding`].
|
||||||
|
//
|
||||||
|
// Since this is a pre-existing condition, for the time
|
||||||
|
// being, provide 1 as the value here, to cause as little
|
||||||
|
// trouble as possible.
|
||||||
|
uniform_bounds_check_alignment: wgt::BufferSize::new(1).unwrap(),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
@ -1647,9 +1647,27 @@ pub struct InstanceDescriptor<'a> {
|
|||||||
pub struct Alignments {
|
pub struct Alignments {
|
||||||
/// The alignment of the start of the buffer used as a GPU copy source.
|
/// The alignment of the start of the buffer used as a GPU copy source.
|
||||||
pub buffer_copy_offset: wgt::BufferSize,
|
pub buffer_copy_offset: wgt::BufferSize,
|
||||||
|
|
||||||
/// The alignment of the row pitch of the texture data stored in a buffer that is
|
/// The alignment of the row pitch of the texture data stored in a buffer that is
|
||||||
/// used in a GPU copy operation.
|
/// used in a GPU copy operation.
|
||||||
pub buffer_copy_pitch: wgt::BufferSize,
|
pub buffer_copy_pitch: wgt::BufferSize,
|
||||||
|
|
||||||
|
/// The finest alignment of bound range checking for uniform buffers.
|
||||||
|
///
|
||||||
|
/// When `wgpu_hal` restricts shader references to the [accessible
|
||||||
|
/// region][ar] of a [`Uniform`] buffer, the size of the accessible region
|
||||||
|
/// is the bind group binding's stated [size], rounded up to the next
|
||||||
|
/// multiple of this value.
|
||||||
|
///
|
||||||
|
/// We don't need an analogous field for storage buffer bindings, because
|
||||||
|
/// all our backends promise to enforce the size at least to a four-byte
|
||||||
|
/// alignment, and `wgpu_hal` requires bound range lengths to be a multiple
|
||||||
|
/// of four anyway.
|
||||||
|
///
|
||||||
|
/// [ar]: struct.BufferBinding.html#accessible-region
|
||||||
|
/// [`Uniform`]: wgt::BufferBindingType::Uniform
|
||||||
|
/// [size]: BufferBinding::size
|
||||||
|
pub uniform_bounds_check_alignment: wgt::BufferSize,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
@ -1819,6 +1837,40 @@ pub struct PipelineLayoutDescriptor<'a, B: DynBindGroupLayout + ?Sized> {
|
|||||||
pub push_constant_ranges: &'a [wgt::PushConstantRange],
|
pub push_constant_ranges: &'a [wgt::PushConstantRange],
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// A region of a buffer made visible to shaders via a [`BindGroup`].
|
||||||
|
///
|
||||||
|
/// [`BindGroup`]: Api::BindGroup
|
||||||
|
///
|
||||||
|
/// ## 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`]:
|
||||||
|
///
|
||||||
|
/// - 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
|
||||||
|
/// [`Alignments::uniform_bounds_check_alignment`].
|
||||||
|
///
|
||||||
|
/// Note that this guarantee is stricter than WGSL's requirements for
|
||||||
|
/// [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
|
||||||
|
/// [`offset`]: BufferBinding::offset
|
||||||
|
/// [`size`]: BufferBinding::size
|
||||||
|
/// [`Storage`]: wgt::BufferBindingType::Storage
|
||||||
|
/// [`Uniform`]: wgt::BufferBindingType::Uniform
|
||||||
|
/// [woob]: https://gpuweb.github.io/gpuweb/wgsl/#out-of-bounds-access-sec
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct BufferBinding<'a, B: DynBuffer + ?Sized> {
|
pub struct BufferBinding<'a, B: DynBuffer + ?Sized> {
|
||||||
/// The buffer being bound.
|
/// The buffer being bound.
|
||||||
@ -1937,6 +1989,26 @@ pub enum ShaderInput<'a> {
|
|||||||
|
|
||||||
pub struct ShaderModuleDescriptor<'a> {
|
pub struct ShaderModuleDescriptor<'a> {
|
||||||
pub label: Label<'a>,
|
pub label: Label<'a>,
|
||||||
|
|
||||||
|
/// Enforce bounds checks in shaders, even if the underlying driver doesn't
|
||||||
|
/// support doing so natively.
|
||||||
|
///
|
||||||
|
/// When this is `true`, `wgpu_hal` promises that shaders can only read or
|
||||||
|
/// write the [accessible region][ar] of a bindgroup's buffer bindings. If
|
||||||
|
/// the underlying graphics platform cannot implement these bounds checks
|
||||||
|
/// itself, `wgpu_hal` will inject bounds checks before presenting the
|
||||||
|
/// shader to the platform.
|
||||||
|
///
|
||||||
|
/// When this is `false`, `wgpu_hal` only enforces such bounds checks if the
|
||||||
|
/// underlying platform provides a way to do so itself. `wgpu_hal` does not
|
||||||
|
/// itself add any bounds checks to generated shader code.
|
||||||
|
///
|
||||||
|
/// Note that `wgpu_hal` users may try to initialize only those portions of
|
||||||
|
/// buffers that they anticipate might be read from. Passing `false` here
|
||||||
|
/// may allow shaders to see wider regions of the buffers than expected,
|
||||||
|
/// making such deferred initialization visible to the application.
|
||||||
|
///
|
||||||
|
/// [ar]: struct.BufferBinding.html#accessible-region
|
||||||
pub runtime_checks: bool,
|
pub runtime_checks: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -997,6 +997,10 @@ impl super::PrivateCapabilities {
|
|||||||
alignments: crate::Alignments {
|
alignments: crate::Alignments {
|
||||||
buffer_copy_offset: wgt::BufferSize::new(self.buffer_alignment).unwrap(),
|
buffer_copy_offset: wgt::BufferSize::new(self.buffer_alignment).unwrap(),
|
||||||
buffer_copy_pitch: wgt::BufferSize::new(4).unwrap(),
|
buffer_copy_pitch: wgt::BufferSize::new(4).unwrap(),
|
||||||
|
// This backend has Naga incorporate bounds checks into the
|
||||||
|
// Metal Shading Language it generates, so from `wgpu_hal`'s
|
||||||
|
// users' point of view, references are tightly checked.
|
||||||
|
uniform_bounds_check_alignment: wgt::BufferSize::new(1).unwrap(),
|
||||||
},
|
},
|
||||||
downlevel,
|
downlevel,
|
||||||
}
|
}
|
||||||
|
@ -342,9 +342,6 @@ impl PhysicalDeviceFeatures {
|
|||||||
None
|
None
|
||||||
},
|
},
|
||||||
robustness2: if enabled_extensions.contains(&ext::robustness2::NAME) {
|
robustness2: if enabled_extensions.contains(&ext::robustness2::NAME) {
|
||||||
// Note: enabling `robust_buffer_access2` isn't requires, strictly speaking
|
|
||||||
// since we can enable `robust_buffer_access` all the time. But it improves
|
|
||||||
// program portability, so we opt into it if they are supported.
|
|
||||||
Some(
|
Some(
|
||||||
vk::PhysicalDeviceRobustness2FeaturesEXT::default()
|
vk::PhysicalDeviceRobustness2FeaturesEXT::default()
|
||||||
.robust_buffer_access2(private_caps.robust_buffer_access2)
|
.robust_buffer_access2(private_caps.robust_buffer_access2)
|
||||||
@ -842,6 +839,10 @@ pub struct PhysicalDeviceProperties {
|
|||||||
/// `VK_EXT_subgroup_size_control` extension, promoted to Vulkan 1.3.
|
/// `VK_EXT_subgroup_size_control` extension, promoted to Vulkan 1.3.
|
||||||
subgroup_size_control: Option<vk::PhysicalDeviceSubgroupSizeControlProperties<'static>>,
|
subgroup_size_control: Option<vk::PhysicalDeviceSubgroupSizeControlProperties<'static>>,
|
||||||
|
|
||||||
|
/// Additional `vk::PhysicalDevice` properties from the
|
||||||
|
/// `VK_EXT_robustness2` extension.
|
||||||
|
robustness2: Option<vk::PhysicalDeviceRobustness2PropertiesEXT<'static>>,
|
||||||
|
|
||||||
/// The device API version.
|
/// The device API version.
|
||||||
///
|
///
|
||||||
/// Which is the version of Vulkan supported for device-level functionality.
|
/// Which is the version of Vulkan supported for device-level functionality.
|
||||||
@ -1097,13 +1098,38 @@ impl PhysicalDeviceProperties {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn to_hal_alignments(&self) -> crate::Alignments {
|
/// Return a `wgpu_hal::Alignments` structure describing this adapter.
|
||||||
|
///
|
||||||
|
/// The `using_robustness2` argument says how this adapter will implement
|
||||||
|
/// `wgpu_hal`'s guarantee that shaders can only read the [accessible
|
||||||
|
/// region][ar] of bindgroup's buffer bindings:
|
||||||
|
///
|
||||||
|
/// - If this adapter will depend on `VK_EXT_robustness2`'s
|
||||||
|
/// `robustBufferAccess2` feature to apply bounds checks to shader buffer
|
||||||
|
/// access, `using_robustness2` must be `true`.
|
||||||
|
///
|
||||||
|
/// - Otherwise, this adapter must use Naga to inject bounds checks on
|
||||||
|
/// buffer accesses, and `using_robustness2` must be `false`.
|
||||||
|
///
|
||||||
|
/// [ar]: ../../struct.BufferBinding.html#accessible-region
|
||||||
|
fn to_hal_alignments(&self, using_robustness2: bool) -> crate::Alignments {
|
||||||
let limits = &self.properties.limits;
|
let limits = &self.properties.limits;
|
||||||
crate::Alignments {
|
crate::Alignments {
|
||||||
buffer_copy_offset: wgt::BufferSize::new(limits.optimal_buffer_copy_offset_alignment)
|
buffer_copy_offset: wgt::BufferSize::new(limits.optimal_buffer_copy_offset_alignment)
|
||||||
.unwrap(),
|
.unwrap(),
|
||||||
buffer_copy_pitch: wgt::BufferSize::new(limits.optimal_buffer_copy_row_pitch_alignment)
|
buffer_copy_pitch: wgt::BufferSize::new(limits.optimal_buffer_copy_row_pitch_alignment)
|
||||||
.unwrap(),
|
.unwrap(),
|
||||||
|
uniform_bounds_check_alignment: {
|
||||||
|
let alignment = if using_robustness2 {
|
||||||
|
self.robustness2
|
||||||
|
.unwrap() // if we're using it, we should have its properties
|
||||||
|
.robust_uniform_buffer_access_size_alignment
|
||||||
|
} else {
|
||||||
|
// If the `robustness2` properties are unavailable, then `robustness2` is not available either Naga-injected bounds checks are precise.
|
||||||
|
1
|
||||||
|
};
|
||||||
|
wgt::BufferSize::new(alignment).unwrap()
|
||||||
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1133,6 +1159,7 @@ impl super::InstanceShared {
|
|||||||
let supports_subgroup_size_control = capabilities.device_api_version
|
let supports_subgroup_size_control = capabilities.device_api_version
|
||||||
>= vk::API_VERSION_1_3
|
>= vk::API_VERSION_1_3
|
||||||
|| capabilities.supports_extension(ext::subgroup_size_control::NAME);
|
|| capabilities.supports_extension(ext::subgroup_size_control::NAME);
|
||||||
|
let supports_robustness2 = capabilities.supports_extension(ext::robustness2::NAME);
|
||||||
|
|
||||||
let supports_acceleration_structure =
|
let supports_acceleration_structure =
|
||||||
capabilities.supports_extension(khr::acceleration_structure::NAME);
|
capabilities.supports_extension(khr::acceleration_structure::NAME);
|
||||||
@ -1180,6 +1207,13 @@ impl super::InstanceShared {
|
|||||||
properties2 = properties2.push_next(next);
|
properties2 = properties2.push_next(next);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if supports_robustness2 {
|
||||||
|
let next = capabilities
|
||||||
|
.robustness2
|
||||||
|
.insert(vk::PhysicalDeviceRobustness2PropertiesEXT::default());
|
||||||
|
properties2 = properties2.push_next(next);
|
||||||
|
}
|
||||||
|
|
||||||
unsafe {
|
unsafe {
|
||||||
get_device_properties.get_physical_device_properties2(phd, &mut properties2)
|
get_device_properties.get_physical_device_properties2(phd, &mut properties2)
|
||||||
};
|
};
|
||||||
@ -1191,6 +1225,7 @@ impl super::InstanceShared {
|
|||||||
capabilities
|
capabilities
|
||||||
.supported_extensions
|
.supported_extensions
|
||||||
.retain(|&x| x.extension_name_as_c_str() != Ok(ext::robustness2::NAME));
|
.retain(|&x| x.extension_name_as_c_str() != Ok(ext::robustness2::NAME));
|
||||||
|
capabilities.robustness2 = None;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
capabilities
|
capabilities
|
||||||
@ -1507,7 +1542,7 @@ impl super::Instance {
|
|||||||
};
|
};
|
||||||
let capabilities = crate::Capabilities {
|
let capabilities = crate::Capabilities {
|
||||||
limits: phd_capabilities.to_wgpu_limits(),
|
limits: phd_capabilities.to_wgpu_limits(),
|
||||||
alignments: phd_capabilities.to_hal_alignments(),
|
alignments: phd_capabilities.to_hal_alignments(private_caps.robust_buffer_access2),
|
||||||
downlevel: wgt::DownlevelCapabilities {
|
downlevel: wgt::DownlevelCapabilities {
|
||||||
flags: downlevel_flags,
|
flags: downlevel_flags,
|
||||||
limits: wgt::DownlevelLimits {},
|
limits: wgt::DownlevelLimits {},
|
||||||
@ -1779,7 +1814,7 @@ impl super::Adapter {
|
|||||||
capabilities: Some(capabilities.iter().cloned().collect()),
|
capabilities: Some(capabilities.iter().cloned().collect()),
|
||||||
bounds_check_policies: naga::proc::BoundsCheckPolicies {
|
bounds_check_policies: naga::proc::BoundsCheckPolicies {
|
||||||
index: naga::proc::BoundsCheckPolicy::Restrict,
|
index: naga::proc::BoundsCheckPolicy::Restrict,
|
||||||
buffer: if self.private_caps.robust_buffer_access {
|
buffer: if self.private_caps.robust_buffer_access2 {
|
||||||
naga::proc::BoundsCheckPolicy::Unchecked
|
naga::proc::BoundsCheckPolicy::Unchecked
|
||||||
} else {
|
} else {
|
||||||
naga::proc::BoundsCheckPolicy::Restrict
|
naga::proc::BoundsCheckPolicy::Restrict
|
||||||
|
@ -493,9 +493,36 @@ struct PrivateCapabilities {
|
|||||||
/// Ability to present contents to any screen. Only needed to work around broken platform configurations.
|
/// Ability to present contents to any screen. Only needed to work around broken platform configurations.
|
||||||
can_present: bool,
|
can_present: bool,
|
||||||
non_coherent_map_mask: wgt::BufferAddress,
|
non_coherent_map_mask: wgt::BufferAddress,
|
||||||
|
|
||||||
|
/// True if this adapter advertises the [`robustBufferAccess`][vrba] feature.
|
||||||
|
///
|
||||||
|
/// Note that Vulkan's `robustBufferAccess` is not sufficient to implement
|
||||||
|
/// `wgpu_hal`'s guarantee that shaders will not access buffer contents via
|
||||||
|
/// a given bindgroup binding outside that binding's [accessible
|
||||||
|
/// region][ar]. Enabling `robustBufferAccess` does ensure that
|
||||||
|
/// out-of-bounds reads and writes are not undefined behavior (that's good),
|
||||||
|
/// but still permits out-of-bounds reads to return data from anywhere
|
||||||
|
/// within the buffer, not just the accessible region.
|
||||||
|
///
|
||||||
|
/// [ar]: ../struct.BufferBinding.html#accessible-region
|
||||||
|
/// [vrba]: https://registry.khronos.org/vulkan/specs/1.3-extensions/html/vkspec.html#features-robustBufferAccess
|
||||||
robust_buffer_access: bool,
|
robust_buffer_access: bool,
|
||||||
|
|
||||||
robust_image_access: bool,
|
robust_image_access: bool,
|
||||||
|
|
||||||
|
/// True if this adapter supports the [`VK_EXT_robustness2`] extension's
|
||||||
|
/// [`robustBufferAccess2`] feature.
|
||||||
|
///
|
||||||
|
/// This is sufficient to implement `wgpu_hal`'s [required bounds-checking][ar] of
|
||||||
|
/// shader accesses to buffer contents. If this feature is not available,
|
||||||
|
/// this backend must have Naga inject bounds checks in the generated
|
||||||
|
/// SPIR-V.
|
||||||
|
///
|
||||||
|
/// [`VK_EXT_robustness2`]: https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VK_EXT_robustness2.html
|
||||||
|
/// [`robustBufferAccess2`]: https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceRobustness2FeaturesEXT.html#features-robustBufferAccess2
|
||||||
|
/// [ar]: ../struct.BufferBinding.html#accessible-region
|
||||||
robust_buffer_access2: bool,
|
robust_buffer_access2: bool,
|
||||||
|
|
||||||
robust_image_access2: bool,
|
robust_image_access2: bool,
|
||||||
zero_initialize_workgroup_memory: bool,
|
zero_initialize_workgroup_memory: bool,
|
||||||
image_format_list: bool,
|
image_format_list: bool,
|
||||||
|
@ -7310,8 +7310,15 @@ impl ShaderBoundChecks {
|
|||||||
/// Creates a new configuration where the shader isn't bound checked.
|
/// Creates a new configuration where the shader isn't bound checked.
|
||||||
///
|
///
|
||||||
/// # Safety
|
/// # Safety
|
||||||
/// The caller MUST ensure that all shaders built with this configuration don't perform any
|
///
|
||||||
/// out of bounds reads or writes.
|
/// The caller MUST ensure that all shaders built with this configuration
|
||||||
|
/// don't perform any out of bounds reads or writes.
|
||||||
|
///
|
||||||
|
/// Note that `wgpu_core`, in particular, initializes only those portions of
|
||||||
|
/// buffers that it expects might be read, and it does not expect contents
|
||||||
|
/// outside the ranges bound in bindgroups to be accessible, so using this
|
||||||
|
/// configuration with ill-behaved shaders could expose uninitialized GPU
|
||||||
|
/// memory contents to the application.
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub unsafe fn unchecked() -> Self {
|
pub unsafe fn unchecked() -> Self {
|
||||||
ShaderBoundChecks {
|
ShaderBoundChecks {
|
||||||
|
Loading…
Reference in New Issue
Block a user