added more code to shader compiler and split into seperate files
[kazan.git] / shader-compiler / src / parsed_shader_create.rs
1 // SPDX-License-Identifier: LGPL-2.1-or-later
2 // Copyright 2018 Jacob Lifshay
3
4 use super::{
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,
9 };
10 use spirv_parser::{BuiltIn, Decoration, ExecutionModel, IdRef, Instruction, StorageClass};
11 use std::mem;
12 use std::rc::Rc;
13
14 #[cfg_attr(feature = "cargo-clippy", allow(clippy::cyclomatic_complexity))]
15 pub(super) fn create(
16 context: &mut Context,
17 stage_info: ShaderStageCreateInfo,
18 execution_model: ExecutionModel,
19 ) -> ParsedShader {
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:");
27 print!("{}", header);
28 for instruction in instructions.iter() {
29 print!("{}", instruction);
30 }
31 let mut ids = Ids((0..header.bound)
32 .map(|_| IdProperties {
33 kind: IdKind::Undefined,
34 decorations: Vec::new(),
35 member_decorations: Vec::new(),
36 })
37 .collect());
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)));
49 None
50 }
51 instruction => {
52 function.1.instructions.push(instruction);
53 Some(function)
54 }
55 };
56 continue;
57 }
58 None => current_function = None,
59 }
60 match instruction {
61 Instruction::Function {
62 id_result_type,
63 id_result,
64 function_control,
65 function_type,
66 } => {
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((
70 id_result.0,
71 ParsedShaderFunction {
72 instructions: vec![Instruction::Function {
73 id_result_type,
74 id_result,
75 function_control,
76 function_type,
77 }],
78 decorations,
79 },
80 ));
81 }
82 Instruction::EntryPoint {
83 execution_model: current_execution_model,
84 entry_point: main_function_id,
85 name,
86 interface,
87 } => {
88 if execution_model == current_execution_model && name == stage_info.entry_point_name
89 {
90 assert!(entry_point.is_none());
91 entry_point = Some(ShaderEntryPoint {
92 main_function_id,
93 interface_variables: interface.clone(),
94 });
95 }
96 }
97 Instruction::ExecutionMode {
98 entry_point: entry_point_id,
99 mode,
100 }
101 | Instruction::ExecutionModeId {
102 entry_point: entry_point_id,
103 mode,
104 } => {
105 if entry_point_id == entry_point.as_ref().unwrap().main_function_id {
106 execution_modes.push(mode);
107 }
108 }
109 Instruction::Decorate { target, decoration }
110 | Instruction::DecorateId { target, decoration } => {
111 ids[target].decorations.push(decoration);
112 }
113 Instruction::MemberDecorate {
114 structure_type,
115 member,
116 decoration,
117 } => {
118 ids[structure_type]
119 .member_decorations
120 .push(MemberDecoration { member, decoration });
121 }
122 Instruction::DecorationGroup { id_result } => {
123 ids[id_result.0].set_kind(IdKind::DecorationGroup);
124 }
125 Instruction::GroupDecorate {
126 decoration_group,
127 targets,
128 } => {
129 let decorations = ids[decoration_group].decorations.clone();
130 for target in targets {
131 ids[target]
132 .decorations
133 .extend(decorations.iter().map(Clone::clone));
134 }
135 }
136 Instruction::GroupMemberDecorate {
137 decoration_group,
138 targets,
139 } => {
140 let decorations = ids[decoration_group].decorations.clone();
141 for target in targets {
142 ids[target.0]
143 .member_decorations
144 .extend(decorations.iter().map(|decoration| MemberDecoration {
145 member: target.1,
146 decoration: decoration.clone(),
147 }));
148 }
149 }
150 Instruction::TypeFunction {
151 id_result,
152 return_type,
153 parameter_types,
154 } => {
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
159 .iter()
160 .map(|argument| ids[*argument].get_nonvoid_type().clone())
161 .collect(),
162 };
163 ids[id_result.0].set_kind(kind);
164 }
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);
168 }
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))));
172 }
173 Instruction::TypeInt {
174 id_result,
175 width,
176 signedness,
177 } => {
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" },
192 width
193 ),
194 },
195 ))));
196 }
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),
204 }))));
205 }
206 Instruction::TypeVector {
207 id_result,
208 component_type,
209 component_count,
210 } => {
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 {
214 element,
215 element_count: component_count as usize,
216 }))));
217 }
218 Instruction::TypeForwardPointer { pointer_type, .. } => {
219 ids[pointer_type].set_kind(IdKind::ForwardPointer(Rc::new(Type::Scalar(
220 ScalarType::Pointer(PointerType::unresolved()),
221 ))));
222 }
223 Instruction::TypePointer {
224 id_result,
225 type_: pointee,
226 ..
227 } => {
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),
233 ))),
234 IdKind::ForwardPointer(pointer) => {
235 if let Type::Scalar(ScalarType::Pointer(pointer)) = &*pointer {
236 pointer.resolve(context, pointee);
237 } else {
238 unreachable!();
239 }
240 pointer
241 }
242 _ => unreachable!("duplicate id"),
243 };
244 ids[id_result.0].set_kind(IdKind::Type(pointer));
245 }
246 Instruction::TypeStruct {
247 id_result,
248 member_types,
249 } => {
250 let decorations = ids[id_result.0].decorations.clone();
251 let struct_type = {
252 let mut members: Vec<_> = member_types
253 .into_iter()
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"),
260 },
261 })
262 .collect();
263 for member_decoration in &ids[id_result.0].member_decorations {
264 members[member_decoration.member as usize]
265 .decorations
266 .push(member_decoration.decoration.clone());
267 }
268 StructType {
269 id: StructId::new(context),
270 decorations,
271 members,
272 }
273 };
274 ids[id_result.0].set_kind(IdKind::Type(Rc::new(Type::Struct(struct_type))));
275 }
276 Instruction::TypeRuntimeArray {
277 id_result,
278 element_type,
279 } => {
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 {
284 decorations,
285 element,
286 element_count: None,
287 }))));
288 }
289 Instruction::Variable {
290 id_result_type,
291 id_result,
292 storage_class,
293 initializer,
294 } => {
295 ids[id_result.0].assert_no_member_decorations(id_result.0);
296 if let Some(built_in) =
297 ids[id_result.0]
298 .decorations
299 .iter()
300 .find_map(|decoration| match *decoration {
301 Decoration::BuiltIn { built_in } => Some(built_in),
302 _ => None,
303 }) {
304 let built_in_variable = match built_in {
305 BuiltIn::GlobalInvocationId => {
306 for decoration in &ids[id_result.0].decorations {
307 match decoration {
308 Decoration::BuiltIn { .. } => {}
309 _ => unimplemented!(
310 "unimplemented decoration on {:?}: {:?}",
311 built_in,
312 decoration
313 ),
314 }
315 }
316 assert!(initializer.is_none());
317 BuiltInVariable { built_in }
318 }
319 _ => unimplemented!("unimplemented built-in: {:?}", built_in),
320 };
321 assert_eq!(
322 built_in_variable.get_type(context),
323 ids[id_result_type.0]
324 .get_nonvoid_type()
325 .get_nonvoid_pointee()
326 );
327 ids[id_result.0].set_kind(IdKind::BuiltInVariable(built_in_variable));
328 } else {
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 {
335 match *decoration {
336 Decoration::DescriptorSet { descriptor_set: v } => {
337 assert!(
338 descriptor_set.is_none(),
339 "duplicate DescriptorSet decoration"
340 );
341 descriptor_set = Some(v);
342 }
343 Decoration::Binding { binding_point: v } => {
344 assert!(binding.is_none(), "duplicate Binding decoration");
345 binding = Some(v);
346 }
347 _ => unimplemented!(
348 "unimplemented decoration on uniform variable: {:?}",
349 decoration
350 ),
351 }
352 }
353 let descriptor_set = descriptor_set
354 .expect("uniform variable is missing DescriptorSet decoration");
355 let binding =
356 binding.expect("uniform variable is missing Binding decoration");
357 assert!(initializer.is_none());
358 ids[id_result.0].set_kind(IdKind::UniformVariable(UniformVariable {
359 binding,
360 descriptor_set,
361 variable_type,
362 }));
363 }
364 StorageClass::Input => unimplemented!(),
365 _ => unimplemented!(
366 "unimplemented OpVariable StorageClass: {:?}",
367 storage_class
368 ),
369 }
370 }
371 }
372 Instruction::Constant32 {
373 id_result_type,
374 id_result,
375 value,
376 } => {
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)))
384 }
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)))
389 }
390 Type::Scalar(ScalarType::U32) => {
391 Constant::Scalar(ScalarConstant::U32(Undefable::Defined(value)))
392 }
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)))
397 }
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)))
402 }
403 Type::Scalar(ScalarType::I32) => {
404 Constant::Scalar(ScalarConstant::I32(Undefable::Defined(value as i32)))
405 }
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)))
410 }
411 Type::Scalar(ScalarType::F32) => Constant::Scalar(ScalarConstant::F32(
412 Undefable::Defined(f32::from_bits(value)),
413 )),
414 _ => unreachable!("invalid type"),
415 };
416 ids[id_result.0].set_kind(IdKind::Constant(Rc::new(constant)));
417 }
418 Instruction::Constant64 {
419 id_result_type,
420 id_result,
421 value,
422 } => {
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)))
427 }
428 Type::Scalar(ScalarType::I64) => {
429 Constant::Scalar(ScalarConstant::I64(Undefable::Defined(value as i64)))
430 }
431 Type::Scalar(ScalarType::F64) => Constant::Scalar(ScalarConstant::F64(
432 Undefable::Defined(f64::from_bits(value)),
433 )),
434 _ => unreachable!("invalid type"),
435 };
436 ids[id_result.0].set_kind(IdKind::Constant(Rc::new(constant)));
437 }
438 Instruction::ConstantFalse {
439 id_result_type,
440 id_result,
441 } => {
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)))
446 }
447 _ => unreachable!("invalid type"),
448 };
449 ids[id_result.0].set_kind(IdKind::Constant(Rc::new(constant)));
450 }
451 Instruction::ConstantTrue {
452 id_result_type,
453 id_result,
454 } => {
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)))
459 }
460 _ => unreachable!("invalid type"),
461 };
462 ids[id_result.0].set_kind(IdKind::Constant(Rc::new(constant)));
463 }
464 Instruction::ConstantComposite {
465 id_result_type,
466 id_result,
467 constituents,
468 } => {
469 let constant = match **ids[id_result_type.0].get_nonvoid_type() {
470 Type::Vector(VectorType {
471 ref element,
472 element_count,
473 }) => {
474 assert_eq!(element_count, constituents.len());
475 let constituents = constituents
476 .iter()
477 .map(|id| *ids[*id].get_constant().get_scalar());
478 match *element {
479 ScalarType::U8 => {
480 VectorConstant::U8(constituents.map(|v| v.get_u8()).collect())
481 }
482 ScalarType::U16 => {
483 VectorConstant::U16(constituents.map(|v| v.get_u16()).collect())
484 }
485 ScalarType::U32 => {
486 VectorConstant::U32(constituents.map(|v| v.get_u32()).collect())
487 }
488 ScalarType::U64 => {
489 VectorConstant::U64(constituents.map(|v| v.get_u64()).collect())
490 }
491 ScalarType::I8 => {
492 VectorConstant::I8(constituents.map(|v| v.get_i8()).collect())
493 }
494 ScalarType::I16 => {
495 VectorConstant::I16(constituents.map(|v| v.get_i16()).collect())
496 }
497 ScalarType::I32 => {
498 VectorConstant::I32(constituents.map(|v| v.get_i32()).collect())
499 }
500 ScalarType::I64 => {
501 VectorConstant::I64(constituents.map(|v| v.get_i64()).collect())
502 }
503 ScalarType::F16 => {
504 VectorConstant::F16(constituents.map(|v| v.get_f16()).collect())
505 }
506 ScalarType::F32 => {
507 VectorConstant::F32(constituents.map(|v| v.get_f32()).collect())
508 }
509 ScalarType::F64 => {
510 VectorConstant::F64(constituents.map(|v| v.get_f64()).collect())
511 }
512 ScalarType::Bool => {
513 VectorConstant::Bool(constituents.map(|v| v.get_bool()).collect())
514 }
515 ScalarType::Pointer(_) => unimplemented!(),
516 }
517 }
518 _ => unimplemented!(),
519 };
520 for decoration in &ids[id_result.0].decorations {
521 match decoration {
522 Decoration::BuiltIn {
523 built_in: BuiltIn::WorkgroupSize,
524 } => {
525 assert!(
526 workgroup_size.is_none(),
527 "duplicate WorkgroupSize decorations"
528 );
529 workgroup_size = match constant {
530 VectorConstant::U32(ref v) => {
531 assert_eq!(
532 v.len(),
533 3,
534 "invalid type for WorkgroupSize built-in"
535 );
536 Some((v[0].unwrap(), v[1].unwrap(), v[2].unwrap()))
537 }
538 _ => unreachable!("invalid type for WorkgroupSize built-in"),
539 };
540 }
541 _ => unimplemented!(
542 "unimplemented decoration on constant {:?}: {:?}",
543 Constant::Vector(constant),
544 decoration
545 ),
546 }
547 }
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))));
550 }
551 Instruction::MemoryModel {
552 addressing_model,
553 memory_model,
554 } => {
555 assert_eq!(addressing_model, spirv_parser::AddressingModel::Logical);
556 assert_eq!(memory_model, spirv_parser::MemoryModel::GLSL450);
557 }
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),
570 }
571 }
572 assert!(
573 current_function.is_none(),
574 "missing terminating OpFunctionEnd"
575 );
576 let ShaderEntryPoint {
577 main_function_id,
578 interface_variables,
579 } = entry_point.unwrap();
580 ParsedShader {
581 ids,
582 main_function_id,
583 interface_variables,
584 execution_modes,
585 workgroup_size,
586 }
587 }