mirror of
https://github.com/vulkano-rs/vulkano.git
synced 2024-11-21 14:24:18 +00:00
Add runtime SPIR-V validation (#2460)
* Add runtime SPIR-V validation * Remove copyright message * fmt * Up vk version in shader compilation (#2467) * Up vk version in shader compilation * Update test in codegen.rs * cargo +nightly fmt * Update lib.rs * clippy + fmt fixes * simplify changes * post merge * #2467 changelog * Remove windows specific dnd disable (#2474) * Fix unnecessarily strict validation for DRM format modifiers (#2469) * #2469 changelog * Add support for querying memory requirements directly from the device (#2470) * #2470 changelog * Make image_index and final_views accessible, and add new example. (#2473) * Make image_index and final_views accessible, and new example. The first 2 changes should make creating frame buffers easier. The new example should make it easier to learn vulkano-util. * Remove unnecessary imports, and run clippy. * Run fmt. * .acquire() no longer returns image_index * rename final_views() to swapchain_image_views() The name change makes it more consistent with swapchain_image_view(). Personally I don't understand why the field name is final_views, yet we externally in function names refer to it as swapchain image views and such like. * Fractal example no longer creates framebuffer every frame. * Game of life example no longer creates framebuffer every frame. (Also removed a piece of code I had commented out, but had forgotten to remove from the fractal example.) * Rename if_recreate_swapchain to on_recreate_swapchain and update acquire() documentation. to on_recreate_swapchain * on_recreate_swapchain is now impl FnOnce instead of generics based FnMut Thanks marc0246! Co-authored-by: marc0246 <40955683+marc0246@users.noreply.github.com> * Replace empty comment with an actual comment. --------- Co-authored-by: marc0246 <40955683+marc0246@users.noreply.github.com> * Fix `VulkanoWindowRenderer::swapchain_image_views` return type I have only noticed this as I was writing the changelog. @coolcatcoder for future reference, `&Vec<T>` is an anti-pattern. There's nothing more you can do with it than with `&[T]` (because the reference is immutable) and it means that we can't use a different underlying buffer without a breaking change. * #2473 changelog * Fix `VulkanoWindowRenderer::acquire` taking `&Vec<T>` as well * Replace cgmath with glam in the examples (#2475) * Replace cgmath with glam in the examples * Implement type_for_format! for glam * Remove comment where I'm freaking out because of OpenGL flashbacks * Update Cargo.toml Co-authored-by: marc0246 <40955683+marc0246@users.noreply.github.com> * Update vulkano/autogen/formats.rs Co-authored-by: marc0246 <40955683+marc0246@users.noreply.github.com> * Fix glam type_for_format * Format the code --------- Co-authored-by: marc0246 <40955683+marc0246@users.noreply.github.com> * #2475 changelog * Fix alignment checks when allocating buffers (#2476) * #2476 changelog * Add `DepthState::reverse` helper method (#2483) * #2483 changelog * Add runtime SPIR-V validation * Remove copyright message * fmt --------- Co-authored-by: maratik123 <marat.buharov@gmail.com> Co-authored-by: Okko Hakola <okkohakola@gmail.com> Co-authored-by: marc0246 <40955683+marc0246@users.noreply.github.com> Co-authored-by: Katt <51190960+coolcatcoder@users.noreply.github.com> Co-authored-by: stefnotch <stefnotch@users.noreply.github.com> Co-authored-by: José Miguel Sánchez García <soy.jmi2k@gmail.com>
This commit is contained in:
parent
16973acdab
commit
4666a9c722
@ -4,6 +4,7 @@ use heck::ToSnakeCase;
|
||||
use once_cell::sync::Lazy;
|
||||
use proc_macro2::{Ident, TokenStream};
|
||||
use quote::{format_ident, quote};
|
||||
use std::borrow::Cow;
|
||||
|
||||
// From the documentation of the OpSpecConstantOp instruction.
|
||||
// The instructions requiring the Kernel capability are not listed,
|
||||
@ -88,8 +89,19 @@ pub fn write(grammar: &SpirvGrammar) {
|
||||
#[derive(Clone, Debug)]
|
||||
struct InstructionMember {
|
||||
name: Ident,
|
||||
is_atomic_operation: bool,
|
||||
is_cooperative_matrix: bool,
|
||||
is_cooperative_matrix_nv: bool,
|
||||
is_group_operation: bool,
|
||||
is_quad_group_operation: bool,
|
||||
is_image_gather: bool,
|
||||
is_image_fetch: bool,
|
||||
is_image_sample: bool,
|
||||
has_result_id: bool,
|
||||
has_result_type_id: bool,
|
||||
has_execution_scope_id: bool,
|
||||
has_memory_scope_id: bool,
|
||||
has_image_operands: Option<bool>,
|
||||
opcode: u16,
|
||||
operands: Vec<OperandMember>,
|
||||
}
|
||||
@ -187,6 +199,153 @@ fn instruction_output(members: &[InstructionMember], spec_constant: bool) -> Tok
|
||||
}
|
||||
},
|
||||
);
|
||||
let is_cooperative_matrix_items = members.iter().filter_map(
|
||||
|InstructionMember {
|
||||
name,
|
||||
is_cooperative_matrix,
|
||||
..
|
||||
}| {
|
||||
if *is_cooperative_matrix {
|
||||
Some(quote! { Self::#name { .. } })
|
||||
} else {
|
||||
None
|
||||
}
|
||||
},
|
||||
);
|
||||
let is_cooperative_matrix_nv_items = members.iter().filter_map(
|
||||
|InstructionMember {
|
||||
name,
|
||||
is_cooperative_matrix_nv,
|
||||
..
|
||||
}| {
|
||||
if *is_cooperative_matrix_nv {
|
||||
Some(quote! { Self::#name { .. } })
|
||||
} else {
|
||||
None
|
||||
}
|
||||
},
|
||||
);
|
||||
let is_group_operation_items = members.iter().filter_map(
|
||||
|InstructionMember {
|
||||
name,
|
||||
is_group_operation,
|
||||
..
|
||||
}| {
|
||||
if *is_group_operation {
|
||||
Some(quote! { Self::#name { .. } })
|
||||
} else {
|
||||
None
|
||||
}
|
||||
},
|
||||
);
|
||||
let is_quad_group_operation_items = members.iter().filter_map(
|
||||
|InstructionMember {
|
||||
name,
|
||||
is_quad_group_operation,
|
||||
..
|
||||
}| {
|
||||
if *is_quad_group_operation {
|
||||
Some(quote! { Self::#name { .. } })
|
||||
} else {
|
||||
None
|
||||
}
|
||||
},
|
||||
);
|
||||
let is_image_fetch_items = members.iter().filter_map(
|
||||
|InstructionMember {
|
||||
name,
|
||||
is_image_fetch,
|
||||
..
|
||||
}| {
|
||||
if *is_image_fetch {
|
||||
Some(quote! { Self::#name { .. } })
|
||||
} else {
|
||||
None
|
||||
}
|
||||
},
|
||||
);
|
||||
let is_image_gather_items = members.iter().filter_map(
|
||||
|InstructionMember {
|
||||
name,
|
||||
is_image_gather,
|
||||
..
|
||||
}| {
|
||||
if *is_image_gather {
|
||||
Some(quote! { Self::#name { .. } })
|
||||
} else {
|
||||
None
|
||||
}
|
||||
},
|
||||
);
|
||||
let is_image_sample_items = members.iter().filter_map(
|
||||
|InstructionMember {
|
||||
name,
|
||||
is_image_sample,
|
||||
..
|
||||
}| {
|
||||
if *is_image_sample {
|
||||
Some(quote! { Self::#name { .. } })
|
||||
} else {
|
||||
None
|
||||
}
|
||||
},
|
||||
);
|
||||
let atomic_pointer_id_items = members.iter().filter_map(
|
||||
|InstructionMember {
|
||||
name,
|
||||
is_atomic_operation,
|
||||
..
|
||||
}| {
|
||||
if *is_atomic_operation {
|
||||
Some(quote! { Self::#name { pointer, .. } })
|
||||
} else {
|
||||
None
|
||||
}
|
||||
},
|
||||
);
|
||||
let execution_scope_id_items = members.iter().filter_map(
|
||||
|InstructionMember {
|
||||
name,
|
||||
has_execution_scope_id,
|
||||
..
|
||||
}| {
|
||||
if *has_execution_scope_id {
|
||||
Some(quote! { Self::#name { execution, .. } })
|
||||
} else {
|
||||
None
|
||||
}
|
||||
},
|
||||
);
|
||||
let memory_scope_id_items = members.iter().filter_map(
|
||||
|InstructionMember {
|
||||
name,
|
||||
has_memory_scope_id,
|
||||
..
|
||||
}| {
|
||||
if *has_memory_scope_id {
|
||||
Some(quote! { Self::#name { memory, .. } })
|
||||
} else {
|
||||
None
|
||||
}
|
||||
},
|
||||
);
|
||||
let image_operands_items = members.iter().filter_map(
|
||||
|InstructionMember {
|
||||
name,
|
||||
has_image_operands,
|
||||
..
|
||||
}| {
|
||||
if let Some(has_image_operands) = *has_image_operands {
|
||||
if has_image_operands {
|
||||
Some(quote! { Self::#name { image_operands: Some(image_operands), .. } })
|
||||
} else {
|
||||
Some(quote! { Self::#name { image_operands, .. } })
|
||||
}
|
||||
} else {
|
||||
None
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
quote! {
|
||||
/// Returns the `Id` that is assigned by this instruction, if any.
|
||||
@ -204,6 +363,94 @@ fn instruction_output(members: &[InstructionMember], spec_constant: bool) -> Tok
|
||||
_ => None
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the `Id` of the pointer in an atomic operation, if any.
|
||||
pub fn atomic_pointer_id(&self) -> Option<Id> {
|
||||
match self {
|
||||
#(#atomic_pointer_id_items)|* => Some(*pointer),
|
||||
_ => None
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns whether the instruction is a cooperative matrix instruction.
|
||||
pub fn is_cooperative_matrix(&self) -> bool {
|
||||
matches!(
|
||||
self,
|
||||
#(#is_cooperative_matrix_items)|*
|
||||
)
|
||||
}
|
||||
|
||||
/// Returns whether the instruction is an NV cooperative matrix instruction.
|
||||
pub fn is_cooperative_matrix_nv(&self) -> bool {
|
||||
matches!(
|
||||
self,
|
||||
#(#is_cooperative_matrix_nv_items)|*
|
||||
)
|
||||
}
|
||||
|
||||
/// Returns whether the instruction is a group operation instruction.
|
||||
pub fn is_group_operation(&self) -> bool {
|
||||
matches!(
|
||||
self,
|
||||
#(#is_group_operation_items)|*
|
||||
)
|
||||
}
|
||||
|
||||
/// Returns whether the instruction is a quad group operation instruction.
|
||||
pub fn is_quad_group_operation(&self) -> bool {
|
||||
matches!(
|
||||
self,
|
||||
#(#is_quad_group_operation_items)|*
|
||||
)
|
||||
}
|
||||
|
||||
/// Returns whether the instruction is an `ImageFetch*` instruction.
|
||||
pub fn is_image_fetch(&self) -> bool {
|
||||
matches!(
|
||||
self,
|
||||
#(#is_image_fetch_items)|*
|
||||
)
|
||||
}
|
||||
|
||||
/// Returns whether the instruction is an `Image*Gather` instruction.
|
||||
pub fn is_image_gather(&self) -> bool {
|
||||
matches!(
|
||||
self,
|
||||
#(#is_image_gather_items)|*
|
||||
)
|
||||
}
|
||||
|
||||
/// Returns whether the instruction is an `ImageSample*` instruction.
|
||||
pub fn is_image_sample(&self) -> bool {
|
||||
matches!(
|
||||
self,
|
||||
#(#is_image_sample_items)|*
|
||||
)
|
||||
}
|
||||
|
||||
/// Returns the `Id` of the execution scope ID operand, if any.
|
||||
pub fn execution_scope_id(&self) -> Option<Id> {
|
||||
match self {
|
||||
#(#execution_scope_id_items)|* => Some(*execution),
|
||||
_ => None
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the `Id` of the memory scope ID operand, if any.
|
||||
pub fn memory_scope_id(&self) -> Option<Id> {
|
||||
match self {
|
||||
#(#memory_scope_id_items)|* => Some(*memory),
|
||||
_ => None
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the image operands, if any.
|
||||
pub fn image_operands(&self) -> Option<&ImageOperands> {
|
||||
match self {
|
||||
#(#image_operands_items)|* => Some(image_operands),
|
||||
_ => None
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@ -242,9 +489,23 @@ fn instruction_members(grammar: &SpirvGrammar) -> Vec<InstructionMember> {
|
||||
.instructions
|
||||
.iter()
|
||||
.map(|instruction| {
|
||||
let name = format_ident!("{}", instruction.opname.strip_prefix("Op").unwrap());
|
||||
let name = instruction.opname.strip_prefix("Op").unwrap();
|
||||
let is_atomic_operation = instruction.class == "Atomic";
|
||||
let is_cooperative_matrix =
|
||||
name.starts_with("CooperativeMatrix") && !name.ends_with("NV");
|
||||
let is_cooperative_matrix_nv =
|
||||
name.starts_with("CooperativeMatrix") && name.ends_with("NV");
|
||||
let is_group_operation =
|
||||
instruction.class == "Group" || instruction.class == "Non-Uniform";
|
||||
let is_quad_group_operation = is_group_operation && instruction.opname.contains("Quad");
|
||||
let is_image_fetch = name.starts_with("ImageFetch");
|
||||
let is_image_gather = name.starts_with("Image") && name.ends_with("Gather");
|
||||
let is_image_sample = name.starts_with("ImageSample");
|
||||
let mut has_result_id = false;
|
||||
let mut has_result_type_id = false;
|
||||
let mut has_execution_scope_id = false;
|
||||
let mut has_memory_scope_id = false;
|
||||
let mut has_image_operands = None;
|
||||
let mut operand_names = HashMap::default();
|
||||
|
||||
let mut operands = instruction
|
||||
@ -258,7 +519,23 @@ fn instruction_members(grammar: &SpirvGrammar) -> Vec<InstructionMember> {
|
||||
has_result_type_id = true;
|
||||
format_ident!("result_type_id")
|
||||
} else {
|
||||
to_member_name(&operand.kind, operand.name.as_deref())
|
||||
let member_name = to_member_name(&operand.kind, operand.name.as_deref());
|
||||
|
||||
if operand.kind == "IdScope" {
|
||||
if member_name == "execution" {
|
||||
has_execution_scope_id = true;
|
||||
} else if member_name == "memory" {
|
||||
has_memory_scope_id = true;
|
||||
}
|
||||
} else if operand.kind == "ImageOperands" {
|
||||
if operand.quantifier == Some('?') {
|
||||
has_image_operands = Some(true);
|
||||
} else {
|
||||
has_image_operands = Some(false);
|
||||
}
|
||||
}
|
||||
|
||||
format_ident!("{}", member_name)
|
||||
};
|
||||
|
||||
*operand_names.entry(name.clone()).or_insert(0) += 1;
|
||||
@ -305,9 +582,20 @@ fn instruction_members(grammar: &SpirvGrammar) -> Vec<InstructionMember> {
|
||||
}
|
||||
|
||||
InstructionMember {
|
||||
name,
|
||||
name: format_ident!("{}", name),
|
||||
is_atomic_operation,
|
||||
is_cooperative_matrix,
|
||||
is_cooperative_matrix_nv,
|
||||
is_group_operation,
|
||||
is_quad_group_operation,
|
||||
is_image_fetch,
|
||||
is_image_gather,
|
||||
is_image_sample,
|
||||
has_result_id,
|
||||
has_result_type_id,
|
||||
has_execution_scope_id,
|
||||
has_memory_scope_id,
|
||||
has_image_operands,
|
||||
opcode: instruction.opcode,
|
||||
operands,
|
||||
}
|
||||
@ -465,7 +753,10 @@ fn bit_enum_members(grammar: &SpirvGrammar) -> Vec<(Ident, Vec<KindEnumMember>)>
|
||||
.parameters
|
||||
.iter()
|
||||
.map(|param| {
|
||||
let name = to_member_name(¶m.kind, param.name.as_deref());
|
||||
let name = format_ident!(
|
||||
"{}",
|
||||
to_member_name(¶m.kind, param.name.as_deref())
|
||||
);
|
||||
let (ty, parse) = parameter_kinds[param.kind.as_str()].clone();
|
||||
|
||||
OperandMember { name, ty, parse }
|
||||
@ -614,7 +905,10 @@ fn value_enum_members(grammar: &SpirvGrammar) -> Vec<(Ident, Vec<KindEnumMember>
|
||||
.parameters
|
||||
.iter()
|
||||
.map(|param| {
|
||||
let name = to_member_name(¶m.kind, param.name.as_deref());
|
||||
let name = format_ident!(
|
||||
"{}",
|
||||
to_member_name(¶m.kind, param.name.as_deref())
|
||||
);
|
||||
let (ty, parse) = parameter_kinds[param.kind.as_str()].clone();
|
||||
|
||||
OperandMember { name, ty, parse }
|
||||
@ -634,24 +928,24 @@ fn value_enum_members(grammar: &SpirvGrammar) -> Vec<(Ident, Vec<KindEnumMember>
|
||||
.collect()
|
||||
}
|
||||
|
||||
fn to_member_name(kind: &str, name: Option<&str>) -> Ident {
|
||||
fn to_member_name(kind: &str, name: Option<&str>) -> Cow<'static, str> {
|
||||
if let Some(name) = name {
|
||||
let name = name.to_snake_case();
|
||||
|
||||
// Fix some weird names
|
||||
match name.as_str() {
|
||||
"argument_0_argument_1" => format_ident!("arguments"),
|
||||
"member_0_type_member_1_type" => format_ident!("member_types"),
|
||||
"operand_1_operand_2" => format_ident!("operands"),
|
||||
"parameter_0_type_parameter_1_type" => format_ident!("parameter_types"),
|
||||
"the_name_of_the_opaque_type" => format_ident!("name"),
|
||||
"d_ref" => format_ident!("dref"),
|
||||
"type" => format_ident!("ty"), // type is a keyword
|
||||
"use" => format_ident!("usage"), // use is a keyword
|
||||
_ => format_ident!("{}", name.replace("operand_", "operand")),
|
||||
"argument_0_argument_1" => "arguments".into(),
|
||||
"member_0_type_member_1_type" => "member_types".into(),
|
||||
"operand_1_operand_2" => "operands".into(),
|
||||
"parameter_0_type_parameter_1_type" => "parameter_types".into(),
|
||||
"the_name_of_the_opaque_type" => "name".into(),
|
||||
"d_ref" => "dref".into(),
|
||||
"type" => "ty".into(), // type is a keyword
|
||||
"use" => "usage".into(), // use is a keyword
|
||||
_ => name.replace("operand_", "operand").into(),
|
||||
}
|
||||
} else {
|
||||
format_ident!("{}", kind.to_snake_case())
|
||||
kind.to_snake_case().into()
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -209,11 +209,11 @@ fn get_variables_by_key<'a>(
|
||||
variable_id,
|
||||
filter_storage_class,
|
||||
|key, data| {
|
||||
if let InputOutputKey::Location {
|
||||
if let InputOutputKey::User(InputOutputUserKey {
|
||||
location,
|
||||
component,
|
||||
..
|
||||
} = key
|
||||
}) = key
|
||||
{
|
||||
let InputOutputData {
|
||||
variable_id,
|
||||
@ -646,6 +646,15 @@ pub(crate) enum ShaderInterfaceLocationWidth {
|
||||
Bits64,
|
||||
}
|
||||
|
||||
impl ShaderInterfaceLocationWidth {
|
||||
pub(crate) fn component_count(self) -> u32 {
|
||||
match self {
|
||||
ShaderInterfaceLocationWidth::Bits32 => 1,
|
||||
ShaderInterfaceLocationWidth::Bits64 => 2,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<u32> for ShaderInterfaceLocationWidth {
|
||||
#[inline]
|
||||
fn from(value: u32) -> Self {
|
||||
@ -662,138 +671,6 @@ pub(crate) fn shader_interface_location_info(
|
||||
entry_point_id: Id,
|
||||
filter_storage_class: StorageClass,
|
||||
) -> HashMap<u32, ShaderInterfaceLocationInfo> {
|
||||
fn add_type(
|
||||
locations: &mut HashMap<u32, ShaderInterfaceLocationInfo>,
|
||||
spirv: &Spirv,
|
||||
mut location: u32,
|
||||
mut component: u32,
|
||||
index: u32,
|
||||
type_id: Id,
|
||||
) -> (u32, u32) {
|
||||
debug_assert!(component < 4);
|
||||
|
||||
let mut add_scalar = |numeric_type: NumericType, width: u32| -> (u32, u32) {
|
||||
let width = ShaderInterfaceLocationWidth::from(width);
|
||||
let components_to_add = match width {
|
||||
ShaderInterfaceLocationWidth::Bits32 => {
|
||||
ColorComponents::from_index(component as usize)
|
||||
}
|
||||
ShaderInterfaceLocationWidth::Bits64 => {
|
||||
debug_assert!(component & 1 == 0);
|
||||
ColorComponents::from_index(component as usize)
|
||||
| ColorComponents::from_index(component as usize + 1)
|
||||
}
|
||||
};
|
||||
|
||||
let location_info = match locations.entry(location) {
|
||||
Entry::Occupied(entry) => {
|
||||
let location_info = entry.into_mut();
|
||||
debug_assert_eq!(location_info.numeric_type, numeric_type);
|
||||
debug_assert_eq!(location_info.width, width);
|
||||
location_info
|
||||
}
|
||||
Entry::Vacant(entry) => entry.insert(ShaderInterfaceLocationInfo {
|
||||
numeric_type,
|
||||
width,
|
||||
components: [ColorComponents::empty(); 2],
|
||||
}),
|
||||
};
|
||||
|
||||
let components = &mut location_info.components[index as usize];
|
||||
debug_assert!(!components.intersects(components_to_add));
|
||||
*components |= components_to_add;
|
||||
|
||||
(components_to_add.count(), 1)
|
||||
};
|
||||
|
||||
match *spirv.id(type_id).instruction() {
|
||||
Instruction::TypeInt {
|
||||
width, signedness, ..
|
||||
} => {
|
||||
let numeric_type = if signedness == 1 {
|
||||
NumericType::Int
|
||||
} else {
|
||||
NumericType::Uint
|
||||
};
|
||||
|
||||
add_scalar(numeric_type, width)
|
||||
}
|
||||
Instruction::TypeFloat { width, .. } => add_scalar(NumericType::Float, width),
|
||||
Instruction::TypeVector {
|
||||
component_type,
|
||||
component_count,
|
||||
..
|
||||
} => {
|
||||
let mut total_locations_added = 1;
|
||||
|
||||
for _ in 0..component_count {
|
||||
// Overflow into next location
|
||||
if component == 4 {
|
||||
component = 0;
|
||||
location += 1;
|
||||
total_locations_added += 1;
|
||||
} else {
|
||||
debug_assert!(component < 4);
|
||||
}
|
||||
|
||||
let (_, components_added) =
|
||||
add_type(locations, spirv, location, component, index, component_type);
|
||||
component += components_added;
|
||||
}
|
||||
|
||||
(total_locations_added, 0)
|
||||
}
|
||||
Instruction::TypeMatrix {
|
||||
column_type,
|
||||
column_count,
|
||||
..
|
||||
} => {
|
||||
let mut total_locations_added = 0;
|
||||
|
||||
for _ in 0..column_count {
|
||||
let (locations_added, _) =
|
||||
add_type(locations, spirv, location, component, index, column_type);
|
||||
location += locations_added;
|
||||
total_locations_added += locations_added;
|
||||
}
|
||||
|
||||
(total_locations_added, 0)
|
||||
}
|
||||
Instruction::TypeArray {
|
||||
element_type,
|
||||
length,
|
||||
..
|
||||
} => {
|
||||
let length = get_constant(spirv, length).unwrap();
|
||||
let mut total_locations_added = 0;
|
||||
|
||||
for _ in 0..length {
|
||||
let (locations_added, _) =
|
||||
add_type(locations, spirv, location, component, index, element_type);
|
||||
location += locations_added;
|
||||
total_locations_added += locations_added;
|
||||
}
|
||||
|
||||
(total_locations_added, 0)
|
||||
}
|
||||
Instruction::TypeStruct {
|
||||
ref member_types, ..
|
||||
} => {
|
||||
let mut total_locations_added = 0;
|
||||
|
||||
for &member_type in member_types {
|
||||
let (locations_added, _) =
|
||||
add_type(locations, spirv, location, component, index, member_type);
|
||||
location += locations_added;
|
||||
total_locations_added += locations_added;
|
||||
}
|
||||
|
||||
(total_locations_added, 0)
|
||||
}
|
||||
_ => unimplemented!(),
|
||||
}
|
||||
}
|
||||
|
||||
let (execution_model, interface) = match spirv.function(entry_point_id).entry_point() {
|
||||
Some(&Instruction::EntryPoint {
|
||||
execution_model,
|
||||
@ -803,7 +680,42 @@ pub(crate) fn shader_interface_location_info(
|
||||
_ => unreachable!(),
|
||||
};
|
||||
|
||||
let mut locations = HashMap::default();
|
||||
let mut locations: HashMap<u32, ShaderInterfaceLocationInfo> = HashMap::default();
|
||||
let mut scalar_func = |key: InputOutputUserKey,
|
||||
width: ShaderInterfaceLocationWidth,
|
||||
numeric_type: NumericType| {
|
||||
let InputOutputUserKey {
|
||||
location,
|
||||
component,
|
||||
index,
|
||||
} = key;
|
||||
|
||||
let location_info = match locations.entry(location) {
|
||||
Entry::Occupied(entry) => {
|
||||
let location_info = entry.into_mut();
|
||||
debug_assert_eq!(location_info.numeric_type, numeric_type);
|
||||
debug_assert_eq!(location_info.width, width);
|
||||
location_info
|
||||
}
|
||||
Entry::Vacant(entry) => entry.insert(ShaderInterfaceLocationInfo {
|
||||
numeric_type,
|
||||
width,
|
||||
components: [ColorComponents::empty(); 2],
|
||||
}),
|
||||
};
|
||||
let components = &mut location_info.components[index as usize];
|
||||
|
||||
let components_to_add = match width {
|
||||
ShaderInterfaceLocationWidth::Bits32 => ColorComponents::from_index(component as usize),
|
||||
ShaderInterfaceLocationWidth::Bits64 => {
|
||||
debug_assert!(component & 1 == 0);
|
||||
ColorComponents::from_index(component as usize)
|
||||
| ColorComponents::from_index(component as usize + 1)
|
||||
}
|
||||
};
|
||||
debug_assert!(!components.intersects(components_to_add));
|
||||
*components |= components_to_add;
|
||||
};
|
||||
|
||||
for &variable_id in interface {
|
||||
input_output_map(
|
||||
@ -812,14 +724,9 @@ pub(crate) fn shader_interface_location_info(
|
||||
variable_id,
|
||||
filter_storage_class,
|
||||
|key, data| {
|
||||
if let InputOutputKey::Location {
|
||||
location,
|
||||
component,
|
||||
index,
|
||||
} = key
|
||||
{
|
||||
if let InputOutputKey::User(key) = key {
|
||||
let InputOutputData { type_id, .. } = data;
|
||||
add_type(&mut locations, spirv, location, component, index, type_id);
|
||||
shader_interface_analyze_type(spirv, type_id, key, &mut scalar_func);
|
||||
}
|
||||
},
|
||||
);
|
||||
@ -828,16 +735,121 @@ pub(crate) fn shader_interface_location_info(
|
||||
locations
|
||||
}
|
||||
|
||||
/// Recursively analyzes the type `type_id` with the given `key`. Calls `scalar_func` on every
|
||||
/// scalar type that is encountered, and returns the number of locations and components to advance.
|
||||
pub(crate) fn shader_interface_analyze_type(
|
||||
spirv: &Spirv,
|
||||
type_id: Id,
|
||||
mut key: InputOutputUserKey,
|
||||
scalar_func: &mut impl FnMut(InputOutputUserKey, ShaderInterfaceLocationWidth, NumericType),
|
||||
) -> (u32, u32) {
|
||||
debug_assert!(key.component < 4);
|
||||
|
||||
match *spirv.id(type_id).instruction() {
|
||||
Instruction::TypeInt {
|
||||
width, signedness, ..
|
||||
} => {
|
||||
let numeric_type = if signedness == 1 {
|
||||
NumericType::Int
|
||||
} else {
|
||||
NumericType::Uint
|
||||
};
|
||||
|
||||
let width = ShaderInterfaceLocationWidth::from(width);
|
||||
scalar_func(key, width, numeric_type);
|
||||
(1, width.component_count())
|
||||
}
|
||||
Instruction::TypeFloat { width, .. } => {
|
||||
let width = ShaderInterfaceLocationWidth::from(width);
|
||||
scalar_func(key, width, NumericType::Float);
|
||||
(1, width.component_count())
|
||||
}
|
||||
Instruction::TypeVector {
|
||||
component_type,
|
||||
component_count,
|
||||
..
|
||||
} => {
|
||||
let mut total_locations_added = 1;
|
||||
|
||||
for _ in 0..component_count {
|
||||
// Overflow into next location
|
||||
if key.component == 4 {
|
||||
key.component = 0;
|
||||
key.location += 1;
|
||||
total_locations_added += 1;
|
||||
} else {
|
||||
debug_assert!(key.component < 4);
|
||||
}
|
||||
|
||||
let (_, components_added) =
|
||||
shader_interface_analyze_type(spirv, component_type, key, scalar_func);
|
||||
key.component += components_added;
|
||||
}
|
||||
|
||||
(total_locations_added, 0)
|
||||
}
|
||||
Instruction::TypeMatrix {
|
||||
column_type,
|
||||
column_count,
|
||||
..
|
||||
} => {
|
||||
let mut total_locations_added = 0;
|
||||
|
||||
for _ in 0..column_count {
|
||||
let (locations_added, _) =
|
||||
shader_interface_analyze_type(spirv, column_type, key, scalar_func);
|
||||
key.location += locations_added;
|
||||
total_locations_added += locations_added;
|
||||
}
|
||||
|
||||
(total_locations_added, 0)
|
||||
}
|
||||
Instruction::TypeArray {
|
||||
element_type,
|
||||
length,
|
||||
..
|
||||
} => {
|
||||
let length = get_constant(spirv, length).unwrap();
|
||||
let mut total_locations_added = 0;
|
||||
|
||||
for _ in 0..length {
|
||||
let (locations_added, _) =
|
||||
shader_interface_analyze_type(spirv, element_type, key, scalar_func);
|
||||
key.location += locations_added;
|
||||
total_locations_added += locations_added;
|
||||
}
|
||||
|
||||
(total_locations_added, 0)
|
||||
}
|
||||
Instruction::TypeStruct {
|
||||
ref member_types, ..
|
||||
} => {
|
||||
let mut total_locations_added = 0;
|
||||
|
||||
for &member_type in member_types {
|
||||
let (locations_added, _) =
|
||||
shader_interface_analyze_type(spirv, member_type, key, scalar_func);
|
||||
key.location += locations_added;
|
||||
total_locations_added += locations_added;
|
||||
}
|
||||
|
||||
(total_locations_added, 0)
|
||||
}
|
||||
_ => unimplemented!(),
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
|
||||
pub(crate) enum InputOutputKey {
|
||||
Location {
|
||||
location: u32,
|
||||
component: u32,
|
||||
index: u32,
|
||||
},
|
||||
BuiltIn {
|
||||
built_in: BuiltIn,
|
||||
},
|
||||
User(InputOutputUserKey),
|
||||
BuiltIn(BuiltIn),
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Hash)]
|
||||
pub(crate) struct InputOutputUserKey {
|
||||
pub(crate) location: u32,
|
||||
pub(crate) component: u32,
|
||||
pub(crate) index: u32,
|
||||
}
|
||||
|
||||
pub(crate) struct InputOutputData {
|
||||
@ -895,11 +907,11 @@ pub(crate) fn input_output_map(
|
||||
|
||||
if let Some(location) = location {
|
||||
func(
|
||||
InputOutputKey::Location {
|
||||
InputOutputKey::User(InputOutputUserKey {
|
||||
location,
|
||||
component,
|
||||
index,
|
||||
},
|
||||
}),
|
||||
InputOutputData {
|
||||
variable_id,
|
||||
pointer_type_id,
|
||||
@ -909,7 +921,7 @@ pub(crate) fn input_output_map(
|
||||
);
|
||||
} else if let Some(built_in) = built_in {
|
||||
func(
|
||||
InputOutputKey::BuiltIn { built_in },
|
||||
InputOutputKey::BuiltIn(built_in),
|
||||
InputOutputData {
|
||||
variable_id,
|
||||
pointer_type_id,
|
||||
@ -949,11 +961,11 @@ pub(crate) fn input_output_map(
|
||||
|
||||
if let Some(location) = location {
|
||||
func(
|
||||
InputOutputKey::Location {
|
||||
InputOutputKey::User(InputOutputUserKey {
|
||||
location,
|
||||
component,
|
||||
index,
|
||||
},
|
||||
}),
|
||||
InputOutputData {
|
||||
variable_id,
|
||||
pointer_type_id,
|
||||
@ -966,7 +978,7 @@ pub(crate) fn input_output_map(
|
||||
);
|
||||
} else if let Some(built_in) = built_in {
|
||||
func(
|
||||
InputOutputKey::BuiltIn { built_in },
|
||||
InputOutputKey::BuiltIn(built_in),
|
||||
InputOutputData {
|
||||
variable_id,
|
||||
pointer_type_id,
|
||||
|
@ -9,6 +9,7 @@ use crate::{
|
||||
};
|
||||
|
||||
pub(crate) mod inout_interface;
|
||||
pub(crate) mod validate_runtime;
|
||||
|
||||
/// Specifies a single shader stage when creating a pipeline.
|
||||
#[derive(Clone, Debug)]
|
||||
@ -62,6 +63,9 @@ impl PipelineShaderStageCreateInfo {
|
||||
} = self;
|
||||
|
||||
let spirv = entry_point.module().spirv();
|
||||
validate_runtime::validate_runtime(device, spirv, entry_point.id())
|
||||
.map_err(|err| err.add_context("entry_point"))?;
|
||||
|
||||
let properties = device.physical_device().properties();
|
||||
|
||||
flags.validate_device(device).map_err(|err| {
|
||||
|
2925
vulkano/src/pipeline/shader/validate_runtime.rs
Normal file
2925
vulkano/src/pipeline/shader/validate_runtime.rs
Normal file
File diff suppressed because it is too large
Load Diff
@ -138,13 +138,23 @@
|
||||
//! then if the shader accesses a descriptor in that binding, the descriptor must be initialized
|
||||
//! and contain a valid resource.
|
||||
//!
|
||||
//! ## Buffers
|
||||
//! ## Buffers and memory accesses
|
||||
//!
|
||||
//! - If the [`robust_buffer_access`](Features::robust_buffer_access) feature is not enabled on the
|
||||
//! device, then the shader must not access any values outside the range of the buffer, as
|
||||
//! specified when writing the descriptor set. <sup>[\[06935\]] [\[06936\]]</sup>
|
||||
//! - If any `PhysicalStorageBuffer` pointers to device memory are dereferenced in the shader, then
|
||||
//! they must point to valid buffer memory of the correct type.
|
||||
//! - If any `PhysicalStorageBuffer` pointers to device memory are dereferenced in the shader,
|
||||
//! then:
|
||||
//! - The pointer must point to valid memory of the correct type.
|
||||
//! - The pointer must be aligned to a multiple of the largest scalar type within the type that
|
||||
//! it points to. <sup>[\[06314\]]</sup>
|
||||
//! - If the instruction has `Aligned` as one of its memory operands, the pointer must be aligned
|
||||
//! to the specified alignment. <sup>[\[06315\]]</sup>
|
||||
//! - For `OpCooperativeMatrixLoadKHR`, `OpCooperativeMatrixStoreKHR`, `OpCooperativeMatrixLoadNV`
|
||||
//! and `OpCooperativeMatrixStoreNV` instructions, the `Pointer` and `Stride` operands must both
|
||||
//! be aligned to the minimum of either 16 bytes or the number of bytes per row/column of the
|
||||
//! matrix (depending on the `ColumnMajor` and `RowMajor` decorations). <sup>[\[06324\]]
|
||||
//! [\[08986\]]</sup>
|
||||
//!
|
||||
//! ## Image views and buffer views
|
||||
//!
|
||||
@ -160,6 +170,8 @@
|
||||
//! only if the format of the bound image view or buffer view also has a 64-bit component.
|
||||
//! Otherwise, it must have a `Width` of 32. <sup>[\[04470\]] [\[04471\]] [\[04472\]]
|
||||
//! [\[04473\]]</sup>
|
||||
//! - The [`samples`](Image::samples) of the underlying image of the bound image view must match
|
||||
//! the `MS` operand of the `OpImageType`. <sup>[\[08725\]] [\[08726\]]</sup>
|
||||
//! - For a storage image/texel buffer declared with `OpTypeImage` with an `Unknown` format:
|
||||
//! - If it is written to in the shader, the format of the bound image view or buffer view must
|
||||
//! have the [`FormatFeatures::STORAGE_WRITE_WITHOUT_FORMAT`] format feature. <sup>[\[07027\]]
|
||||
@ -209,54 +221,197 @@
|
||||
//! - The sampler must not be used with the `ConstOffset` or `Offset` image operands.
|
||||
//! <sup>[\[06551\]]</sup>
|
||||
//!
|
||||
//! ## Acceleration structures
|
||||
//! ## Mesh shading
|
||||
//!
|
||||
//! - If the shader declares the `OutputPoints` execution mode with a value greater than 0, and the
|
||||
//! [`maintenance5`](Features::maintenance5) feature is not enabled on the device, then the
|
||||
//! shader must write to a variable decorated with `PointSize` for each output point.
|
||||
//! <sup>[\[09218\]]</sup>
|
||||
//!
|
||||
//! For `OpSetMeshOutputsEXT` instructions:
|
||||
//!
|
||||
//! - The `Vertex Count` operand must be less than or equal to the value declared with the shader's
|
||||
//! `OutputVertices` execution mode. <sup>[\[07332\]]</sup>
|
||||
//! - The `Primitive Count` operand must be less than or equal to the value declared with the
|
||||
//! shader's `OutputPrimitivesEXT` execution mode. <sup>[\[07333\]]</sup>
|
||||
//!
|
||||
//! ## Acceleration structures, ray queries and ray tracing
|
||||
//!
|
||||
//! - Acceleration structures that are used as operands to an instruction must have been built as a
|
||||
//! top-level acceleration structure. <sup>[\[06352\]] [\[06359\]] [\[06365\]] [\[07709\]]</sup>
|
||||
//! - In any top-level acceleration structure, the pointers that refer to the contained
|
||||
//! bottom-level acceleration structure instances must point to valid acceleration structures.
|
||||
//! bottom-level acceleration structure instances must point to valid bottom-level acceleration
|
||||
//! structures.
|
||||
//!
|
||||
//! For `OpRayQueryInitializeKHR` and `OpTraceRayKHR` instructions:
|
||||
//!
|
||||
//! - The `Rayflags` operand must not contain more than one of:
|
||||
//! - `SkipTrianglesKHR`, `CullBackFacingTrianglesKHR` and `CullFrontFacingTrianglesKHR`
|
||||
//! <sup>[\[06889\]] [\[06892\]]</sup>
|
||||
//! - `SkipTrianglesKHR` and `SkipAABBsKHR` <sup>[\[06890\]] [\[06552\]] [\[07712\]]</sup>
|
||||
//! - `OpaqueKHR`, `NoOpaqueKHR`, `CullOpaqueKHR`, and `CullNoOpaqueKHR` <sup>[\[06891\]]
|
||||
//! [\[06893\]]</sup>
|
||||
//! - The `RayOrigin` and `RayDirection` operands must not contain infinite or NaN values. <sup>
|
||||
//! [\[06348\]] [\[06351\]] [\[06355\]] [\[06358\]] </sup>
|
||||
//! - The `RayTmin` and `RayTmax` operands must not contain negative or NaN values, and `RayTmin`
|
||||
//! must be less than or equal to `RayTmax`. <sup> [\[06349\]] [\[06350\]] [\[06351\]]
|
||||
//! [\[06356\]] [\[06357\]] [\[06358\]] </sup>
|
||||
//!
|
||||
//! For `OpRayQueryGenerateIntersectionKHR` instructions:
|
||||
//!
|
||||
//! - The `Hit T` operand must be greater than or equal to the value that would be returned by
|
||||
//! `OpRayQueryGetRayTMinKHR`. <sup>[\[06353\]]</sup>
|
||||
//! - The `Hit T` operand must be less than or equal to the value that would be returned by
|
||||
//! `OpRayQueryGetIntersectionTKHR` for the current committed intersection.
|
||||
//! <sup>[\[06353\]]</sup>
|
||||
//!
|
||||
//! For `OpReportIntersectionKHR` instructions:
|
||||
//!
|
||||
//! - The `Hit Kind` operand must be between 0 and 127 inclusive. <sup>[\[06998\]]</sup>
|
||||
//!
|
||||
//! ## Dynamically uniform values and control flow
|
||||
//!
|
||||
//! In a shader, a value (expression, variable) is *[dynamically uniform]* if its value is the same
|
||||
//! for all shader invocations within an *invocation group*. What counts as an invocation group
|
||||
//! depends on the type of shader being executed:
|
||||
//!
|
||||
//! - For compute, task and mesh shaders, an invocation group is the same as the (local) workgroup.
|
||||
//! A single `dispatch` command value spawns one distinct invocation group for every element in
|
||||
//! the product of the given `group_counts` argument.
|
||||
//! - For all other graphics shaders, an invocation group is all shaders invoked by a single draw
|
||||
//! command. For indirect draws, each element of the indirect buffer creates one draw call.
|
||||
//! - For ray tracing shaders, an invocation group is an implementation-dependent subset of the
|
||||
//! shaders invoked by a single ray tracing command.
|
||||
//!
|
||||
//! Vulkan and SPIR-V assume that certain values within a shader are dynamically uniform, and will
|
||||
//! optimize the generated shader code accordingly. If such a value is not actually dynamically
|
||||
//! uniform, this results in undefined behavior. This concerns the following values:
|
||||
//!
|
||||
//! - The index into an arrayed descriptor binding. If the index is not dynamically uniform, you
|
||||
//! must explicitly mark it with the `NonUniform` decoration in SPIR-V, or the `nonuniformEXT`
|
||||
//! function in GLSL. <sup>[\[06274\]]</sup>
|
||||
//! - The `Index` argument of the `OpGroupNonUniformQuadBroadcast` instruction.
|
||||
//! <sup>[\[06276\]]</sup>
|
||||
//! - The `Id` argument of the `OpGroupNonUniformBroadcast` instruction. <sup>[\[06277\]]</sup>
|
||||
//! - The arguments of the `OpEmitMeshTasksEXT` and `OpSetMeshOutputsEXT` instructions.
|
||||
//! <sup>[\[07117\]] [\[07118\]]</sup>
|
||||
//! - The `Texture Sampled Image` and `Weight Image` arguments of the `OpImageWeightedSampleQCOM`
|
||||
//! instruction. <sup>[\[06979\]]</sup>
|
||||
//! - The `Texture Sampled Image`, `Reference Sampled Image` and `Block Size` arguments of the
|
||||
//! `OpImageBlockMatchSADQCOM` and `OpImageBlockMatchSSDQCOM` instructions.
|
||||
//! <sup>[\[06982\]]</sup>
|
||||
//! - The `Sampled Texture Image` and `Box Size` arguments of the `OpImageBoxFilterQCOM`
|
||||
//! instruction. <sup>[\[06990\]]</sup>
|
||||
//! - The `Target Sampled Image`, `Reference Sampled Image` and `Block Size` arguments of any
|
||||
//! `OpImageBlockMatchWindow*QCOM` or `OpImageBlockMatchGather*QCOM` instructions.
|
||||
//! <sup>[\[09219\]]</sup>
|
||||
//!
|
||||
//! Some operations have specific requirements for control flow within the shader:
|
||||
//!
|
||||
//! - The `OpEmitMeshTasksEXT` and `OpSetMeshOutputsEXT` instructions must be executed uniformly
|
||||
//! within the invocation group. That means that, either all shader invocations within the
|
||||
//! invocation group must execute the instruction, or none of them must execute it.
|
||||
//! <sup>[\[07117\]] [\[07118\]]</sup>
|
||||
//! - If the `PointSize` built-in is written to, then all execution paths must write to it.
|
||||
//! <sup>[\[09190\]]</sup>
|
||||
//!
|
||||
//! [alignment rules]: https://registry.khronos.org/vulkan/specs/1.3-extensions/html/chap15.html#interfaces-resources-layout
|
||||
//! [`GL_EXT_scalar_block_layout`]: https://github.com/KhronosGroup/GLSL/blob/master/extensions/ext/GL_EXT_scalar_block_layout.txt
|
||||
//! [`scalar_block_layout`]: crate::device::Features::scalar_block_layout
|
||||
//! [`uniform_buffer_standard_layout`]: crate::device::Features::uniform_buffer_standard_layout
|
||||
//! [\[06935\]]: https://registry.khronos.org/vulkan/specs/1.3-extensions/html/vkspec.html#VUID-vkCmdDispatch-uniformBuffers-06935
|
||||
//! [\[06936\]]: https://registry.khronos.org/vulkan/specs/1.3-extensions/html/vkspec.html#VUID-vkCmdDispatch-storageBuffers-06936
|
||||
//! [\[07752\]]: https://registry.khronos.org/vulkan/specs/1.3-extensions/html/vkspec.html#VUID-vkCmdDispatch-viewType-07752
|
||||
//! [\[07753\]]: https://registry.khronos.org/vulkan/specs/1.3-extensions/html/vkspec.html#VUID-vkCmdDispatch-format-07753
|
||||
//! [`scalar_block_layout`]: Features::scalar_block_layout
|
||||
//! [`uniform_buffer_standard_layout`]: Features::uniform_buffer_standard_layout
|
||||
//! [dynamically uniform]: https://registry.khronos.org/SPIR-V/specs/unified1/SPIRV.html#_uniformity
|
||||
//! [\[02691\]]: https://registry.khronos.org/vulkan/specs/1.3-extensions/html/vkspec.html#VUID-vkCmdDispatch-None-02691
|
||||
//! [\[02692\]]: https://registry.khronos.org/vulkan/specs/1.3-extensions/html/vkspec.html#VUID-vkCmdDispatch-None-02692
|
||||
//! [\[02694\]]: https://registry.khronos.org/vulkan/specs/1.3-extensions/html/vkspec.html#VUID-vkCmdDispatch-filterCubic-02694
|
||||
//! [\[02695\]]: https://registry.khronos.org/vulkan/specs/1.3-extensions/html/vkspec.html#VUID-vkCmdDispatch-filterCubicMinmax-02695
|
||||
//! [\[04469\]]: https://registry.khronos.org/vulkan/specs/1.3-extensions/html/vkspec.html#VUID-vkCmdDispatch-OpImageWrite-04469
|
||||
//! [\[08795\]]: https://registry.khronos.org/vulkan/specs/1.3-extensions/html/vkspec.html#VUID-vkCmdDispatch-OpImageWrite-08795
|
||||
//! [\[08796\]]: https://registry.khronos.org/vulkan/specs/1.3-extensions/html/vkspec.html#VUID-vkCmdDispatch-OpImageWrite-08796
|
||||
//! [\[04470\]]: https://registry.khronos.org/vulkan/specs/1.3-extensions/html/vkspec.html#VUID-vkCmdDispatch-SampledType-04470
|
||||
//! [\[04471\]]: https://registry.khronos.org/vulkan/specs/1.3-extensions/html/vkspec.html#VUID-vkCmdDispatch-SampledType-04471
|
||||
//! [\[04472\]]: https://registry.khronos.org/vulkan/specs/1.3-extensions/html/vkspec.html#VUID-vkCmdDispatch-SampledType-04472
|
||||
//! [\[04473\]]: https://registry.khronos.org/vulkan/specs/1.3-extensions/html/vkspec.html#VUID-vkCmdDispatch-SampledType-04473
|
||||
//! [\[04553\]]: https://registry.khronos.org/vulkan/specs/1.3-extensions/html/vkspec.html#VUID-vkCmdDispatch-magFilter-04553
|
||||
//! [\[04770\]]: https://registry.khronos.org/vulkan/specs/1.3-extensions/html/vkspec.html#VUID-vkCmdDispatch-mipmapMode-04770
|
||||
//! [\[06274\]]: https://registry.khronos.org/vulkan/specs/1.3-extensions/html/vkspec.html#VUID-RuntimeSpirv-NonUniform-06274
|
||||
//! [\[06276\]]: https://registry.khronos.org/vulkan/specs/1.3-extensions/html/vkspec.html#VUID-RuntimeSpirv-subgroupBroadcastDynamicId-06276
|
||||
//! [\[06277\]]: https://registry.khronos.org/vulkan/specs/1.3-extensions/html/vkspec.html#VUID-RuntimeSpirv-subgroupBroadcastDynamicId-06277
|
||||
//! [\[06314\]]: https://registry.khronos.org/vulkan/specs/1.3-extensions/html/vkspec.html#VUID-RuntimeSpirv-PhysicalStorageBuffer64-06314
|
||||
//! [\[06315\]]: https://registry.khronos.org/vulkan/specs/1.3-extensions/html/vkspec.html#VUID-RuntimeSpirv-PhysicalStorageBuffer64-06315
|
||||
//! [\[06324\]]: https://registry.khronos.org/vulkan/specs/1.3-extensions/html/vkspec.html#VUID-RuntimeSpirv-OpCooperativeMatrixLoadNV-06324
|
||||
//! [\[06348\]]: https://registry.khronos.org/vulkan/specs/1.3-extensions/html/vkspec.html#VUID-RuntimeSpirv-OpRayQueryInitializeKHR-06348
|
||||
//! [\[06349\]]: https://registry.khronos.org/vulkan/specs/1.3-extensions/html/vkspec.html#VUID-RuntimeSpirv-OpRayQueryInitializeKHR-06349
|
||||
//! [\[06350\]]: https://registry.khronos.org/vulkan/specs/1.3-extensions/html/vkspec.html#VUID-RuntimeSpirv-OpRayQueryInitializeKHR-06350
|
||||
//! [\[06351\]]: https://registry.khronos.org/vulkan/specs/1.3-extensions/html/vkspec.html#VUID-RuntimeSpirv-OpRayQueryInitializeKHR-06351
|
||||
//! [\[06352\]]: https://registry.khronos.org/vulkan/specs/1.3-extensions/html/vkspec.html#VUID-RuntimeSpirv-OpRayQueryInitializeKHR-06352
|
||||
//! [\[06353\]]: https://registry.khronos.org/vulkan/specs/1.3-extensions/html/vkspec.html#VUID-RuntimeSpirv-OpRayQueryGenerateIntersectionKHR-06353
|
||||
//! [\[06355\]]: https://registry.khronos.org/vulkan/specs/1.3-extensions/html/vkspec.html#VUID-RuntimeSpirv-OpTraceRayKHR-06355
|
||||
//! [\[06356\]]: https://registry.khronos.org/vulkan/specs/1.3-extensions/html/vkspec.html#VUID-RuntimeSpirv-OpTraceRayKHR-06356
|
||||
//! [\[06357\]]: https://registry.khronos.org/vulkan/specs/1.3-extensions/html/vkspec.html#VUID-RuntimeSpirv-OpTraceRayKHR-06357
|
||||
//! [\[06358\]]: https://registry.khronos.org/vulkan/specs/1.3-extensions/html/vkspec.html#VUID-RuntimeSpirv-OpTraceRayKHR-06358
|
||||
//! [\[06359\]]: https://registry.khronos.org/vulkan/specs/1.3-extensions/html/vkspec.html#VUID-RuntimeSpirv-OpTraceRayKHR-06359
|
||||
//! [\[06361\]]: https://registry.khronos.org/vulkan/specs/1.3-extensions/html/vkspec.html#VUID-RuntimeSpirv-OpTraceRayMotionNV-06361
|
||||
//! [\[06362\]]: https://registry.khronos.org/vulkan/specs/1.3-extensions/html/vkspec.html#VUID-RuntimeSpirv-OpTraceRayMotionNV-06362
|
||||
//! [\[06363\]]: https://registry.khronos.org/vulkan/specs/1.3-extensions/html/vkspec.html#VUID-RuntimeSpirv-OpTraceRayMotionNV-06363
|
||||
//! [\[06364\]]: https://registry.khronos.org/vulkan/specs/1.3-extensions/html/vkspec.html#VUID-RuntimeSpirv-OpTraceRayMotionNV-06364
|
||||
//! [\[06365\]]: https://registry.khronos.org/vulkan/specs/1.3-extensions/html/vkspec.html#VUID-RuntimeSpirv-OpTraceRayMotionNV-06365
|
||||
//! [\[06366\]]: https://registry.khronos.org/vulkan/specs/1.3-extensions/html/vkspec.html#VUID-RuntimeSpirv-OpTraceRayMotionNV-06366
|
||||
//! [\[06479\]]: https://registry.khronos.org/vulkan/specs/1.3-extensions/html/vkspec.html#VUID-vkCmdDispatch-None-06479
|
||||
//! [\[06550\]]: https://registry.khronos.org/vulkan/specs/1.3-extensions/html/vkspec.html#VUID-vkCmdDispatch-None-06550
|
||||
//! [\[06551\]]: https://registry.khronos.org/vulkan/specs/1.3-extensions/html/vkspec.html#VUID-vkCmdDispatch-ConstOffset-06551
|
||||
//! [\[06552\]]: https://registry.khronos.org/vulkan/specs/1.3-extensions/html/vkspec.html#VUID-RuntimeSpirv-OpTraceRayKHR-06552
|
||||
//! [\[06889\]]: https://registry.khronos.org/vulkan/specs/1.3-extensions/html/vkspec.html#VUID-RuntimeSpirv-OpRayQueryInitializeKHR-06889
|
||||
//! [\[06890\]]: https://registry.khronos.org/vulkan/specs/1.3-extensions/html/vkspec.html#VUID-RuntimeSpirv-OpRayQueryInitializeKHR-06890
|
||||
//! [\[06891\]]: https://registry.khronos.org/vulkan/specs/1.3-extensions/html/vkspec.html#VUID-RuntimeSpirv-OpRayQueryInitializeKHR-06891
|
||||
//! [\[06892\]]: https://registry.khronos.org/vulkan/specs/1.3-extensions/html/vkspec.html#VUID-RuntimeSpirv-OpTraceRayKHR-06892
|
||||
//! [\[06893\]]: https://registry.khronos.org/vulkan/specs/1.3-extensions/html/vkspec.html#VUID-RuntimeSpirv-OpTraceRayKHR-06893
|
||||
//! [\[06935\]]: https://registry.khronos.org/vulkan/specs/1.3-extensions/html/vkspec.html#VUID-vkCmdDispatch-uniformBuffers-06935
|
||||
//! [\[06936\]]: https://registry.khronos.org/vulkan/specs/1.3-extensions/html/vkspec.html#VUID-vkCmdDispatch-storageBuffers-06936
|
||||
//! [\[06979\]]: https://registry.khronos.org/vulkan/specs/1.3-extensions/html/vkspec.html#VUID-RuntimeSpirv-OpImageWeightedSampleQCOM-06979
|
||||
//! [\[06982\]]: https://registry.khronos.org/vulkan/specs/1.3-extensions/html/vkspec.html#VUID-RuntimeSpirv-OpImageBlockMatchSADQCOM-06982
|
||||
//! [\[06990\]]: https://registry.khronos.org/vulkan/specs/1.3-extensions/html/vkspec.html#VUID-RuntimeSpirv-OpImageBoxFilterQCOM-06990
|
||||
//! [\[06998\]]: https://registry.khronos.org/vulkan/specs/1.3-extensions/html/vkspec.html#VUID-RuntimeSpirv-OpReportIntersectionKHR-06998
|
||||
//! [\[07027\]]: https://registry.khronos.org/vulkan/specs/1.3-extensions/html/vkspec.html#VUID-vkCmdDispatch-OpTypeImage-07027
|
||||
//! [\[07029\]]: https://registry.khronos.org/vulkan/specs/1.3-extensions/html/vkspec.html#VUID-vkCmdDispatch-OpTypeImage-07029
|
||||
//! [\[07028\]]: https://registry.khronos.org/vulkan/specs/1.3-extensions/html/vkspec.html#VUID-vkCmdDispatch-OpTypeImage-07028
|
||||
//! [\[07030\]]: https://registry.khronos.org/vulkan/specs/1.3-extensions/html/vkspec.html#VUID-vkCmdDispatch-OpTypeImage-07030
|
||||
//! [\[02691\]]: https://registry.khronos.org/vulkan/specs/1.3-extensions/html/vkspec.html#VUID-vkCmdDispatch-None-02691
|
||||
//! [\[07117\]]: https://registry.khronos.org/vulkan/specs/1.3-extensions/html/vkspec.html#VUID-RuntimeSpirv-TaskEXT-07117
|
||||
//! [\[07118\]]: https://registry.khronos.org/vulkan/specs/1.3-extensions/html/vkspec.html#VUID-RuntimeSpirv-MeshEXT-07118
|
||||
//! [\[07332\]]: https://registry.khronos.org/vulkan/specs/1.3-extensions/html/vkspec.html#VUID-RuntimeSpirv-MeshEXT-07332
|
||||
//! [\[07333\]]: https://registry.khronos.org/vulkan/specs/1.3-extensions/html/vkspec.html#VUID-RuntimeSpirv-MeshEXT-07333
|
||||
//! [\[07705\]]: https://registry.khronos.org/vulkan/specs/1.3-extensions/html/vkspec.html#VUID-RuntimeSpirv-OpHitObjectTraceRayNV-07705
|
||||
//! [\[07706\]]: https://registry.khronos.org/vulkan/specs/1.3-extensions/html/vkspec.html#VUID-RuntimeSpirv-OpHitObjectTraceRayNV-07706
|
||||
//! [\[07707\]]: https://registry.khronos.org/vulkan/specs/1.3-extensions/html/vkspec.html#VUID-RuntimeSpirv-OpHitObjectTraceRayNV-07707
|
||||
//! [\[07708\]]: https://registry.khronos.org/vulkan/specs/1.3-extensions/html/vkspec.html#VUID-RuntimeSpirv-OpHitObjectTraceRayNV-07708
|
||||
//! [\[07709\]]: https://registry.khronos.org/vulkan/specs/1.3-extensions/html/vkspec.html#VUID-RuntimeSpirv-OpHitObjectTraceRayMotionNV-07709
|
||||
//! [\[07710\]]: https://registry.khronos.org/vulkan/specs/1.3-extensions/html/vkspec.html#VUID-RuntimeSpirv-OpHitObjectTraceRayNV-07710
|
||||
//! [\[07712\]]: https://registry.khronos.org/vulkan/specs/1.3-extensions/html/vkspec.html#VUID-RuntimeSpirv-OpHitObjectTraceRayNV-07712
|
||||
//! [\[07713\]]: https://registry.khronos.org/vulkan/specs/1.3-extensions/html/vkspec.html#VUID-RuntimeSpirv-OpHitObjectTraceRayNV-07713
|
||||
//! [\[07714\]]: https://registry.khronos.org/vulkan/specs/1.3-extensions/html/vkspec.html#VUID-RuntimeSpirv-OpHitObjectTraceRayNV-07714
|
||||
//! [\[07752\]]: https://registry.khronos.org/vulkan/specs/1.3-extensions/html/vkspec.html#VUID-vkCmdDispatch-viewType-07752
|
||||
//! [\[07753\]]: https://registry.khronos.org/vulkan/specs/1.3-extensions/html/vkspec.html#VUID-vkCmdDispatch-format-07753
|
||||
//! [\[07888\]]: https://registry.khronos.org/vulkan/specs/1.3-extensions/html/vkspec.html#VUID-vkCmdDispatch-None-07888
|
||||
//! [\[04553\]]: https://registry.khronos.org/vulkan/specs/1.3-extensions/html/vkspec.html#VUID-vkCmdDispatch-magFilter-04553
|
||||
//! [\[04770\]]: https://registry.khronos.org/vulkan/specs/1.3-extensions/html/vkspec.html#VUID-vkCmdDispatch-mipmapMode-04770
|
||||
//! [\[02692\]]: https://registry.khronos.org/vulkan/specs/1.3-extensions/html/vkspec.html#VUID-vkCmdDispatch-None-02692
|
||||
//! [\[02694\]]: https://registry.khronos.org/vulkan/specs/1.3-extensions/html/vkspec.html#VUID-vkCmdDispatch-filterCubic-02694
|
||||
//! [\[02695\]]: https://registry.khronos.org/vulkan/specs/1.3-extensions/html/vkspec.html#VUID-vkCmdDispatch-filterCubicMinmax-02695
|
||||
//! [\[06479\]]: https://registry.khronos.org/vulkan/specs/1.3-extensions/html/vkspec.html#VUID-vkCmdDispatch-None-06479
|
||||
//! [\[08609\]]: https://registry.khronos.org/vulkan/specs/1.3-extensions/html/vkspec.html#VUID-vkCmdDispatch-None-08609
|
||||
//! [\[08610\]]: https://registry.khronos.org/vulkan/specs/1.3-extensions/html/vkspec.html#VUID-vkCmdDispatch-None-08610
|
||||
//! [\[08611\]]: https://registry.khronos.org/vulkan/specs/1.3-extensions/html/vkspec.html#VUID-vkCmdDispatch-None-08611
|
||||
//! [\[06550\]]: https://registry.khronos.org/vulkan/specs/1.3-extensions/html/vkspec.html#VUID-vkCmdDispatch-None-06550
|
||||
//! [\[06551\]]: https://registry.khronos.org/vulkan/specs/1.3-extensions/html/vkspec.html#VUID-vkCmdDispatch-ConstOffset-06551
|
||||
//! [\[08725\]]: https://registry.khronos.org/vulkan/specs/1.3-extensions/html/vkspec.html#VUID-RuntimeSpirv-samples-08725
|
||||
//! [\[08726\]]: https://registry.khronos.org/vulkan/specs/1.3-extensions/html/vkspec.html#VUID-RuntimeSpirv-samples-08726
|
||||
//! [\[08795\]]: https://registry.khronos.org/vulkan/specs/1.3-extensions/html/vkspec.html#VUID-vkCmdDispatch-OpImageWrite-08795
|
||||
//! [\[08796\]]: https://registry.khronos.org/vulkan/specs/1.3-extensions/html/vkspec.html#VUID-vkCmdDispatch-OpImageWrite-08796
|
||||
//! [\[08986\]]: https://registry.khronos.org/vulkan/specs/1.3-extensions/html/vkspec.html#VUID-RuntimeSpirv-OpCooperativeMatrixLoadKHR-08986
|
||||
//! [\[09190\]]: https://registry.khronos.org/vulkan/specs/1.3-extensions/html/vkspec.html#VUID-RuntimeSpirv-maintenance5-09190
|
||||
//! [\[09218\]]: https://registry.khronos.org/vulkan/specs/1.3-extensions/html/vkspec.html#VUID-RuntimeSpirv-MeshEXT-09218
|
||||
//! [\[09219\]]: https://registry.khronos.org/vulkan/specs/1.3-extensions/html/vkspec.html#VUID-RuntimeSpirv-OpImageBlockMatchWindow-09219
|
||||
|
||||
use self::spirv::{Id, Instruction};
|
||||
#[cfg(doc)]
|
||||
use crate::{
|
||||
acceleration_structure::BuildAccelerationStructureFlags,
|
||||
descriptor_set::layout::DescriptorBindingFlags,
|
||||
device::{physical::PhysicalDevice, Features},
|
||||
device::{physical::PhysicalDevice, Features, Properties},
|
||||
format::FormatFeatures,
|
||||
image::{
|
||||
sampler::{Filter, Sampler, SamplerCreateInfo, SamplerMipmapMode, SamplerReductionMode},
|
||||
view::ImageView,
|
||||
ImageFormatProperties,
|
||||
Image, ImageFormatProperties,
|
||||
},
|
||||
};
|
||||
use crate::{
|
||||
|
@ -15,6 +15,7 @@ use crate::{
|
||||
};
|
||||
use ahash::{HashMap, HashSet};
|
||||
use half::f16;
|
||||
use smallvec::{smallvec, SmallVec};
|
||||
use std::borrow::Cow;
|
||||
|
||||
/// Returns an iterator over all entry points in `spirv`, with information about the entry point.
|
||||
@ -1450,6 +1451,96 @@ pub(crate) fn get_constant(spirv: &Spirv, id: Id) -> Option<u64> {
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn get_constant_composite(spirv: &Spirv, id: Id) -> Option<SmallVec<[u64; 4]>> {
|
||||
match spirv.id(id).instruction() {
|
||||
Instruction::ConstantComposite { constituents, .. } => Some(
|
||||
constituents
|
||||
.iter()
|
||||
.map(|&id| match spirv.id(id).instruction() {
|
||||
Instruction::Constant { value, .. } => match value.len() {
|
||||
1 => value[0] as u64,
|
||||
2 => value[0] as u64 | (value[1] as u64) << 32,
|
||||
_ => panic!("constant {} is larger than 64 bits", id),
|
||||
},
|
||||
_ => unreachable!(),
|
||||
})
|
||||
.collect(),
|
||||
),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn get_constant_float_composite(spirv: &Spirv, id: Id) -> Option<SmallVec<[f64; 4]>> {
|
||||
match spirv.id(id).instruction() {
|
||||
Instruction::ConstantComposite { constituents, .. } => Some(
|
||||
constituents
|
||||
.iter()
|
||||
.map(|&id| match spirv.id(id).instruction() {
|
||||
Instruction::Constant { value, .. } => match value.len() {
|
||||
1 => f32::from_bits(value[0]) as f64,
|
||||
2 => f64::from_bits(value[0] as u64 | (value[1] as u64) << 32),
|
||||
_ => panic!("constant {} is larger than 64 bits", id),
|
||||
},
|
||||
_ => unreachable!(),
|
||||
})
|
||||
.collect(),
|
||||
),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn get_constant_maybe_composite(spirv: &Spirv, id: Id) -> Option<SmallVec<[u64; 4]>> {
|
||||
match spirv.id(id).instruction() {
|
||||
Instruction::Constant { value, .. } => match value.len() {
|
||||
1 => Some(smallvec![value[0] as u64]),
|
||||
2 => Some(smallvec![value[0] as u64 | (value[1] as u64) << 32]),
|
||||
_ => panic!("constant {} is larger than 64 bits", id),
|
||||
},
|
||||
Instruction::ConstantComposite { constituents, .. } => Some(
|
||||
constituents
|
||||
.iter()
|
||||
.map(|&id| match spirv.id(id).instruction() {
|
||||
Instruction::Constant { value, .. } => match value.len() {
|
||||
1 => value[0] as u64,
|
||||
2 => value[0] as u64 | (value[1] as u64) << 32,
|
||||
_ => panic!("constant {} is larger than 64 bits", id),
|
||||
},
|
||||
_ => unreachable!(),
|
||||
})
|
||||
.collect(),
|
||||
),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn get_constant_composite_composite(
|
||||
spirv: &Spirv,
|
||||
id: Id,
|
||||
) -> Option<SmallVec<[SmallVec<[u64; 4]>; 4]>> {
|
||||
match spirv.id(id).instruction() {
|
||||
Instruction::ConstantComposite { constituents, .. } => Some(
|
||||
constituents
|
||||
.iter()
|
||||
.map(|&id| match spirv.id(id).instruction() {
|
||||
Instruction::ConstantComposite { constituents, .. } => constituents
|
||||
.iter()
|
||||
.map(|&id| match spirv.id(id).instruction() {
|
||||
Instruction::Constant { value, .. } => match value.len() {
|
||||
1 => value[0] as u64,
|
||||
2 => value[0] as u64 | (value[1] as u64) << 32,
|
||||
_ => panic!("constant {} is larger than 64 bits", id),
|
||||
},
|
||||
_ => unreachable!(),
|
||||
})
|
||||
.collect(),
|
||||
_ => unreachable!(),
|
||||
})
|
||||
.collect(),
|
||||
),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::{HashMap, PushConstantRange, ShaderStages, Version};
|
||||
|
Loading…
Reference in New Issue
Block a user