mirror of
				https://github.com/hedge-dev/XenosRecomp.git
				synced 2025-10-30 07:12:17 +00:00 
			
		
		
		
	Add simple control flow detection.
This commit is contained in:
		
							parent
							
								
									8743874ffe
								
							
						
					
					
						commit
						9ebccbae90
					
				
					 2 changed files with 216 additions and 103 deletions
				
			
		|  | @ -1232,32 +1232,27 @@ void ShaderRecompiler::recompile(const uint8_t* shaderData) | |||
|     if (isPixelShader) | ||||
|         out += "\tCubeMapData cubeMapData = (CubeMapData)0;\n"; | ||||
| 
 | ||||
|     out += "\n\tuint pc = 0;\n"; | ||||
|     out += "\twhile (true)\n"; | ||||
|     out += "\t{\n"; | ||||
|     out += "\t\tswitch (pc)\n"; | ||||
|     out += "\t\t{\n"; | ||||
| 
 | ||||
|     const be<uint32_t>* code = reinterpret_cast<const be<uint32_t>*>(shaderData + shaderContainer->virtualSize + shader->physicalOffset); | ||||
| 
 | ||||
|     auto controlFlowCode = code; | ||||
|     uint32_t pc = 0; | ||||
|     uint32_t minInstrAddress = shader->size; | ||||
| 
 | ||||
|     while (pc * 6 < minInstrAddress) | ||||
|     union | ||||
|     { | ||||
|         union | ||||
|         ControlFlowInstruction controlFlow[2]; | ||||
|         struct | ||||
|         { | ||||
|             ControlFlowInstruction controlFlow[2]; | ||||
|             struct | ||||
|             { | ||||
|                 uint32_t code0; | ||||
|                 uint32_t code1; | ||||
|                 uint32_t code2; | ||||
|                 uint32_t code3; | ||||
|             }; | ||||
|             uint32_t code0; | ||||
|             uint32_t code1; | ||||
|             uint32_t code2; | ||||
|             uint32_t code3; | ||||
|         }; | ||||
|     }; | ||||
| 
 | ||||
|     auto controlFlowCode = code; | ||||
|     uint32_t instrAddress = 0; | ||||
|     uint32_t instrSize = shader->size; | ||||
|     bool simpleControlFlow = true; | ||||
| 
 | ||||
|     while (instrAddress < instrSize) | ||||
|     { | ||||
|         code0 = controlFlowCode[0]; | ||||
|         code1 = controlFlowCode[1] & 0xFFFF; | ||||
|         code2 = (controlFlowCode[1] >> 16) | (controlFlowCode[2] << 16); | ||||
|  | @ -1265,27 +1260,108 @@ void ShaderRecompiler::recompile(const uint8_t* shaderData) | |||
| 
 | ||||
|         for (auto& cfInstr : controlFlow) | ||||
|         { | ||||
|             indentation = 3; | ||||
|             println("\t\tcase {}:", pc); | ||||
|             uint32_t address = 0; | ||||
| 
 | ||||
|             switch (cfInstr.opcode) | ||||
|             { | ||||
|             case ControlFlowOpcode::Exec: | ||||
|             case ControlFlowOpcode::ExecEnd: | ||||
|                 address = cfInstr.exec.address; | ||||
|                 break; | ||||
| 
 | ||||
|             case ControlFlowOpcode::CondExec: | ||||
|             case ControlFlowOpcode::CondExecEnd: | ||||
|             case ControlFlowOpcode::CondExecPredClean: | ||||
|             case ControlFlowOpcode::CondExecPredCleanEnd: | ||||
|                 address = cfInstr.condExec.address; | ||||
|                 break; | ||||
| 
 | ||||
|             case ControlFlowOpcode::CondExecPred: | ||||
|             case ControlFlowOpcode::CondExecPredEnd: | ||||
|                 address = cfInstr.condExecPred.address; | ||||
|                 break; | ||||
| 
 | ||||
|             case ControlFlowOpcode::CondJmp: | ||||
|             { | ||||
|                 if (cfInstr.condJmp.isUnconditional || cfInstr.condJmp.direction) | ||||
|                     simpleControlFlow = false; | ||||
|                 else | ||||
|                     ++ifEndLabels[cfInstr.condJmp.address]; | ||||
| 
 | ||||
|                 break; | ||||
|             } | ||||
|             } | ||||
| 
 | ||||
|             if (address != 0) | ||||
|                 instrSize = std::min<uint32_t>(instrSize, address * 12); | ||||
|         } | ||||
| 
 | ||||
|         controlFlowCode += 3; | ||||
|         instrAddress += 12; | ||||
|     } | ||||
| 
 | ||||
