1 // SPDX-License-Identifier: LGPL-2.1-or-later
2 // Copyright 2018 Jacob Lifshay
5 ArrayType, BuiltInVariable, Constant, Context, IdKind, IdProperties, Ids, MemberDecoration,
6 ParsedShader, ParsedShaderFunction, PointerType, ScalarConstant, ScalarType, ShaderEntryPoint,
7 ShaderStageCreateInfo, StructId, StructMember, StructType, Type, Undefable, UniformVariable,
8 VectorConstant, VectorType,
10 use spirv_parser::{BuiltIn, Decoration, ExecutionModel, IdRef, Instruction, StorageClass};
14 #[cfg_attr(feature = "cargo-clippy", allow(clippy::cyclomatic_complexity))]
16 context: &mut Context,
17 stage_info: ShaderStageCreateInfo,
18 execution_model: ExecutionModel,
20 let parser = spirv_parser::Parser::start(stage_info.code).unwrap();
21 let header = *parser.header();
22 assert_eq!(header.instruction_schema, 0);
23 assert_eq!(header.version.0, 1);
24 assert!(header.version.1 <= 3);
25 let instructions: Vec<_> = parser.map(Result::unwrap).collect();
26 println!("Parsing Shader:");
28 for instruction in instructions.iter() {
29 print!("{}", instruction);
31 let mut ids = Ids((0..header.bound)
32 .map(|_| IdProperties {
33 kind: IdKind::Undefined,
34 decorations: Vec::new(),
35 member_decorations: Vec::new(),
38 let mut entry_point = None;
39 let mut current_function: Option<(IdRef, ParsedShaderFunction)> = None;
40 let mut execution_modes = Vec::new();
41 let mut workgroup_size = None;
42 for instruction in instructions {
43 match current_function {
44 Some(mut function) => {
45 current_function = match instruction {
46 instruction @ Instruction::FunctionEnd {} => {
47 function.1.instructions.push(instruction);
48 ids[function.0].set_kind(IdKind::Function(Some(function.1)));
52 function.1.instructions.push(instruction);
58 None => current_function = None,
61 Instruction::Function {
67 ids[id_result.0].assert_no_member_decorations(id_result.0);
68 let decorations = ids[id_result.0].decorations.clone();
69 current_function = Some((
71 ParsedShaderFunction {
72 instructions: vec![Instruction::Function {
82 Instruction::EntryPoint {
83 execution_model: current_execution_model,
84 entry_point: main_function_id,
88 if execution_model == current_execution_model && name == stage_info.entry_point_name
90 assert!(entry_point.is_none());
91 entry_point = Some(ShaderEntryPoint {
93 interface_variables: interface.clone(),
97 Instruction::ExecutionMode {
98 entry_point: entry_point_id,
101 | Instruction::ExecutionModeId {
102 entry_point: entry_point_id,
105 if entry_point_id == entry_point.as_ref().unwrap().main_function_id {
106 execution_modes.push(mode);
109 Instruction::Decorate { target, decoration }
110 | Instruction::DecorateId { target, decoration } => {
111 ids[target].decorations.push(decoration);
113 Instruction::MemberDecorate {
120 .push(MemberDecoration { member, decoration });
122 Instruction::DecorationGroup { id_result } => {
123 ids[id_result.0].set_kind(IdKind::DecorationGroup);
125 Instruction::GroupDecorate {
129 let decorations = ids[decoration_group].decorations.clone();
130 for target in targets {
133 .extend(decorations.iter().map(Clone::clone));
136 Instruction::GroupMemberDecorate {
140 let decorations = ids[decoration_group].decorations.clone();
141 for target in targets {
144 .extend(decorations.iter().map(|decoration| MemberDecoration {
146 decoration: decoration.clone(),
150 Instruction::TypeFunction {
155 ids[id_result.0].assert_no_decorations(id_result.0);
156 let kind = IdKind::FunctionType {
157 return_type: ids[return_type].get_type().map(Clone::clone),
158 arguments: parameter_types
160 .map(|argument| ids[*argument].get_nonvoid_type().clone())
163 ids[id_result.0].set_kind(kind);
165 Instruction::TypeVoid { id_result } => {
166 ids[id_result.0].assert_no_decorations(id_result.0);
167 ids[id_result.0].set_kind(IdKind::VoidType);
169 Instruction::TypeBool { id_result } => {
170 ids[id_result.0].assert_no_decorations(id_result.0);
171 ids[id_result.0].set_kind(IdKind::Type(Rc::new(Type::Scalar(ScalarType::Bool))));
173 Instruction::TypeInt {
178 ids[id_result.0].assert_no_decorations(id_result.0);
179 ids[id_result.0].set_kind(IdKind::Type(Rc::new(Type::Scalar(
180 match (width, signedness != 0) {
181 (8, false) => ScalarType::U8,
182 (8, true) => ScalarType::I8,
183 (16, false) => ScalarType::U16,
184 (16, true) => ScalarType::I16,
185 (32, false) => ScalarType::U32,
186 (32, true) => ScalarType::I32,
187 (64, false) => ScalarType::U64,
188 (64, true) => ScalarType::I64,
189 (width, signedness) => unreachable!(
190 "unsupported int type: {}{}",
191 if signedness { "i" } else { "u" },
197 Instruction::TypeFloat { id_result, width } => {
198 ids[id_result.0].assert_no_decorations(id_result.0);
199 ids[id_result.0].set_kind(IdKind::Type(Rc::new(Type::Scalar(match width {
200 16 => ScalarType::F16,
201 32 => ScalarType::F32,
202 64 => ScalarType::F64,
203 _ => unreachable!("unsupported float type: f{}", width),
206 Instruction::TypeVector {
211 ids[id_result.0].assert_no_decorations(id_result.0);
212 let element = ids[component_type].get_nonvoid_type().get_scalar().clone();
213 ids[id_result.0].set_kind(IdKind::Type(Rc::new(Type::Vector(VectorType {
215 element_count: component_count as usize,
218 Instruction::TypeForwardPointer { pointer_type, .. } => {
219 ids[pointer_type].set_kind(IdKind::ForwardPointer(Rc::new(Type::Scalar(
220 ScalarType::Pointer(PointerType::unresolved()),
223 Instruction::TypePointer {
228 ids[id_result.0].assert_no_decorations(id_result.0);
229 let pointee = ids[pointee].get_type().map(Clone::clone);
230 let pointer = match mem::replace(&mut ids[id_result.0].kind, IdKind::Undefined) {
231 IdKind::Undefined => Rc::new(Type::Scalar(ScalarType::Pointer(
232 PointerType::new(context, pointee),
234 IdKind::ForwardPointer(pointer) => {
235 if let Type::Scalar(ScalarType::Pointer(pointer)) = &*pointer {
236 pointer.resolve(context, pointee);
242 _ => unreachable!("duplicate id"),
244 ids[id_result.0].set_kind(IdKind::Type(pointer));
246 Instruction::TypeStruct {
250 let decorations = ids[id_result.0].decorations.clone();
252 let mut members: Vec<_> = member_types
254 .map(|member_type| StructMember {
255 decorations: Vec::new(),
256 member_type: match ids[member_type].kind {
257 IdKind::Type(ref t) => t.clone(),
258 IdKind::ForwardPointer(ref t) => t.clone(),
259 _ => unreachable!("invalid struct member type"),
263 for member_decoration in &ids[id_result.0].member_decorations {
264 members[member_decoration.member as usize]
266 .push(member_decoration.decoration.clone());
269 id: StructId::new(context),
274 ids[id_result.0].set_kind(IdKind::Type(Rc::new(Type::Struct(struct_type))));
276 Instruction::TypeRuntimeArray {
280 ids[id_result.0].assert_no_member_decorations(id_result.0);
281 let decorations = ids[id_result.0].decorations.clone();
282 let element = ids[element_type].get_nonvoid_type().clone();
283 ids[id_result.0].set_kind(IdKind::Type(Rc::new(Type::Array(ArrayType {
289 Instruction::Variable {
295 ids[id_result.0].assert_no_member_decorations(id_result.0);
296 if let Some(built_in) =
300 .find_map(|decoration| match *decoration {
301 Decoration::BuiltIn { built_in } => Some(built_in),
304 let built_in_variable = match built_in {
305 BuiltIn::GlobalInvocationId => {
306 for decoration in &ids[id_result.0].decorations {
308 Decoration::BuiltIn { .. } => {}
310 "unimplemented decoration on {:?}: {:?}",
316 assert!(initializer.is_none());
317 BuiltInVariable { built_in }
319 _ => unimplemented!("unimplemented built-in: {:?}", built_in),
322 built_in_variable.get_type(context),
323 ids[id_result_type.0]
325 .get_nonvoid_pointee()
327 ids[id_result.0].set_kind(IdKind::BuiltInVariable(built_in_variable));
329 let variable_type = ids[id_result_type.0].get_nonvoid_type().clone();
330 match storage_class {
331 StorageClass::Uniform => {
332 let mut descriptor_set = None;
333 let mut binding = None;
334 for decoration in &ids[id_result.0].decorations {
336 Decoration::DescriptorSet { descriptor_set: v } => {
338 descriptor_set.is_none(),
339 "duplicate DescriptorSet decoration"
341 descriptor_set = Some(v);
343 Decoration::Binding { binding_point: v } => {
344 assert!(binding.is_none(), "duplicate Binding decoration");
348 "unimplemented decoration on uniform variable: {:?}",
353 let descriptor_set = descriptor_set
354 .expect("uniform variable is missing DescriptorSet decoration");
356 binding.expect("uniform variable is missing Binding decoration");
357 assert!(initializer.is_none());
358 ids[id_result.0].set_kind(IdKind::UniformVariable(UniformVariable {
364 StorageClass::Input => unimplemented!(),
366 "unimplemented OpVariable StorageClass: {:?}",
372 Instruction::Constant32 {
377 ids[id_result.0].assert_no_decorations(id_result.0);
378 #[cfg_attr(feature = "cargo-clippy", allow(clippy::cast_lossless))]
379 let constant = match **ids[id_result_type.0].get_nonvoid_type() {
380 Type::Scalar(ScalarType::U8) => {
381 let converted_value = value as u8;
382 assert_eq!(converted_value as u32, value);
383 Constant::Scalar(ScalarConstant::U8(Undefable::Defined(converted_value)))
385 Type::Scalar(ScalarType::U16) => {
386 let converted_value = value as u16;
387 assert_eq!(converted_value as u32, value);
388 Constant::Scalar(ScalarConstant::U16(Undefable::Defined(converted_value)))
390 Type::Scalar(ScalarType::U32) => {
391 Constant::Scalar(ScalarConstant::U32(Undefable::Defined(value)))
393 Type::Scalar(ScalarType::I8) => {
394 let converted_value = value as i8;
395 assert_eq!(converted_value as u32, value);
396 Constant::Scalar(ScalarConstant::I8(Undefable::Defined(converted_value)))
398 Type::Scalar(ScalarType::I16) => {
399 let converted_value = value as i16;
400 assert_eq!(converted_value as u32, value);
401 Constant::Scalar(ScalarConstant::I16(Undefable::Defined(converted_value)))
403 Type::Scalar(ScalarType::I32) => {
404 Constant::Scalar(ScalarConstant::I32(Undefable::Defined(value as i32)))
406 Type::Scalar(ScalarType::F16) => {
407 let converted_value = value as u16;
408 assert_eq!(converted_value as u32, value);
409 Constant::Scalar(ScalarConstant::F16(Undefable::Defined(converted_value)))
411 Type::Scalar(ScalarType::F32) => Constant::Scalar(ScalarConstant::F32(
412 Undefable::Defined(f32::from_bits(value)),
414 _ => unreachable!("invalid type"),
416 ids[id_result.0].set_kind(IdKind::Constant(Rc::new(constant)));
418 Instruction::Constant64 {
423 ids[id_result.0].assert_no_decorations(id_result.0);
424 let constant = match **ids[id_result_type.0].get_nonvoid_type() {
425 Type::Scalar(ScalarType::U64) => {
426 Constant::Scalar(ScalarConstant::U64(Undefable::Defined(value)))
428 Type::Scalar(ScalarType::I64) => {
429 Constant::Scalar(ScalarConstant::I64(Undefable::Defined(value as i64)))
431 Type::Scalar(ScalarType::F64) => Constant::Scalar(ScalarConstant::F64(
432 Undefable::Defined(f64::from_bits(value)),
434 _ => unreachable!("invalid type"),
436 ids[id_result.0].set_kind(IdKind::Constant(Rc::new(constant)));
438 Instruction::ConstantFalse {
442 ids[id_result.0].assert_no_decorations(id_result.0);
443 let constant = match **ids[id_result_type.0].get_nonvoid_type() {
444 Type::Scalar(ScalarType::Bool) => {
445 Constant::Scalar(ScalarConstant::Bool(Undefable::Defined(false)))
447 _ => unreachable!("invalid type"),
449 ids[id_result.0].set_kind(IdKind::Constant(Rc::new(constant)));
451 Instruction::ConstantTrue {
455 ids[id_result.0].assert_no_decorations(id_result.0);
456 let constant = match **ids[id_result_type.0].get_nonvoid_type() {
457 Type::Scalar(ScalarType::Bool) => {
458 Constant::Scalar(ScalarConstant::Bool(Undefable::Defined(true)))
460 _ => unreachable!("invalid type"),
462 ids[id_result.0].set_kind(IdKind::Constant(Rc::new(constant)));
464 Instruction::ConstantComposite {
469 let constant = match **ids[id_result_type.0].get_nonvoid_type() {
470 Type::Vector(VectorType {
474 assert_eq!(element_count, constituents.len());
475 let constituents = constituents
477 .map(|id| *ids[*id].get_constant().get_scalar());
480 VectorConstant::U8(constituents.map(|v| v.get_u8()).collect())
483 VectorConstant::U16(constituents.map(|v| v.get_u16()).collect())
486 VectorConstant::U32(constituents.map(|v| v.get_u32()).collect())
489 VectorConstant::U64(constituents.map(|v| v.get_u64()).collect())
492 VectorConstant::I8(constituents.map(|v| v.get_i8()).collect())
495 VectorConstant::I16(constituents.map(|v| v.get_i16()).collect())
498 VectorConstant::I32(constituents.map(|v| v.get_i32()).collect())
501 VectorConstant::I64(constituents.map(|v| v.get_i64()).collect())
504 VectorConstant::F16(constituents.map(|v| v.get_f16()).collect())
507 VectorConstant::F32(constituents.map(|v| v.get_f32()).collect())
510 VectorConstant::F64(constituents.map(|v| v.get_f64()).collect())
512 ScalarType::Bool => {
513 VectorConstant::Bool(constituents.map(|v| v.get_bool()).collect())
515 ScalarType::Pointer(_) => unimplemented!(),
518 _ => unimplemented!(),
520 for decoration in &ids[id_result.0].decorations {
522 Decoration::BuiltIn {
523 built_in: BuiltIn::WorkgroupSize,
526 workgroup_size.is_none(),
527 "duplicate WorkgroupSize decorations"
529 workgroup_size = match constant {
530 VectorConstant::U32(ref v) => {
534 "invalid type for WorkgroupSize built-in"
536 Some((v[0].unwrap(), v[1].unwrap(), v[2].unwrap()))
538 _ => unreachable!("invalid type for WorkgroupSize built-in"),
542 "unimplemented decoration on constant {:?}: {:?}",
543 Constant::Vector(constant),
548 ids[id_result.0].assert_no_member_decorations(id_result.0);
549 ids[id_result.0].set_kind(IdKind::Constant(Rc::new(Constant::Vector(constant))));
551 Instruction::MemoryModel {
555 assert_eq!(addressing_model, spirv_parser::AddressingModel::Logical);
556 assert_eq!(memory_model, spirv_parser::MemoryModel::GLSL450);
558 Instruction::Capability { .. }
559 | Instruction::ExtInstImport { .. }
560 | Instruction::Source { .. }
561 | Instruction::SourceExtension { .. }
562 | Instruction::Name { .. }
563 | Instruction::MemberName { .. } => {}
564 Instruction::SpecConstant32 { .. } => unimplemented!(),
565 Instruction::SpecConstant64 { .. } => unimplemented!(),
566 Instruction::SpecConstantTrue { .. } => unimplemented!(),
567 Instruction::SpecConstantFalse { .. } => unimplemented!(),
568 Instruction::SpecConstantOp { .. } => unimplemented!(),
569 instruction => unimplemented!("unimplemented instruction:\n{}", instruction),
573 current_function.is_none(),
574 "missing terminating OpFunctionEnd"
576 let ShaderEntryPoint {
579 } = entry_point.unwrap();