diff --git a/render/naga-pixelbender/src/lib.rs b/render/naga-pixelbender/src/lib.rs index bf84f2d47..4f4a9e3cf 100644 --- a/render/naga-pixelbender/src/lib.rs +++ b/render/naga-pixelbender/src/lib.rs @@ -1388,8 +1388,44 @@ impl<'a> ShaderBuilder<'a> { } } } - Operation::Loop { unknown } => { - tracing::warn!("Unimplemented Loop opcode with data: {unknown:?}") + Operation::Select { + src1, + src2, + dst, + condition, + } => { + let src1_expr = self.load_src_register(src1)?; + let src2_expr = self.load_src_register(src2)?; + + let expr_zero: Handle = match condition.kind { + PixelBenderRegKind::Float => self.zerof32, + PixelBenderRegKind::Int => self.zeroi32, + }; + if condition.channels.len() != 1 { + panic!("'Select' condition must be a scalar: {condition:?}"); + } + + // FIXME - `load_src_register` always gives us a vec4 - ideally, we would + // have a flag to avoid this pointless splat-and-extract. + let cond_expr = self.load_src_register(condition)?; + let first_component = self.evaluate_expr(Expression::AccessIndex { + base: cond_expr, + index: 0, + }); + + let is_true = self.evaluate_expr(Expression::Binary { + op: BinaryOperator::NotEqual, + left: first_component, + right: expr_zero, + }); + + let select_expr = self.evaluate_expr(Expression::Select { + condition: is_true, + accept: src1_expr, + reject: src2_expr, + }); + + self.emit_dest_store(select_expr, dst)?; } Operation::Nop => {} } diff --git a/render/src/pixel_bender.rs b/render/src/pixel_bender.rs index e1e402dc0..c415c4dfe 100644 --- a/render/src/pixel_bender.rs +++ b/render/src/pixel_bender.rs @@ -199,7 +199,7 @@ pub enum Opcode { SampleNearest = 0x30, SampleLinear = 0x31, LoadIntOrFloat = 0x32, - Loop = 0x33, + Select = 0x33, If = 0x34, Else = 0x35, EndIf = 0x36, @@ -250,8 +250,11 @@ pub enum Operation { }, Else, EndIf, - Loop { - unknown: Box<[u8]>, + Select { + src1: PixelBenderReg, + src2: PixelBenderReg, + condition: PixelBenderReg, + dst: PixelBenderReg, }, } @@ -585,11 +588,29 @@ fn read_op( _ => unreachable!(), } } - Opcode::Loop => { - let mut unknown = vec![0u8; 23]; - data.read_exact(&mut unknown)?; - shader.operations.push(Operation::Loop { - unknown: unknown.into(), + Opcode::Select => { + let dst = data.read_u16::()?; + let mask = data.read_u8()?; + assert_eq!(mask & 0xF, 0); + let dst_reg = read_dst_reg(dst, mask >> 4)?; + + let condition = read_uint24(data)?; + assert_eq!(data.read_u8()?, 0); + let condition_reg = read_src_reg(condition, 1)?; + + let src1 = read_uint24(data)?; + assert_eq!(data.read_u8()?, 0); + let src_reg1 = read_src_reg(src1, 1)?; + + let src2 = read_uint24(data)?; + assert_eq!(data.read_u8()?, 0); + let src_reg2 = read_src_reg(src2, 1)?; + + shader.operations.push(Operation::Select { + condition: condition_reg, + src1: src_reg1, + src2: src_reg2, + dst: dst_reg, }); } _ => { diff --git a/tests/tests/swfs/avm2/pixelbender_dithering/output.expected.png b/tests/tests/swfs/avm2/pixelbender_dithering/output.expected.png new file mode 100644 index 000000000..77e551a1c Binary files /dev/null and b/tests/tests/swfs/avm2/pixelbender_dithering/output.expected.png differ diff --git a/tests/tests/swfs/avm2/pixelbender_dithering/output.txt b/tests/tests/swfs/avm2/pixelbender_dithering/output.txt new file mode 100644 index 000000000..79b1f9446 --- /dev/null +++ b/tests/tests/swfs/avm2/pixelbender_dithering/output.txt @@ -0,0 +1,8 @@ +Shader metadata: description Value: Ordered Dithering +Shader parameter: matrixHeight Value: 4 +Shader parameter: matrixWidth Value: 4 +Shader metadata: name Value: OrderDithering +Shader metadata: namespace Value: YourNamespace +Shader input: src Value: null +Shader metadata: vendor Value: YourVendor +Shader metadata: version Value: 1 diff --git a/tests/tests/swfs/avm2/pixelbender_dithering/test.swf b/tests/tests/swfs/avm2/pixelbender_dithering/test.swf new file mode 100644 index 000000000..2f29f306a Binary files /dev/null and b/tests/tests/swfs/avm2/pixelbender_dithering/test.swf differ diff --git a/tests/tests/swfs/avm2/pixelbender_dithering/test.toml b/tests/tests/swfs/avm2/pixelbender_dithering/test.toml new file mode 100644 index 000000000..bd83309b2 --- /dev/null +++ b/tests/tests/swfs/avm2/pixelbender_dithering/test.toml @@ -0,0 +1,10 @@ +# Based on https://github.com/FlashBacks1998/Custom-Pixel-Bender-Example-Ordered-Dithering- +# The prints were sorted to avoid relying on object iteration order +num_ticks = 1 + +[image_comparisons.output] +tolerance = 1 +max_outliers = 19813 + +[player_options] +with_renderer = { optional = false, sample_count = 1 }