|     if (simpleControlFlow) | ||||
|     { | ||||
|         out += '\n'; | ||||
|         indentation = 1; | ||||
|     } | ||||
|     else | ||||
|     { | ||||
|         out += "\n\tuint pc = 0;\n"; | ||||
|         out += "\twhile (true)\n"; | ||||
|         out += "\t{\n"; | ||||
|         out += "\t\tswitch (pc)\n"; | ||||
|         out += "\t\t{\n"; | ||||
|     } | ||||
| 
 | ||||
|     controlFlowCode = code; | ||||
|     instrAddress = 0; | ||||
|     uint32_t pc = 0; | ||||
| 
 | ||||
|     while (instrAddress < instrSize) | ||||
|     { | ||||
|         code0 = controlFlowCode[0]; | ||||
|         code1 = controlFlowCode[1] & 0xFFFF; | ||||
|         code2 = (controlFlowCode[1] >> 16) | (controlFlowCode[2] << 16); | ||||
|         code3 = controlFlowCode[2] >> 16; | ||||
| 
 | ||||
|         for (auto& cfInstr : controlFlow) | ||||
|         { | ||||
|             if (!simpleControlFlow) | ||||
|             { | ||||
|                 indentation = 3; | ||||
|                 println("\t\tcase {}:", pc); | ||||
|             } | ||||
|             else | ||||
|             { | ||||
|                 auto findResult = ifEndLabels.find(pc); | ||||
|                 if (findResult != ifEndLabels.end()) | ||||
|                 { | ||||
|                     for (uint32_t i = 0; i < findResult->second; i++) | ||||
|                     { | ||||
|                         --indentation; | ||||
|                         indent(); | ||||
|                         out += "}\n"; | ||||
|                     } | ||||
|                 } | ||||
|             } | ||||
| 
 | ||||
|             ++pc; | ||||
| 
 | ||||
|             uint32_t address = 0; | ||||
|             uint32_t count = 0; | ||||
|             uint32_t sequence = 0; | ||||
|             bool shouldBreak = false; | ||||
|             bool shouldReturn = false; | ||||
|             bool shouldCloseCurlyBracket = false; | ||||
| 
 | ||||
|             switch (cfInstr.opcode) | ||||
|             { | ||||
|             case ControlFlowOpcode::Nop: | ||||
|                 break; | ||||
| 
 | ||||
|             case ControlFlowOpcode::Exec: | ||||
|             case ControlFlowOpcode::ExecEnd: | ||||
|                 address = cfInstr.exec.address; | ||||
|                 count = cfInstr.exec.count; | ||||
|                 sequence = cfInstr.exec.sequence; | ||||
|                 shouldBreak = (cfInstr.opcode == ControlFlowOpcode::ExecEnd); | ||||
|                 shouldReturn = (cfInstr.opcode == ControlFlowOpcode::ExecEnd); | ||||
|                 break; | ||||
| 
 | ||||
|             case ControlFlowOpcode::CondExec: | ||||
|  | @ -1295,7 +1371,7 @@ void ShaderRecompiler::recompile(const uint8_t* shaderData) | |||
|                 address = cfInstr.condExec.address; | ||||
|                 count = cfInstr.condExec.count; | ||||
|                 sequence = cfInstr.condExec.sequence; | ||||
|                 shouldBreak = (cfInstr.opcode == ControlFlowOpcode::CondExecEnd || cfInstr.opcode == ControlFlowOpcode::CondExecEnd); | ||||
|                 shouldReturn = (cfInstr.opcode == ControlFlowOpcode::CondExecEnd || cfInstr.opcode == ControlFlowOpcode::CondExecEnd); | ||||
|                 break; | ||||
| 
 | ||||
|             case ControlFlowOpcode::CondExecPred: | ||||
|  | @ -1303,127 +1379,163 @@ void ShaderRecompiler::recompile(const uint8_t* shaderData) | |||
|                 address = cfInstr.condExecPred.address; | ||||
|                 count = cfInstr.condExecPred.count; | ||||
|                 sequence = cfInstr.condExecPred.sequence; | ||||
|                 shouldBreak = (cfInstr.opcode == ControlFlowOpcode::CondExecPredEnd); | ||||
|                 shouldReturn = (cfInstr.opcode == ControlFlowOpcode::CondExecPredEnd); | ||||
|                 break; | ||||
| 
 | ||||
|             case ControlFlowOpcode::LoopStart: | ||||
|                 out += "\t\t\taL = 0;\n"; | ||||
|                 if (simpleControlFlow) | ||||
|                 { | ||||
|                     indent(); | ||||
|                     println("for (aL = 0; aL < i{}.x; aL++)", uint32_t(cfInstr.loopStart.loopId)); | ||||
|                     indent(); | ||||
|                     out += "{\n"; | ||||
|                     ++indentation; | ||||
|                 } | ||||
|                 else  | ||||
|                 { | ||||
|                     out += "\t\t\taL = 0;\n"; | ||||
|                 } | ||||
|                 break; | ||||
| 
 | ||||
|             case ControlFlowOpcode::LoopEnd: | ||||
|                 out += "\t\t\t++aL;\n"; | ||||
|                 println("\t\t\tif (aL < i{}.x)", uint32_t(cfInstr.loopEnd.loopId)); | ||||
|                 out += "\t\t\t{\n"; | ||||
|                 println("\t\t\t\tpc = {};", uint32_t(cfInstr.loopEnd.address)); | ||||
|                 out += "\t\t\t\tcontinue;\n"; | ||||
|                 out += "\t\t\t}\n"; | ||||
|                 break; | ||||
| 
 | ||||
|             case ControlFlowOpcode::CondCall: | ||||
|             case ControlFlowOpcode::Return: | ||||
|                 if (simpleControlFlow) | ||||
|                 { | ||||
|                     --indentation; | ||||
|                     indent(); | ||||
|                     out += "}\n"; | ||||
|                 } | ||||
|                 else | ||||
|                 { | ||||
|                     out += "\t\t\t++aL;\n"; | ||||
|                     println("\t\t\tif (aL < i{}.x)", uint32_t(cfInstr.loopEnd.loopId)); | ||||
|                     out += "\t\t\t{\n"; | ||||
|                     println("\t\t\t\tpc = {};", uint32_t(cfInstr.loopEnd.address)); | ||||
|                     out += "\t\t\t\tcontinue;\n"; | ||||
|                     out += "\t\t\t}\n"; | ||||
|                 } | ||||
|                 break; | ||||
| 
 | ||||
|             case ControlFlowOpcode::CondJmp: | ||||
|             { | ||||
|                 if (cfInstr.condJmp.isUnconditional) | ||||
|                 { | ||||
|                     assert(!simpleControlFlow); | ||||
|                     println("\t\t\tpc = {};", uint32_t(cfInstr.condJmp.address)); | ||||
|                     out += "\t\t\tcontinue;\n"; | ||||
|                 } | ||||
|                 else | ||||
|                 { | ||||
|                     indent(); | ||||
|                     if (cfInstr.condJmp.isPredicated) | ||||
|                     { | ||||
|                         println("\t\t\tif ({}p0)", cfInstr.condJmp.condition ? "" : "!"); | ||||
|                         println("if ({}p0)", cfInstr.condJmp.condition ^ simpleControlFlow ? "" : "!"); | ||||
|                     } | ||||
|                     else | ||||
|                     { | ||||
|                         auto findResult = boolConstants.find(cfInstr.condJmp.boolAddress); | ||||
|                         if (findResult != boolConstants.end()) | ||||
|                             println("\t\t\tif ((GET_SHARED_CONSTANT(g_Booleans) & {}) {}= 0)", findResult->second, cfInstr.condJmp.condition ? "!" : "="); | ||||
|                             println("if ((GET_SHARED_CONSTANT(g_Booleans) & {}) {}= 0)", findResult->second, cfInstr.condJmp.condition ^ simpleControlFlow ? "!" : "="); | ||||
|                         else | ||||
|                             println("\t\t\tif (b{} {}= 0)", uint32_t(cfInstr.condJmp.boolAddress), cfInstr.condJmp.condition ? "!" : "="); | ||||
|                             println("if (b{} {}= 0)", uint32_t(cfInstr.condJmp.boolAddress), cfInstr.condJmp.condition ^ simpleControlFlow ? "!" : "="); | ||||
|                     } | ||||
| 
 | ||||
|                     out += "\t\t\t{\n"; | ||||
|                     println("\t\t\t\tpc = {};", uint32_t(cfInstr.condJmp.address)); | ||||
|                     out += "\t\t\t\tcontinue;\n"; | ||||
|                     out += "\t\t\t}\n"; | ||||
|                 } | ||||
|                 break; | ||||
|             } | ||||
| 
 | ||||
|             case ControlFlowOpcode::Alloc: | ||||
|             case ControlFlowOpcode::MarkVsFetchDone: | ||||
|                 break; | ||||
|             } | ||||
| 
 | ||||
|             if (count != 0) | ||||
|             { | ||||
|                 minInstrAddress = std::min<uint32_t>(minInstrAddress, address * 12); | ||||
|                 auto instructionCode = code + address * 3; | ||||
| 
 | ||||
|                 for (uint32_t i = 0; i < count; i++) | ||||
|                 { | ||||
|                     union | ||||
|                     if (simpleControlFlow) | ||||
|                     { | ||||
|                         VertexFetchInstruction vertexFetch; | ||||
|                         TextureFetchInstruction textureFetch; | ||||
|                         AluInstruction alu; | ||||
|                         struct | ||||
|                         { | ||||
|                             uint32_t code0; | ||||
|                             uint32_t code1; | ||||
|                             uint32_t code2; | ||||
|                         }; | ||||
|                     }; | ||||
| 
 | ||||
|                     code0 = instructionCode[0]; | ||||
|                     code1 = instructionCode[1]; | ||||
|                     code2 = instructionCode[2]; | ||||
| 
 | ||||
|                     if ((sequence & 0x1) != 0) | ||||
|                     { | ||||
|                         if (vertexFetch.opcode == FetchOpcode::VertexFetch) | ||||
|                             recompile(vertexFetch, address + i); | ||||
|                         else | ||||
|                             recompile(textureFetch); | ||||
|                         indent(); | ||||
|                         out += "{\n"; | ||||
|                         ++indentation; | ||||
|                     } | ||||
|                     else | ||||
|                     { | ||||
|                         recompile(alu); | ||||
|                         out += "\t\t\t{\n"; | ||||
|                         println("\t\t\t\tpc = {};", uint32_t(cfInstr.condJmp.address)); | ||||
|                         out += "\t\t\t\tcontinue;\n"; | ||||
|                         out += "\t\t\t}\n"; | ||||
|                     } | ||||
| 
 | ||||
|                     sequence >>= 2; | ||||
|                     instructionCode += 3; | ||||
|                 } | ||||
|                 break; | ||||
|             } | ||||
|             } | ||||
| 
 | ||||
|             if (shouldBreak) | ||||
|                 out += "\t\t\tbreak;\n"; | ||||
|             auto instructionCode = code + address * 3; | ||||
|              | ||||
|             for (uint32_t i = 0; i < count; i++) | ||||
|             { | ||||
|                 union | ||||
|                 { | ||||
|                     VertexFetchInstruction vertexFetch; | ||||
|                     TextureFetchInstruction textureFetch; | ||||
|                     AluInstruction alu; | ||||
|                     struct | ||||
|                     { | ||||
|                         uint32_t code0; | ||||
|                         uint32_t code1; | ||||
|                         uint32_t code2; | ||||
|                     }; | ||||
|                 }; | ||||
|              | ||||
|                 code0 = instructionCode[0]; | ||||
|                 code1 = instructionCode[1]; | ||||
|                 code2 = instructionCode[2]; | ||||
|              | ||||
|                 if ((sequence & 0x1) != 0) | ||||
|                 { | ||||
|                     if (vertexFetch.opcode == FetchOpcode::VertexFetch) | ||||
|                         recompile(vertexFetch, address + i); | ||||
|                     else | ||||
|                         recompile(textureFetch); | ||||
|                 } | ||||
|                 else | ||||
|                 { | ||||
|                     recompile(alu); | ||||
|                 } | ||||
|              | ||||
|                 sequence >>= 2; | ||||
|                 instructionCode += 3; | ||||
|             } | ||||
| 
 | ||||
|             if (shouldReturn) | ||||
|             { | ||||
|                 if (isPixelShader) | ||||
|                 { | ||||
|                     indent(); | ||||
|                     out += "if (GET_SHARED_CONSTANT(g_AlphaTestMode) != 0) clip(oC0.w - GET_SHARED_CONSTANT(g_AlphaThreshold));\n"; | ||||
|                 } | ||||
|                 else if (isCsdShader) | ||||
|                 { | ||||
|                     indent(); | ||||
|                     out += "oPos.xy += float2(GET_CONSTANT(g_ViewportSize.z), -GET_CONSTANT(g_ViewportSize.w));\n"; | ||||
|                 } | ||||
| 
 | ||||
|                 if (simpleControlFlow) | ||||
|                 { | ||||
|                     indent(); | ||||
|                     out += "return;\n"; | ||||
|                 } | ||||
|                 else | ||||
|                 { | ||||
|                     out += "\t\t\tbreak;\n"; | ||||
|                 } | ||||
|             } | ||||
| 
 | ||||
|             if (shouldCloseCurlyBracket) | ||||
|             { | ||||
|                 --indentation; | ||||
|                 out += "\t\t\t}\n"; | ||||
|                 indent(); | ||||
|                 out += "}\n"; | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         controlFlowCode += 3; | ||||
|         instrAddress += 12; | ||||
|     } | ||||
| 
 | ||||
|     out += "\t\t\tbreak;\n"; | ||||
|     out += "\t\t}\n"; | ||||
|     out += "\t\tbreak;\n"; | ||||
|     out += "\t}\n"; | ||||
| 
 | ||||
|     if (isPixelShader) | ||||
|     if (!simpleControlFlow) | ||||
|     { | ||||
|         out += "\tif (GET_SHARED_CONSTANT(g_AlphaTestMode) != 0) clip(oC0.w - GET_SHARED_CONSTANT(g_AlphaThreshold));\n"; | ||||
|     } | ||||
|     else if (isCsdShader) | ||||
|     { | ||||
|         out += "\toPos.xy += float2(GET_CONSTANT(g_ViewportSize.z), -GET_CONSTANT(g_ViewportSize.w));\n"; | ||||
|         out += "\t\t\tbreak;\n"; | ||||
|         out += "\t\t}\n"; | ||||
|         out += "\t\tbreak;\n"; | ||||
|         out += "\t}\n"; | ||||
|     } | ||||
| 
 | ||||
|     out += "}"; | ||||
|  |  | |||
|  | @ -14,6 +14,7 @@ struct ShaderRecompiler | |||
|     std::unordered_map<uint32_t, const ConstantInfo*> float4Constants; | ||||
|     std::unordered_map<uint32_t, const char*> boolConstants; | ||||
|     std::unordered_map<uint32_t, const char*> samplers; | ||||
|     std::unordered_map<uint32_t, uint32_t> ifEndLabels; | ||||
| 
 | ||||
|     void indent() | ||||
|     { | ||||
|  |  | |||
		Loading…
	
	Add table
		
		Reference in a new issue
	
	 Skyth
						Skyth