diff --git a/src/back/spv/writer.rs b/src/back/spv/writer.rs index 91fcada40a..94b7ab2e16 100644 --- a/src/back/spv/writer.rs +++ b/src/back/spv/writer.rs @@ -53,10 +53,15 @@ struct LocalVariable { instruction: Instruction, } -#[derive(Default)] +struct ResultMember { + id: Word, + type_id: Word, + built_in: Option, +} + struct EntryPointContext { argument_ids: Vec, - result_ids_typed: Vec<(Word, Word)>, + results: Vec, } #[derive(Default)] @@ -362,6 +367,24 @@ impl Writer { id } + fn get_index_constant( + &mut self, + index: Word, + types: &Arena, + ) -> Result { + let type_id = self.get_type_id( + types, + LookupType::Local(LocalType::Value { + vector_size: None, + kind: crate::ScalarKind::Sint, + width: 4, + pointer_class: None, + }), + )?; + //TODO: cache this + Ok(self.create_constant(type_id, &[index])) + } + fn write_function( &mut self, ir_function: &crate::Function, @@ -398,7 +421,10 @@ impl Writer { let prelude_id = self.id_gen.next(); let mut prelude = Block::new(prelude_id); - let mut ep_context = EntryPointContext::default(); + let mut ep_context = EntryPointContext { + argument_ids: Vec::new(), + results: Vec::new(), + }; let mut parameter_type_ids = Vec::with_capacity(ir_function.arguments.len()); for argument in ir_function.arguments.iter() { @@ -465,7 +491,11 @@ impl Writer { let varying_id = self.write_varying(ir_module, class, None, result.ty, binding)?; list.push(varying_id); - ep_context.result_ids_typed.push((varying_id, type_id)); + ep_context.results.push(ResultMember { + id: varying_id, + type_id, + built_in: binding.to_built_in(), + }); } else if let crate::TypeInner::Struct { block: _, ref members, @@ -479,7 +509,11 @@ impl Writer { let varying_id = self.write_varying(ir_module, class, name, member.ty, binding)?; list.push(varying_id); - ep_context.result_ids_typed.push((varying_id, type_id)); + ep_context.results.push(ResultMember { + id: varying_id, + type_id, + built_in: binding.to_built_in(), + }); } } else { unreachable!("Missing result binding on an entry point"); @@ -1900,16 +1934,7 @@ impl Writer { base } crate::Expression::AccessIndex { base, index } => { - let const_ty_id = self.get_type_id( - &ir_module.types, - LookupType::Local(LocalType::Value { - vector_size: None, - kind: crate::ScalarKind::Sint, - width: 4, - pointer_class: None, - }), - )?; - let const_id = self.create_constant(const_ty_id, &[index]); + let const_id = self.get_index_constant(index, &ir_module.types)?; self.temp_chain.push(const_id); base } @@ -1958,6 +1983,77 @@ impl Writer { } } + fn write_entry_point_return( + &mut self, + value_id: Word, + ir_result: &crate::FunctionResult, + type_arena: &Arena, + result_members: &[ResultMember], + body: &mut Vec, + ) -> Result<(), Error> { + for (index, res_member) in result_members.iter().enumerate() { + let member_value_id = match ir_result.binding { + Some(_) => value_id, + None => { + let member_value_id = self.id_gen.next(); + body.push(Instruction::composite_extract( + res_member.type_id, + member_value_id, + value_id, + &[index as u32], + )); + member_value_id + } + }; + + body.push(Instruction::store(res_member.id, member_value_id, None)); + + // Flip Y coordinate to adjust for coordinate space difference + // between SPIR-V and our IR. + if res_member.built_in == Some(crate::BuiltIn::Position) { + let access_id = self.id_gen.next(); + let float_ptr_type_id = self.get_type_id( + type_arena, + LookupType::Local(LocalType::Value { + vector_size: None, + kind: crate::ScalarKind::Float, + width: 4, + pointer_class: Some(spirv::StorageClass::Output), + }), + )?; + let index_y_id = self.get_index_constant(1, type_arena)?; + body.push(Instruction::access_chain( + float_ptr_type_id, + access_id, + res_member.id, + &[index_y_id], + )); + + let load_id = self.id_gen.next(); + let float_type_id = self.get_type_id( + type_arena, + LookupType::Local(LocalType::Value { + vector_size: None, + kind: crate::ScalarKind::Float, + width: 4, + pointer_class: None, + }), + )?; + body.push(Instruction::load(float_type_id, load_id, access_id, None)); + + let neg_id = self.id_gen.next(); + body.push(Instruction::unary( + spirv::Op::FNegate, + float_type_id, + neg_id, + load_id, + )); + body.push(Instruction::store(access_id, neg_id, None)); + } + } + Ok(()) + } + //TODO: put most of these into a `BlockContext` structure! #[allow(clippy::too_many_arguments)] fn write_block( @@ -2193,30 +2289,13 @@ impl Writer { // If this is an entry point, and we need to return anything, // let's instead store the output variables and return `void`. Some(ref context) => { - let result = ir_function.result.as_ref().unwrap(); - if result.binding.is_none() { - for (index, &(varying_id, type_id)) in - context.result_ids_typed.iter().enumerate() - { - let member_value_id = self.id_gen.next(); - block.body.push(Instruction::composite_extract( - type_id, - member_value_id, - value_id, - &[index as u32], - )); - block.body.push(Instruction::store( - varying_id, - member_value_id, - None, - )); - } - } else { - let (varying_id, _) = context.result_ids_typed[0]; - block - .body - .push(Instruction::store(varying_id, value_id, None)); - }; + self.write_entry_point_return( + value_id, + ir_function.result.as_ref().unwrap(), + &ir_module.types, + &context.results, + &mut block.body, + )?; Instruction::return_void() } None => Instruction::return_value(value_id), diff --git a/src/proc/mod.rs b/src/proc/mod.rs index c0d1e74a2f..2bb277c703 100644 --- a/src/proc/mod.rs +++ b/src/proc/mod.rs @@ -174,3 +174,12 @@ impl crate::Constant { } } } + +impl crate::Binding { + pub fn to_built_in(&self) -> Option { + match *self { + Self::BuiltIn(bi) => Some(bi), + Self::Location(..) => None, + } + } +} diff --git a/tests/out/quad.spvasm.snap b/tests/out/quad.spvasm.snap index ef0b768a01..f6c3487d20 100644 --- a/tests/out/quad.spvasm.snap +++ b/tests/out/quad.spvasm.snap @@ -5,13 +5,13 @@ expression: dis ; SPIR-V ; Version: 1.0 ; Generator: rspirv -; Bound: 61 +; Bound: 66 OpCapability Shader %1 = OpExtInstImport "GLSL.std.450" OpMemoryModel Logical GLSL450 OpEntryPoint Vertex %28 "main" %19 %22 %24 %26 -OpEntryPoint Fragment %47 "main" %44 %46 -OpExecutionMode %47 OriginUpperLeft +OpEntryPoint Fragment %52 "main" %49 %51 +OpExecutionMode %52 OriginUpperLeft OpSource GLSL 450 OpName %3 "c_scale" OpName %9 "VertexOutput" @@ -26,9 +26,9 @@ OpName %24 "uv" OpName %26 "position" OpName %28 "main" OpName %28 "main" -OpName %44 "uv" -OpName %47 "main" -OpName %47 "main" +OpName %49 "uv" +OpName %52 "main" +OpName %52 "main" OpMemberDecorate %9 0 Offset 0 OpMemberDecorate %9 1 Offset 16 OpDecorate %12 DescriptorSet 0 @@ -39,8 +39,8 @@ OpDecorate %19 Location 0 OpDecorate %22 Location 1 OpDecorate %24 Location 0 OpDecorate %26 BuiltIn Position -OpDecorate %44 Location 0 -OpDecorate %46 Location 0 +OpDecorate %49 Location 0 +OpDecorate %51 Location 0 %2 = OpTypeVoid %4 = OpTypeFloat 32 %3 = OpConstant %4 1.2 @@ -69,10 +69,12 @@ OpDecorate %46 Location 0 %33 = OpConstant %32 0 %35 = OpTypePointer Function %8 %38 = OpConstant %32 1 -%44 = OpVariable %20 Input -%46 = OpVariable %27 Output -%51 = OpTypeSampledImage %10 -%55 = OpTypeBool +%44 = OpTypePointer Output %4 +%45 = OpConstant %32 1 +%49 = OpVariable %20 Input +%51 = OpVariable %27 Output +%56 = OpTypeSampledImage %10 +%60 = OpTypeBool %28 = OpFunction %2 None %29 %18 = OpLabel %16 = OpVariable %17 Function @@ -91,26 +93,30 @@ OpStore %39 %37 OpStore %24 %41 %42 = OpCompositeExtract %8 %40 1 OpStore %26 %42 +%43 = OpAccessChain %44 %26 %45 +%46 = OpLoad %4 %43 +%47 = OpFNegate %4 %46 +OpStore %43 %47 OpReturn OpFunctionEnd -%47 = OpFunction %2 None %29 -%43 = OpLabel -%45 = OpLoad %7 %44 -%48 = OpLoad %10 %12 -%49 = OpLoad %11 %14 -OpBranch %50 -%50 = OpLabel -%52 = OpSampledImage %51 %48 %49 -%53 = OpImageSampleImplicitLod %8 %52 %45 -%54 = OpCompositeExtract %4 %53 3 -%56 = OpFOrdEqual %55 %54 %5 -OpSelectionMerge %57 None -OpBranchConditional %56 %58 %57 -%58 = OpLabel +%52 = OpFunction %2 None %29 +%48 = OpLabel +%50 = OpLoad %7 %49 +%53 = OpLoad %10 %12 +%54 = OpLoad %11 %14 +OpBranch %55 +%55 = OpLabel +%57 = OpSampledImage %56 %53 %54 +%58 = OpImageSampleImplicitLod %8 %57 %50 +%59 = OpCompositeExtract %4 %58 3 +%61 = OpFOrdEqual %60 %59 %5 +OpSelectionMerge %62 None +OpBranchConditional %61 %63 %62 +%63 = OpLabel OpKill -%57 = OpLabel -%59 = OpCompositeExtract %4 %53 3 -%60 = OpVectorTimesScalar %8 %53 %59 -OpStore %46 %60 +%62 = OpLabel +%64 = OpCompositeExtract %4 %58 3 +%65 = OpVectorTimesScalar %8 %58 %64 +OpStore %51 %65 OpReturn OpFunctionEnd diff --git a/tests/out/skybox.spvasm.snap b/tests/out/skybox.spvasm.snap index 112aacac50..c7b1d7d250 100644 --- a/tests/out/skybox.spvasm.snap +++ b/tests/out/skybox.spvasm.snap @@ -5,13 +5,13 @@ expression: dis ; SPIR-V ; Version: 1.0 ; Generator: rspirv -; Bound: 116 +; Bound: 121 OpCapability Shader %1 = OpExtInstImport "GLSL.std.450" OpMemoryModel Logical GLSL450 OpEntryPoint Vertex %38 "vs_main" %31 %34 %36 -OpEntryPoint Fragment %108 "fs_main" %101 %104 %107 -OpExecutionMode %108 OriginUpperLeft +OpEntryPoint Fragment %113 "fs_main" %106 %109 %112 +OpExecutionMode %113 OriginUpperLeft OpSource GLSL 450 OpName %12 "VertexOutput" OpMemberName %12 0 "position" @@ -30,10 +30,10 @@ OpName %34 "position" OpName %36 "uv" OpName %38 "vs_main" OpName %38 "vs_main" -OpName %101 "position" -OpName %104 "uv" -OpName %108 "fs_main" -OpName %108 "fs_main" +OpName %106 "position" +OpName %109 "uv" +OpName %113 "fs_main" +OpName %113 "fs_main" OpMemberDecorate %12 0 Offset 0 OpMemberDecorate %12 1 Offset 16 OpDecorate %14 Block @@ -52,9 +52,9 @@ OpDecorate %23 Binding 2 OpDecorate %31 BuiltIn VertexIndex OpDecorate %34 BuiltIn Position OpDecorate %36 Location 0 -OpDecorate %101 BuiltIn FragCoord -OpDecorate %104 Location 0 -OpDecorate %107 Location 0 +OpDecorate %106 BuiltIn FragCoord +OpDecorate %109 Location 0 +OpDecorate %112 Location 0 %2 = OpTypeVoid %4 = OpTypeInt 32 1 %3 = OpConstant %4 2 @@ -96,12 +96,14 @@ OpDecorate %107 Location 0 %91 = OpConstant %4 1 %93 = OpTypePointer Function %10 %94 = OpConstant %4 0 -%102 = OpTypePointer Input %10 -%101 = OpVariable %102 Input -%105 = OpTypePointer Input %11 -%104 = OpVariable %105 Input -%107 = OpVariable %35 Output -%113 = OpTypeSampledImage %17 +%99 = OpTypePointer Output %7 +%100 = OpConstant %4 1 +%107 = OpTypePointer Input %10 +%106 = OpVariable %107 Input +%110 = OpTypePointer Input %11 +%109 = OpVariable %110 Input +%112 = OpVariable %35 Output +%118 = OpTypeSampledImage %17 %38 = OpFunction %2 None %39 %30 = OpLabel %25 = OpVariable %26 Function @@ -163,22 +165,26 @@ OpStore %95 %53 %96 = OpLoad %12 %28 %97 = OpCompositeExtract %10 %96 0 OpStore %34 %97 -%98 = OpCompositeExtract %11 %96 1 -OpStore %36 %98 +%98 = OpAccessChain %99 %34 %100 +%101 = OpLoad %7 %98 +%102 = OpFNegate %7 %101 +OpStore %98 %102 +%103 = OpCompositeExtract %11 %96 1 +OpStore %36 %103 OpReturn OpFunctionEnd -%108 = OpFunction %2 None %39 -%99 = OpLabel -%103 = OpLoad %10 %101 -%106 = OpLoad %11 %104 -%100 = OpCompositeConstruct %12 %103 %106 -%109 = OpLoad %17 %21 -%110 = OpLoad %18 %23 -OpBranch %111 -%111 = OpLabel -%112 = OpCompositeExtract %11 %100 1 -%114 = OpSampledImage %113 %109 %110 -%115 = OpImageSampleImplicitLod %10 %114 %112 -OpStore %107 %115 +%113 = OpFunction %2 None %39 +%104 = OpLabel +%108 = OpLoad %10 %106 +%111 = OpLoad %11 %109 +%105 = OpCompositeConstruct %12 %108 %111 +%114 = OpLoad %17 %21 +%115 = OpLoad %18 %23 +OpBranch %116 +%116 = OpLabel +%117 = OpCompositeExtract %11 %105 1 +%119 = OpSampledImage %118 %114 %115 +%120 = OpImageSampleImplicitLod %10 %119 %117 +OpStore %112 %120 OpReturn OpFunctionEnd