mirror of
https://github.com/gfx-rs/wgpu.git
synced 2025-12-08 21:26:17 +00:00
Implement clip-distances extension for GL and Vulkan backends (#7730)
* Basic implementation of `clip_distances` for Vulkan and GL backends * Added GPU test for `clip-distances` * Update feature array size * Add changelog entry * Validate `clip_distances` array size * Check for `clip_distances` enable directive * Consolidate code for generating `enable` directives in WGSL backend and add `clip_distances`.
This commit is contained in:
parent
486a77d682
commit
bbb7cc79ef
@ -52,6 +52,7 @@ Bottom level categories:
|
|||||||
- Add support for astc-sliced-3d feature. By @mehmetoguzderin in [#7577](https://github.com/gfx-rs/wgpu/issues/7577)
|
- Add support for astc-sliced-3d feature. By @mehmetoguzderin in [#7577](https://github.com/gfx-rs/wgpu/issues/7577)
|
||||||
- Add support for rendering to slices of 3D texture views and single layered 2D-Array texture views (this requires `VK_KHR_maintenance1` which should be widely available on newer drivers). By @teoxoy in [#7596](https://github.com/gfx-rs/wgpu/pull/7596)
|
- Add support for rendering to slices of 3D texture views and single layered 2D-Array texture views (this requires `VK_KHR_maintenance1` which should be widely available on newer drivers). By @teoxoy in [#7596](https://github.com/gfx-rs/wgpu/pull/7596)
|
||||||
- Add extra acceleration structure vertex formats. By @Vecvec in [#7580](https://github.com/gfx-rs/wgpu/pull/7580).
|
- Add extra acceleration structure vertex formats. By @Vecvec in [#7580](https://github.com/gfx-rs/wgpu/pull/7580).
|
||||||
|
- Add support for clip-distances feature for Vulkan and GL backends. By @dzamkov in [#7730](https://github.com/gfx-rs/wgpu/pull/7730)
|
||||||
|
|
||||||
#### Naga
|
#### Naga
|
||||||
|
|
||||||
|
|||||||
@ -377,6 +377,8 @@ pub struct ReflectionInfo {
|
|||||||
pub varying: crate::FastHashMap<String, VaryingLocation>,
|
pub varying: crate::FastHashMap<String, VaryingLocation>,
|
||||||
/// List of push constant items in the shader.
|
/// List of push constant items in the shader.
|
||||||
pub push_constant_items: Vec<PushConstantItem>,
|
pub push_constant_items: Vec<PushConstantItem>,
|
||||||
|
/// Number of user-defined clip planes. Only applicable to vertex shaders.
|
||||||
|
pub clip_distance_count: u32,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Mapping between a texture and its sampler, if it exists.
|
/// Mapping between a texture and its sampler, if it exists.
|
||||||
@ -475,7 +477,7 @@ impl VaryingOptions {
|
|||||||
/// Helper wrapper used to get a name for a varying
|
/// Helper wrapper used to get a name for a varying
|
||||||
///
|
///
|
||||||
/// Varying have different naming schemes depending on their binding:
|
/// Varying have different naming schemes depending on their binding:
|
||||||
/// - Varyings with builtin bindings get the from [`glsl_built_in`].
|
/// - Varyings with builtin bindings get their name from [`glsl_built_in`].
|
||||||
/// - Varyings with location bindings are named `_S_location_X` where `S` is a
|
/// - Varyings with location bindings are named `_S_location_X` where `S` is a
|
||||||
/// prefix identifying which pipeline stage the varying connects, and `X` is
|
/// prefix identifying which pipeline stage the varying connects, and `X` is
|
||||||
/// the location.
|
/// the location.
|
||||||
@ -621,6 +623,8 @@ pub struct Writer<'a, W> {
|
|||||||
multiview: Option<core::num::NonZeroU32>,
|
multiview: Option<core::num::NonZeroU32>,
|
||||||
/// Mapping of varying variables to their location. Needed for reflections.
|
/// Mapping of varying variables to their location. Needed for reflections.
|
||||||
varying: crate::FastHashMap<String, VaryingLocation>,
|
varying: crate::FastHashMap<String, VaryingLocation>,
|
||||||
|
/// Number of user-defined clip planes. Only non-zero for vertex shaders.
|
||||||
|
clip_distance_count: u32,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, W: Write> Writer<'a, W> {
|
impl<'a, W: Write> Writer<'a, W> {
|
||||||
@ -688,6 +692,7 @@ impl<'a, W: Write> Writer<'a, W> {
|
|||||||
need_bake_expressions: Default::default(),
|
need_bake_expressions: Default::default(),
|
||||||
continue_ctx: back::continue_forward::ContinueCtx::default(),
|
continue_ctx: back::continue_forward::ContinueCtx::default(),
|
||||||
varying: Default::default(),
|
varying: Default::default(),
|
||||||
|
clip_distance_count: 0,
|
||||||
};
|
};
|
||||||
|
|
||||||
// Find all features required to print this module
|
// Find all features required to print this module
|
||||||
@ -1610,31 +1615,47 @@ impl<'a, W: Write> Writer<'a, W> {
|
|||||||
blend_src,
|
blend_src,
|
||||||
} => (location, interpolation, sampling, blend_src),
|
} => (location, interpolation, sampling, blend_src),
|
||||||
crate::Binding::BuiltIn(built_in) => {
|
crate::Binding::BuiltIn(built_in) => {
|
||||||
if let crate::BuiltIn::Position { invariant: true } = built_in {
|
match built_in {
|
||||||
match (self.options.version, self.entry_point.stage) {
|
crate::BuiltIn::Position { invariant: true } => {
|
||||||
(
|
match (self.options.version, self.entry_point.stage) {
|
||||||
Version::Embedded {
|
(
|
||||||
version: 300,
|
Version::Embedded {
|
||||||
is_webgl: true,
|
version: 300,
|
||||||
},
|
is_webgl: true,
|
||||||
ShaderStage::Fragment,
|
},
|
||||||
) => {
|
ShaderStage::Fragment,
|
||||||
// `invariant gl_FragCoord` is not allowed in WebGL2 and possibly
|
) => {
|
||||||
// OpenGL ES in general (waiting on confirmation).
|
// `invariant gl_FragCoord` is not allowed in WebGL2 and possibly
|
||||||
//
|
// OpenGL ES in general (waiting on confirmation).
|
||||||
// See https://github.com/KhronosGroup/WebGL/issues/3518
|
//
|
||||||
}
|
// See https://github.com/KhronosGroup/WebGL/issues/3518
|
||||||
_ => {
|
}
|
||||||
writeln!(
|
_ => {
|
||||||
self.out,
|
writeln!(
|
||||||
"invariant {};",
|
self.out,
|
||||||
glsl_built_in(
|
"invariant {};",
|
||||||
built_in,
|
glsl_built_in(
|
||||||
VaryingOptions::from_writer_options(self.options, output)
|
built_in,
|
||||||
)
|
VaryingOptions::from_writer_options(self.options, output)
|
||||||
)?;
|
)
|
||||||
|
)?;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
crate::BuiltIn::ClipDistance => {
|
||||||
|
// Re-declare `gl_ClipDistance` with number of clip planes.
|
||||||
|
let TypeInner::Array { size, .. } = self.module.types[ty].inner else {
|
||||||
|
unreachable!();
|
||||||
|
};
|
||||||
|
let proc::IndexableLength::Known(size) =
|
||||||
|
size.resolve(self.module.to_ctx())?
|
||||||
|
else {
|
||||||
|
unreachable!();
|
||||||
|
};
|
||||||
|
self.clip_distance_count = size;
|
||||||
|
writeln!(self.out, "out float gl_ClipDistance[{size}];")?;
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
}
|
}
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
@ -5049,6 +5070,7 @@ impl<'a, W: Write> Writer<'a, W> {
|
|||||||
uniforms,
|
uniforms,
|
||||||
varying: mem::take(&mut self.varying),
|
varying: mem::take(&mut self.varying),
|
||||||
push_constant_items,
|
push_constant_items,
|
||||||
|
clip_distance_count: self.clip_distance_count,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -5,7 +5,6 @@ use alloc::{
|
|||||||
vec::Vec,
|
vec::Vec,
|
||||||
};
|
};
|
||||||
use core::fmt::Write;
|
use core::fmt::Write;
|
||||||
use hashbrown::HashSet;
|
|
||||||
|
|
||||||
use super::Error;
|
use super::Error;
|
||||||
use super::ToWgslIfImplemented as _;
|
use super::ToWgslIfImplemented as _;
|
||||||
@ -127,9 +126,6 @@ impl<W: Write> Writer<W> {
|
|||||||
|
|
||||||
self.reset(module);
|
self.reset(module);
|
||||||
|
|
||||||
// Write all needed directives.
|
|
||||||
self.write_enable_dual_source_blending_if_needed(module)?;
|
|
||||||
|
|
||||||
// Write all `enable` declarations
|
// Write all `enable` declarations
|
||||||
self.write_enable_declarations(module)?;
|
self.write_enable_declarations(module)?;
|
||||||
|
|
||||||
@ -227,31 +223,52 @@ impl<W: Write> Writer<W> {
|
|||||||
/// Helper method which writes all the `enable` declarations
|
/// Helper method which writes all the `enable` declarations
|
||||||
/// needed for a module.
|
/// needed for a module.
|
||||||
fn write_enable_declarations(&mut self, module: &Module) -> BackendResult {
|
fn write_enable_declarations(&mut self, module: &Module) -> BackendResult {
|
||||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
|
let mut needs_f16 = false;
|
||||||
enum WrittenDeclarations {
|
let mut needs_dual_source_blending = false;
|
||||||
F16,
|
let mut needs_clip_distances = false;
|
||||||
}
|
|
||||||
|
|
||||||
let mut written_declarations = HashSet::new();
|
// Determine which `enable` declarations are needed
|
||||||
|
|
||||||
// Write all the `enable` declarations
|
|
||||||
for (_, ty) in module.types.iter() {
|
for (_, ty) in module.types.iter() {
|
||||||
match ty.inner {
|
match ty.inner {
|
||||||
TypeInner::Scalar(scalar)
|
TypeInner::Scalar(scalar)
|
||||||
| TypeInner::Vector { scalar, .. }
|
| TypeInner::Vector { scalar, .. }
|
||||||
| TypeInner::Matrix { scalar, .. } => {
|
| TypeInner::Matrix { scalar, .. } => {
|
||||||
if scalar == crate::Scalar::F16
|
needs_f16 |= scalar == crate::Scalar::F16;
|
||||||
&& !written_declarations.contains(&WrittenDeclarations::F16)
|
}
|
||||||
{
|
TypeInner::Struct { ref members, .. } => {
|
||||||
writeln!(self.out, "enable f16;")?;
|
for binding in members.iter().filter_map(|m| m.binding.as_ref()) {
|
||||||
written_declarations.insert(WrittenDeclarations::F16);
|
match *binding {
|
||||||
|
crate::Binding::Location {
|
||||||
|
blend_src: Some(_), ..
|
||||||
|
} => {
|
||||||
|
needs_dual_source_blending = true;
|
||||||
|
}
|
||||||
|
crate::Binding::BuiltIn(crate::BuiltIn::ClipDistance) => {
|
||||||
|
needs_clip_distances = true;
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if !written_declarations.is_empty() {
|
// Write required declarations
|
||||||
|
let mut any_written = false;
|
||||||
|
if needs_f16 {
|
||||||
|
writeln!(self.out, "enable f16;")?;
|
||||||
|
any_written = true;
|
||||||
|
}
|
||||||
|
if needs_dual_source_blending {
|
||||||
|
writeln!(self.out, "enable dual_source_blending;")?;
|
||||||
|
any_written = true;
|
||||||
|
}
|
||||||
|
if needs_clip_distances {
|
||||||
|
writeln!(self.out, "enable clip_distances;")?;
|
||||||
|
any_written = true;
|
||||||
|
}
|
||||||
|
if any_written {
|
||||||
// Empty line for readability
|
// Empty line for readability
|
||||||
writeln!(self.out)?;
|
writeln!(self.out)?;
|
||||||
}
|
}
|
||||||
@ -404,32 +421,6 @@ impl<W: Write> Writer<W> {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Writes all the necessary directives out
|
|
||||||
fn write_enable_dual_source_blending_if_needed(&mut self, module: &Module) -> BackendResult {
|
|
||||||
// Check for dual source blending.
|
|
||||||
if module.types.iter().any(|(_handle, ty)| {
|
|
||||||
if let TypeInner::Struct { ref members, .. } = ty.inner {
|
|
||||||
members.iter().any(|member| {
|
|
||||||
member.binding.as_ref().is_some_and(|binding| {
|
|
||||||
matches!(
|
|
||||||
binding,
|
|
||||||
&crate::Binding::Location {
|
|
||||||
blend_src: Some(_),
|
|
||||||
..
|
|
||||||
}
|
|
||||||
)
|
|
||||||
})
|
|
||||||
})
|
|
||||||
} else {
|
|
||||||
false
|
|
||||||
}
|
|
||||||
}) {
|
|
||||||
writeln!(self.out, "enable dual_source_blending;")?;
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Helper method used to write structs
|
/// Helper method used to write structs
|
||||||
/// Write the full declaration of a struct type.
|
/// Write the full declaration of a struct type.
|
||||||
///
|
///
|
||||||
|
|||||||
@ -165,6 +165,7 @@ impl TryToWgsl for crate::BuiltIn {
|
|||||||
Bi::ViewIndex => "view_index",
|
Bi::ViewIndex => "view_index",
|
||||||
Bi::InstanceIndex => "instance_index",
|
Bi::InstanceIndex => "instance_index",
|
||||||
Bi::VertexIndex => "vertex_index",
|
Bi::VertexIndex => "vertex_index",
|
||||||
|
Bi::ClipDistance => "clip_distances",
|
||||||
Bi::FragDepth => "frag_depth",
|
Bi::FragDepth => "frag_depth",
|
||||||
Bi::FrontFacing => "front_facing",
|
Bi::FrontFacing => "front_facing",
|
||||||
Bi::PrimitiveIndex => "primitive_index",
|
Bi::PrimitiveIndex => "primitive_index",
|
||||||
@ -183,7 +184,6 @@ impl TryToWgsl for crate::BuiltIn {
|
|||||||
// Non-standard built-ins.
|
// Non-standard built-ins.
|
||||||
Bi::BaseInstance
|
Bi::BaseInstance
|
||||||
| Bi::BaseVertex
|
| Bi::BaseVertex
|
||||||
| Bi::ClipDistance
|
|
||||||
| Bi::CullDistance
|
| Bi::CullDistance
|
||||||
| Bi::PointSize
|
| Bi::PointSize
|
||||||
| Bi::DrawID
|
| Bi::DrawID
|
||||||
|
|||||||
@ -20,13 +20,18 @@ pub fn map_address_space(word: &str, span: Span) -> Result<'_, crate::AddressSpa
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn map_built_in(word: &str, span: Span) -> Result<'_, crate::BuiltIn> {
|
pub fn map_built_in(
|
||||||
Ok(match word {
|
enable_extensions: &EnableExtensions,
|
||||||
|
word: &str,
|
||||||
|
span: Span,
|
||||||
|
) -> Result<'static, crate::BuiltIn> {
|
||||||
|
let built_in = match word {
|
||||||
"position" => crate::BuiltIn::Position { invariant: false },
|
"position" => crate::BuiltIn::Position { invariant: false },
|
||||||
// vertex
|
// vertex
|
||||||
"vertex_index" => crate::BuiltIn::VertexIndex,
|
"vertex_index" => crate::BuiltIn::VertexIndex,
|
||||||
"instance_index" => crate::BuiltIn::InstanceIndex,
|
"instance_index" => crate::BuiltIn::InstanceIndex,
|
||||||
"view_index" => crate::BuiltIn::ViewIndex,
|
"view_index" => crate::BuiltIn::ViewIndex,
|
||||||
|
"clip_distances" => crate::BuiltIn::ClipDistance,
|
||||||
// fragment
|
// fragment
|
||||||
"front_facing" => crate::BuiltIn::FrontFacing,
|
"front_facing" => crate::BuiltIn::FrontFacing,
|
||||||
"frag_depth" => crate::BuiltIn::FragDepth,
|
"frag_depth" => crate::BuiltIn::FragDepth,
|
||||||
@ -45,7 +50,19 @@ pub fn map_built_in(word: &str, span: Span) -> Result<'_, crate::BuiltIn> {
|
|||||||
"subgroup_size" => crate::BuiltIn::SubgroupSize,
|
"subgroup_size" => crate::BuiltIn::SubgroupSize,
|
||||||
"subgroup_invocation_id" => crate::BuiltIn::SubgroupInvocationId,
|
"subgroup_invocation_id" => crate::BuiltIn::SubgroupInvocationId,
|
||||||
_ => return Err(Box::new(Error::UnknownBuiltin(span))),
|
_ => return Err(Box::new(Error::UnknownBuiltin(span))),
|
||||||
})
|
};
|
||||||
|
match built_in {
|
||||||
|
crate::BuiltIn::ClipDistance => {
|
||||||
|
if !enable_extensions.contains(ImplementedEnableExtension::ClipDistances) {
|
||||||
|
return Err(Box::new(Error::EnableExtensionNotEnabled {
|
||||||
|
span,
|
||||||
|
kind: ImplementedEnableExtension::ClipDistances.into(),
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
Ok(built_in)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn map_interpolation(word: &str, span: Span) -> Result<'_, crate::Interpolation> {
|
pub fn map_interpolation(word: &str, span: Span) -> Result<'_, crate::Interpolation> {
|
||||||
|
|||||||
@ -13,6 +13,7 @@ pub struct EnableExtensions {
|
|||||||
dual_source_blending: bool,
|
dual_source_blending: bool,
|
||||||
/// Whether `enable f16;` was written earlier in the shader module.
|
/// Whether `enable f16;` was written earlier in the shader module.
|
||||||
f16: bool,
|
f16: bool,
|
||||||
|
clip_distances: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl EnableExtensions {
|
impl EnableExtensions {
|
||||||
@ -20,6 +21,7 @@ impl EnableExtensions {
|
|||||||
Self {
|
Self {
|
||||||
f16: false,
|
f16: false,
|
||||||
dual_source_blending: false,
|
dual_source_blending: false,
|
||||||
|
clip_distances: false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -28,6 +30,7 @@ impl EnableExtensions {
|
|||||||
let field = match ext {
|
let field = match ext {
|
||||||
ImplementedEnableExtension::DualSourceBlending => &mut self.dual_source_blending,
|
ImplementedEnableExtension::DualSourceBlending => &mut self.dual_source_blending,
|
||||||
ImplementedEnableExtension::F16 => &mut self.f16,
|
ImplementedEnableExtension::F16 => &mut self.f16,
|
||||||
|
ImplementedEnableExtension::ClipDistances => &mut self.clip_distances,
|
||||||
};
|
};
|
||||||
*field = true;
|
*field = true;
|
||||||
}
|
}
|
||||||
@ -37,6 +40,7 @@ impl EnableExtensions {
|
|||||||
match ext {
|
match ext {
|
||||||
ImplementedEnableExtension::DualSourceBlending => self.dual_source_blending,
|
ImplementedEnableExtension::DualSourceBlending => self.dual_source_blending,
|
||||||
ImplementedEnableExtension::F16 => self.f16,
|
ImplementedEnableExtension::F16 => self.f16,
|
||||||
|
ImplementedEnableExtension::ClipDistances => self.clip_distances,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -72,9 +76,7 @@ impl EnableExtension {
|
|||||||
pub(crate) fn from_ident(word: &str, span: Span) -> Result<Self> {
|
pub(crate) fn from_ident(word: &str, span: Span) -> Result<Self> {
|
||||||
Ok(match word {
|
Ok(match word {
|
||||||
Self::F16 => Self::Implemented(ImplementedEnableExtension::F16),
|
Self::F16 => Self::Implemented(ImplementedEnableExtension::F16),
|
||||||
Self::CLIP_DISTANCES => {
|
Self::CLIP_DISTANCES => Self::Implemented(ImplementedEnableExtension::ClipDistances),
|
||||||
Self::Unimplemented(UnimplementedEnableExtension::ClipDistances)
|
|
||||||
}
|
|
||||||
Self::DUAL_SOURCE_BLENDING => {
|
Self::DUAL_SOURCE_BLENDING => {
|
||||||
Self::Implemented(ImplementedEnableExtension::DualSourceBlending)
|
Self::Implemented(ImplementedEnableExtension::DualSourceBlending)
|
||||||
}
|
}
|
||||||
@ -89,9 +91,9 @@ impl EnableExtension {
|
|||||||
Self::Implemented(kind) => match kind {
|
Self::Implemented(kind) => match kind {
|
||||||
ImplementedEnableExtension::DualSourceBlending => Self::DUAL_SOURCE_BLENDING,
|
ImplementedEnableExtension::DualSourceBlending => Self::DUAL_SOURCE_BLENDING,
|
||||||
ImplementedEnableExtension::F16 => Self::F16,
|
ImplementedEnableExtension::F16 => Self::F16,
|
||||||
|
ImplementedEnableExtension::ClipDistances => Self::CLIP_DISTANCES,
|
||||||
},
|
},
|
||||||
Self::Unimplemented(kind) => match kind {
|
Self::Unimplemented(kind) => match kind {
|
||||||
UnimplementedEnableExtension::ClipDistances => Self::CLIP_DISTANCES,
|
|
||||||
UnimplementedEnableExtension::Subgroups => Self::SUBGROUPS,
|
UnimplementedEnableExtension::Subgroups => Self::SUBGROUPS,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
@ -113,17 +115,17 @@ pub enum ImplementedEnableExtension {
|
|||||||
///
|
///
|
||||||
/// [`enable dual_source_blending;`]: https://www.w3.org/TR/WGSL/#extension-dual_source_blending
|
/// [`enable dual_source_blending;`]: https://www.w3.org/TR/WGSL/#extension-dual_source_blending
|
||||||
DualSourceBlending,
|
DualSourceBlending,
|
||||||
}
|
|
||||||
|
|
||||||
/// A variant of [`EnableExtension::Unimplemented`].
|
|
||||||
#[derive(Clone, Copy, Debug, Hash, Eq, PartialEq)]
|
|
||||||
pub enum UnimplementedEnableExtension {
|
|
||||||
/// Enables the `clip_distances` variable in WGSL.
|
/// Enables the `clip_distances` variable in WGSL.
|
||||||
///
|
///
|
||||||
/// In the WGSL standard, this corresponds to [`enable clip_distances;`].
|
/// In the WGSL standard, this corresponds to [`enable clip_distances;`].
|
||||||
///
|
///
|
||||||
/// [`enable clip_distances;`]: https://www.w3.org/TR/WGSL/#extension-clip_distances
|
/// [`enable clip_distances;`]: https://www.w3.org/TR/WGSL/#extension-clip_distances
|
||||||
ClipDistances,
|
ClipDistances,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A variant of [`EnableExtension::Unimplemented`].
|
||||||
|
#[derive(Clone, Copy, Debug, Hash, Eq, PartialEq)]
|
||||||
|
pub enum UnimplementedEnableExtension {
|
||||||
/// Enables subgroup built-ins in all languages.
|
/// Enables subgroup built-ins in all languages.
|
||||||
///
|
///
|
||||||
/// In the WGSL standard, this corresponds to [`enable subgroups;`].
|
/// In the WGSL standard, this corresponds to [`enable subgroups;`].
|
||||||
@ -135,7 +137,6 @@ pub enum UnimplementedEnableExtension {
|
|||||||
impl UnimplementedEnableExtension {
|
impl UnimplementedEnableExtension {
|
||||||
pub(crate) const fn tracking_issue_num(self) -> u16 {
|
pub(crate) const fn tracking_issue_num(self) -> u16 {
|
||||||
match self {
|
match self {
|
||||||
Self::ClipDistances => 6236,
|
|
||||||
Self::Subgroups => 5555,
|
Self::Subgroups => 5555,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -199,8 +199,10 @@ impl<'a> BindingParser<'a> {
|
|||||||
"builtin" => {
|
"builtin" => {
|
||||||
lexer.expect(Token::Paren('('))?;
|
lexer.expect(Token::Paren('('))?;
|
||||||
let (raw, span) = lexer.next_ident_with_span()?;
|
let (raw, span) = lexer.next_ident_with_span()?;
|
||||||
self.built_in
|
self.built_in.set(
|
||||||
.set(conv::map_built_in(raw, span)?, name_span)?;
|
conv::map_built_in(&lexer.enable_extensions, raw, span)?,
|
||||||
|
name_span,
|
||||||
|
)?;
|
||||||
lexer.expect(Token::Paren(')'))?;
|
lexer.expect(Token::Paren(')'))?;
|
||||||
}
|
}
|
||||||
"interpolate" => {
|
"interpolate" => {
|
||||||
|
|||||||
@ -212,8 +212,12 @@ impl VaryingContext<'_> {
|
|||||||
Bi::ClipDistance | Bi::CullDistance => (
|
Bi::ClipDistance | Bi::CullDistance => (
|
||||||
self.stage == St::Vertex && self.output,
|
self.stage == St::Vertex && self.output,
|
||||||
match *ty_inner {
|
match *ty_inner {
|
||||||
Ti::Array { base, .. } => {
|
Ti::Array { base, size, .. } => {
|
||||||
self.types[base].inner == Ti::Scalar(crate::Scalar::F32)
|
self.types[base].inner == Ti::Scalar(crate::Scalar::F32)
|
||||||
|
&& match size {
|
||||||
|
crate::ArraySize::Constant(non_zero) => non_zero.get() <= 8,
|
||||||
|
_ => false,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
_ => false,
|
_ => false,
|
||||||
},
|
},
|
||||||
|
|||||||
5
naga/tests/in/wgsl/clip-distances.toml
Normal file
5
naga/tests/in/wgsl/clip-distances.toml
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
god_mode = true
|
||||||
|
targets = "SPIRV | GLSL | WGSL"
|
||||||
|
|
||||||
|
[glsl]
|
||||||
|
version.Desktop = 330
|
||||||
12
naga/tests/in/wgsl/clip-distances.wgsl
Normal file
12
naga/tests/in/wgsl/clip-distances.wgsl
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
enable clip_distances;
|
||||||
|
struct VertexOutput {
|
||||||
|
@builtin(position) position: vec4<f32>,
|
||||||
|
@builtin(clip_distances) clip_distances: array<f32, 1>,
|
||||||
|
}
|
||||||
|
|
||||||
|
@vertex
|
||||||
|
fn main() -> VertexOutput {
|
||||||
|
var out: VertexOutput;
|
||||||
|
out.clip_distances[0] = 0.5;
|
||||||
|
return out;
|
||||||
|
}
|
||||||
@ -3667,3 +3667,78 @@ fn subgroup_invalid_broadcast() {
|
|||||||
naga::valid::Capabilities::SUBGROUP
|
naga::valid::Capabilities::SUBGROUP
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn invalid_clip_distances() {
|
||||||
|
// Missing capability.
|
||||||
|
check_validation! {
|
||||||
|
r#"
|
||||||
|
enable clip_distances;
|
||||||
|
struct VertexOutput {
|
||||||
|
@builtin(position) pos: vec4f,
|
||||||
|
@builtin(clip_distances) clip_distances: array<f32, 8>,
|
||||||
|
}
|
||||||
|
|
||||||
|
@vertex
|
||||||
|
fn vs_main() -> VertexOutput {
|
||||||
|
var out: VertexOutput;
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
"#:
|
||||||
|
Err(
|
||||||
|
naga::valid::ValidationError::EntryPoint {
|
||||||
|
stage: naga::ShaderStage::Vertex,
|
||||||
|
source: naga::valid::EntryPointError::Result(
|
||||||
|
naga::valid::VaryingError::UnsupportedCapability(Capabilities::CLIP_DISTANCE),
|
||||||
|
),
|
||||||
|
..
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Missing enable directive.
|
||||||
|
// Note that this is a parsing error, not a validation error.
|
||||||
|
check(
|
||||||
|
r#"
|
||||||
|
@vertex
|
||||||
|
fn vs_main() -> @builtin(clip_distances) array<f32, 8> {
|
||||||
|
var out: array<f32, 8>;
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
"#,
|
||||||
|
r###"error: the `clip_distances` enable extension is not enabled
|
||||||
|
┌─ wgsl:3:38
|
||||||
|
│
|
||||||
|
3 │ fn vs_main() -> @builtin(clip_distances) array<f32, 8> {
|
||||||
|
│ ^^^^^^^^^^^^^^ the `clip_distances` "Enable Extension" is needed for this functionality, but it is not currently enabled.
|
||||||
|
│
|
||||||
|
= note: You can enable this extension by adding `enable clip_distances;` at the top of the shader, before any other items.
|
||||||
|
|
||||||
|
"###,
|
||||||
|
);
|
||||||
|
|
||||||
|
// Maximum clip distances exceeded
|
||||||
|
check_validation! {
|
||||||
|
r#"
|
||||||
|
enable clip_distances;
|
||||||
|
struct VertexOutput {
|
||||||
|
@builtin(position) pos: vec4f,
|
||||||
|
@builtin(clip_distances) clip_distances: array<f32, 9>,
|
||||||
|
}
|
||||||
|
|
||||||
|
@vertex
|
||||||
|
fn vs_main() -> VertexOutput {
|
||||||
|
var out: VertexOutput;
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
"#:
|
||||||
|
Err(naga::valid::ValidationError::EntryPoint {
|
||||||
|
stage: naga::ShaderStage::Vertex,
|
||||||
|
source: naga::valid::EntryPointError::Result(
|
||||||
|
naga::valid::VaryingError::InvalidBuiltInType(naga::ir::BuiltIn::ClipDistance)
|
||||||
|
),
|
||||||
|
..
|
||||||
|
}),
|
||||||
|
naga::valid::Capabilities::CLIP_DISTANCE
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
17
naga/tests/out/glsl/wgsl-clip-distances.main.Vertex.glsl
Normal file
17
naga/tests/out/glsl/wgsl-clip-distances.main.Vertex.glsl
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
#version 330 core
|
||||||
|
struct VertexOutput {
|
||||||
|
vec4 position;
|
||||||
|
float clip_distances[1];
|
||||||
|
};
|
||||||
|
out float gl_ClipDistance[1];
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
VertexOutput out_ = VertexOutput(vec4(0.0), float[1](0.0));
|
||||||
|
out_.clip_distances[0] = 0.5;
|
||||||
|
VertexOutput _e4 = out_;
|
||||||
|
gl_Position = _e4.position;
|
||||||
|
gl_ClipDistance = _e4.clip_distances;
|
||||||
|
gl_Position.yz = vec2(-gl_Position.y, gl_Position.z * 2.0 - gl_Position.w);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
46
naga/tests/out/spv/wgsl-clip-distances.spvasm
Normal file
46
naga/tests/out/spv/wgsl-clip-distances.spvasm
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
; SPIR-V
|
||||||
|
; Version: 1.1
|
||||||
|
; Generator: rspirv
|
||||||
|
; Bound: 28
|
||||||
|
OpCapability Shader
|
||||||
|
OpCapability ClipDistance
|
||||||
|
%1 = OpExtInstImport "GLSL.std.450"
|
||||||
|
OpMemoryModel Logical GLSL450
|
||||||
|
OpEntryPoint Vertex %14 "main" %10 %12
|
||||||
|
OpDecorate %5 ArrayStride 4
|
||||||
|
OpMemberDecorate %8 0 Offset 0
|
||||||
|
OpMemberDecorate %8 1 Offset 16
|
||||||
|
OpDecorate %10 BuiltIn Position
|
||||||
|
OpDecorate %12 BuiltIn ClipDistance
|
||||||
|
%2 = OpTypeVoid
|
||||||
|
%3 = OpTypeFloat 32
|
||||||
|
%4 = OpTypeVector %3 4
|
||||||
|
%7 = OpTypeInt 32 0
|
||||||
|
%6 = OpConstant %7 1
|
||||||
|
%5 = OpTypeArray %3 %6
|
||||||
|
%8 = OpTypeStruct %4 %5
|
||||||
|
%11 = OpTypePointer Output %4
|
||||||
|
%10 = OpVariable %11 Output
|
||||||
|
%13 = OpTypePointer Output %5
|
||||||
|
%12 = OpVariable %13 Output
|
||||||
|
%15 = OpTypeFunction %2
|
||||||
|
%16 = OpConstant %3 0.5
|
||||||
|
%18 = OpTypePointer Function %8
|
||||||
|
%19 = OpConstantNull %8
|
||||||
|
%21 = OpTypePointer Function %5
|
||||||
|
%22 = OpTypePointer Function %3
|
||||||
|
%23 = OpConstant %7 0
|
||||||
|
%14 = OpFunction %2 None %15
|
||||||
|
%9 = OpLabel
|
||||||
|
%17 = OpVariable %18 Function %19
|
||||||
|
OpBranch %20
|
||||||
|
%20 = OpLabel
|
||||||
|
%24 = OpAccessChain %22 %17 %6 %23
|
||||||
|
OpStore %24 %16
|
||||||
|
%25 = OpLoad %8 %17
|
||||||
|
%26 = OpCompositeExtract %4 %25 0
|
||||||
|
OpStore %10 %26
|
||||||
|
%27 = OpCompositeExtract %5 %25 1
|
||||||
|
OpStore %12 %27
|
||||||
|
OpReturn
|
||||||
|
OpFunctionEnd
|
||||||
@ -1,4 +1,5 @@
|
|||||||
enable dual_source_blending;
|
enable dual_source_blending;
|
||||||
|
|
||||||
struct FragmentOutput {
|
struct FragmentOutput {
|
||||||
@location(0) @blend_src(0) output0_: vec4<f32>,
|
@location(0) @blend_src(0) output0_: vec4<f32>,
|
||||||
@location(0) @blend_src(1) output1_: vec4<f32>,
|
@location(0) @blend_src(1) output1_: vec4<f32>,
|
||||||
|
|||||||
15
naga/tests/out/wgsl/wgsl-clip-distances.wgsl
Normal file
15
naga/tests/out/wgsl/wgsl-clip-distances.wgsl
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
enable clip_distances;
|
||||||
|
|
||||||
|
struct VertexOutput {
|
||||||
|
@builtin(position) position: vec4<f32>,
|
||||||
|
@builtin(clip_distances) clip_distances: array<f32, 1>,
|
||||||
|
}
|
||||||
|
|
||||||
|
@vertex
|
||||||
|
fn main() -> VertexOutput {
|
||||||
|
var out: VertexOutput;
|
||||||
|
|
||||||
|
out.clip_distances[0] = 0.5f;
|
||||||
|
let _e4 = out;
|
||||||
|
return _e4;
|
||||||
|
}
|
||||||
@ -1,4 +1,5 @@
|
|||||||
enable dual_source_blending;
|
enable dual_source_blending;
|
||||||
|
|
||||||
struct FragmentOutput {
|
struct FragmentOutput {
|
||||||
@location(0) @blend_src(0) output0_: vec4<f32>,
|
@location(0) @blend_src(0) output0_: vec4<f32>,
|
||||||
@location(0) @blend_src(1) output1_: vec4<f32>,
|
@location(0) @blend_src(1) output1_: vec4<f32>,
|
||||||
|
|||||||
152
tests/tests/wgpu-gpu/clip_distances.rs
Normal file
152
tests/tests/wgpu-gpu/clip_distances.rs
Normal file
@ -0,0 +1,152 @@
|
|||||||
|
use wgpu_test::{gpu_test, GpuTestConfiguration, TestParameters, TestingContext};
|
||||||
|
|
||||||
|
#[gpu_test]
|
||||||
|
static CLIP_DISTANCES: GpuTestConfiguration = GpuTestConfiguration::new()
|
||||||
|
.parameters(TestParameters::default().features(wgpu::Features::CLIP_DISTANCES))
|
||||||
|
.run_async(clip_distances);
|
||||||
|
|
||||||
|
async fn clip_distances(ctx: TestingContext) {
|
||||||
|
// Create pipeline
|
||||||
|
let shader = ctx
|
||||||
|
.device
|
||||||
|
.create_shader_module(wgpu::ShaderModuleDescriptor {
|
||||||
|
label: None,
|
||||||
|
source: wgpu::ShaderSource::Wgsl(SHADER_SRC.into()),
|
||||||
|
});
|
||||||
|
let pipeline = ctx
|
||||||
|
.device
|
||||||
|
.create_render_pipeline(&wgpu::RenderPipelineDescriptor {
|
||||||
|
label: None,
|
||||||
|
layout: None,
|
||||||
|
vertex: wgpu::VertexState {
|
||||||
|
buffers: &[],
|
||||||
|
module: &shader,
|
||||||
|
entry_point: Some("vs_main"),
|
||||||
|
compilation_options: Default::default(),
|
||||||
|
},
|
||||||
|
primitive: wgpu::PrimitiveState::default(),
|
||||||
|
depth_stencil: None,
|
||||||
|
multisample: wgpu::MultisampleState::default(),
|
||||||
|
fragment: Some(wgpu::FragmentState {
|
||||||
|
module: &shader,
|
||||||
|
entry_point: Some("fs_main"),
|
||||||
|
compilation_options: Default::default(),
|
||||||
|
targets: &[Some(wgpu::ColorTargetState {
|
||||||
|
format: wgpu::TextureFormat::R8Unorm,
|
||||||
|
blend: None,
|
||||||
|
write_mask: wgpu::ColorWrites::ALL,
|
||||||
|
})],
|
||||||
|
}),
|
||||||
|
multiview: None,
|
||||||
|
cache: None,
|
||||||
|
});
|
||||||
|
|
||||||
|
// Create render target
|
||||||
|
let render_texture = ctx.device.create_texture(&wgpu::TextureDescriptor {
|
||||||
|
label: Some("Render Texture"),
|
||||||
|
size: wgpu::Extent3d {
|
||||||
|
width: 256,
|
||||||
|
height: 256,
|
||||||
|
depth_or_array_layers: 1,
|
||||||
|
},
|
||||||
|
mip_level_count: 1,
|
||||||
|
sample_count: 1,
|
||||||
|
dimension: wgpu::TextureDimension::D2,
|
||||||
|
format: wgpu::TextureFormat::R8Unorm,
|
||||||
|
usage: wgpu::TextureUsages::RENDER_ATTACHMENT | wgpu::TextureUsages::COPY_SRC,
|
||||||
|
view_formats: &[],
|
||||||
|
});
|
||||||
|
|
||||||
|
// Perform render
|
||||||
|
let mut encoder = ctx
|
||||||
|
.device
|
||||||
|
.create_command_encoder(&wgpu::CommandEncoderDescriptor::default());
|
||||||
|
{
|
||||||
|
let mut rpass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor {
|
||||||
|
label: None,
|
||||||
|
color_attachments: &[Some(wgpu::RenderPassColorAttachment {
|
||||||
|
ops: wgpu::Operations {
|
||||||
|
load: wgpu::LoadOp::Clear(wgpu::Color {
|
||||||
|
r: 0.0,
|
||||||
|
g: 0.0,
|
||||||
|
b: 0.0,
|
||||||
|
a: 0.0,
|
||||||
|
}),
|
||||||
|
store: wgpu::StoreOp::Store,
|
||||||
|
},
|
||||||
|
resolve_target: None,
|
||||||
|
view: &render_texture.create_view(&wgpu::TextureViewDescriptor::default()),
|
||||||
|
depth_slice: None,
|
||||||
|
})],
|
||||||
|
depth_stencil_attachment: None,
|
||||||
|
timestamp_writes: None,
|
||||||
|
occlusion_query_set: None,
|
||||||
|
});
|
||||||
|
rpass.set_pipeline(&pipeline);
|
||||||
|
rpass.draw(0..3, 0..1);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Read texture data
|
||||||
|
let readback_buffer = ctx.device.create_buffer(&wgpu::BufferDescriptor {
|
||||||
|
label: None,
|
||||||
|
size: 256 * 256,
|
||||||
|
usage: wgpu::BufferUsages::COPY_DST | wgpu::BufferUsages::MAP_READ,
|
||||||
|
mapped_at_creation: false,
|
||||||
|
});
|
||||||
|
encoder.copy_texture_to_buffer(
|
||||||
|
wgpu::TexelCopyTextureInfo {
|
||||||
|
texture: &render_texture,
|
||||||
|
mip_level: 0,
|
||||||
|
origin: wgpu::Origin3d::ZERO,
|
||||||
|
aspect: wgpu::TextureAspect::All,
|
||||||
|
},
|
||||||
|
wgpu::TexelCopyBufferInfo {
|
||||||
|
buffer: &readback_buffer,
|
||||||
|
layout: wgpu::TexelCopyBufferLayout {
|
||||||
|
offset: 0,
|
||||||
|
bytes_per_row: Some(256),
|
||||||
|
rows_per_image: None,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
wgpu::Extent3d {
|
||||||
|
width: 256,
|
||||||
|
height: 256,
|
||||||
|
depth_or_array_layers: 1,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
ctx.queue.submit([encoder.finish()]);
|
||||||
|
let slice = readback_buffer.slice(..);
|
||||||
|
slice.map_async(wgpu::MapMode::Read, |_| ());
|
||||||
|
ctx.async_poll(wgpu::PollType::wait()).await.unwrap();
|
||||||
|
let data: &[u8] = &slice.get_mapped_range();
|
||||||
|
|
||||||
|
// We should have filled the upper sector of the texture. Verify that this is the case.
|
||||||
|
assert_eq!(data[128 + 64 * 256], 0xFF);
|
||||||
|
assert_eq!(data[64 + 128 * 256], 0x00);
|
||||||
|
assert_eq!(data[192 + 128 * 256], 0x00);
|
||||||
|
assert_eq!(data[128 + 192 * 256], 0x00);
|
||||||
|
}
|
||||||
|
|
||||||
|
const SHADER_SRC: &str = "
|
||||||
|
enable clip_distances;
|
||||||
|
struct VertexOutput {
|
||||||
|
@builtin(position) pos: vec4f,
|
||||||
|
@builtin(clip_distances) clip_distances: array<f32, 2>,
|
||||||
|
}
|
||||||
|
|
||||||
|
@vertex
|
||||||
|
fn vs_main(@builtin(vertex_index) vertex_index: u32) -> VertexOutput {
|
||||||
|
var out: VertexOutput;
|
||||||
|
let x = f32(i32(vertex_index) / 2) * 4.0 - 1.0;
|
||||||
|
let y = f32(i32(vertex_index) & 1) * 4.0 - 1.0;
|
||||||
|
out.pos = vec4f(x, y, 0.5, 1.0);
|
||||||
|
out.clip_distances[0] = x + y;
|
||||||
|
out.clip_distances[1] = y - x;
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
@fragment
|
||||||
|
fn fs_main() -> @location(0) vec4f {
|
||||||
|
return vec4f(1.0);
|
||||||
|
}
|
||||||
|
";
|
||||||
@ -19,6 +19,7 @@ mod buffer;
|
|||||||
mod buffer_copy;
|
mod buffer_copy;
|
||||||
mod buffer_usages;
|
mod buffer_usages;
|
||||||
mod clear_texture;
|
mod clear_texture;
|
||||||
|
mod clip_distances;
|
||||||
mod cloneable_types;
|
mod cloneable_types;
|
||||||
mod compute_pass_ownership;
|
mod compute_pass_ownership;
|
||||||
mod create_surface_error;
|
mod create_surface_error;
|
||||||
|
|||||||
@ -461,6 +461,10 @@ pub fn create_validator(
|
|||||||
Caps::DUAL_SOURCE_BLENDING,
|
Caps::DUAL_SOURCE_BLENDING,
|
||||||
features.contains(wgt::Features::DUAL_SOURCE_BLENDING),
|
features.contains(wgt::Features::DUAL_SOURCE_BLENDING),
|
||||||
);
|
);
|
||||||
|
caps.set(
|
||||||
|
Caps::CLIP_DISTANCE,
|
||||||
|
features.contains(wgt::Features::CLIP_DISTANCES),
|
||||||
|
);
|
||||||
caps.set(
|
caps.set(
|
||||||
Caps::CUBE_ARRAY_TEXTURES,
|
Caps::CUBE_ARRAY_TEXTURES,
|
||||||
downlevel.contains(wgt::DownlevelFlags::CUBE_ARRAY_TEXTURES),
|
downlevel.contains(wgt::DownlevelFlags::CUBE_ARRAY_TEXTURES),
|
||||||
|
|||||||
@ -465,6 +465,10 @@ impl super::Adapter {
|
|||||||
extensions.contains("GL_EXT_blend_func_extended")
|
extensions.contains("GL_EXT_blend_func_extended")
|
||||||
|| extensions.contains("GL_ARB_blend_func_extended"),
|
|| extensions.contains("GL_ARB_blend_func_extended"),
|
||||||
);
|
);
|
||||||
|
features.set(
|
||||||
|
wgt::Features::CLIP_DISTANCES,
|
||||||
|
full_ver.is_some() || extensions.contains("GL_EXT_clip_cull_distance"),
|
||||||
|
);
|
||||||
features.set(
|
features.set(
|
||||||
wgt::Features::SHADER_PRIMITIVE_INDEX,
|
wgt::Features::SHADER_PRIMITIVE_INDEX,
|
||||||
supported((3, 2), (3, 2))
|
supported((3, 2), (3, 2))
|
||||||
|
|||||||
@ -37,6 +37,7 @@ pub(super) struct State {
|
|||||||
// The current state of the push constant data block.
|
// The current state of the push constant data block.
|
||||||
current_push_constant_data: [u32; super::MAX_PUSH_CONSTANTS],
|
current_push_constant_data: [u32; super::MAX_PUSH_CONSTANTS],
|
||||||
end_of_pass_timestamp: Option<glow::Query>,
|
end_of_pass_timestamp: Option<glow::Query>,
|
||||||
|
clip_distance_count: u32,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for State {
|
impl Default for State {
|
||||||
@ -65,6 +66,7 @@ impl Default for State {
|
|||||||
push_constant_descs: Default::default(),
|
push_constant_descs: Default::default(),
|
||||||
current_push_constant_data: [0; super::MAX_PUSH_CONSTANTS],
|
current_push_constant_data: [0; super::MAX_PUSH_CONSTANTS],
|
||||||
end_of_pass_timestamp: Default::default(),
|
end_of_pass_timestamp: Default::default(),
|
||||||
|
clip_distance_count: Default::default(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -981,6 +983,15 @@ impl crate::CommandEncoder for super::CommandEncoder {
|
|||||||
for ct in pipeline.color_targets.iter() {
|
for ct in pipeline.color_targets.iter() {
|
||||||
self.state.color_targets.push(ct.clone());
|
self.state.color_targets.push(ct.clone());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// set clip plane count
|
||||||
|
if pipeline.inner.clip_distance_count != self.state.clip_distance_count {
|
||||||
|
self.cmd_buffer.commands.push(C::SetClipDistances {
|
||||||
|
old_count: self.state.clip_distance_count,
|
||||||
|
new_count: pipeline.inner.clip_distance_count,
|
||||||
|
});
|
||||||
|
self.state.clip_distance_count = pipeline.inner.clip_distance_count;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe fn set_index_buffer<'a>(
|
unsafe fn set_index_buffer<'a>(
|
||||||
|
|||||||
@ -23,6 +23,7 @@ struct CompilationContext<'a> {
|
|||||||
name_binding_map: &'a mut NameBindingMap,
|
name_binding_map: &'a mut NameBindingMap,
|
||||||
push_constant_items: &'a mut Vec<naga::back::glsl::PushConstantItem>,
|
push_constant_items: &'a mut Vec<naga::back::glsl::PushConstantItem>,
|
||||||
multiview: Option<NonZeroU32>,
|
multiview: Option<NonZeroU32>,
|
||||||
|
clip_distance_count: &'a mut u32,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl CompilationContext<'_> {
|
impl CompilationContext<'_> {
|
||||||
@ -103,6 +104,10 @@ impl CompilationContext<'_> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
*self.push_constant_items = reflection_info.push_constant_items;
|
*self.push_constant_items = reflection_info.push_constant_items;
|
||||||
|
|
||||||
|
if naga_stage == naga::ShaderStage::Vertex {
|
||||||
|
*self.clip_distance_count = reflection_info.clip_distance_count;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -372,6 +377,7 @@ impl super::Device {
|
|||||||
let mut sampler_map = [None; super::MAX_TEXTURE_SLOTS];
|
let mut sampler_map = [None; super::MAX_TEXTURE_SLOTS];
|
||||||
let mut has_stages = wgt::ShaderStages::empty();
|
let mut has_stages = wgt::ShaderStages::empty();
|
||||||
let mut shaders_to_delete = ArrayVec::<_, { crate::MAX_CONCURRENT_SHADER_STAGES }>::new();
|
let mut shaders_to_delete = ArrayVec::<_, { crate::MAX_CONCURRENT_SHADER_STAGES }>::new();
|
||||||
|
let mut clip_distance_count = 0;
|
||||||
|
|
||||||
for &(naga_stage, stage) in &shaders {
|
for &(naga_stage, stage) in &shaders {
|
||||||
has_stages |= map_naga_stage(naga_stage);
|
has_stages |= map_naga_stage(naga_stage);
|
||||||
@ -385,6 +391,7 @@ impl super::Device {
|
|||||||
name_binding_map: &mut name_binding_map,
|
name_binding_map: &mut name_binding_map,
|
||||||
push_constant_items: pc_item,
|
push_constant_items: pc_item,
|
||||||
multiview,
|
multiview,
|
||||||
|
clip_distance_count: &mut clip_distance_count,
|
||||||
};
|
};
|
||||||
|
|
||||||
let shader = Self::create_shader(gl, naga_stage, stage, context, program)?;
|
let shader = Self::create_shader(gl, naga_stage, stage, context, program)?;
|
||||||
@ -496,6 +503,7 @@ impl super::Device {
|
|||||||
sampler_map,
|
sampler_map,
|
||||||
first_instance_location,
|
first_instance_location,
|
||||||
push_constant_descs: uniforms,
|
push_constant_descs: uniforms,
|
||||||
|
clip_distance_count,
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -669,6 +669,7 @@ struct PipelineInner {
|
|||||||
sampler_map: SamplerBindMap,
|
sampler_map: SamplerBindMap,
|
||||||
first_instance_location: Option<glow::UniformLocation>,
|
first_instance_location: Option<glow::UniformLocation>,
|
||||||
push_constant_descs: ArrayVec<PushConstantDesc, MAX_PUSH_CONSTANT_COMMANDS>,
|
push_constant_descs: ArrayVec<PushConstantDesc, MAX_PUSH_CONSTANT_COMMANDS>,
|
||||||
|
clip_distance_count: u32,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
@ -1006,6 +1007,10 @@ enum Command {
|
|||||||
/// Offset from the start of the `data_bytes`
|
/// Offset from the start of the `data_bytes`
|
||||||
offset: u32,
|
offset: u32,
|
||||||
},
|
},
|
||||||
|
SetClipDistances {
|
||||||
|
old_count: u32,
|
||||||
|
new_count: u32,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
|
|||||||
@ -1824,6 +1824,20 @@ impl super::Queue {
|
|||||||
_ => panic!("Unsupported uniform datatype: {:?}!", uniform.ty),
|
_ => panic!("Unsupported uniform datatype: {:?}!", uniform.ty),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
C::SetClipDistances {
|
||||||
|
old_count,
|
||||||
|
new_count,
|
||||||
|
} => {
|
||||||
|
// Disable clip planes that are no longer active
|
||||||
|
for i in new_count..old_count {
|
||||||
|
unsafe { gl.disable(glow::CLIP_DISTANCE0 + i) };
|
||||||
|
}
|
||||||
|
|
||||||
|
// Enable clip planes that are now active
|
||||||
|
for i in old_count..new_count {
|
||||||
|
unsafe { gl.enable(glow::CLIP_DISTANCE0 + i) };
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -308,7 +308,7 @@ impl PhysicalDeviceFeatures {
|
|||||||
| wgt::Features::STORAGE_RESOURCE_BINDING_ARRAY,
|
| wgt::Features::STORAGE_RESOURCE_BINDING_ARRAY,
|
||||||
))
|
))
|
||||||
//.shader_storage_image_array_dynamic_indexing(
|
//.shader_storage_image_array_dynamic_indexing(
|
||||||
//.shader_clip_distance(requested_features.contains(wgt::Features::SHADER_CLIP_DISTANCE))
|
.shader_clip_distance(requested_features.contains(wgt::Features::CLIP_DISTANCES))
|
||||||
//.shader_cull_distance(requested_features.contains(wgt::Features::SHADER_CULL_DISTANCE))
|
//.shader_cull_distance(requested_features.contains(wgt::Features::SHADER_CULL_DISTANCE))
|
||||||
.shader_float64(requested_features.contains(wgt::Features::SHADER_F64))
|
.shader_float64(requested_features.contains(wgt::Features::SHADER_F64))
|
||||||
.shader_int64(requested_features.contains(wgt::Features::SHADER_INT64))
|
.shader_int64(requested_features.contains(wgt::Features::SHADER_INT64))
|
||||||
@ -709,6 +709,7 @@ impl PhysicalDeviceFeatures {
|
|||||||
|
|
||||||
features.set(F::DEPTH_CLIP_CONTROL, self.core.depth_clamp != 0);
|
features.set(F::DEPTH_CLIP_CONTROL, self.core.depth_clamp != 0);
|
||||||
features.set(F::DUAL_SOURCE_BLENDING, self.core.dual_src_blend != 0);
|
features.set(F::DUAL_SOURCE_BLENDING, self.core.dual_src_blend != 0);
|
||||||
|
features.set(F::CLIP_DISTANCES, self.core.shader_clip_distance != 0);
|
||||||
|
|
||||||
if let Some(ref multiview) = self.multiview {
|
if let Some(ref multiview) = self.multiview {
|
||||||
features.set(F::MULTIVIEW, multiview.multiview != 0);
|
features.set(F::MULTIVIEW, multiview.multiview != 0);
|
||||||
@ -2023,6 +2024,10 @@ impl super::Adapter {
|
|||||||
capabilities.push(spv::Capability::AtomicFloat32AddEXT);
|
capabilities.push(spv::Capability::AtomicFloat32AddEXT);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if features.contains(wgt::Features::CLIP_DISTANCES) {
|
||||||
|
capabilities.push(spv::Capability::ClipDistance);
|
||||||
|
}
|
||||||
|
|
||||||
let mut flags = spv::WriterFlags::empty();
|
let mut flags = spv::WriterFlags::empty();
|
||||||
flags.set(
|
flags.set(
|
||||||
spv::WriterFlags::DEBUG,
|
spv::WriterFlags::DEBUG,
|
||||||
|
|||||||
@ -59,6 +59,9 @@ mod webgpu_impl {
|
|||||||
|
|
||||||
#[doc(hidden)]
|
#[doc(hidden)]
|
||||||
pub const WEBGPU_FEATURE_DUAL_SOURCE_BLENDING: u64 = 1 << 13;
|
pub const WEBGPU_FEATURE_DUAL_SOURCE_BLENDING: u64 = 1 << 13;
|
||||||
|
|
||||||
|
#[doc(hidden)]
|
||||||
|
pub const WEBGPU_FEATURE_CLIP_DISTANCES: u64 = 1 << 14;
|
||||||
}
|
}
|
||||||
|
|
||||||
macro_rules! bitflags_array_impl {
|
macro_rules! bitflags_array_impl {
|
||||||
@ -1463,7 +1466,18 @@ bitflags_array! {
|
|||||||
/// - Metal (with MSL 1.2+)
|
/// - Metal (with MSL 1.2+)
|
||||||
/// - Vulkan (with dualSrcBlend)
|
/// - Vulkan (with dualSrcBlend)
|
||||||
/// - DX12
|
/// - DX12
|
||||||
|
///
|
||||||
|
/// This is a web and native feature.
|
||||||
const DUAL_SOURCE_BLENDING = WEBGPU_FEATURE_DUAL_SOURCE_BLENDING;
|
const DUAL_SOURCE_BLENDING = WEBGPU_FEATURE_DUAL_SOURCE_BLENDING;
|
||||||
|
|
||||||
|
/// Allows the use of `@builtin(clip_distances)` in WGSL.
|
||||||
|
///
|
||||||
|
/// Supported platforms:
|
||||||
|
/// - Vulkan (mainly on Desktop GPUs)
|
||||||
|
/// - GL (Desktop or `GL_EXT_clip_cull_distance`)
|
||||||
|
///
|
||||||
|
/// This is a web and native feature.
|
||||||
|
const CLIP_DISTANCES = WEBGPU_FEATURE_CLIP_DISTANCES;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -712,7 +712,7 @@ fn map_map_mode(mode: crate::MapMode) -> u32 {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const FEATURES_MAPPING: [(wgt::Features, webgpu_sys::GpuFeatureName); 14] = [
|
const FEATURES_MAPPING: [(wgt::Features, webgpu_sys::GpuFeatureName); 15] = [
|
||||||
(
|
(
|
||||||
wgt::Features::DEPTH_CLIP_CONTROL,
|
wgt::Features::DEPTH_CLIP_CONTROL,
|
||||||
webgpu_sys::GpuFeatureName::DepthClipControl,
|
webgpu_sys::GpuFeatureName::DepthClipControl,
|
||||||
@ -769,6 +769,10 @@ const FEATURES_MAPPING: [(wgt::Features, webgpu_sys::GpuFeatureName); 14] = [
|
|||||||
wgt::Features::DUAL_SOURCE_BLENDING,
|
wgt::Features::DUAL_SOURCE_BLENDING,
|
||||||
webgpu_sys::GpuFeatureName::DualSourceBlending,
|
webgpu_sys::GpuFeatureName::DualSourceBlending,
|
||||||
),
|
),
|
||||||
|
(
|
||||||
|
wgt::Features::CLIP_DISTANCES,
|
||||||
|
webgpu_sys::GpuFeatureName::ClipDistances,
|
||||||
|
),
|
||||||
];
|
];
|
||||||
|
|
||||||
fn map_wgt_features(supported_features: webgpu_sys::GpuSupportedFeatures) -> wgt::Features {
|
fn map_wgt_features(supported_features: webgpu_sys::GpuSupportedFeatures) -> wgt::Features {
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user