naga/back/spv/
writer.rs

1use super::{
2    block::DebugInfoInner,
3    helpers::{contains_builtin, global_needs_wrapper, map_storage_class},
4    make_local, Block, BlockContext, CachedConstant, CachedExpressions, DebugInfo,
5    EntryPointContext, Error, Function, FunctionArgument, GlobalVariable, IdGenerator, Instruction,
6    LocalType, LocalVariable, LogicalLayout, LookupFunctionType, LookupType, LoopContext, Options,
7    PhysicalLayout, PipelineOptions, ResultMember, Writer, WriterFlags, BITS_PER_BYTE,
8};
9use crate::{
10    arena::{Handle, UniqueArena},
11    back::spv::BindingInfo,
12    proc::{Alignment, TypeResolution},
13    valid::{FunctionInfo, ModuleInfo},
14};
15use spirv::Word;
16use std::collections::hash_map::Entry;
17
18struct FunctionInterface<'a> {
19    varying_ids: &'a mut Vec<Word>,
20    stage: crate::ShaderStage,
21}
22
23impl Function {
24    fn to_words(&self, sink: &mut impl Extend<Word>) {
25        self.signature.as_ref().unwrap().to_words(sink);
26        for argument in self.parameters.iter() {
27            argument.instruction.to_words(sink);
28        }
29        for (index, block) in self.blocks.iter().enumerate() {
30            Instruction::label(block.label_id).to_words(sink);
31            if index == 0 {
32                for local_var in self.variables.values() {
33                    local_var.instruction.to_words(sink);
34                }
35            }
36            for instruction in block.body.iter() {
37                instruction.to_words(sink);
38            }
39        }
40    }
41}
42
43impl Writer {
44    pub fn new(options: &Options) -> Result<Self, Error> {
45        let (major, minor) = options.lang_version;
46        if major != 1 {
47            return Err(Error::UnsupportedVersion(major, minor));
48        }
49        let raw_version = ((major as u32) << 16) | ((minor as u32) << 8);
50
51        let mut capabilities_used = crate::FastIndexSet::default();
52        capabilities_used.insert(spirv::Capability::Shader);
53
54        let mut id_gen = IdGenerator::default();
55        let gl450_ext_inst_id = id_gen.next();
56        let void_type = id_gen.next();
57
58        Ok(Writer {
59            physical_layout: PhysicalLayout::new(raw_version),
60            logical_layout: LogicalLayout::default(),
61            id_gen,
62            capabilities_available: options.capabilities.clone(),
63            capabilities_used,
64            extensions_used: crate::FastIndexSet::default(),
65            debugs: vec![],
66            annotations: vec![],
67            flags: options.flags,
68            bounds_check_policies: options.bounds_check_policies,
69            zero_initialize_workgroup_memory: options.zero_initialize_workgroup_memory,
70            void_type,
71            lookup_type: crate::FastHashMap::default(),
72            lookup_function: crate::FastHashMap::default(),
73            lookup_function_type: crate::FastHashMap::default(),
74            constant_ids: Vec::new(),
75            cached_constants: crate::FastHashMap::default(),
76            global_variables: Vec::new(),
77            binding_map: options.binding_map.clone(),
78            saved_cached: CachedExpressions::default(),
79            gl450_ext_inst_id,
80            temp_list: Vec::new(),
81        })
82    }
83
84    /// Reset `Writer` to its initial state, retaining any allocations.
85    ///
86    /// Why not just implement `Recyclable` for `Writer`? By design,
87    /// `Recyclable::recycle` requires ownership of the value, not just
88    /// `&mut`; see the trait documentation. But we need to use this method
89    /// from functions like `Writer::write`, which only have `&mut Writer`.
90    /// Workarounds include unsafe code (`std::ptr::read`, then `write`, ugh)
91    /// or something like a `Default` impl that returns an oddly-initialized
92    /// `Writer`, which is worse.
93    fn reset(&mut self) {
94        use super::recyclable::Recyclable;
95        use std::mem::take;
96
97        let mut id_gen = IdGenerator::default();
98        let gl450_ext_inst_id = id_gen.next();
99        let void_type = id_gen.next();
100
101        // Every field of the old writer that is not determined by the `Options`
102        // passed to `Writer::new` should be reset somehow.
103        let fresh = Writer {
104            // Copied from the old Writer:
105            flags: self.flags,
106            bounds_check_policies: self.bounds_check_policies,
107            zero_initialize_workgroup_memory: self.zero_initialize_workgroup_memory,
108            capabilities_available: take(&mut self.capabilities_available),
109            binding_map: take(&mut self.binding_map),
110
111            // Initialized afresh:
112            id_gen,
113            void_type,
114            gl450_ext_inst_id,
115
116            // Recycled:
117            capabilities_used: take(&mut self.capabilities_used).recycle(),
118            extensions_used: take(&mut self.extensions_used).recycle(),
119            physical_layout: self.physical_layout.clone().recycle(),
120            logical_layout: take(&mut self.logical_layout).recycle(),
121            debugs: take(&mut self.debugs).recycle(),
122            annotations: take(&mut self.annotations).recycle(),
123            lookup_type: take(&mut self.lookup_type).recycle(),
124            lookup_function: take(&mut self.lookup_function).recycle(),
125            lookup_function_type: take(&mut self.lookup_function_type).recycle(),
126            constant_ids: take(&mut self.constant_ids).recycle(),
127            cached_constants: take(&mut self.cached_constants).recycle(),
128            global_variables: take(&mut self.global_variables).recycle(),
129            saved_cached: take(&mut self.saved_cached).recycle(),
130            temp_list: take(&mut self.temp_list).recycle(),
131        };
132
133        *self = fresh;
134
135        self.capabilities_used.insert(spirv::Capability::Shader);
136    }
137
138    /// Indicate that the code requires any one of the listed capabilities.
139    ///
140    /// If nothing in `capabilities` appears in the available capabilities
141    /// specified in the [`Options`] from which this `Writer` was created,
142    /// return an error. The `what` string is used in the error message to
143    /// explain what provoked the requirement. (If no available capabilities were
144    /// given, assume everything is available.)
145    ///
146    /// The first acceptable capability will be added to this `Writer`'s
147    /// [`capabilities_used`] table, and an `OpCapability` emitted for it in the
148    /// result. For this reason, more specific capabilities should be listed
149    /// before more general.
150    ///
151    /// [`capabilities_used`]: Writer::capabilities_used
152    pub(super) fn require_any(
153        &mut self,
154        what: &'static str,
155        capabilities: &[spirv::Capability],
156    ) -> Result<(), Error> {
157        match *capabilities {
158            [] => Ok(()),
159            [first, ..] => {
160                // Find the first acceptable capability, or return an error if
161                // there is none.
162                let selected = match self.capabilities_available {
163                    None => first,
164                    Some(ref available) => {
165                        match capabilities.iter().find(|cap| available.contains(cap)) {
166                            Some(&cap) => cap,
167                            None => {
168                                return Err(Error::MissingCapabilities(what, capabilities.to_vec()))
169                            }
170                        }
171                    }
172                };
173                self.capabilities_used.insert(selected);
174                Ok(())
175            }
176        }
177    }
178
179    /// Indicate that the code uses the given extension.
180    pub(super) fn use_extension(&mut self, extension: &'static str) {
181        self.extensions_used.insert(extension);
182    }
183
184    pub(super) fn get_type_id(&mut self, lookup_ty: LookupType) -> Word {
185        match self.lookup_type.entry(lookup_ty) {
186            Entry::Occupied(e) => *e.get(),
187            Entry::Vacant(e) => {
188                let local = match lookup_ty {
189                    LookupType::Handle(_handle) => unreachable!("Handles are populated at start"),
190                    LookupType::Local(local) => local,
191                };
192
193                let id = self.id_gen.next();
194                e.insert(id);
195                self.write_type_declaration_local(id, local);
196                id
197            }
198        }
199    }
200
201    pub(super) fn get_expression_lookup_type(&mut self, tr: &TypeResolution) -> LookupType {
202        match *tr {
203            TypeResolution::Handle(ty_handle) => LookupType::Handle(ty_handle),
204            TypeResolution::Value(ref inner) => LookupType::Local(make_local(inner).unwrap()),
205        }
206    }
207
208    pub(super) fn get_expression_type_id(&mut self, tr: &TypeResolution) -> Word {
209        let lookup_ty = self.get_expression_lookup_type(tr);
210        self.get_type_id(lookup_ty)
211    }
212
213    pub(super) fn get_pointer_id(
214        &mut self,
215        arena: &UniqueArena<crate::Type>,
216        handle: Handle<crate::Type>,
217        class: spirv::StorageClass,
218    ) -> Result<Word, Error> {
219        let ty_id = self.get_type_id(LookupType::Handle(handle));
220        if let crate::TypeInner::Pointer { .. } = arena[handle].inner {
221            return Ok(ty_id);
222        }
223        let lookup_type = LookupType::Local(LocalType::Pointer {
224            base: handle,
225            class,
226        });
227        Ok(if let Some(&id) = self.lookup_type.get(&lookup_type) {
228            id
229        } else {
230            let id = self.id_gen.next();
231            let instruction = Instruction::type_pointer(id, class, ty_id);
232            instruction.to_words(&mut self.logical_layout.declarations);
233            self.lookup_type.insert(lookup_type, id);
234            id
235        })
236    }
237
238    pub(super) fn get_uint_type_id(&mut self) -> Word {
239        let local_type = LocalType::Value {
240            vector_size: None,
241            scalar: crate::Scalar::U32,
242            pointer_space: None,
243        };
244        self.get_type_id(local_type.into())
245    }
246
247    pub(super) fn get_float_type_id(&mut self) -> Word {
248        let local_type = LocalType::Value {
249            vector_size: None,
250            scalar: crate::Scalar::F32,
251            pointer_space: None,
252        };
253        self.get_type_id(local_type.into())
254    }
255
256    pub(super) fn get_uint3_type_id(&mut self) -> Word {
257        let local_type = LocalType::Value {
258            vector_size: Some(crate::VectorSize::Tri),
259            scalar: crate::Scalar::U32,
260            pointer_space: None,
261        };
262        self.get_type_id(local_type.into())
263    }
264
265    pub(super) fn get_float_pointer_type_id(&mut self, class: spirv::StorageClass) -> Word {
266        let lookup_type = LookupType::Local(LocalType::Value {
267            vector_size: None,
268            scalar: crate::Scalar::F32,
269            pointer_space: Some(class),
270        });
271        if let Some(&id) = self.lookup_type.get(&lookup_type) {
272            id
273        } else {
274            let id = self.id_gen.next();
275            let ty_id = self.get_float_type_id();
276            let instruction = Instruction::type_pointer(id, class, ty_id);
277            instruction.to_words(&mut self.logical_layout.declarations);
278            self.lookup_type.insert(lookup_type, id);
279            id
280        }
281    }
282
283    pub(super) fn get_uint3_pointer_type_id(&mut self, class: spirv::StorageClass) -> Word {
284        let lookup_type = LookupType::Local(LocalType::Value {
285            vector_size: Some(crate::VectorSize::Tri),
286            scalar: crate::Scalar::U32,
287            pointer_space: Some(class),
288        });
289        if let Some(&id) = self.lookup_type.get(&lookup_type) {
290            id
291        } else {
292            let id = self.id_gen.next();
293            let ty_id = self.get_uint3_type_id();
294            let instruction = Instruction::type_pointer(id, class, ty_id);
295            instruction.to_words(&mut self.logical_layout.declarations);
296            self.lookup_type.insert(lookup_type, id);
297            id
298        }
299    }
300
301    pub(super) fn get_bool_type_id(&mut self) -> Word {
302        let local_type = LocalType::Value {
303            vector_size: None,
304            scalar: crate::Scalar::BOOL,
305            pointer_space: None,
306        };
307        self.get_type_id(local_type.into())
308    }
309
310    pub(super) fn get_bool3_type_id(&mut self) -> Word {
311        let local_type = LocalType::Value {
312            vector_size: Some(crate::VectorSize::Tri),
313            scalar: crate::Scalar::BOOL,
314            pointer_space: None,
315        };
316        self.get_type_id(local_type.into())
317    }
318
319    pub(super) fn decorate(&mut self, id: Word, decoration: spirv::Decoration, operands: &[Word]) {
320        self.annotations
321            .push(Instruction::decorate(id, decoration, operands));
322    }
323
324    fn write_function(
325        &mut self,
326        ir_function: &crate::Function,
327        info: &FunctionInfo,
328        ir_module: &crate::Module,
329        mut interface: Option<FunctionInterface>,
330        debug_info: &Option<DebugInfoInner>,
331    ) -> Result<Word, Error> {
332        let mut function = Function::default();
333
334        let prelude_id = self.id_gen.next();
335        let mut prelude = Block::new(prelude_id);
336        let mut ep_context = EntryPointContext {
337            argument_ids: Vec::new(),
338            results: Vec::new(),
339        };
340
341        let mut local_invocation_id = None;
342
343        let mut parameter_type_ids = Vec::with_capacity(ir_function.arguments.len());
344        for argument in ir_function.arguments.iter() {
345            let class = spirv::StorageClass::Input;
346            let handle_ty = ir_module.types[argument.ty].inner.is_handle();
347            let argument_type_id = match handle_ty {
348                true => self.get_pointer_id(
349                    &ir_module.types,
350                    argument.ty,
351                    spirv::StorageClass::UniformConstant,
352                )?,
353                false => self.get_type_id(LookupType::Handle(argument.ty)),
354            };
355
356            if let Some(ref mut iface) = interface {
357                let id = if let Some(ref binding) = argument.binding {
358                    let name = argument.name.as_deref();
359
360                    let varying_id = self.write_varying(
361                        ir_module,
362                        iface.stage,
363                        class,
364                        name,
365                        argument.ty,
366                        binding,
367                    )?;
368                    iface.varying_ids.push(varying_id);
369                    let id = self.id_gen.next();
370                    prelude
371                        .body
372                        .push(Instruction::load(argument_type_id, id, varying_id, None));
373
374                    if binding == &crate::Binding::BuiltIn(crate::BuiltIn::LocalInvocationId) {
375                        local_invocation_id = Some(id);
376                    }
377
378                    id
379                } else if let crate::TypeInner::Struct { ref members, .. } =
380                    ir_module.types[argument.ty].inner
381                {
382                    let struct_id = self.id_gen.next();
383                    let mut constituent_ids = Vec::with_capacity(members.len());
384                    for member in members {
385                        let type_id = self.get_type_id(LookupType::Handle(member.ty));
386                        let name = member.name.as_deref();
387                        let binding = member.binding.as_ref().unwrap();
388                        let varying_id = self.write_varying(
389                            ir_module,
390                            iface.stage,
391                            class,
392                            name,
393                            member.ty,
394                            binding,
395                        )?;
396                        iface.varying_ids.push(varying_id);
397                        let id = self.id_gen.next();
398                        prelude
399                            .body
400                            .push(Instruction::load(type_id, id, varying_id, None));
401                        constituent_ids.push(id);
402
403                        if binding == &crate::Binding::BuiltIn(crate::BuiltIn::GlobalInvocationId) {
404                            local_invocation_id = Some(id);
405                        }
406                    }
407                    prelude.body.push(Instruction::composite_construct(
408                        argument_type_id,
409                        struct_id,
410                        &constituent_ids,
411                    ));
412                    struct_id
413                } else {
414                    unreachable!("Missing argument binding on an entry point");
415                };
416                ep_context.argument_ids.push(id);
417            } else {
418                let argument_id = self.id_gen.next();
419                let instruction = Instruction::function_parameter(argument_type_id, argument_id);
420                if self.flags.contains(WriterFlags::DEBUG) {
421                    if let Some(ref name) = argument.name {
422                        self.debugs.push(Instruction::name(argument_id, name));
423                    }
424                }
425                function.parameters.push(FunctionArgument {
426                    instruction,
427                    handle_id: if handle_ty {
428                        let id = self.id_gen.next();
429                        prelude.body.push(Instruction::load(
430                            self.get_type_id(LookupType::Handle(argument.ty)),
431                            id,
432                            argument_id,
433                            None,
434                        ));
435                        id
436                    } else {
437                        0
438                    },
439                });
440                parameter_type_ids.push(argument_type_id);
441            };
442        }
443
444        let return_type_id = match ir_function.result {
445            Some(ref result) => {
446                if let Some(ref mut iface) = interface {
447                    let mut has_point_size = false;
448                    let class = spirv::StorageClass::Output;
449                    if let Some(ref binding) = result.binding {
450                        has_point_size |=
451                            *binding == crate::Binding::BuiltIn(crate::BuiltIn::PointSize);
452                        let type_id = self.get_type_id(LookupType::Handle(result.ty));
453                        let varying_id = self.write_varying(
454                            ir_module,
455                            iface.stage,
456                            class,
457                            None,
458                            result.ty,
459                            binding,
460                        )?;
461                        iface.varying_ids.push(varying_id);
462                        ep_context.results.push(ResultMember {
463                            id: varying_id,
464                            type_id,
465                            built_in: binding.to_built_in(),
466                        });
467                    } else if let crate::TypeInner::Struct { ref members, .. } =
468                        ir_module.types[result.ty].inner
469                    {
470                        for member in members {
471                            let type_id = self.get_type_id(LookupType::Handle(member.ty));
472                            let name = member.name.as_deref();
473                            let binding = member.binding.as_ref().unwrap();
474                            has_point_size |=
475                                *binding == crate::Binding::BuiltIn(crate::BuiltIn::PointSize);
476                            let varying_id = self.write_varying(
477                                ir_module,
478                                iface.stage,
479                                class,
480                                name,
481                                member.ty,
482                                binding,
483                            )?;
484                            iface.varying_ids.push(varying_id);
485                            ep_context.results.push(ResultMember {
486                                id: varying_id,
487                                type_id,
488                                built_in: binding.to_built_in(),
489                            });
490                        }
491                    } else {
492                        unreachable!("Missing result binding on an entry point");
493                    }
494
495                    if self.flags.contains(WriterFlags::FORCE_POINT_SIZE)
496                        && iface.stage == crate::ShaderStage::Vertex
497                        && !has_point_size
498                    {
499                        // add point size artificially
500                        let varying_id = self.id_gen.next();
501                        let pointer_type_id = self.get_float_pointer_type_id(class);
502                        Instruction::variable(pointer_type_id, varying_id, class, None)
503                            .to_words(&mut self.logical_layout.declarations);
504                        self.decorate(
505                            varying_id,
506                            spirv::Decoration::BuiltIn,
507                            &[spirv::BuiltIn::PointSize as u32],
508                        );
509                        iface.varying_ids.push(varying_id);
510
511                        let default_value_id = self.get_constant_scalar(crate::Literal::F32(1.0));
512                        prelude
513                            .body
514                            .push(Instruction::store(varying_id, default_value_id, None));
515                    }
516                    self.void_type
517                } else {
518                    self.get_type_id(LookupType::Handle(result.ty))
519                }
520            }
521            None => self.void_type,
522        };
523
524        let lookup_function_type = LookupFunctionType {
525            parameter_type_ids,
526            return_type_id,
527        };
528
529        let function_id = self.id_gen.next();
530        if self.flags.contains(WriterFlags::DEBUG) {
531            if let Some(ref name) = ir_function.name {
532                self.debugs.push(Instruction::name(function_id, name));
533            }
534        }
535
536        let function_type = self.get_function_type(lookup_function_type);
537        function.signature = Some(Instruction::function(
538            return_type_id,
539            function_id,
540            spirv::FunctionControl::empty(),
541            function_type,
542        ));
543
544        if interface.is_some() {
545            function.entry_point_context = Some(ep_context);
546        }
547
548        // fill up the `GlobalVariable::access_id`
549        for gv in self.global_variables.iter_mut() {
550            gv.reset_for_function();
551        }
552        for (handle, var) in ir_module.global_variables.iter() {
553            if info[handle].is_empty() {
554                continue;
555            }
556
557            let mut gv = self.global_variables[handle.index()].clone();
558            if let Some(ref mut iface) = interface {
559                // Have to include global variables in the interface
560                if self.physical_layout.version >= 0x10400 {
561                    iface.varying_ids.push(gv.var_id);
562                }
563            }
564
565            // Handle globals are pre-emitted and should be loaded automatically.
566            //
567            // Any that are binding arrays we skip as we cannot load the array, we must load the result after indexing.
568            match ir_module.types[var.ty].inner {
569                crate::TypeInner::BindingArray { .. } => {
570                    gv.access_id = gv.var_id;
571                }
572                _ => {
573                    if var.space == crate::AddressSpace::Handle {
574                        let var_type_id = self.get_type_id(LookupType::Handle(var.ty));
575                        let id = self.id_gen.next();
576                        prelude
577                            .body
578                            .push(Instruction::load(var_type_id, id, gv.var_id, None));
579                        gv.access_id = gv.var_id;
580                        gv.handle_id = id;
581                    } else if global_needs_wrapper(ir_module, var) {
582                        let class = map_storage_class(var.space);
583                        let pointer_type_id =
584                            self.get_pointer_id(&ir_module.types, var.ty, class)?;
585                        let index_id = self.get_index_constant(0);
586                        let id = self.id_gen.next();
587                        prelude.body.push(Instruction::access_chain(
588                            pointer_type_id,
589                            id,
590                            gv.var_id,
591                            &[index_id],
592                        ));
593                        gv.access_id = id;
594                    } else {
595                        // by default, the variable ID is accessed as is
596                        gv.access_id = gv.var_id;
597                    };
598                }
599            }
600
601            // work around borrow checking in the presence of `self.xxx()` calls
602            self.global_variables[handle.index()] = gv;
603        }
604
605        // Create a `BlockContext` for generating SPIR-V for the function's
606        // body.
607        let mut context = BlockContext {
608            ir_module,
609            ir_function,
610            fun_info: info,
611            function: &mut function,
612            // Re-use the cached expression table from prior functions.
613            cached: std::mem::take(&mut self.saved_cached),
614
615            // Steal the Writer's temp list for a bit.
616            temp_list: std::mem::take(&mut self.temp_list),
617            writer: self,
618            expression_constness: super::ExpressionConstnessTracker::from_arena(
619                &ir_function.expressions,
620            ),
621        };
622
623        // fill up the pre-emitted and const expressions
624        context.cached.reset(ir_function.expressions.len());
625        for (handle, expr) in ir_function.expressions.iter() {
626            if (expr.needs_pre_emit() && !matches!(*expr, crate::Expression::LocalVariable(_)))
627                || context.expression_constness.is_const(handle)
628            {
629                context.cache_expression_value(handle, &mut prelude)?;
630            }
631        }
632
633        for (handle, variable) in ir_function.local_variables.iter() {
634            let id = context.gen_id();
635
636            if context.writer.flags.contains(WriterFlags::DEBUG) {
637                if let Some(ref name) = variable.name {
638                    context.writer.debugs.push(Instruction::name(id, name));
639                }
640            }
641
642            let init_word = variable.init.map(|constant| context.cached[constant]);
643            let pointer_type_id = context.writer.get_pointer_id(
644                &ir_module.types,
645                variable.ty,
646                spirv::StorageClass::Function,
647            )?;
648            let instruction = Instruction::variable(
649                pointer_type_id,
650                id,
651                spirv::StorageClass::Function,
652                init_word.or_else(|| match ir_module.types[variable.ty].inner {
653                    crate::TypeInner::RayQuery => None,
654                    _ => {
655                        let type_id = context.get_type_id(LookupType::Handle(variable.ty));
656                        Some(context.writer.write_constant_null(type_id))
657                    }
658                }),
659            );
660            context
661                .function
662                .variables
663                .insert(handle, LocalVariable { id, instruction });
664        }
665
666        // cache local variable expressions
667        for (handle, expr) in ir_function.expressions.iter() {
668            if matches!(*expr, crate::Expression::LocalVariable(_)) {
669                context.cache_expression_value(handle, &mut prelude)?;
670            }
671        }
672
673        let next_id = context.gen_id();
674
675        context
676            .function
677            .consume(prelude, Instruction::branch(next_id));
678
679        let workgroup_vars_init_exit_block_id =
680            match (context.writer.zero_initialize_workgroup_memory, interface) {
681                (
682                    super::ZeroInitializeWorkgroupMemoryMode::Polyfill,
683                    Some(
684                        ref mut interface @ FunctionInterface {
685                            stage: crate::ShaderStage::Compute,
686                            ..
687                        },
688                    ),
689                ) => context.writer.generate_workgroup_vars_init_block(
690                    next_id,
691                    ir_module,
692                    info,
693                    local_invocation_id,
694                    interface,
695                    context.function,
696                ),
697                _ => None,
698            };
699
700        let main_id = if let Some(exit_id) = workgroup_vars_init_exit_block_id {
701            exit_id
702        } else {
703            next_id
704        };
705
706        context.write_block(
707            main_id,
708            &ir_function.body,
709            super::block::BlockExit::Return,
710            LoopContext::default(),
711            debug_info.as_ref(),
712        )?;
713
714        // Consume the `BlockContext`, ending its borrows and letting the
715        // `Writer` steal back its cached expression table and temp_list.
716        let BlockContext {
717            cached, temp_list, ..
718        } = context;
719        self.saved_cached = cached;
720        self.temp_list = temp_list;
721
722        function.to_words(&mut self.logical_layout.function_definitions);
723        Instruction::function_end().to_words(&mut self.logical_layout.function_definitions);
724
725        Ok(function_id)
726    }
727
728    fn write_execution_mode(
729        &mut self,
730        function_id: Word,
731        mode: spirv::ExecutionMode,
732    ) -> Result<(), Error> {
733        //self.check(mode.required_capabilities())?;
734        Instruction::execution_mode(function_id, mode, &[])
735            .to_words(&mut self.logical_layout.execution_modes);
736        Ok(())
737    }
738
739    // TODO Move to instructions module
740    fn write_entry_point(
741        &mut self,
742        entry_point: &crate::EntryPoint,
743        info: &FunctionInfo,
744        ir_module: &crate::Module,
745        debug_info: &Option<DebugInfoInner>,
746    ) -> Result<Instruction, Error> {
747        let mut interface_ids = Vec::new();
748        let function_id = self.write_function(
749            &entry_point.function,
750            info,
751            ir_module,
752            Some(FunctionInterface {
753                varying_ids: &mut interface_ids,
754                stage: entry_point.stage,
755            }),
756            debug_info,
757        )?;
758
759        let exec_model = match entry_point.stage {
760            crate::ShaderStage::Vertex => spirv::ExecutionModel::Vertex,
761            crate::ShaderStage::Fragment => {
762                self.write_execution_mode(function_id, spirv::ExecutionMode::OriginUpperLeft)?;
763                if let Some(ref result) = entry_point.function.result {
764                    if contains_builtin(
765                        result.binding.as_ref(),
766                        result.ty,
767                        &ir_module.types,
768                        crate::BuiltIn::FragDepth,
769                    ) {
770                        self.write_execution_mode(
771                            function_id,
772                            spirv::ExecutionMode::DepthReplacing,
773                        )?;
774                    }
775                }
776                spirv::ExecutionModel::Fragment
777            }
778            crate::ShaderStage::Compute => {
779                let execution_mode = spirv::ExecutionMode::LocalSize;
780                //self.check(execution_mode.required_capabilities())?;
781                Instruction::execution_mode(
782                    function_id,
783                    execution_mode,
784                    &entry_point.workgroup_size,
785                )
786                .to_words(&mut self.logical_layout.execution_modes);
787                spirv::ExecutionModel::GLCompute
788            }
789        };
790        //self.check(exec_model.required_capabilities())?;
791
792        Ok(Instruction::entry_point(
793            exec_model,
794            function_id,
795            &entry_point.name,
796            interface_ids.as_slice(),
797        ))
798    }
799
800    fn make_scalar(&mut self, id: Word, scalar: crate::Scalar) -> Instruction {
801        use crate::ScalarKind as Sk;
802
803        let bits = (scalar.width * BITS_PER_BYTE) as u32;
804        match scalar.kind {
805            Sk::Sint | Sk::Uint => {
806                let signedness = if scalar.kind == Sk::Sint {
807                    super::instructions::Signedness::Signed
808                } else {
809                    super::instructions::Signedness::Unsigned
810                };
811                let cap = match bits {
812                    8 => Some(spirv::Capability::Int8),
813                    16 => Some(spirv::Capability::Int16),
814                    64 => Some(spirv::Capability::Int64),
815                    _ => None,
816                };
817                if let Some(cap) = cap {
818                    self.capabilities_used.insert(cap);
819                }
820                Instruction::type_int(id, bits, signedness)
821            }
822            Sk::Float => {
823                if bits == 64 {
824                    self.capabilities_used.insert(spirv::Capability::Float64);
825                }
826                Instruction::type_float(id, bits)
827            }
828            Sk::Bool => Instruction::type_bool(id),
829            Sk::AbstractInt | Sk::AbstractFloat => {
830                unreachable!("abstract types should never reach the backend");
831            }
832        }
833    }
834
835    fn request_type_capabilities(&mut self, inner: &crate::TypeInner) -> Result<(), Error> {
836        match *inner {
837            crate::TypeInner::Image {
838                dim,
839                arrayed,
840                class,
841            } => {
842                let sampled = match class {
843                    crate::ImageClass::Sampled { .. } => true,
844                    crate::ImageClass::Depth { .. } => true,
845                    crate::ImageClass::Storage { format, .. } => {
846                        self.request_image_format_capabilities(format.into())?;
847                        false
848                    }
849                };
850
851                match dim {
852                    crate::ImageDimension::D1 => {
853                        if sampled {
854                            self.require_any("sampled 1D images", &[spirv::Capability::Sampled1D])?;
855                        } else {
856                            self.require_any("1D storage images", &[spirv::Capability::Image1D])?;
857                        }
858                    }
859                    crate::ImageDimension::Cube if arrayed => {
860                        if sampled {
861                            self.require_any(
862                                "sampled cube array images",
863                                &[spirv::Capability::SampledCubeArray],
864                            )?;
865                        } else {
866                            self.require_any(
867                                "cube array storage images",
868                                &[spirv::Capability::ImageCubeArray],
869                            )?;
870                        }
871                    }
872                    _ => {}
873                }
874            }
875            crate::TypeInner::AccelerationStructure => {
876                self.require_any("Acceleration Structure", &[spirv::Capability::RayQueryKHR])?;
877            }
878            crate::TypeInner::RayQuery => {
879                self.require_any("Ray Query", &[spirv::Capability::RayQueryKHR])?;
880            }
881            _ => {}
882        }
883        Ok(())
884    }
885
886    fn write_type_declaration_local(&mut self, id: Word, local_ty: LocalType) {
887        let instruction = match local_ty {
888            LocalType::Value {
889                vector_size: None,
890                scalar,
891                pointer_space: None,
892            } => self.make_scalar(id, scalar),
893            LocalType::Value {
894                vector_size: Some(size),
895                scalar,
896                pointer_space: None,
897            } => {
898                let scalar_id = self.get_type_id(LookupType::Local(LocalType::Value {
899                    vector_size: None,
900                    scalar,
901                    pointer_space: None,
902                }));
903                Instruction::type_vector(id, scalar_id, size)
904            }
905            LocalType::Matrix {
906                columns,
907                rows,
908                width,
909            } => {
910                let vector_id = self.get_type_id(LookupType::Local(LocalType::Value {
911                    vector_size: Some(rows),
912                    scalar: crate::Scalar::float(width),
913                    pointer_space: None,
914                }));
915                Instruction::type_matrix(id, vector_id, columns)
916            }
917            LocalType::Pointer { base, class } => {
918                let type_id = self.get_type_id(LookupType::Handle(base));
919                Instruction::type_pointer(id, class, type_id)
920            }
921            LocalType::Value {
922                vector_size,
923                scalar,
924                pointer_space: Some(class),
925            } => {
926                let type_id = self.get_type_id(LookupType::Local(LocalType::Value {
927                    vector_size,
928                    scalar,
929                    pointer_space: None,
930                }));
931                Instruction::type_pointer(id, class, type_id)
932            }
933            LocalType::Image(image) => {
934                let local_type = LocalType::Value {
935                    vector_size: None,
936                    scalar: crate::Scalar {
937                        kind: image.sampled_type,
938                        width: 4,
939                    },
940                    pointer_space: None,
941                };
942                let type_id = self.get_type_id(LookupType::Local(local_type));
943                Instruction::type_image(id, type_id, image.dim, image.flags, image.image_format)
944            }
945            LocalType::Sampler => Instruction::type_sampler(id),
946            LocalType::SampledImage { image_type_id } => {
947                Instruction::type_sampled_image(id, image_type_id)
948            }
949            LocalType::BindingArray { base, size } => {
950                let inner_ty = self.get_type_id(LookupType::Handle(base));
951                let scalar_id = self.get_constant_scalar(crate::Literal::U32(size));
952                Instruction::type_array(id, inner_ty, scalar_id)
953            }
954            LocalType::PointerToBindingArray { base, size, space } => {
955                let inner_ty =
956                    self.get_type_id(LookupType::Local(LocalType::BindingArray { base, size }));
957                let class = map_storage_class(space);
958                Instruction::type_pointer(id, class, inner_ty)
959            }
960            LocalType::AccelerationStructure => Instruction::type_acceleration_structure(id),
961            LocalType::RayQuery => Instruction::type_ray_query(id),
962        };
963
964        instruction.to_words(&mut self.logical_layout.declarations);
965    }
966
967    fn write_type_declaration_arena(
968        &mut self,
969        arena: &UniqueArena<crate::Type>,
970        handle: Handle<crate::Type>,
971    ) -> Result<Word, Error> {
972        let ty = &arena[handle];
973        // If it's a type that needs SPIR-V capabilities, request them now.
974        // This needs to happen regardless of the LocalType lookup succeeding,
975        // because some types which map to the same LocalType have different
976        // capability requirements. See https://github.com/gfx-rs/wgpu/issues/5569
977        self.request_type_capabilities(&ty.inner)?;
978        let id = if let Some(local) = make_local(&ty.inner) {
979            // This type can be represented as a `LocalType`, so check if we've
980            // already written an instruction for it. If not, do so now, with
981            // `write_type_declaration_local`.
982            match self.lookup_type.entry(LookupType::Local(local)) {
983                // We already have an id for this `LocalType`.
984                Entry::Occupied(e) => *e.get(),
985
986                // It's a type we haven't seen before.
987                Entry::Vacant(e) => {
988                    let id = self.id_gen.next();
989                    e.insert(id);
990
991                    self.write_type_declaration_local(id, local);
992
993                    id
994                }
995            }
996        } else {
997            use spirv::Decoration;
998
999            let id = self.id_gen.next();
1000            let instruction = match ty.inner {
1001                crate::TypeInner::Array { base, size, stride } => {
1002                    self.decorate(id, Decoration::ArrayStride, &[stride]);
1003
1004                    let type_id = self.get_type_id(LookupType::Handle(base));
1005                    match size {
1006                        crate::ArraySize::Constant(length) => {
1007                            let length_id = self.get_index_constant(length.get());
1008                            Instruction::type_array(id, type_id, length_id)
1009                        }
1010                        crate::ArraySize::Dynamic => Instruction::type_runtime_array(id, type_id),
1011                    }
1012                }
1013                crate::TypeInner::BindingArray { base, size } => {
1014                    let type_id = self.get_type_id(LookupType::Handle(base));
1015                    match size {
1016                        crate::ArraySize::Constant(length) => {
1017                            let length_id = self.get_index_constant(length.get());
1018                            Instruction::type_array(id, type_id, length_id)
1019                        }
1020                        crate::ArraySize::Dynamic => Instruction::type_runtime_array(id, type_id),
1021                    }
1022                }
1023                crate::TypeInner::Struct {
1024                    ref members,
1025                    span: _,
1026                } => {
1027                    let mut has_runtime_array = false;
1028                    let mut member_ids = Vec::with_capacity(members.len());
1029                    for (index, member) in members.iter().enumerate() {
1030                        let member_ty = &arena[member.ty];
1031                        match member_ty.inner {
1032                            crate::TypeInner::Array {
1033                                base: _,
1034                                size: crate::ArraySize::Dynamic,
1035                                stride: _,
1036                            } => {
1037                                has_runtime_array = true;
1038                            }
1039                            _ => (),
1040                        }
1041                        self.decorate_struct_member(id, index, member, arena)?;
1042                        let member_id = self.get_type_id(LookupType::Handle(member.ty));
1043                        member_ids.push(member_id);
1044                    }
1045                    if has_runtime_array {
1046                        self.decorate(id, Decoration::Block, &[]);
1047                    }
1048                    Instruction::type_struct(id, member_ids.as_slice())
1049                }
1050
1051                // These all have TypeLocal representations, so they should have been
1052                // handled by `write_type_declaration_local` above.
1053                crate::TypeInner::Scalar(_)
1054                | crate::TypeInner::Atomic(_)
1055                | crate::TypeInner::Vector { .. }
1056                | crate::TypeInner::Matrix { .. }
1057                | crate::TypeInner::Pointer { .. }
1058                | crate::TypeInner::ValuePointer { .. }
1059                | crate::TypeInner::Image { .. }
1060                | crate::TypeInner::Sampler { .. }
1061                | crate::TypeInner::AccelerationStructure
1062                | crate::TypeInner::RayQuery => unreachable!(),
1063            };
1064
1065            instruction.to_words(&mut self.logical_layout.declarations);
1066            id
1067        };
1068
1069        // Add this handle as a new alias for that type.
1070        self.lookup_type.insert(LookupType::Handle(handle), id);
1071
1072        if self.flags.contains(WriterFlags::DEBUG) {
1073            if let Some(ref name) = ty.name {
1074                self.debugs.push(Instruction::name(id, name));
1075            }
1076        }
1077
1078        Ok(id)
1079    }
1080
1081    fn request_image_format_capabilities(
1082        &mut self,
1083        format: spirv::ImageFormat,
1084    ) -> Result<(), Error> {
1085        use spirv::ImageFormat as If;
1086        match format {
1087            If::Rg32f
1088            | If::Rg16f
1089            | If::R11fG11fB10f
1090            | If::R16f
1091            | If::Rgba16
1092            | If::Rgb10A2
1093            | If::Rg16
1094            | If::Rg8
1095            | If::R16
1096            | If::R8
1097            | If::Rgba16Snorm
1098            | If::Rg16Snorm
1099            | If::Rg8Snorm
1100            | If::R16Snorm
1101            | If::R8Snorm
1102            | If::Rg32i
1103            | If::Rg16i
1104            | If::Rg8i
1105            | If::R16i
1106            | If::R8i
1107            | If::Rgb10a2ui
1108            | If::Rg32ui
1109            | If::Rg16ui
1110            | If::Rg8ui
1111            | If::R16ui
1112            | If::R8ui => self.require_any(
1113                "storage image format",
1114                &[spirv::Capability::StorageImageExtendedFormats],
1115            ),
1116            If::R64ui | If::R64i => self.require_any(
1117                "64-bit integer storage image format",
1118                &[spirv::Capability::Int64ImageEXT],
1119            ),
1120            If::Unknown
1121            | If::Rgba32f
1122            | If::Rgba16f
1123            | If::R32f
1124            | If::Rgba8
1125            | If::Rgba8Snorm
1126            | If::Rgba32i
1127            | If::Rgba16i
1128            | If::Rgba8i
1129            | If::R32i
1130            | If::Rgba32ui
1131            | If::Rgba16ui
1132            | If::Rgba8ui
1133            | If::R32ui => Ok(()),
1134        }
1135    }
1136
1137    pub(super) fn get_index_constant(&mut self, index: Word) -> Word {
1138        self.get_constant_scalar(crate::Literal::U32(index))
1139    }
1140
1141    pub(super) fn get_constant_scalar_with(
1142        &mut self,
1143        value: u8,
1144        scalar: crate::Scalar,
1145    ) -> Result<Word, Error> {
1146        Ok(
1147            self.get_constant_scalar(crate::Literal::new(value, scalar).ok_or(
1148                Error::Validation("Unexpected kind and/or width for Literal"),
1149            )?),
1150        )
1151    }
1152
1153    pub(super) fn get_constant_scalar(&mut self, value: crate::Literal) -> Word {
1154        let scalar = CachedConstant::Literal(value.into());
1155        if let Some(&id) = self.cached_constants.get(&scalar) {
1156            return id;
1157        }
1158        let id = self.id_gen.next();
1159        self.write_constant_scalar(id, &value, None);
1160        self.cached_constants.insert(scalar, id);
1161        id
1162    }
1163
1164    fn write_constant_scalar(
1165        &mut self,
1166        id: Word,
1167        value: &crate::Literal,
1168        debug_name: Option<&String>,
1169    ) {
1170        if self.flags.contains(WriterFlags::DEBUG) {
1171            if let Some(name) = debug_name {
1172                self.debugs.push(Instruction::name(id, name));
1173            }
1174        }
1175        let type_id = self.get_type_id(LookupType::Local(LocalType::Value {
1176            vector_size: None,
1177            scalar: value.scalar(),
1178            pointer_space: None,
1179        }));
1180        let instruction = match *value {
1181            crate::Literal::F64(value) => {
1182                let bits = value.to_bits();
1183                Instruction::constant_64bit(type_id, id, bits as u32, (bits >> 32) as u32)
1184            }
1185            crate::Literal::F32(value) => Instruction::constant_32bit(type_id, id, value.to_bits()),
1186            crate::Literal::U32(value) => Instruction::constant_32bit(type_id, id, value),
1187            crate::Literal::I32(value) => Instruction::constant_32bit(type_id, id, value as u32),
1188            crate::Literal::U64(value) => {
1189                Instruction::constant_64bit(type_id, id, value as u32, (value >> 32) as u32)
1190            }
1191            crate::Literal::I64(value) => {
1192                Instruction::constant_64bit(type_id, id, value as u32, (value >> 32) as u32)
1193            }
1194            crate::Literal::Bool(true) => Instruction::constant_true(type_id, id),
1195            crate::Literal::Bool(false) => Instruction::constant_false(type_id, id),
1196            crate::Literal::AbstractInt(_) | crate::Literal::AbstractFloat(_) => {
1197                unreachable!("Abstract types should not appear in IR presented to backends");
1198            }
1199        };
1200
1201        instruction.to_words(&mut self.logical_layout.declarations);
1202    }
1203
1204    pub(super) fn get_constant_composite(
1205        &mut self,
1206        ty: LookupType,
1207        constituent_ids: &[Word],
1208    ) -> Word {
1209        let composite = CachedConstant::Composite {
1210            ty,
1211            constituent_ids: constituent_ids.to_vec(),
1212        };
1213        if let Some(&id) = self.cached_constants.get(&composite) {
1214            return id;
1215        }
1216        let id = self.id_gen.next();
1217        self.write_constant_composite(id, ty, constituent_ids, None);
1218        self.cached_constants.insert(composite, id);
1219        id
1220    }
1221
1222    fn write_constant_composite(
1223        &mut self,
1224        id: Word,
1225        ty: LookupType,
1226        constituent_ids: &[Word],
1227        debug_name: Option<&String>,
1228    ) {
1229        if self.flags.contains(WriterFlags::DEBUG) {
1230            if let Some(name) = debug_name {
1231                self.debugs.push(Instruction::name(id, name));
1232            }
1233        }
1234        let type_id = self.get_type_id(ty);
1235        Instruction::constant_composite(type_id, id, constituent_ids)
1236            .to_words(&mut self.logical_layout.declarations);
1237    }
1238
1239    pub(super) fn get_constant_null(&mut self, type_id: Word) -> Word {
1240        let null = CachedConstant::ZeroValue(type_id);
1241        if let Some(&id) = self.cached_constants.get(&null) {
1242            return id;
1243        }
1244        let id = self.write_constant_null(type_id);
1245        self.cached_constants.insert(null, id);
1246        id
1247    }
1248
1249    pub(super) fn write_constant_null(&mut self, type_id: Word) -> Word {
1250        let null_id = self.id_gen.next();
1251        Instruction::constant_null(type_id, null_id)
1252            .to_words(&mut self.logical_layout.declarations);
1253        null_id
1254    }
1255
1256    fn write_constant_expr(
1257        &mut self,
1258        handle: Handle<crate::Expression>,
1259        ir_module: &crate::Module,
1260        mod_info: &ModuleInfo,
1261    ) -> Result<Word, Error> {
1262        let id = match ir_module.global_expressions[handle] {
1263            crate::Expression::Literal(literal) => self.get_constant_scalar(literal),
1264            crate::Expression::Constant(constant) => {
1265                let constant = &ir_module.constants[constant];
1266                self.constant_ids[constant.init.index()]
1267            }
1268            crate::Expression::ZeroValue(ty) => {
1269                let type_id = self.get_type_id(LookupType::Handle(ty));
1270                self.get_constant_null(type_id)
1271            }
1272            crate::Expression::Compose { ty, ref components } => {
1273                let component_ids: Vec<_> = crate::proc::flatten_compose(
1274                    ty,
1275                    components,
1276                    &ir_module.global_expressions,
1277                    &ir_module.types,
1278                )
1279                .map(|component| self.constant_ids[component.index()])
1280                .collect();
1281                self.get_constant_composite(LookupType::Handle(ty), component_ids.as_slice())
1282            }
1283            crate::Expression::Splat { size, value } => {
1284                let value_id = self.constant_ids[value.index()];
1285                let component_ids = &[value_id; 4][..size as usize];
1286
1287                let ty = self.get_expression_lookup_type(&mod_info[handle]);
1288
1289                self.get_constant_composite(ty, component_ids)
1290            }
1291            _ => unreachable!(),
1292        };
1293
1294        self.constant_ids[handle.index()] = id;
1295
1296        Ok(id)
1297    }
1298
1299    pub(super) fn write_barrier(&mut self, flags: crate::Barrier, block: &mut Block) {
1300        let memory_scope = if flags.contains(crate::Barrier::STORAGE) {
1301            spirv::Scope::Device
1302        } else {
1303            spirv::Scope::Workgroup
1304        };
1305        let mut semantics = spirv::MemorySemantics::ACQUIRE_RELEASE;
1306        semantics.set(
1307            spirv::MemorySemantics::UNIFORM_MEMORY,
1308            flags.contains(crate::Barrier::STORAGE),
1309        );
1310        semantics.set(
1311            spirv::MemorySemantics::WORKGROUP_MEMORY,
1312            flags.contains(crate::Barrier::WORK_GROUP),
1313        );
1314        let exec_scope_id = if flags.contains(crate::Barrier::SUB_GROUP) {
1315            self.get_index_constant(spirv::Scope::Subgroup as u32)
1316        } else {
1317            self.get_index_constant(spirv::Scope::Workgroup as u32)
1318        };
1319        let mem_scope_id = self.get_index_constant(memory_scope as u32);
1320        let semantics_id = self.get_index_constant(semantics.bits());
1321        block.body.push(Instruction::control_barrier(
1322            exec_scope_id,
1323            mem_scope_id,
1324            semantics_id,
1325        ));
1326    }
1327
1328    fn generate_workgroup_vars_init_block(
1329        &mut self,
1330        entry_id: Word,
1331        ir_module: &crate::Module,
1332        info: &FunctionInfo,
1333        local_invocation_id: Option<Word>,
1334        interface: &mut FunctionInterface,
1335        function: &mut Function,
1336    ) -> Option<Word> {
1337        let body = ir_module
1338            .global_variables
1339            .iter()
1340            .filter(|&(handle, var)| {
1341                !info[handle].is_empty() && var.space == crate::AddressSpace::WorkGroup
1342            })
1343            .map(|(handle, var)| {
1344                // It's safe to use `var_id` here, not `access_id`, because only
1345                // variables in the `Uniform` and `StorageBuffer` address spaces
1346                // get wrapped, and we're initializing `WorkGroup` variables.
1347                let var_id = self.global_variables[handle.index()].var_id;
1348                let var_type_id = self.get_type_id(LookupType::Handle(var.ty));
1349                let init_word = self.get_constant_null(var_type_id);
1350                Instruction::store(var_id, init_word, None)
1351            })
1352            .collect::<Vec<_>>();
1353
1354        if body.is_empty() {
1355            return None;
1356        }
1357
1358        let uint3_type_id = self.get_uint3_type_id();
1359
1360        let mut pre_if_block = Block::new(entry_id);
1361
1362        let local_invocation_id = if let Some(local_invocation_id) = local_invocation_id {
1363            local_invocation_id
1364        } else {
1365            let varying_id = self.id_gen.next();
1366            let class = spirv::StorageClass::Input;
1367            let pointer_type_id = self.get_uint3_pointer_type_id(class);
1368
1369            Instruction::variable(pointer_type_id, varying_id, class, None)
1370                .to_words(&mut self.logical_layout.declarations);
1371
1372            self.decorate(
1373                varying_id,
1374                spirv::Decoration::BuiltIn,
1375                &[spirv::BuiltIn::LocalInvocationId as u32],
1376            );
1377
1378            interface.varying_ids.push(varying_id);
1379            let id = self.id_gen.next();
1380            pre_if_block
1381                .body
1382                .push(Instruction::load(uint3_type_id, id, varying_id, None));
1383
1384            id
1385        };
1386
1387        let zero_id = self.get_constant_null(uint3_type_id);
1388        let bool3_type_id = self.get_bool3_type_id();
1389
1390        let eq_id = self.id_gen.next();
1391        pre_if_block.body.push(Instruction::binary(
1392            spirv::Op::IEqual,
1393            bool3_type_id,
1394            eq_id,
1395            local_invocation_id,
1396            zero_id,
1397        ));
1398
1399        let condition_id = self.id_gen.next();
1400        let bool_type_id = self.get_bool_type_id();
1401        pre_if_block.body.push(Instruction::relational(
1402            spirv::Op::All,
1403            bool_type_id,
1404            condition_id,
1405            eq_id,
1406        ));
1407
1408        let merge_id = self.id_gen.next();
1409        pre_if_block.body.push(Instruction::selection_merge(
1410            merge_id,
1411            spirv::SelectionControl::NONE,
1412        ));
1413
1414        let accept_id = self.id_gen.next();
1415        function.consume(
1416            pre_if_block,
1417            Instruction::branch_conditional(condition_id, accept_id, merge_id),
1418        );
1419
1420        let accept_block = Block {
1421            label_id: accept_id,
1422            body,
1423        };
1424        function.consume(accept_block, Instruction::branch(merge_id));
1425
1426        let mut post_if_block = Block::new(merge_id);
1427
1428        self.write_barrier(crate::Barrier::WORK_GROUP, &mut post_if_block);
1429
1430        let next_id = self.id_gen.next();
1431        function.consume(post_if_block, Instruction::branch(next_id));
1432        Some(next_id)
1433    }
1434
1435    /// Generate an `OpVariable` for one value in an [`EntryPoint`]'s IO interface.
1436    ///
1437    /// The [`Binding`]s of the arguments and result of an [`EntryPoint`]'s
1438    /// [`Function`] describe a SPIR-V shader interface. In SPIR-V, the
1439    /// interface is represented by global variables in the `Input` and `Output`
1440    /// storage classes, with decorations indicating which builtin or location
1441    /// each variable corresponds to.
1442    ///
1443    /// This function emits a single global `OpVariable` for a single value from
1444    /// the interface, and adds appropriate decorations to indicate which
1445    /// builtin or location it represents, how it should be interpolated, and so
1446    /// on. The `class` argument gives the variable's SPIR-V storage class,
1447    /// which should be either [`Input`] or [`Output`].
1448    ///
1449    /// [`Binding`]: crate::Binding
1450    /// [`Function`]: crate::Function
1451    /// [`EntryPoint`]: crate::EntryPoint
1452    /// [`Input`]: spirv::StorageClass::Input
1453    /// [`Output`]: spirv::StorageClass::Output
1454    fn write_varying(
1455        &mut self,
1456        ir_module: &crate::Module,
1457        stage: crate::ShaderStage,
1458        class: spirv::StorageClass,
1459        debug_name: Option<&str>,
1460        ty: Handle<crate::Type>,
1461        binding: &crate::Binding,
1462    ) -> Result<Word, Error> {
1463        let id = self.id_gen.next();
1464        let pointer_type_id = self.get_pointer_id(&ir_module.types, ty, class)?;
1465        Instruction::variable(pointer_type_id, id, class, None)
1466            .to_words(&mut self.logical_layout.declarations);
1467
1468        if self
1469            .flags
1470            .contains(WriterFlags::DEBUG | WriterFlags::LABEL_VARYINGS)
1471        {
1472            if let Some(name) = debug_name {
1473                self.debugs.push(Instruction::name(id, name));
1474            }
1475        }
1476
1477        use spirv::{BuiltIn, Decoration};
1478
1479        match *binding {
1480            crate::Binding::Location {
1481                location,
1482                interpolation,
1483                sampling,
1484                second_blend_source,
1485            } => {
1486                self.decorate(id, Decoration::Location, &[location]);
1487
1488                let no_decorations =
1489                    // VUID-StandaloneSpirv-Flat-06202
1490                    // > The Flat, NoPerspective, Sample, and Centroid decorations
1491                    // > must not be used on variables with the Input storage class in a vertex shader
1492                    (class == spirv::StorageClass::Input && stage == crate::ShaderStage::Vertex) ||
1493                    // VUID-StandaloneSpirv-Flat-06201
1494                    // > The Flat, NoPerspective, Sample, and Centroid decorations
1495                    // > must not be used on variables with the Output storage class in a fragment shader
1496                    (class == spirv::StorageClass::Output && stage == crate::ShaderStage::Fragment);
1497
1498                if !no_decorations {
1499                    match interpolation {
1500                        // Perspective-correct interpolation is the default in SPIR-V.
1501                        None | Some(crate::Interpolation::Perspective) => (),
1502                        Some(crate::Interpolation::Flat) => {
1503                            self.decorate(id, Decoration::Flat, &[]);
1504                        }
1505                        Some(crate::Interpolation::Linear) => {
1506                            self.decorate(id, Decoration::NoPerspective, &[]);
1507                        }
1508                    }
1509                    match sampling {
1510                        // Center sampling is the default in SPIR-V.
1511                        None | Some(crate::Sampling::Center) => (),
1512                        Some(crate::Sampling::Centroid) => {
1513                            self.decorate(id, Decoration::Centroid, &[]);
1514                        }
1515                        Some(crate::Sampling::Sample) => {
1516                            self.require_any(
1517                                "per-sample interpolation",
1518                                &[spirv::Capability::SampleRateShading],
1519                            )?;
1520                            self.decorate(id, Decoration::Sample, &[]);
1521                        }
1522                    }
1523                }
1524                if second_blend_source {
1525                    self.decorate(id, Decoration::Index, &[1]);
1526                }
1527            }
1528            crate::Binding::BuiltIn(built_in) => {
1529                use crate::BuiltIn as Bi;
1530                let built_in = match built_in {
1531                    Bi::Position { invariant } => {
1532                        if invariant {
1533                            self.decorate(id, Decoration::Invariant, &[]);
1534                        }
1535
1536                        if class == spirv::StorageClass::Output {
1537                            BuiltIn::Position
1538                        } else {
1539                            BuiltIn::FragCoord
1540                        }
1541                    }
1542                    Bi::ViewIndex => {
1543                        self.require_any("`view_index` built-in", &[spirv::Capability::MultiView])?;
1544                        BuiltIn::ViewIndex
1545                    }
1546                    // vertex
1547                    Bi::BaseInstance => BuiltIn::BaseInstance,
1548                    Bi::BaseVertex => BuiltIn::BaseVertex,
1549                    Bi::ClipDistance => {
1550                        self.require_any(
1551                            "`clip_distance` built-in",
1552                            &[spirv::Capability::ClipDistance],
1553                        )?;
1554                        BuiltIn::ClipDistance
1555                    }
1556                    Bi::CullDistance => {
1557                        self.require_any(
1558                            "`cull_distance` built-in",
1559                            &[spirv::Capability::CullDistance],
1560                        )?;
1561                        BuiltIn::CullDistance
1562                    }
1563                    Bi::InstanceIndex => BuiltIn::InstanceIndex,
1564                    Bi::PointSize => BuiltIn::PointSize,
1565                    Bi::VertexIndex => BuiltIn::VertexIndex,
1566                    // fragment
1567                    Bi::FragDepth => BuiltIn::FragDepth,
1568                    Bi::PointCoord => BuiltIn::PointCoord,
1569                    Bi::FrontFacing => BuiltIn::FrontFacing,
1570                    Bi::PrimitiveIndex => {
1571                        self.require_any(
1572                            "`primitive_index` built-in",
1573                            &[spirv::Capability::Geometry],
1574                        )?;
1575                        BuiltIn::PrimitiveId
1576                    }
1577                    Bi::SampleIndex => {
1578                        self.require_any(
1579                            "`sample_index` built-in",
1580                            &[spirv::Capability::SampleRateShading],
1581                        )?;
1582
1583                        BuiltIn::SampleId
1584                    }
1585                    Bi::SampleMask => BuiltIn::SampleMask,
1586                    // compute
1587                    Bi::GlobalInvocationId => BuiltIn::GlobalInvocationId,
1588                    Bi::LocalInvocationId => BuiltIn::LocalInvocationId,
1589                    Bi::LocalInvocationIndex => BuiltIn::LocalInvocationIndex,
1590                    Bi::WorkGroupId => BuiltIn::WorkgroupId,
1591                    Bi::WorkGroupSize => BuiltIn::WorkgroupSize,
1592                    Bi::NumWorkGroups => BuiltIn::NumWorkgroups,
1593                    // Subgroup
1594                    Bi::NumSubgroups => {
1595                        self.require_any(
1596                            "`num_subgroups` built-in",
1597                            &[spirv::Capability::GroupNonUniform],
1598                        )?;
1599                        BuiltIn::NumSubgroups
1600                    }
1601                    Bi::SubgroupId => {
1602                        self.require_any(
1603                            "`subgroup_id` built-in",
1604                            &[spirv::Capability::GroupNonUniform],
1605                        )?;
1606                        BuiltIn::SubgroupId
1607                    }
1608                    Bi::SubgroupSize => {
1609                        self.require_any(
1610                            "`subgroup_size` built-in",
1611                            &[
1612                                spirv::Capability::GroupNonUniform,
1613                                spirv::Capability::SubgroupBallotKHR,
1614                            ],
1615                        )?;
1616                        BuiltIn::SubgroupSize
1617                    }
1618                    Bi::SubgroupInvocationId => {
1619                        self.require_any(
1620                            "`subgroup_invocation_id` built-in",
1621                            &[
1622                                spirv::Capability::GroupNonUniform,
1623                                spirv::Capability::SubgroupBallotKHR,
1624                            ],
1625                        )?;
1626                        BuiltIn::SubgroupLocalInvocationId
1627                    }
1628                };
1629
1630                self.decorate(id, Decoration::BuiltIn, &[built_in as u32]);
1631
1632                use crate::ScalarKind as Sk;
1633
1634                // Per the Vulkan spec, `VUID-StandaloneSpirv-Flat-04744`:
1635                //
1636                // > Any variable with integer or double-precision floating-
1637                // > point type and with Input storage class in a fragment
1638                // > shader, must be decorated Flat
1639                if class == spirv::StorageClass::Input && stage == crate::ShaderStage::Fragment {
1640                    let is_flat = match ir_module.types[ty].inner {
1641                        crate::TypeInner::Scalar(scalar)
1642                        | crate::TypeInner::Vector { scalar, .. } => match scalar.kind {
1643                            Sk::Uint | Sk::Sint | Sk::Bool => true,
1644                            Sk::Float => false,
1645                            Sk::AbstractInt | Sk::AbstractFloat => {
1646                                return Err(Error::Validation(
1647                                    "Abstract types should not appear in IR presented to backends",
1648                                ))
1649                            }
1650                        },
1651                        _ => false,
1652                    };
1653
1654                    if is_flat {
1655                        self.decorate(id, Decoration::Flat, &[]);
1656                    }
1657                }
1658            }
1659        }
1660
1661        Ok(id)
1662    }
1663
1664    fn write_global_variable(
1665        &mut self,
1666        ir_module: &crate::Module,
1667        global_variable: &crate::GlobalVariable,
1668    ) -> Result<Word, Error> {
1669        use spirv::Decoration;
1670
1671        let id = self.id_gen.next();
1672        let class = map_storage_class(global_variable.space);
1673
1674        //self.check(class.required_capabilities())?;
1675
1676        if self.flags.contains(WriterFlags::DEBUG) {
1677            if let Some(ref name) = global_variable.name {
1678                self.debugs.push(Instruction::name(id, name));
1679            }
1680        }
1681
1682        let storage_access = match global_variable.space {
1683            crate::AddressSpace::Storage { access } => Some(access),
1684            _ => match ir_module.types[global_variable.ty].inner {
1685                crate::TypeInner::Image {
1686                    class: crate::ImageClass::Storage { access, .. },
1687                    ..
1688                } => Some(access),
1689                _ => None,
1690            },
1691        };
1692        if let Some(storage_access) = storage_access {
1693            if !storage_access.contains(crate::StorageAccess::LOAD) {
1694                self.decorate(id, Decoration::NonReadable, &[]);
1695            }
1696            if !storage_access.contains(crate::StorageAccess::STORE) {
1697                self.decorate(id, Decoration::NonWritable, &[]);
1698            }
1699        }
1700
1701        // Note: we should be able to substitute `binding_array<Foo, 0>`,
1702        // but there is still code that tries to register the pre-substituted type,
1703        // and it is failing on 0.
1704        let mut substitute_inner_type_lookup = None;
1705        if let Some(ref res_binding) = global_variable.binding {
1706            self.decorate(id, Decoration::DescriptorSet, &[res_binding.group]);
1707            self.decorate(id, Decoration::Binding, &[res_binding.binding]);
1708
1709            if let Some(&BindingInfo {
1710                binding_array_size: Some(remapped_binding_array_size),
1711            }) = self.binding_map.get(res_binding)
1712            {
1713                if let crate::TypeInner::BindingArray { base, .. } =
1714                    ir_module.types[global_variable.ty].inner
1715                {
1716                    substitute_inner_type_lookup =
1717                        Some(LookupType::Local(LocalType::PointerToBindingArray {
1718                            base,
1719                            size: remapped_binding_array_size,
1720                            space: global_variable.space,
1721                        }))
1722                }
1723            }
1724        };
1725
1726        let init_word = global_variable
1727            .init
1728            .map(|constant| self.constant_ids[constant.index()]);
1729        let inner_type_id = self.get_type_id(
1730            substitute_inner_type_lookup.unwrap_or(LookupType::Handle(global_variable.ty)),
1731        );
1732
1733        // generate the wrapping structure if needed
1734        let pointer_type_id = if global_needs_wrapper(ir_module, global_variable) {
1735            let wrapper_type_id = self.id_gen.next();
1736
1737            self.decorate(wrapper_type_id, Decoration::Block, &[]);
1738            let member = crate::StructMember {
1739                name: None,
1740                ty: global_variable.ty,
1741                binding: None,
1742                offset: 0,
1743            };
1744            self.decorate_struct_member(wrapper_type_id, 0, &member, &ir_module.types)?;
1745
1746            Instruction::type_struct(wrapper_type_id, &[inner_type_id])
1747                .to_words(&mut self.logical_layout.declarations);
1748
1749            let pointer_type_id = self.id_gen.next();
1750            Instruction::type_pointer(pointer_type_id, class, wrapper_type_id)
1751                .to_words(&mut self.logical_layout.declarations);
1752
1753            pointer_type_id
1754        } else {
1755            // This is a global variable in the Storage address space. The only
1756            // way it could have `global_needs_wrapper() == false` is if it has
1757            // a runtime-sized or binding array.
1758            // Runtime-sized arrays were decorated when iterating through struct content.
1759            // Now binding arrays require Block decorating.
1760            if let crate::AddressSpace::Storage { .. } = global_variable.space {
1761                match ir_module.types[global_variable.ty].inner {
1762                    crate::TypeInner::BindingArray { base, .. } => {
1763                        let decorated_id = self.get_type_id(LookupType::Handle(base));
1764                        self.decorate(decorated_id, Decoration::Block, &[]);
1765                    }
1766                    _ => (),
1767                };
1768            }
1769            if substitute_inner_type_lookup.is_some() {
1770                inner_type_id
1771            } else {
1772                self.get_pointer_id(&ir_module.types, global_variable.ty, class)?
1773            }
1774        };
1775
1776        let init_word = match (global_variable.space, self.zero_initialize_workgroup_memory) {
1777            (crate::AddressSpace::Private, _)
1778            | (crate::AddressSpace::WorkGroup, super::ZeroInitializeWorkgroupMemoryMode::Native) => {
1779                init_word.or_else(|| Some(self.get_constant_null(inner_type_id)))
1780            }
1781            _ => init_word,
1782        };
1783
1784        Instruction::variable(pointer_type_id, id, class, init_word)
1785            .to_words(&mut self.logical_layout.declarations);
1786        Ok(id)
1787    }
1788
1789    /// Write the necessary decorations for a struct member.
1790    ///
1791    /// Emit decorations for the `index`'th member of the struct type
1792    /// designated by `struct_id`, described by `member`.
1793    fn decorate_struct_member(
1794        &mut self,
1795        struct_id: Word,
1796        index: usize,
1797        member: &crate::StructMember,
1798        arena: &UniqueArena<crate::Type>,
1799    ) -> Result<(), Error> {
1800        use spirv::Decoration;
1801
1802        self.annotations.push(Instruction::member_decorate(
1803            struct_id,
1804            index as u32,
1805            Decoration::Offset,
1806            &[member.offset],
1807        ));
1808
1809        if self.flags.contains(WriterFlags::DEBUG) {
1810            if let Some(ref name) = member.name {
1811                self.debugs
1812                    .push(Instruction::member_name(struct_id, index as u32, name));
1813            }
1814        }
1815
1816        // Matrices and arrays of matrices both require decorations,
1817        // so "see through" an array to determine if they're needed.
1818        let member_array_subty_inner = match arena[member.ty].inner {
1819            crate::TypeInner::Array { base, .. } => &arena[base].inner,
1820            ref other => other,
1821        };
1822        if let crate::TypeInner::Matrix {
1823            columns: _,
1824            rows,
1825            scalar,
1826        } = *member_array_subty_inner
1827        {
1828            let byte_stride = Alignment::from(rows) * scalar.width as u32;
1829            self.annotations.push(Instruction::member_decorate(
1830                struct_id,
1831                index as u32,
1832                Decoration::ColMajor,
1833                &[],
1834            ));
1835            self.annotations.push(Instruction::member_decorate(
1836                struct_id,
1837                index as u32,
1838                Decoration::MatrixStride,
1839                &[byte_stride],
1840            ));
1841        }
1842
1843        Ok(())
1844    }
1845
1846    fn get_function_type(&mut self, lookup_function_type: LookupFunctionType) -> Word {
1847        match self
1848            .lookup_function_type
1849            .entry(lookup_function_type.clone())
1850        {
1851            Entry::Occupied(e) => *e.get(),
1852            Entry::Vacant(_) => {
1853                let id = self.id_gen.next();
1854                let instruction = Instruction::type_function(
1855                    id,
1856                    lookup_function_type.return_type_id,
1857                    &lookup_function_type.parameter_type_ids,
1858                );
1859                instruction.to_words(&mut self.logical_layout.declarations);
1860                self.lookup_function_type.insert(lookup_function_type, id);
1861                id
1862            }
1863        }
1864    }
1865
1866    fn write_physical_layout(&mut self) {
1867        self.physical_layout.bound = self.id_gen.0 + 1;
1868    }
1869
1870    fn write_logical_layout(
1871        &mut self,
1872        ir_module: &crate::Module,
1873        mod_info: &ModuleInfo,
1874        ep_index: Option<usize>,
1875        debug_info: &Option<DebugInfo>,
1876    ) -> Result<(), Error> {
1877        fn has_view_index_check(
1878            ir_module: &crate::Module,
1879            binding: Option<&crate::Binding>,
1880            ty: Handle<crate::Type>,
1881        ) -> bool {
1882            match ir_module.types[ty].inner {
1883                crate::TypeInner::Struct { ref members, .. } => members.iter().any(|member| {
1884                    has_view_index_check(ir_module, member.binding.as_ref(), member.ty)
1885                }),
1886                _ => binding == Some(&crate::Binding::BuiltIn(crate::BuiltIn::ViewIndex)),
1887            }
1888        }
1889
1890        let has_storage_buffers =
1891            ir_module
1892                .global_variables
1893                .iter()
1894                .any(|(_, var)| match var.space {
1895                    crate::AddressSpace::Storage { .. } => true,
1896                    _ => false,
1897                });
1898        let has_view_index = ir_module
1899            .entry_points
1900            .iter()
1901            .flat_map(|entry| entry.function.arguments.iter())
1902            .any(|arg| has_view_index_check(ir_module, arg.binding.as_ref(), arg.ty));
1903        let mut has_ray_query = ir_module.special_types.ray_desc.is_some()
1904            | ir_module.special_types.ray_intersection.is_some();
1905
1906        for (_, &crate::Type { ref inner, .. }) in ir_module.types.iter() {
1907            if let &crate::TypeInner::AccelerationStructure | &crate::TypeInner::RayQuery = inner {
1908                has_ray_query = true
1909            }
1910        }
1911
1912        if self.physical_layout.version < 0x10300 && has_storage_buffers {
1913            // enable the storage buffer class on < SPV-1.3
1914            Instruction::extension("SPV_KHR_storage_buffer_storage_class")
1915                .to_words(&mut self.logical_layout.extensions);
1916        }
1917        if has_view_index {
1918            Instruction::extension("SPV_KHR_multiview")
1919                .to_words(&mut self.logical_layout.extensions)
1920        }
1921        if has_ray_query {
1922            Instruction::extension("SPV_KHR_ray_query")
1923                .to_words(&mut self.logical_layout.extensions)
1924        }
1925        Instruction::type_void(self.void_type).to_words(&mut self.logical_layout.declarations);
1926        Instruction::ext_inst_import(self.gl450_ext_inst_id, "GLSL.std.450")
1927            .to_words(&mut self.logical_layout.ext_inst_imports);
1928
1929        let mut debug_info_inner = None;
1930        if self.flags.contains(WriterFlags::DEBUG) {
1931            if let Some(debug_info) = debug_info.as_ref() {
1932                let source_file_id = self.id_gen.next();
1933                self.debugs.push(Instruction::string(
1934                    &debug_info.file_name.display().to_string(),
1935                    source_file_id,
1936                ));
1937
1938                debug_info_inner = Some(DebugInfoInner {
1939                    source_code: debug_info.source_code,
1940                    source_file_id,
1941                });
1942                self.debugs.append(&mut Instruction::source_auto_continued(
1943                    spirv::SourceLanguage::Unknown,
1944                    0,
1945                    &debug_info_inner,
1946                ));
1947            }
1948        }
1949
1950        // write all types
1951        for (handle, _) in ir_module.types.iter() {
1952            self.write_type_declaration_arena(&ir_module.types, handle)?;
1953        }
1954
1955        // write all const-expressions as constants
1956        self.constant_ids
1957            .resize(ir_module.global_expressions.len(), 0);
1958        for (handle, _) in ir_module.global_expressions.iter() {
1959            self.write_constant_expr(handle, ir_module, mod_info)?;
1960        }
1961        debug_assert!(self.constant_ids.iter().all(|&id| id != 0));
1962
1963        // write the name of constants on their respective const-expression initializer
1964        if self.flags.contains(WriterFlags::DEBUG) {
1965            for (_, constant) in ir_module.constants.iter() {
1966                if let Some(ref name) = constant.name {
1967                    let id = self.constant_ids[constant.init.index()];
1968                    self.debugs.push(Instruction::name(id, name));
1969                }
1970            }
1971        }
1972
1973        // write all global variables
1974        for (handle, var) in ir_module.global_variables.iter() {
1975            // If a single entry point was specified, only write `OpVariable` instructions
1976            // for the globals it actually uses. Emit dummies for the others,
1977            // to preserve the indices in `global_variables`.
1978            let gvar = match ep_index {
1979                Some(index) if mod_info.get_entry_point(index)[handle].is_empty() => {
1980                    GlobalVariable::dummy()
1981                }
1982                _ => {
1983                    let id = self.write_global_variable(ir_module, var)?;
1984                    GlobalVariable::new(id)
1985                }
1986            };
1987            self.global_variables.push(gvar);
1988        }
1989
1990        // write all functions
1991        for (handle, ir_function) in ir_module.functions.iter() {
1992            let info = &mod_info[handle];
1993            if let Some(index) = ep_index {
1994                let ep_info = mod_info.get_entry_point(index);
1995                // If this function uses globals that we omitted from the SPIR-V
1996                // because the entry point and its callees didn't use them,
1997                // then we must skip it.
1998                if !ep_info.dominates_global_use(info) {
1999                    log::info!("Skip function {:?}", ir_function.name);
2000                    continue;
2001                }
2002
2003                // Skip functions that that are not compatible with this entry point's stage.
2004                //
2005                // When validation is enabled, it rejects modules whose entry points try to call
2006                // incompatible functions, so if we got this far, then any functions incompatible
2007                // with our selected entry point must not be used.
2008                //
2009                // When validation is disabled, `fun_info.available_stages` is always just
2010                // `ShaderStages::all()`, so this will write all functions in the module, and
2011                // the downstream GLSL compiler will catch any problems.
2012                if !info.available_stages.contains(ep_info.available_stages) {
2013                    continue;
2014                }
2015            }
2016            let id = self.write_function(ir_function, info, ir_module, None, &debug_info_inner)?;
2017            self.lookup_function.insert(handle, id);
2018        }
2019
2020        // write all or one entry points
2021        for (index, ir_ep) in ir_module.entry_points.iter().enumerate() {
2022            if ep_index.is_some() && ep_index != Some(index) {
2023                continue;
2024            }
2025            let info = mod_info.get_entry_point(index);
2026            let ep_instruction =
2027                self.write_entry_point(ir_ep, info, ir_module, &debug_info_inner)?;
2028            ep_instruction.to_words(&mut self.logical_layout.entry_points);
2029        }
2030
2031        for capability in self.capabilities_used.iter() {
2032            Instruction::capability(*capability).to_words(&mut self.logical_layout.capabilities);
2033        }
2034        for extension in self.extensions_used.iter() {
2035            Instruction::extension(extension).to_words(&mut self.logical_layout.extensions);
2036        }
2037        if ir_module.entry_points.is_empty() {
2038            // SPIR-V doesn't like modules without entry points
2039            Instruction::capability(spirv::Capability::Linkage)
2040                .to_words(&mut self.logical_layout.capabilities);
2041        }
2042
2043        let addressing_model = spirv::AddressingModel::Logical;
2044        let memory_model = spirv::MemoryModel::GLSL450;
2045        //self.check(addressing_model.required_capabilities())?;
2046        //self.check(memory_model.required_capabilities())?;
2047
2048        Instruction::memory_model(addressing_model, memory_model)
2049            .to_words(&mut self.logical_layout.memory_model);
2050
2051        if self.flags.contains(WriterFlags::DEBUG) {
2052            for debug in self.debugs.iter() {
2053                debug.to_words(&mut self.logical_layout.debugs);
2054            }
2055        }
2056
2057        for annotation in self.annotations.iter() {
2058            annotation.to_words(&mut self.logical_layout.annotations);
2059        }
2060
2061        Ok(())
2062    }
2063
2064    pub fn write(
2065        &mut self,
2066        ir_module: &crate::Module,
2067        info: &ModuleInfo,
2068        pipeline_options: Option<&PipelineOptions>,
2069        debug_info: &Option<DebugInfo>,
2070        words: &mut Vec<Word>,
2071    ) -> Result<(), Error> {
2072        if !ir_module.overrides.is_empty() {
2073            return Err(Error::Override);
2074        }
2075
2076        self.reset();
2077
2078        // Try to find the entry point and corresponding index
2079        let ep_index = match pipeline_options {
2080            Some(po) => {
2081                let index = ir_module
2082                    .entry_points
2083                    .iter()
2084                    .position(|ep| po.shader_stage == ep.stage && po.entry_point == ep.name)
2085                    .ok_or(Error::EntryPointNotFound)?;
2086                Some(index)
2087            }
2088            None => None,
2089        };
2090
2091        self.write_logical_layout(ir_module, info, ep_index, debug_info)?;
2092        self.write_physical_layout();
2093
2094        self.physical_layout.in_words(words);
2095        self.logical_layout.in_words(words);
2096        Ok(())
2097    }
2098
2099    /// Return the set of capabilities the last module written used.
2100    pub const fn get_capabilities_used(&self) -> &crate::FastIndexSet<spirv::Capability> {
2101        &self.capabilities_used
2102    }
2103
2104    pub fn decorate_non_uniform_binding_array_access(&mut self, id: Word) -> Result<(), Error> {
2105        self.require_any("NonUniformEXT", &[spirv::Capability::ShaderNonUniform])?;
2106        self.use_extension("SPV_EXT_descriptor_indexing");
2107        self.decorate(id, spirv::Decoration::NonUniform, &[]);
2108        Ok(())
2109    }
2110}
2111
2112#[test]
2113fn test_write_physical_layout() {
2114    let mut writer = Writer::new(&Options::default()).unwrap();
2115    assert_eq!(writer.physical_layout.bound, 0);
2116    writer.write_physical_layout();
2117    assert_eq!(writer.physical_layout.bound, 3);
2118}