diff --git a/src/back/hlsl/writer.rs b/src/back/hlsl/writer.rs index 0c6ce9bb66..e1325e5abf 100644 --- a/src/back/hlsl/writer.rs +++ b/src/back/hlsl/writer.rs @@ -1835,6 +1835,12 @@ impl<'a, W: fmt::Write> super::Writer<'a, W> { } } + // The new block is not only stylistic, it plays a role here: + // We might end up having to write the same case body + // multiple times due to FXC not supporting fallthrough. + // Therefore, some `Expression`s written by `Statement::Emit` + // will end up having the same name (`_expr`). + // So we need to put each case in its own scope. let write_block_braces = !(case.fall_through && case.body.is_empty()); if write_block_braces { writeln!(self.out, " {{")?; @@ -1842,7 +1848,23 @@ impl<'a, W: fmt::Write> super::Writer<'a, W> { writeln!(self.out)?; } - // FXC doesn't support fallthrough so we duplicate the body of the following case blocks + // Although FXC does support a series of case clauses before + // a block[^yes], it does not support fallthrough from a + // non-empty case block to the next[^no]. If this case has a + // non-empty body with a fallthrough, emulate that by + // duplicating the bodies of all the cases it would fall + // into as extensions of this case's own body. This makes + // the HLSL output potentially quadratic in the size of the + // Naga IR. + // + // [^yes]: ```hlsl + // case 1: + // case 2: do_stuff() + // ``` + // [^no]: ```hlsl + // case 1: do_this(); + // case 2: do_that(); + // ``` if case.fall_through && !case.body.is_empty() { let curr_len = i + 1; let end_case_idx = curr_len diff --git a/src/back/spv/block.rs b/src/back/spv/block.rs index 728af63c26..9bf0b8c895 100644 --- a/src/back/spv/block.rs +++ b/src/back/spv/block.rs @@ -1687,6 +1687,7 @@ impl<'w> BlockContext<'w> { let mut raw_cases = Vec::with_capacity(cases.len()); let mut case_ids = Vec::with_capacity(cases.len()); for case in cases.iter() { + // take id of previous empty fall-through case or generate a new one let label_id = last_id.take().unwrap_or_else(|| self.gen_id()); if case.fall_through && case.body.is_empty() {