mirror of
				https://github.com/PabloMK7/citra.git
				synced 2025-10-31 05:40:04 +00:00 
			
		
		
		
	shader_jit: Fix/optimize conditional evaluation (#234)
* shader_jit: Add conditional unit-tests
Tests all permutations of X, Y, AND, OR with each possible input value.
* video_core: Fix shader-interpreter conditional-code initialization
Rather than reserving the incoming state of the conditional codes, the
shader-interpreter was setting them both to false. In pretty much all
cases, the initial state of a shaderunit can be zero-initialized
statically. Just running the interpreter shouldn't necessarily reset the
conditional codes though.  The JIT loads incoming conditional codes
while the shader-interpreter resets them to false. This makes the
interpreter match the behavior of the shader-jit.
* shader_jit_a64: Fix/optimize conditional evaluation
Fix some of the regressions introduced by the previous optimization.
EOR does not support a constant of `0` in its immediate. In these cases
the COND{0,1} registers can be utilized immediately.
* shader_jit_x64: Fix conditional evaluation extended-bit hazard
The unit test seems to have identified a bug in the x64 jit too. The x64
jit was doing 32-bit comparisons despite the condition flags being 8-bit
values and is sensitive to garbage being in the upper 24 bits of the
register. This is fixed by using the proper 8-bit register types rather
than the 32-bit ones(`eax,`ebx` -> `al`, `bl`).
* shader_jit_x64: Zero-extend conditional-code bytes
`mov` was doing a partial update of bits within the register, allowing
garbage to be introduced in the upper bits of the register.
			
			
This commit is contained in:
		
							parent
							
								
									f248fefe06
								
							
						
					
					
						commit
						52f06f757f
					
				
					 6 changed files with 144 additions and 40 deletions
				
			
		|  | @ -674,6 +674,94 @@ TEMPLATE_TEST_CASE("Nested Loop", "[video_core][shader]", ShaderJitTest) { | |||
|     } | ||||
| } | ||||
| 
 | ||||
| SHADER_TEST_CASE("Conditional", "[video_core][shader]") { | ||||
|     const auto sh_input = SourceRegister::MakeInput(0); | ||||
|     const auto sh_temp = SourceRegister::MakeTemporary(0); | ||||
|     const auto sh_output = DestRegister::MakeOutput(0); | ||||
| 
 | ||||
|     const std::initializer_list<nihstro::InlineAsm> assembly_template = { | ||||
|         // IFC configured later
 | ||||
|         {OpCode::Id::NOP}, | ||||
|         // True
 | ||||
|         {OpCode::Id::MOV, sh_output, sh_input}, | ||||
|         {OpCode::Id::END}, | ||||
|         // False
 | ||||
|         {OpCode::Id::MOV, sh_output, sh_temp}, | ||||
|         {OpCode::Id::END}, | ||||
|     }; | ||||
| 
 | ||||
|     const bool ref_x = GENERATE(0, 1); | ||||
|     const bool cmp_x = GENERATE(0, 1); | ||||
|     const bool result_x = (cmp_x == ref_x); | ||||
| 
 | ||||
|     const bool ref_y = GENERATE(0, 1); | ||||
|     const bool cmp_y = GENERATE(0, 1); | ||||
|     const bool result_y = (cmp_y == ref_y); | ||||
| 
 | ||||
|     nihstro::Instruction IFC = {}; | ||||
|     IFC.opcode = nihstro::OpCode::Id::IFC; | ||||
|     IFC.flow_control.num_instructions = 2; | ||||
|     IFC.flow_control.dest_offset = 3; | ||||
|     IFC.flow_control.refx = ref_x; | ||||
|     IFC.flow_control.refy = ref_y; | ||||
| 
 | ||||
|     Pica::ShaderUnit shader_unit; | ||||
|     shader_unit.conditional_code[0] = cmp_x; | ||||
|     shader_unit.conditional_code[1] = cmp_y; | ||||
| 
 | ||||
|     // JustX
 | ||||
|     { | ||||
|         auto shader_setup = CompileShaderSetup(assembly_template); | ||||
|         IFC.flow_control.op = nihstro::Instruction::FlowControlType::Op::JustX; | ||||
|         shader_setup->program_code[0] = IFC.hex; | ||||
|         const float result = result_x ? 1.0f : 0.0f; | ||||
| 
 | ||||
|         auto shader_test = TestType(std::move(shader_setup)); | ||||
|         shader_test.Run(shader_unit, 1.0f); | ||||
| 
 | ||||
|         REQUIRE(shader_unit.output[0].x.ToFloat32() == result); | ||||
|     } | ||||
| 
 | ||||
|     // JustY
 | ||||
|     { | ||||
|         auto shader_setup = CompileShaderSetup(assembly_template); | ||||
|         IFC.flow_control.op = nihstro::Instruction::FlowControlType::Op::JustY; | ||||
|         shader_setup->program_code[0] = IFC.hex; | ||||
|         const float result = result_y ? 1.0f : 0.0f; | ||||
| 
 | ||||
|         auto shader_test = TestType(std::move(shader_setup)); | ||||
|         shader_test.Run(shader_unit, 1.0f); | ||||
| 
 | ||||
|         REQUIRE(shader_unit.output[0].x.ToFloat32() == result); | ||||
|     } | ||||
| 
 | ||||
|     // OR
 | ||||
|     { | ||||
|         auto shader_setup = CompileShaderSetup(assembly_template); | ||||
|         IFC.flow_control.op = nihstro::Instruction::FlowControlType::Op::Or; | ||||
|         shader_setup->program_code[0] = IFC.hex; | ||||
|         const float result = (result_x || result_y) ? 1.0f : 0.0f; | ||||
| 
 | ||||
|         auto shader_test = TestType(std::move(shader_setup)); | ||||
|         shader_test.Run(shader_unit, 1.0f); | ||||
| 
 | ||||
|         REQUIRE(shader_unit.output[0].x.ToFloat32() == result); | ||||
|     } | ||||
| 
 | ||||
|     // AND
 | ||||
|     { | ||||
|         auto shader_setup = CompileShaderSetup(assembly_template); | ||||
|         IFC.flow_control.op = nihstro::Instruction::FlowControlType::Op::And; | ||||
|         shader_setup->program_code[0] = IFC.hex; | ||||
|         const float result = (result_x && result_y) ? 1.0f : 0.0f; | ||||
| 
 | ||||
|         auto shader_test = TestType(std::move(shader_setup)); | ||||
|         shader_test.Run(shader_unit, 1.0f); | ||||
| 
 | ||||
|         REQUIRE(shader_unit.output[0].x.ToFloat32() == result); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| SHADER_TEST_CASE("Source Swizzle", "[video_core][shader]") { | ||||
|     const auto sh_input = SourceRegister::MakeInput(0); | ||||
|     const auto sh_output = DestRegister::MakeOutput(0); | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue