1use alloc::vec::Vec;
2use spirv::Word;
3
4use crate::{
5 back::spv::{
6 helpers::BindingDecorations, writer::FunctionInterface, Block, EntryPointContext, Error,
7 Instruction, WriterFlags,
8 },
9 non_max_u32::NonMaxU32,
10 Handle,
11};
12
13#[derive(Clone, Debug)]
14pub struct MeshReturnMember {
15 pub ty_id: u32,
16 pub binding: crate::Binding,
17}
18
19#[derive(Debug)]
20struct PerOutputTypeMeshReturnInfo {
21 max_length_constant: Word,
22 array_type_id: Word,
23 struct_members: Vec<MeshReturnMember>,
24
25 builtin_block: Option<Word>,
31 bindings: Vec<Word>,
32}
33
34#[derive(Debug)]
35pub struct MeshReturnInfo {
36 out_variable_id: Word,
38 out_members: Vec<MeshReturnMember>,
40 local_invocation_index_var_id: Word,
42 workgroup_size: u32,
44
45 vertex_info: PerOutputTypeMeshReturnInfo,
47 primitive_info: PerOutputTypeMeshReturnInfo,
49 primitive_indices: Option<Word>,
51}
52
53impl super::Writer {
54 pub(super) fn write_mesh_return_global_variable(
56 &mut self,
57 ty: u32,
58 array_size_id: u32,
59 ) -> Result<Word, Error> {
60 let array_ty = self.id_gen.next();
61 Instruction::type_array(array_ty, ty, array_size_id)
62 .to_words(&mut self.logical_layout.declarations);
63 let ptr_ty = self.get_pointer_type_id(array_ty, spirv::StorageClass::Output);
64 let var_id = self.id_gen.next();
65 Instruction::variable(ptr_ty, var_id, spirv::StorageClass::Output, None)
66 .to_words(&mut self.logical_layout.declarations);
67 Ok(var_id)
68 }
69
70 pub(super) fn write_entry_point_mesh_shader_info(
73 &mut self,
74 iface: &mut FunctionInterface,
75 local_invocation_index_var_id: Option<Word>,
76 ir_module: &crate::Module,
77 ep_context: &mut EntryPointContext,
78 ) -> Result<(), Error> {
79 let Some(ref mesh_info) = iface.mesh_info else {
80 return Ok(());
81 };
82 let out_members: Vec<MeshReturnMember> =
84 match &ir_module.types[ir_module.global_variables[mesh_info.output_variable].ty] {
85 &crate::Type {
86 inner: crate::TypeInner::Struct { ref members, .. },
87 ..
88 } => members
89 .iter()
90 .map(|a| MeshReturnMember {
91 ty_id: self.get_handle_type_id(a.ty),
92 binding: a.binding.clone().unwrap(),
93 })
94 .collect(),
95 _ => unreachable!(),
96 };
97 let vertex_array_type_id = out_members
98 .iter()
99 .find(|a| a.binding == crate::Binding::BuiltIn(crate::BuiltIn::Vertices))
100 .unwrap()
101 .ty_id;
102 let primitive_array_type_id = out_members
103 .iter()
104 .find(|a| a.binding == crate::Binding::BuiltIn(crate::BuiltIn::Primitives))
105 .unwrap()
106 .ty_id;
107 let vertex_members = match &ir_module.types[mesh_info.vertex_output_type] {
108 &crate::Type {
109 inner: crate::TypeInner::Struct { ref members, .. },
110 ..
111 } => members
112 .iter()
113 .map(|a| MeshReturnMember {
114 ty_id: self.get_handle_type_id(a.ty),
115 binding: a.binding.clone().unwrap(),
116 })
117 .collect(),
118 _ => unreachable!(),
119 };
120 let primitive_members = match &ir_module.types[mesh_info.primitive_output_type] {
121 &crate::Type {
122 inner: crate::TypeInner::Struct { ref members, .. },
123 ..
124 } => members
125 .iter()
126 .map(|a| MeshReturnMember {
127 ty_id: self.get_handle_type_id(a.ty),
128 binding: a.binding.clone().unwrap(),
129 })
130 .collect(),
131 _ => unreachable!(),
132 };
133 let local_invocation_index_var_id = local_invocation_index_var_id
135 .expect("mesh entry points always declare LocalInvocationIndex");
136 let mut mesh_return_info = MeshReturnInfo {
139 out_variable_id: self.global_variables[mesh_info.output_variable].var_id,
140 out_members,
141 local_invocation_index_var_id,
142 workgroup_size: self
143 .get_constant_scalar(crate::Literal::U32(iface.workgroup_size.iter().product())),
144
145 vertex_info: PerOutputTypeMeshReturnInfo {
146 array_type_id: vertex_array_type_id,
147 struct_members: vertex_members,
148 max_length_constant: self
149 .get_constant_scalar(crate::Literal::U32(mesh_info.max_vertices)),
150 bindings: Vec::new(),
151 builtin_block: None,
152 },
153 primitive_info: PerOutputTypeMeshReturnInfo {
154 array_type_id: primitive_array_type_id,
155 struct_members: primitive_members,
156 max_length_constant: self
157 .get_constant_scalar(crate::Literal::U32(mesh_info.max_primitives)),
158 bindings: Vec::new(),
159 builtin_block: None,
160 },
161 primitive_indices: None,
162 };
163 let vert_array_size_id =
164 self.get_constant_scalar(crate::Literal::U32(mesh_info.max_vertices));
165 let prim_array_size_id =
166 self.get_constant_scalar(crate::Literal::U32(mesh_info.max_primitives));
167
168 if mesh_return_info
177 .vertex_info
178 .struct_members
179 .iter()
180 .any(|a| matches!(a.binding, crate::Binding::BuiltIn(..)))
181 {
182 let builtin_block_ty_id = self.id_gen.next();
183 let mut ins = Instruction::type_struct(builtin_block_ty_id, &[]);
184 let mut bi_index = 0;
185 let mut decorations = Vec::new();
186 for member in &mesh_return_info.vertex_info.struct_members {
187 if let crate::Binding::BuiltIn(_) = member.binding {
188 ins.add_operand(member.ty_id);
189 let binding = self.map_binding(
190 ir_module,
191 iface.stage,
192 spirv::StorageClass::Output,
193 Handle::new(NonMaxU32::new(0).unwrap()),
195 &member.binding,
196 )?;
197 match binding {
198 BindingDecorations::BuiltIn(bi, others) => {
199 decorations.push(Instruction::member_decorate(
200 builtin_block_ty_id,
201 bi_index,
202 spirv::Decoration::BuiltIn,
203 &[bi as Word],
204 ));
205 for other in others {
206 decorations.push(Instruction::member_decorate(
207 builtin_block_ty_id,
208 bi_index,
209 other,
210 &[],
211 ));
212 }
213 }
214 _ => unreachable!(),
215 }
216 bi_index += 1;
217 }
218 }
219 ins.to_words(&mut self.logical_layout.declarations);
220 decorations.push(Instruction::decorate(
221 builtin_block_ty_id,
222 spirv::Decoration::Block,
223 &[],
224 ));
225 for dec in decorations {
226 dec.to_words(&mut self.logical_layout.annotations);
227 }
228 let v =
229 self.write_mesh_return_global_variable(builtin_block_ty_id, vert_array_size_id)?;
230 iface.varying_ids.push(v);
231 if self.flags.contains(WriterFlags::DEBUG) {
232 self.debugs
233 .push(Instruction::name(v, "naga_vertex_builtin_outputs"));
234 }
235 mesh_return_info.vertex_info.builtin_block = Some(v);
236 }
237 if mesh_return_info
239 .primitive_info
240 .struct_members
241 .iter()
242 .any(|a| {
243 !matches!(
244 a.binding,
245 crate::Binding::BuiltIn(
246 crate::BuiltIn::PointIndex
247 | crate::BuiltIn::LineIndices
248 | crate::BuiltIn::TriangleIndices
249 ) | crate::Binding::Location { .. }
250 )
251 })
252 {
253 let builtin_block_ty_id = self.id_gen.next();
254 let mut ins = Instruction::type_struct(builtin_block_ty_id, &[]);
255 let mut bi_index = 0;
256 let mut decorations = Vec::new();
257 for member in &mesh_return_info.primitive_info.struct_members {
258 if let crate::Binding::BuiltIn(bi) = member.binding {
259 if matches!(
261 bi,
262 crate::BuiltIn::PointIndex
263 | crate::BuiltIn::LineIndices
264 | crate::BuiltIn::TriangleIndices,
265 ) {
266 continue;
267 }
268 ins.add_operand(member.ty_id);
269 let binding = self.map_binding(
270 ir_module,
271 iface.stage,
272 spirv::StorageClass::Output,
273 Handle::new(NonMaxU32::new(0).unwrap()),
275 &member.binding,
276 )?;
277 match binding {
278 BindingDecorations::BuiltIn(bi, others) => {
279 decorations.push(Instruction::member_decorate(
280 builtin_block_ty_id,
281 bi_index,
282 spirv::Decoration::BuiltIn,
283 &[bi as Word],
284 ));
285 for other in others {
286 decorations.push(Instruction::member_decorate(
287 builtin_block_ty_id,
288 bi_index,
289 other,
290 &[],
291 ));
292 }
293 }
294 _ => unreachable!(),
295 }
296 bi_index += 1;
297 }
298 }
299 ins.to_words(&mut self.logical_layout.declarations);
300 decorations.push(Instruction::decorate(
301 builtin_block_ty_id,
302 spirv::Decoration::Block,
303 &[],
304 ));
305 for dec in decorations {
306 dec.to_words(&mut self.logical_layout.annotations);
307 }
308 let v =
309 self.write_mesh_return_global_variable(builtin_block_ty_id, prim_array_size_id)?;
310 Instruction::decorate(v, spirv::Decoration::PerPrimitiveEXT, &[])
311 .to_words(&mut self.logical_layout.annotations);
312 iface.varying_ids.push(v);
313 if self.flags.contains(WriterFlags::DEBUG) {
314 self.debugs
315 .push(Instruction::name(v, "naga_primitive_builtin_outputs"));
316 }
317 mesh_return_info.primitive_info.builtin_block = Some(v);
318 }
319
320 for member in &mesh_return_info.vertex_info.struct_members {
322 match member.binding {
323 crate::Binding::Location { location, .. } => {
324 let v =
326 self.write_mesh_return_global_variable(member.ty_id, vert_array_size_id)?;
327 Instruction::decorate(v, spirv::Decoration::Location, &[location])
329 .to_words(&mut self.logical_layout.annotations);
330 iface.varying_ids.push(v);
331 mesh_return_info.vertex_info.bindings.push(v);
332 }
333 crate::Binding::BuiltIn(_) => (),
334 }
335 }
336 for member in &mesh_return_info.primitive_info.struct_members {
339 match member.binding {
340 crate::Binding::BuiltIn(
341 crate::BuiltIn::PointIndex
342 | crate::BuiltIn::LineIndices
343 | crate::BuiltIn::TriangleIndices,
344 ) => {
345 let v =
347 self.write_mesh_return_global_variable(member.ty_id, prim_array_size_id)?;
348 Instruction::decorate(
350 v,
351 spirv::Decoration::BuiltIn,
352 &[match member.binding.to_built_in().unwrap() {
353 crate::BuiltIn::PointIndex => spirv::BuiltIn::PrimitivePointIndicesEXT,
354 crate::BuiltIn::LineIndices => spirv::BuiltIn::PrimitiveLineIndicesEXT,
355 crate::BuiltIn::TriangleIndices => {
356 spirv::BuiltIn::PrimitiveTriangleIndicesEXT
357 }
358 _ => unreachable!(),
359 } as Word],
360 )
361 .to_words(&mut self.logical_layout.annotations);
362 iface.varying_ids.push(v);
363 if self.flags.contains(WriterFlags::DEBUG) {
364 self.debugs
365 .push(Instruction::name(v, "naga_primitive_indices_outputs"));
366 }
367 mesh_return_info.primitive_indices = Some(v);
368 }
369 crate::Binding::Location { location, .. } => {
370 let v =
372 self.write_mesh_return_global_variable(member.ty_id, prim_array_size_id)?;
373 Instruction::decorate(v, spirv::Decoration::Location, &[location])
375 .to_words(&mut self.logical_layout.annotations);
376 Instruction::decorate(v, spirv::Decoration::PerPrimitiveEXT, &[])
378 .to_words(&mut self.logical_layout.annotations);
379 iface.varying_ids.push(v);
380
381 mesh_return_info.primitive_info.bindings.push(v);
382 }
383 crate::Binding::BuiltIn(_) => (),
384 }
385 }
386
387 ep_context.mesh_state = Some(mesh_return_info);
389
390 Ok(())
391 }
392
393 pub(super) fn write_entry_point_task_return(
394 &mut self,
395 value_id: Word,
396 body: &mut Vec<Instruction>,
397 task_payload: Word,
398 ) -> Result<Instruction, Error> {
399 let values = [self.id_gen.next(), self.id_gen.next(), self.id_gen.next()];
404 for (i, &value) in values.iter().enumerate() {
405 let instruction = Instruction::composite_extract(
406 self.get_u32_type_id(),
407 value,
408 value_id,
409 &[i as Word],
410 );
411 body.push(instruction);
412 }
413 let mut instruction = Instruction::new(spirv::Op::EmitMeshTasksEXT);
414 for id in values {
415 instruction.add_operand(id);
416 }
417 instruction.add_operand(task_payload);
419 Ok(instruction)
420 }
421
422 #[allow(clippy::too_many_arguments)]
424 fn write_mesh_copy_loop(
425 &mut self,
426 body: &mut Vec<Instruction>,
427 mut loop_body_block: Vec<Instruction>,
428 loop_header: u32,
429 loop_merge: u32,
430 count_id: u32,
431 index_var: u32,
432 return_info: &MeshReturnInfo,
433 ) {
434 let u32_id = self.get_u32_type_id();
435 let condition_check = self.id_gen.next();
436 let loop_continue = self.id_gen.next();
437 let loop_body = self.id_gen.next();
438
439 {
441 body.push(Instruction::label(loop_header));
442 body.push(Instruction::loop_merge(
443 loop_merge,
444 loop_continue,
445 spirv::SelectionControl::empty(),
446 ));
447 body.push(Instruction::branch(condition_check));
448 }
449 {
451 body.push(Instruction::label(condition_check));
452
453 let val_i = self.id_gen.next();
454 body.push(Instruction::load(u32_id, val_i, index_var, None));
455
456 let cond = self.id_gen.next();
457 body.push(Instruction::binary(
458 spirv::Op::ULessThan,
459 self.get_bool_type_id(),
460 cond,
461 val_i,
462 count_id,
463 ));
464 body.push(Instruction::branch_conditional(cond, loop_body, loop_merge));
465 }
466 {
468 body.push(Instruction::label(loop_body));
469 body.append(&mut loop_body_block);
470 body.push(Instruction::branch(loop_continue));
471 }
472 {
474 body.push(Instruction::label(loop_continue));
475
476 let prev_val_i = self.id_gen.next();
477 body.push(Instruction::load(u32_id, prev_val_i, index_var, None));
478 let new_val_i = self.id_gen.next();
479 body.push(Instruction::binary(
480 spirv::Op::IAdd,
481 u32_id,
482 new_val_i,
483 prev_val_i,
484 return_info.workgroup_size,
485 ));
486 body.push(Instruction::store(index_var, new_val_i, None));
487
488 body.push(Instruction::branch(loop_header));
489 }
490 }
491
492 fn write_mesh_copy_body(
495 &mut self,
496 is_primitive: bool,
497 return_info: &MeshReturnInfo,
498 index_var: u32,
499 vert_array_ptr: u32,
500 prim_array_ptr: u32,
501 ) -> Vec<Instruction> {
502 let u32_type_id = self.get_u32_type_id();
503 let mut body = Vec::new();
504 let val_i = self.id_gen.next();
506 body.push(Instruction::load(u32_type_id, val_i, index_var, None));
507
508 let info = if is_primitive {
509 &return_info.primitive_info
510 } else {
511 &return_info.vertex_info
512 };
513 let array_ptr = if is_primitive {
514 prim_array_ptr
515 } else {
516 vert_array_ptr
517 };
518
519 let mut builtin_index = 0;
520 let mut binding_index = 0;
521 for (member_id, member) in info.struct_members.iter().enumerate() {
523 let val_to_copy_ptr = self.id_gen.next();
524 body.push(Instruction::access_chain(
525 self.get_pointer_type_id(member.ty_id, spirv::StorageClass::Workgroup),
526 val_to_copy_ptr,
527 array_ptr,
528 &[
529 val_i,
530 self.get_constant_scalar(crate::Literal::U32(member_id as u32)),
531 ],
532 ));
533 let val_to_copy = self.id_gen.next();
534 body.push(Instruction::load(
535 member.ty_id,
536 val_to_copy,
537 val_to_copy_ptr,
538 None,
539 ));
540 let mut needs_y_flip = false;
541 let ptr_to_copy_to = self.id_gen.next();
542 match member.binding {
544 crate::Binding::BuiltIn(
545 crate::BuiltIn::PointIndex
546 | crate::BuiltIn::LineIndices
547 | crate::BuiltIn::TriangleIndices,
548 ) => {
549 body.push(Instruction::access_chain(
550 self.get_pointer_type_id(member.ty_id, spirv::StorageClass::Output),
551 ptr_to_copy_to,
552 return_info.primitive_indices.unwrap(),
553 &[val_i],
554 ));
555 }
556 crate::Binding::BuiltIn(bi) => {
557 body.push(Instruction::access_chain(
558 self.get_pointer_type_id(member.ty_id, spirv::StorageClass::Output),
559 ptr_to_copy_to,
560 info.builtin_block.unwrap(),
561 &[
562 val_i,
563 self.get_constant_scalar(crate::Literal::U32(builtin_index)),
564 ],
565 ));
566 needs_y_flip = matches!(bi, crate::BuiltIn::Position { .. })
567 && self.flags.contains(WriterFlags::ADJUST_COORDINATE_SPACE);
568 builtin_index += 1;
569 }
570 crate::Binding::Location { .. } => {
571 body.push(Instruction::access_chain(
572 self.get_pointer_type_id(member.ty_id, spirv::StorageClass::Output),
573 ptr_to_copy_to,
574 info.bindings[binding_index],
575 &[val_i],
576 ));
577 binding_index += 1;
578 }
579 }
580 body.push(Instruction::store(ptr_to_copy_to, val_to_copy, None));
581 if needs_y_flip {
584 let prev_y = self.id_gen.next();
585 body.push(Instruction::composite_extract(
586 self.get_f32_type_id(),
587 prev_y,
588 val_to_copy,
589 &[1],
590 ));
591 let new_y = self.id_gen.next();
592 body.push(Instruction::unary(
593 spirv::Op::FNegate,
594 self.get_f32_type_id(),
595 new_y,
596 prev_y,
597 ));
598 let new_ptr_to_copy_to = self.id_gen.next();
599 body.push(Instruction::access_chain(
600 self.get_f32_pointer_type_id(spirv::StorageClass::Output),
601 new_ptr_to_copy_to,
602 ptr_to_copy_to,
603 &[self.get_constant_scalar(crate::Literal::U32(1))],
604 ));
605 body.push(Instruction::store(new_ptr_to_copy_to, new_y, None));
606 }
607 }
608 body
609 }
610
611 pub(super) fn write_mesh_shader_return(
614 &mut self,
615 return_info: &MeshReturnInfo,
616 block: &mut Block,
617 loop_counter_vertices: u32,
618 loop_counter_primitives: u32,
619 local_invocation_index_id: Word,
620 ) -> Result<(), Error> {
621 let u32_id = self.get_u32_type_id();
622
623 let mut load_u32_by_member_index =
625 |members: &[MeshReturnMember], bi: crate::BuiltIn, max: u32| {
626 let member_index = members
627 .iter()
628 .position(|a| a.binding == crate::Binding::BuiltIn(bi))
629 .unwrap() as u32;
630 let ptr_id = self.id_gen.next();
631 block.body.push(Instruction::access_chain(
632 self.get_pointer_type_id(u32_id, spirv::StorageClass::Workgroup),
633 ptr_id,
634 return_info.out_variable_id,
635 &[self.get_constant_scalar(crate::Literal::U32(member_index))],
636 ));
637 let before_min_id = self.id_gen.next();
638 block
639 .body
640 .push(Instruction::load(u32_id, before_min_id, ptr_id, None));
641
642 let id = self.id_gen.next();
644 block.body.push(Instruction::ext_inst_gl_op(
645 self.gl450_ext_inst_id,
646 spirv::GlslStd450Op::UMin,
647 u32_id,
648 id,
649 &[before_min_id, max],
650 ));
651 id
652 };
653 let vert_count_id = load_u32_by_member_index(
654 &return_info.out_members,
655 crate::BuiltIn::VertexCount,
656 return_info.vertex_info.max_length_constant,
657 );
658 let prim_count_id = load_u32_by_member_index(
659 &return_info.out_members,
660 crate::BuiltIn::PrimitiveCount,
661 return_info.primitive_info.max_length_constant,
662 );
663
664 let mut get_array_ptr = |bi: crate::BuiltIn, array_type_id: u32| {
666 let id = self.id_gen.next();
667 block.body.push(Instruction::access_chain(
668 self.get_pointer_type_id(array_type_id, spirv::StorageClass::Workgroup),
669 id,
670 return_info.out_variable_id,
671 &[self.get_constant_scalar(crate::Literal::U32(
672 return_info
673 .out_members
674 .iter()
675 .position(|a| a.binding == crate::Binding::BuiltIn(bi))
676 .unwrap() as u32,
677 ))],
678 ));
679 id
680 };
681 let vert_array_ptr = get_array_ptr(
682 crate::BuiltIn::Vertices,
683 return_info.vertex_info.array_type_id,
684 );
685 let prim_array_ptr = get_array_ptr(
686 crate::BuiltIn::Primitives,
687 return_info.primitive_info.array_type_id,
688 );
689
690 {
692 let mut ins = Instruction::new(spirv::Op::SetMeshOutputsEXT);
693 ins.add_operand(vert_count_id);
694 ins.add_operand(prim_count_id);
695 block.body.push(ins);
696 }
697
698 let vertex_loop_header = self.id_gen.next();
701 let prim_loop_header = self.id_gen.next();
702 let in_between_loops = self.id_gen.next();
703 let func_end = self.id_gen.next();
704
705 block.body.push(Instruction::store(
706 loop_counter_vertices,
707 local_invocation_index_id,
708 None,
709 ));
710 block.body.push(Instruction::branch(vertex_loop_header));
711
712 let vertex_copy_body = self.write_mesh_copy_body(
713 false,
714 return_info,
715 loop_counter_vertices,
716 vert_array_ptr,
717 prim_array_ptr,
718 );
719 self.write_mesh_copy_loop(
721 &mut block.body,
722 vertex_copy_body,
723 vertex_loop_header,
724 in_between_loops,
725 vert_count_id,
726 loop_counter_vertices,
727 return_info,
728 );
729
730 {
732 block.body.push(Instruction::label(in_between_loops));
733
734 block.body.push(Instruction::store(
735 loop_counter_primitives,
736 local_invocation_index_id,
737 None,
738 ));
739
740 block.body.push(Instruction::branch(prim_loop_header));
741 }
742 let primitive_copy_body = self.write_mesh_copy_body(
743 true,
744 return_info,
745 loop_counter_primitives,
746 vert_array_ptr,
747 prim_array_ptr,
748 );
749 self.write_mesh_copy_loop(
751 &mut block.body,
752 primitive_copy_body,
753 prim_loop_header,
754 func_end,
755 prim_count_id,
756 loop_counter_primitives,
757 return_info,
758 );
759
760 block.body.push(Instruction::label(func_end));
761 Ok(())
762 }
763
764 pub(super) fn write_mesh_shader_wrapper(
765 &mut self,
766 return_info: &MeshReturnInfo,
767 inner_id: u32,
768 ) -> Result<u32, Error> {
769 let out_id = self.id_gen.next();
770 let mut function = super::Function::default();
771 let lookup_function_type = super::LookupFunctionType {
772 parameter_type_ids: alloc::vec![],
773 return_type_id: self.void_type,
774 };
775 let function_type = self.get_function_type(lookup_function_type);
776 function.signature = Some(Instruction::function(
777 self.void_type,
778 out_id,
779 spirv::FunctionControl::empty(),
780 function_type,
781 ));
782 let u32_id = self.get_u32_type_id();
783 {
784 let mut block = Block::new(self.id_gen.next());
785 let loop_counter_vertices = self.id_gen.next();
789 let loop_counter_primitives = self.id_gen.next();
790 block.body.insert(
791 0,
792 Instruction::variable(
793 self.get_pointer_type_id(u32_id, spirv::StorageClass::Function),
794 loop_counter_vertices,
795 spirv::StorageClass::Function,
796 None,
797 ),
798 );
799 block.body.insert(
800 1,
801 Instruction::variable(
802 self.get_pointer_type_id(u32_id, spirv::StorageClass::Function),
803 loop_counter_primitives,
804 spirv::StorageClass::Function,
805 None,
806 ),
807 );
808 let local_invocation_index_id = self.id_gen.next();
809 block.body.push(Instruction::load(
810 u32_id,
811 local_invocation_index_id,
812 return_info.local_invocation_index_var_id,
813 None,
814 ));
815 block.body.push(Instruction::function_call(
816 self.void_type,
817 self.id_gen.next(),
818 inner_id,
819 &[],
820 ));
821 self.write_control_barrier(crate::Barrier::WORK_GROUP, &mut block.body);
822 self.write_mesh_shader_return(
823 return_info,
824 &mut block,
825 loop_counter_vertices,
826 loop_counter_primitives,
827 local_invocation_index_id,
828 )?;
829 function.consume(block, Instruction::return_void());
830 }
831 function.to_words(&mut self.logical_layout.function_definitions);
832 Ok(out_id)
833 }
834
835 pub(super) fn write_task_shader_wrapper(
836 &mut self,
837 task_payload: Word,
838 inner_id: u32,
839 ) -> Result<u32, Error> {
840 let out_id = self.id_gen.next();
841 let mut function = super::Function::default();
842 let lookup_function_type = super::LookupFunctionType {
843 parameter_type_ids: alloc::vec![],
844 return_type_id: self.void_type,
845 };
846 let function_type = self.get_function_type(lookup_function_type);
847 function.signature = Some(Instruction::function(
848 self.void_type,
849 out_id,
850 spirv::FunctionControl::empty(),
851 function_type,
852 ));
853
854 {
855 let mut block = Block::new(self.id_gen.next());
856 let result = self.id_gen.next();
857 block.body.push(Instruction::function_call(
858 self.get_vec3u_type_id(),
859 result,
860 inner_id,
861 &[],
862 ));
863 self.write_control_barrier(crate::Barrier::WORK_GROUP, &mut block.body);
864 let final_value = if let Some(task_limits) = self.task_dispatch_limits {
865 let zero_u32 = self.get_constant_scalar(crate::Literal::U32(0));
866 let max_per_dim = self.get_constant_scalar(crate::Literal::U32(
867 task_limits.max_mesh_workgroups_per_dim,
868 ));
869 let max_total = self.get_constant_scalar(crate::Literal::U32(
870 task_limits.max_mesh_workgroups_total,
871 ));
872 let combined_struct_type = self.get_tuple_of_u32s_ty_id();
873 let values = [self.id_gen.next(), self.id_gen.next(), self.id_gen.next()];
874 for (i, value) in values.into_iter().enumerate() {
875 block.body.push(Instruction::composite_extract(
876 self.get_u32_type_id(),
877 value,
878 result,
879 &[i as u32],
880 ));
881 }
882 let prod_1 = self.id_gen.next();
883 let overflows = [self.id_gen.next(), self.id_gen.next()];
884 {
885 let struct_out = self.id_gen.next();
886 block.body.push(Instruction::binary(
887 spirv::Op::UMulExtended,
888 combined_struct_type,
889 struct_out,
890 values[0],
891 values[1],
892 ));
893 block.body.push(Instruction::composite_extract(
894 self.get_u32_type_id(),
895 prod_1,
896 struct_out,
897 &[0],
898 ));
899 block.body.push(Instruction::composite_extract(
900 self.get_u32_type_id(),
901 overflows[0],
902 struct_out,
903 &[1],
904 ));
905 }
906 let prod_final = self.id_gen.next();
907 {
908 let struct_out = self.id_gen.next();
909 block.body.push(Instruction::binary(
910 spirv::Op::UMulExtended,
911 combined_struct_type,
912 struct_out,
913 prod_1,
914 values[2],
915 ));
916 block.body.push(Instruction::composite_extract(
917 self.get_u32_type_id(),
918 prod_final,
919 struct_out,
920 &[0],
921 ));
922 block.body.push(Instruction::composite_extract(
923 self.get_u32_type_id(),
924 overflows[1],
925 struct_out,
926 &[1],
927 ));
928 }
929 let total_too_large = self.id_gen.next();
930 block.body.push(Instruction::binary(
931 spirv::Op::UGreaterThan,
932 self.get_bool_type_id(),
933 total_too_large,
934 prod_final,
935 max_total,
936 ));
937
938 let too_large = [self.id_gen.next(), self.id_gen.next(), self.id_gen.next()];
939 for (i, value) in values.into_iter().enumerate() {
940 block.body.push(Instruction::binary(
941 spirv::Op::UGreaterThan,
942 self.get_bool_type_id(),
943 too_large[i],
944 value,
945 max_per_dim,
946 ));
947 }
948 let overflow_happens = [self.id_gen.next(), self.id_gen.next()];
949 for (i, value) in overflows.into_iter().enumerate() {
950 block.body.push(Instruction::binary(
951 spirv::Op::INotEqual,
952 self.get_bool_type_id(),
953 overflow_happens[i],
954 value,
955 zero_u32,
956 ));
957 }
958 let mut current_violates_limits = total_too_large;
959 for is_too_large in too_large {
960 let new = self.id_gen.next();
961 block.body.push(Instruction::binary(
962 spirv::Op::LogicalOr,
963 self.get_bool_type_id(),
964 new,
965 current_violates_limits,
966 is_too_large,
967 ));
968 current_violates_limits = new;
969 }
970 for overflow_happens in overflow_happens {
971 let new = self.id_gen.next();
972 block.body.push(Instruction::binary(
973 spirv::Op::LogicalOr,
974 self.get_bool_type_id(),
975 new,
976 current_violates_limits,
977 overflow_happens,
978 ));
979 current_violates_limits = new;
980 }
981 let zero_vec3 = self.id_gen.next();
982 block.body.push(Instruction::composite_construct(
983 self.get_vec3u_type_id(),
984 zero_vec3,
985 &[zero_u32, zero_u32, zero_u32],
986 ));
987 let final_result = self.id_gen.next();
988 block.body.push(Instruction::select(
989 self.get_vec3u_type_id(),
990 final_result,
991 current_violates_limits,
992 zero_vec3,
993 result,
994 ));
995 final_result
996 } else {
997 result
998 };
999 let ins =
1000 self.write_entry_point_task_return(final_value, &mut block.body, task_payload)?;
1001 function.consume(block, ins);
1002 }
1003 function.to_words(&mut self.logical_layout.function_definitions);
1004 Ok(out_id)
1005 }
1006}