diff --git a/src/core/hle/D3D8/XbVertexShader.cpp b/src/core/hle/D3D8/XbVertexShader.cpp index 493ba336c..e2c108b52 100644 --- a/src/core/hle/D3D8/XbVertexShader.cpp +++ b/src/core/hle/D3D8/XbVertexShader.cpp @@ -450,7 +450,7 @@ static const char* ILU_OpCode[] = "rcp", "rcc", "rsq", - "frc", // The Xbox EXP instruction behaves like FRC on PC, so we just translate it as frc. Fixes broken polygons in THPS2X + "expp", // The Xbox EXPP instruction behaves like vs_1_1 "log", "lit" }; @@ -2563,6 +2563,45 @@ D3DVERTEXELEMENT *EmuRecompileVshDeclaration return pHostVertexElements; } +// Xbox expp seems to behave the as vs_1_1 +std::string VshPostProcess_Expp(std::string shader) { + // Find usages of exp with each swizzle + // If there's no swizzle, we should still match so we do the calculation + // for all components + auto exp_x = std::regex("expp (\\w\\d\\d?)(\\.x)?, (.+)$"); + auto exp_y = std::regex("expp (\\w\\d\\d?)(\\.y)?, (.+)$"); + auto exp_z = std::regex("expp (\\w\\d\\d?)(\\.z)?, (.+)$"); + auto exp_w = std::regex("expp (\\w\\d\\d?)(\\.w)?, (.+)$"); + + // We operate on a scalar so the input should have a swizzle? + + if (std::regex_search(shader, exp_x)) + LOG_TEST_CASE("Title uses the x component result of expp"); + + // dest.x = 2 ^ floor(x) + auto exp_x_host = + "frc r31.x, $3\n" + "add r31.x, $1$2, -r31.x\n" + "exp $1.x, r31.x"; + shader = std::regex_replace(shader, exp_x, exp_x_host); + + // dest.y = x - floor(x) + // Test Case: Tony Hawk Pro Skater 2X + auto exp_y_host = "frc $1.y, $3"; + shader = std::regex_replace(shader, exp_y, exp_y_host); + + // dest.z = approximate 2 ^ x + // Test Case: Mechassault + auto exp_z_host = "exp $1.z, $3"; + shader = std::regex_replace(shader, exp_z, exp_z_host); + + // TODO dest.w = 1 + // auto exp_w_host = "mov $1.w, 1"; + //shader = std::regex_replace(shader, exp_w, exp_w_host); + + return shader; +} + // On Xbox, the special indexing register, a0.x, is truncated // But on vs_2_x and up, it's rounded to the closest integer // So we have to truncate it ourselves @@ -2579,6 +2618,12 @@ std::string VshPostProcess_TruncateMovA(std::string shader) { return std::regex_replace(shader, movA, truncate); } +// Post process the shader as a string +std::string VshPostProcess(std::string shader) { + shader = VshPostProcess_Expp(shader); + return VshPostProcess_TruncateMovA(shader); +} + // recompile xbox vertex shader function extern HRESULT EmuRecompileVshFunction ( @@ -2665,7 +2710,7 @@ extern HRESULT EmuRecompileVshFunction VshWriteShader(pShader, pHostShaderDisassembly, pRecompiledDeclaration, TRUE); // Post process the final shader - auto finalHostShader = VshPostProcess_TruncateMovA(pHostShaderDisassembly.str()); + auto finalHostShader = VshPostProcess(pHostShaderDisassembly.str()); DbgVshPrintf("-- After conversion ---\n"); DbgVshPrintf("%s", finalHostShader.c_str());