diff options
| author | Matthew Parlane <parlane@gmail.com> | 2013-08-23 00:51:12 +1200 |
|---|---|---|
| committer | Matthew Parlane <parlane@gmail.com> | 2013-08-23 00:51:12 +1200 |
| commit | b6e054a2beef3236822e27d95dfe38a4ccee2eb1 (patch) | |
| tree | 6f744593b14def9c2fbc7be9e509df5507835cc4 /Source/Core | |
| parent | f274b3b074fb8bb0477b0e9f4e88db0e08bf4f2c (diff) | |
| parent | 41c25d0c90a2461c3e34bf9659dcf1da5e1e8580 (diff) | |
Merge branch 'master' into wii-network
Conflicts:
Source/Core/Core/Core.vcxproj
Source/Core/Core/Core.vcxproj.filters
Source/Core/Core/Src/CoreParameter.cpp
Source/Core/DolphinWX/Dolphin.vcxproj
Source/Core/DolphinWX/Dolphin.vcxproj.filters
Diffstat (limited to 'Source/Core')
112 files changed, 2737 insertions, 2200 deletions
diff --git a/Source/Core/Common/CMakeLists.txt b/Source/Core/Common/CMakeLists.txt index 4891f3c090..6e230c7fa7 100644 --- a/Source/Core/Common/CMakeLists.txt +++ b/Source/Core/Common/CMakeLists.txt @@ -21,7 +21,6 @@ set(SRCS Src/BreakPoints.cpp Src/Thread.cpp Src/Timer.cpp Src/Version.cpp - Src/VideoBackendBase.cpp Src/x64ABI.cpp Src/x64Analyzer.cpp Src/x64Emitter.cpp diff --git a/Source/Core/Common/Common.vcxproj b/Source/Core/Common/Common.vcxproj index 9c21b2a992..4066febcca 100644 --- a/Source/Core/Common/Common.vcxproj +++ b/Source/Core/Common/Common.vcxproj @@ -212,7 +212,6 @@ <ClCompile Include="Src\Thread.cpp" /> <ClCompile Include="Src\Timer.cpp" /> <ClCompile Include="Src\Version.cpp" /> - <ClCompile Include="Src\VideoBackendBase.cpp" /> <ClCompile Include="Src\x64ABI.cpp" /> <ClCompile Include="Src\x64Analyzer.cpp" /> <ClCompile Include="Src\x64CPUDetect.cpp" /> @@ -266,7 +265,6 @@ <ClInclude Include="Src\Thread.h" /> <ClInclude Include="Src\Thunk.h" /> <ClInclude Include="Src\Timer.h" /> - <ClInclude Include="Src\VideoBackendBase.h" /> <ClInclude Include="Src\x64ABI.h" /> <ClInclude Include="Src\x64Analyzer.h" /> <ClInclude Include="Src\x64Emitter.h" /> @@ -277,4 +275,4 @@ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" /> <ImportGroup Label="ExtensionTargets"> </ImportGroup> -</Project>
\ No newline at end of file +</Project> diff --git a/Source/Core/Common/Common.vcxproj.filters b/Source/Core/Common/Common.vcxproj.filters index f16b437f54..a912cc3d8a 100644 --- a/Source/Core/Common/Common.vcxproj.filters +++ b/Source/Core/Common/Common.vcxproj.filters @@ -23,7 +23,6 @@ <ClCompile Include="Src\Thread.cpp" /> <ClCompile Include="Src\Timer.cpp" /> <ClCompile Include="Src\Version.cpp" /> - <ClCompile Include="Src\VideoBackendBase.cpp" /> <ClCompile Include="Src\x64Analyzer.cpp" /> <ClCompile Include="Src\x64Emitter.cpp" /> <ClCompile Include="Src\LogManager.cpp"> @@ -87,7 +86,6 @@ <ClInclude Include="Src\Thread.h" /> <ClInclude Include="Src\Thunk.h" /> <ClInclude Include="Src\Timer.h" /> - <ClInclude Include="Src\VideoBackendBase.h" /> <ClInclude Include="Src\x64Analyzer.h" /> <ClInclude Include="Src\x64Emitter.h" /> <ClInclude Include="Src\Log.h"> @@ -124,4 +122,4 @@ <UniqueIdentifier>{f078f36e-a0ff-4cd0-95f8-476100d68e68}</UniqueIdentifier> </Filter> </ItemGroup> -</Project>
\ No newline at end of file +</Project> diff --git a/Source/Core/Common/Src/ArmCPUDetect.cpp b/Source/Core/Common/Src/ArmCPUDetect.cpp index ca277ade02..ef49d6efb1 100644 --- a/Source/Core/Common/Src/ArmCPUDetect.cpp +++ b/Source/Core/Common/Src/ArmCPUDetect.cpp @@ -17,9 +17,10 @@ #include "Common.h" #include "CPUDetect.h" -#include "StringUtil.h" #include "FileUtil.h" +// Only Linux platforms have /proc/cpuinfo +#if !defined(BLACKBERRY) && !defined(IOS) && !defined(__SYMBIAN32__) const char procfile[] = "/proc/cpuinfo"; char *GetCPUString() @@ -33,7 +34,7 @@ char *GetCPUString() auto const fp = file.GetHandle(); if (!fp) return 0; - + while (fgets(buf, sizeof(buf), fp)) { if (strncmp(buf, marker, sizeof(marker) - 1)) @@ -42,6 +43,7 @@ char *GetCPUString() cpu_string = strndup(cpu_string, strlen(cpu_string) - 1); // Strip the newline break; } + return cpu_string; } @@ -66,6 +68,9 @@ unsigned char GetCPUImplementer() sscanf(implementer_string, "0x%02hhx", &implementer); break; } + + free(implementer_string); + return implementer; } @@ -90,15 +95,17 @@ unsigned short GetCPUPart() sscanf(part_string, "0x%03hx", &part); break; } - return part; + free(part_string); + + return part; } bool CheckCPUFeature(const char *feature) { const char marker[] = "Features\t: "; char buf[1024]; - + File::IOFile file(procfile, "r"); auto const fp = file.GetHandle(); if (!fp) @@ -117,10 +124,18 @@ bool CheckCPUFeature(const char *feature) token = strtok(NULL, " "); } } + return false; } +#endif + int GetCoreCount() { +#ifdef __SYMBIAN32__ + return 1; +#elif defined(BLACKBERRY) || defined(IOS) + return 2; +#else const char marker[] = "processor\t: "; int cores = 0; char buf[1024]; @@ -129,14 +144,16 @@ int GetCoreCount() auto const fp = file.GetHandle(); if (!fp) return 0; - + while (fgets(buf, sizeof(buf), fp)) { if (strncmp(buf, marker, sizeof(marker) - 1)) continue; ++cores; } + return cores; +#endif } CPUInfo cpu_info; @@ -153,12 +170,58 @@ void CPUInfo::Detect() HTT = false; OS64bit = false; CPU64bit = false; - Mode64bit = false; + Mode64bit = false; vendor = VENDOR_ARM; - + // Get the information about the CPU - strncpy(cpu_string, GetCPUString(), sizeof(cpu_string)); num_cores = GetCoreCount(); +#if defined(__SYMBIAN32__) || defined(BLACKBERRY) || defined(IOS) + bool isVFP3 = false; + bool isVFP4 = false; +#ifdef IOS + isVFP3 = true; + // Check for swift arch (VFP4`) + #ifdef __ARM_ARCH_7S__ + isVFP4 = true; + #endif // #ifdef __ARM_ARCH_7S__ +#elif defined(BLACKBERRY) + isVFP3 = true; + const char cpuInfoPath[] = "/pps/services/hw_info/inventory"; + const char marker[] = "Processor_Name::"; + const char qcCPU[] = "MSM"; + char buf[1024]; + FILE* fp; + if (fp = fopen(cpuInfoPath, "r")) + { + while (fgets(buf, sizeof(buf), fp)) + { + if (strncmp(buf, marker, sizeof(marker) - 1)) + continue; + if (strncmp(buf + sizeof(marker) - 1, qcCPU, sizeof(qcCPU) - 1) == 0) + isVFP4 = true; + break; + } + fclose(fp); + } +#endif + // Hardcode this for now + bSwp = true; + bHalf = true; + bThumb = false; + bFastMult = true; + bVFP = true; + bEDSP = true; + bThumbEE = isVFP3; + bNEON = isVFP3; + bVFPv3 = isVFP3; + bTLS = true; + bVFPv4 = isVFP4; + bIDIVa = isVFP4; + bIDIVt = isVFP4; + bFP = false; + bASIMD = false; +#else + strncpy(cpu_string, GetCPUString(), sizeof(cpu_string)); bSwp = CheckCPUFeature("swp"); bHalf = CheckCPUFeature("half"); bThumb = CheckCPUFeature("thumb"); @@ -172,16 +235,15 @@ void CPUInfo::Detect() bVFPv4 = CheckCPUFeature("vfpv4"); bIDIVa = CheckCPUFeature("idiva"); bIDIVt = CheckCPUFeature("idivt"); - // Qualcomm Krait supports IDIVA but it doesn't report it. Check for krait. if (GetCPUImplementer() == 0x51 && GetCPUPart() == 0x6F) // Krait(300) is 0x6F, Scorpion is 0x4D - bIDIVa = bIDIVt = true; - - // These two are ARMv8 specific. + bIDIVa = bIDIVt = true; + // These two require ARMv8 or higher bFP = CheckCPUFeature("fp"); bASIMD = CheckCPUFeature("asimd"); - - +#endif +// On android, we build a separate library for ARMv7 so this is fine. +// TODO: Check for ARMv7 on other platforms. #if defined(__ARM_ARCH_7A__) bArmV7 = true; #else @@ -193,11 +255,14 @@ void CPUInfo::Detect() std::string CPUInfo::Summarize() { std::string sum; +#if defined(BLACKBERRY) || defined(IOS) || defined(__SYMBIAN32__) + sum = StringFromFormat("%i cores", num_cores); +#else if (num_cores == 1) sum = StringFromFormat("%s, %i core", cpu_string, num_cores); else sum = StringFromFormat("%s, %i cores", cpu_string, num_cores); - +#endif if (bSwp) sum += ", SWP"; if (bHalf) sum += ", Half"; if (bThumb) sum += ", Thumb"; diff --git a/Source/Core/Common/Src/ArmEmitter.cpp b/Source/Core/Common/Src/ArmEmitter.cpp index 1b20a1784e..2788760c6d 100644 --- a/Source/Core/Common/Src/ArmEmitter.cpp +++ b/Source/Core/Common/Src/ArmEmitter.cpp @@ -86,7 +86,7 @@ bool TryMakeOperand2_AllowNegation(s32 imm, Operand2 &op2, bool *negated) Operand2 AssumeMakeOperand2(u32 imm) { Operand2 op2; bool result = TryMakeOperand2(imm, op2); - _assert_msg_(DYNA_REC, result, "Could not make assumed Operand2."); + _dbg_assert_msg_(DYNA_REC, result, "Could not make assumed Operand2."); return op2; } @@ -117,14 +117,33 @@ bool ARMXEmitter::TrySetValue_TwoOp(ARMReg reg, u32 val) return true; } -void ARMXEmitter::MOVI2F(ARMReg dest, float val, ARMReg tempReg) +void ARMXEmitter::MOVI2F(ARMReg dest, float val, ARMReg tempReg, bool negate) { union {float f; u32 u;} conv; - conv.f = val; + conv.f = negate ? -val : val; + // Try moving directly first if mantisse is empty + if (cpu_info.bVFPv3 && ((conv.u & 0x7FFFF) == 0)) + { + // VFP Encoding for Imms: <7> Not(<6>) Repeat(<6>,5) <5:0> Zeros(19) + bool bit6 = (conv.u & 0x40000000) == 0x40000000; + bool canEncode = true; + for (u32 mask = 0x20000000; mask >= 0x2000000; mask >>= 1) + { + if (((conv.u & mask) == mask) == bit6) + canEncode = false; + } + if (canEncode) + { + u32 imm8 = (conv.u & 0x80000000) >> 24; // sign bit + imm8 |= (!bit6 << 6); + imm8 |= (conv.u & 0x1F80000) >> 19; + VMOV(dest, IMM(imm8)); + return; + } + } MOVI2R(tempReg, conv.u); VMOV(dest, tempReg); - // TODO: VMOV an IMM directly if possible - // Otherwise, use a literal pool and VLDR directly (+- 1020) + // Otherwise, possible to use a literal pool and VLDR directly (+- 1020) } void ARMXEmitter::ADDI2R(ARMReg rd, ARMReg rs, u32 val, ARMReg scratch) @@ -246,8 +265,12 @@ void ARMXEmitter::MOVI2R(ARMReg reg, u32 val, bool optimize) } void ARMXEmitter::QuickCallFunction(ARMReg reg, void *func) { - MOVI2R(reg, (u32)(func)); - BL(reg); + if (BLInRange(func)) { + BL(func); + } else { + MOVI2R(reg, (u32)(func)); + BL(reg); + } } void ARMXEmitter::SetCodePtr(u8 *ptr) @@ -369,7 +392,7 @@ FixupBranch ARMXEmitter::B_CC(CCFlags Cond) void ARMXEmitter::B_CC(CCFlags Cond, const void *fnptr) { s32 distance = (s32)fnptr - (s32(code) + 8); - _assert_msg_(DYNA_REC, distance > -33554432 + _dbg_assert_msg_(DYNA_REC, distance > -33554432 && distance <= 33554432, "B_CC out of range (%p calls %p)", code, fnptr); @@ -388,7 +411,7 @@ FixupBranch ARMXEmitter::BL_CC(CCFlags Cond) void ARMXEmitter::SetJumpTarget(FixupBranch const &branch) { s32 distance = (s32(code) - 8) - (s32)branch.ptr; - _assert_msg_(DYNA_REC, distance > -33554432 + _dbg_assert_msg_(DYNA_REC, distance > -33554432 && distance <= 33554432, "SetJumpTarget out of range (%p calls %p)", code, branch.ptr); @@ -402,7 +425,7 @@ void ARMXEmitter::SetJumpTarget(FixupBranch const &branch) void ARMXEmitter::B (const void *fnptr) { s32 distance = (s32)fnptr - (s32(code) + 8); - _assert_msg_(DYNA_REC, distance > -33554432 + _dbg_assert_msg_(DYNA_REC, distance > -33554432 && distance <= 33554432, "B out of range (%p calls %p)", code, fnptr); @@ -414,10 +437,18 @@ void ARMXEmitter::B(ARMReg src) Write32(condition | 0x12FFF10 | src); } +bool ARMXEmitter::BLInRange(const void *fnptr) { + s32 distance = (s32)fnptr - (s32(code) + 8); + if (distance <= -33554432 || distance > 33554432) + return false; + else + return true; +} + void ARMXEmitter::BL(const void *fnptr) { s32 distance = (s32)fnptr - (s32(code) + 8); - _assert_msg_(DYNA_REC, distance > -33554432 + _dbg_assert_msg_(DYNA_REC, distance > -33554432 && distance <= 33554432, "BL out of range (%p calls %p)", code, fnptr); Write32(condition | 0x0B000000 | ((distance >> 2) & 0x00FFFFFF)); @@ -555,7 +586,7 @@ void ARMXEmitter::WriteInstruction (u32 Op, ARMReg Rd, ARMReg Rn, Operand2 Rm, b } } if (op == -1) - _assert_msg_(DYNA_REC, false, "%s not yet support %d", InstNames[Op], Rm.GetType()); + _dbg_assert_msg_(DYNA_REC, false, "%s not yet support %d", InstNames[Op], Rm.GetType()); Write32(condition | (op << 21) | (SetFlags ? (1 << 20) : 0) | Rn << 16 | Rd << 12 | Data); } @@ -581,6 +612,8 @@ void ARMXEmitter::LSLS(ARMReg dest, ARMReg src, Operand2 op2) { WriteShiftedData void ARMXEmitter::LSL (ARMReg dest, ARMReg src, ARMReg op2) { WriteShiftedDataOp(1, false, dest, src, op2);} void ARMXEmitter::LSLS(ARMReg dest, ARMReg src, ARMReg op2) { WriteShiftedDataOp(1, true, dest, src, op2);} void ARMXEmitter::LSR (ARMReg dest, ARMReg src, Operand2 op2) { WriteShiftedDataOp(3, false, dest, src, op2);} +void ARMXEmitter::ASR (ARMReg dest, ARMReg src, Operand2 op2) { WriteShiftedDataOp(4, false, dest, src, op2);} +void ARMXEmitter::ASRS(ARMReg dest, ARMReg src, Operand2 op2) { WriteShiftedDataOp(4, true, dest, src, op2);} void ARMXEmitter::MUL (ARMReg dest, ARMReg src, ARMReg op2) { Write32(condition | (dest << 16) | (src << 8) | (9 << 4) | op2); @@ -599,6 +632,11 @@ void ARMXEmitter::UMULL(ARMReg destLo, ARMReg destHi, ARMReg rm, ARMReg rn) Write4OpMultiply(0x8, destLo, destHi, rn, rm); } +void ARMXEmitter::UMULLS(ARMReg destLo, ARMReg destHi, ARMReg rm, ARMReg rn) +{ + Write4OpMultiply(0x9, destLo, destHi, rn, rm); +} + void ARMXEmitter::SMULL(ARMReg destLo, ARMReg destHi, ARMReg rm, ARMReg rn) { Write4OpMultiply(0xC, destLo, destHi, rn, rm); @@ -652,11 +690,11 @@ void ARMXEmitter::RBIT(ARMReg dest, ARMReg src) } void ARMXEmitter::REV (ARMReg dest, ARMReg src) { - Write32(condition | (0x6B << 20) | (0xF << 16) | (dest << 12) | (0xF3 << 4) | src); + Write32(condition | (0x6BF << 16) | (dest << 12) | (0xF3 << 4) | src); } void ARMXEmitter::REV16(ARMReg dest, ARMReg src) { - Write32(condition | (0x3DF << 16) | (dest << 12) | (0xFD << 4) | src); + Write32(condition | (0x6BF << 16) | (dest << 12) | (0xFB << 4) | src); } void ARMXEmitter::_MSR (bool write_nzcvq, bool write_g, Operand2 op2) @@ -677,7 +715,7 @@ void ARMXEmitter::LDREX(ARMReg dest, ARMReg base) } void ARMXEmitter::STREX(ARMReg result, ARMReg base, ARMReg op) { - _assert_msg_(DYNA_REC, (result != base && result != op), "STREX dest can't be other two registers"); + _dbg_assert_msg_(DYNA_REC, (result != base && result != op), "STREX dest can't be other two registers"); Write32(condition | (24 << 20) | (base << 16) | (result << 12) | (0xF9 << 4) | op); } void ARMXEmitter::DMB () @@ -730,7 +768,7 @@ void ARMXEmitter::WriteStoreOp(u32 Op, ARMReg Rt, ARMReg Rn, Operand2 Rm, bool R bool SignedLoad = false; if (op == -1) - _assert_msg_(DYNA_REC, false, "%s does not support %d", LoadStoreNames[Op], Rm.GetType()); + _dbg_assert_msg_(DYNA_REC, false, "%s does not support %d", LoadStoreNames[Op], Rm.GetType()); switch (Op) { @@ -854,10 +892,25 @@ ARMReg ARMXEmitter::SubBase(ARMReg Reg) } // NEON Specific +void ARMXEmitter::VABD(IntegerSize Size, ARMReg Vd, ARMReg Vn, ARMReg Vm) +{ + _dbg_assert_msg_(DYNA_REC, Vd >= D0, "Pass invalid register to VABD(float)"); + _dbg_assert_msg_(DYNA_REC, cpu_info.bNEON, "Can't use VABD(float) when CPU doesn't support it"); + bool register_quad = Vd >= Q0; + + // Gets encoded as a double register + Vd = SubBase(Vd); + Vn = SubBase(Vn); + Vm = SubBase(Vm); + + Write32((0xF3 << 24) | ((Vd & 0x10) << 18) | (Size << 20) | ((Vn & 0xF) << 16) \ + | ((Vd & 0xF) << 12) | (0xD << 8) | ((Vn & 0x10) << 3) | (register_quad << 6) \ + | ((Vm & 0x10) << 2) | (Vm & 0xF)); +} void ARMXEmitter::VADD(IntegerSize Size, ARMReg Vd, ARMReg Vn, ARMReg Vm) { - _assert_msg_(DYNA_REC, Vd >= D0, "Pass invalid register to VADD(integer)"); - _assert_msg_(DYNA_REC, cpu_info.bNEON, "Can't use VADD(integer) when CPU doesn't support it"); + _dbg_assert_msg_(DYNA_REC, Vd >= D0, "Pass invalid register to VADD(integer)"); + _dbg_assert_msg_(DYNA_REC, cpu_info.bNEON, "Can't use VADD(integer) when CPU doesn't support it"); bool register_quad = Vd >= Q0; @@ -868,13 +921,13 @@ void ARMXEmitter::VADD(IntegerSize Size, ARMReg Vd, ARMReg Vn, ARMReg Vm) Write32((0xF2 << 24) | ((Vd & 0x10) << 18) | (Size << 20) | ((Vn & 0xF) << 16) \ | ((Vd & 0xF) << 12) | (0x8 << 8) | ((Vn & 0x10) << 3) | (register_quad << 6) \ - | ((Vm & 0x10) << 1) | (Vm & 0xF)); + | ((Vm & 0x10) << 1) | (Vm & 0xF)); } void ARMXEmitter::VSUB(IntegerSize Size, ARMReg Vd, ARMReg Vn, ARMReg Vm) { - _assert_msg_(DYNA_REC, Vd >= Q0, "Pass invalid register to VSUB(integer)"); - _assert_msg_(DYNA_REC, cpu_info.bNEON, "Can't use VSUB(integer) when CPU doesn't support it"); + _dbg_assert_msg_(DYNA_REC, Vd >= Q0, "Pass invalid register to VSUB(integer)"); + _dbg_assert_msg_(DYNA_REC, cpu_info.bNEON, "Can't use VSUB(integer) when CPU doesn't support it"); // Gets encoded as a double register Vd = SubBase(Vd); @@ -883,36 +936,37 @@ void ARMXEmitter::VSUB(IntegerSize Size, ARMReg Vd, ARMReg Vn, ARMReg Vm) Write32((0xF3 << 24) | ((Vd & 0x10) << 18) | (Size << 20) | ((Vn & 0xF) << 16) \ | ((Vd & 0xF) << 12) | (0x8 << 8) | ((Vn & 0x10) << 3) | (1 << 6) \ - | ((Vm & 0x10) << 2) | (Vm & 0xF)); + | ((Vm & 0x10) << 2) | (Vm & 0xF)); } -// VFP Specific -struct VFPEnc -{ - s16 opc1; - s16 opc2; -}; // Double/single, Neon -const VFPEnc VFPOps[][2] = { +extern const VFPEnc VFPOps[16][2] = { {{0xE0, 0xA0}, {0x20, 0xD1}}, // 0: VMLA - {{0xE0, 0xA4}, {0x22, 0xD1}}, // 1: VMLS - {{0xE3, 0xA0}, {0x20, 0xD0}}, // 2: VADD - {{0xE3, 0xA4}, {0x22, 0xD0}}, // 3: VSUB - {{0xE2, 0xA0}, {0x30, 0xD1}}, // 4: VMUL - {{0xEB, 0xAC}, { -1 /* 0x3B */, -1 /* 0x70 */}}, // 5: VABS(Vn(0x0) used for encoding) - {{0xE8, 0xA0}, { -1, -1}}, // 6: VDIV - {{0xEB, 0xA4}, { -1 /* 0x3B */, -1 /* 0x78 */}}, // 7: VNEG(Vn(0x1) used for encoding) - {{0xEB, 0xAC}, { -1, -1}}, // 8: VSQRT (Vn(0x1) used for encoding) - {{0xEB, 0xA4}, { -1, -1}}, // 9: VCMP (Vn(0x4 | #0 ? 1 : 0) used for encoding) - {{0xEB, 0xAC}, { -1, -1}}, // 10: VCMPE (Vn(0x4 | #0 ? 1 : 0) used for encoding) - {{ -1, -1}, {0x3B, 0x30}}, // 11: VABSi + {{0xE1, 0xA4}, { -1, -1}}, // 1: VNMLA + {{0xE0, 0xA4}, {0x22, 0xD1}}, // 2: VMLS + {{0xE1, 0xA0}, { -1, -1}}, // 3: VNMLS + {{0xE3, 0xA0}, {0x20, 0xD0}}, // 4: VADD + {{0xE3, 0xA4}, {0x22, 0xD0}}, // 5: VSUB + {{0xE2, 0xA0}, {0x30, 0xD1}}, // 6: VMUL + {{0xE2, 0xA4}, { -1, -1}}, // 7: VNMUL + {{0xEB, 0xAC}, { -1 /* 0x3B */, -1 /* 0x70 */}}, // 8: VABS(Vn(0x0) used for encoding) + {{0xE8, 0xA0}, { -1, -1}}, // 9: VDIV + {{0xEB, 0xA4}, { -1 /* 0x3B */, -1 /* 0x78 */}}, // 10: VNEG(Vn(0x1) used for encoding) + {{0xEB, 0xAC}, { -1, -1}}, // 11: VSQRT (Vn(0x1) used for encoding) + {{0xEB, 0xA4}, { -1, -1}}, // 12: VCMP (Vn(0x4 | #0 ? 1 : 0) used for encoding) + {{0xEB, 0xAC}, { -1, -1}}, // 13: VCMPE (Vn(0x4 | #0 ? 1 : 0) used for encoding) + {{ -1, -1}, {0x3B, 0x30}}, // 14: VABSi }; -const char *VFPOpNames[] = { + +extern const char *VFPOpNames[16] = { "VMLA", + "VNMLA", "VMLS", + "VNMLS", "VADD", "VSUB", "VMUL", + "VNMUL", "VABS", "VDIV", "VNEG", @@ -966,6 +1020,7 @@ u32 ARMXEmitter::EncodeVm(ARMReg Vm) else return ((Reg & 0x1) << 5) | (Reg >> 1); } + void ARMXEmitter::WriteVFPDataOp(u32 Op, ARMReg Vd, ARMReg Vn, ARMReg Vm) { bool quad_reg = Vd >= Q0; @@ -973,39 +1028,42 @@ void ARMXEmitter::WriteVFPDataOp(u32 Op, ARMReg Vd, ARMReg Vn, ARMReg Vm) VFPEnc enc = VFPOps[Op][quad_reg]; if (enc.opc1 == -1 && enc.opc2 == -1) - _assert_msg_(DYNA_REC, false, "%s does not support %s", VFPOpNames[Op], quad_reg ? "NEON" : "VFP"); + _dbg_assert_msg_(DYNA_REC, false, "%s does not support %s", VFPOpNames[Op], quad_reg ? "NEON" : "VFP"); u32 VdEnc = EncodeVd(Vd); u32 VnEnc = EncodeVn(Vn); u32 VmEnc = EncodeVm(Vm); u32 cond = quad_reg ? (0xF << 28) : condition; - + Write32(cond | (enc.opc1 << 20) | VnEnc | VdEnc | (enc.opc2 << 4) | (quad_reg << 6) | (double_reg << 8) | VmEnc); } void ARMXEmitter::VMLA(ARMReg Vd, ARMReg Vn, ARMReg Vm){ WriteVFPDataOp(0, Vd, Vn, Vm); } -void ARMXEmitter::VMLS(ARMReg Vd, ARMReg Vn, ARMReg Vm){ WriteVFPDataOp(1, Vd, Vn, Vm); } -void ARMXEmitter::VADD(ARMReg Vd, ARMReg Vn, ARMReg Vm){ WriteVFPDataOp(2, Vd, Vn, Vm); } -void ARMXEmitter::VSUB(ARMReg Vd, ARMReg Vn, ARMReg Vm){ WriteVFPDataOp(3, Vd, Vn, Vm); } -void ARMXEmitter::VMUL(ARMReg Vd, ARMReg Vn, ARMReg Vm){ WriteVFPDataOp(4, Vd, Vn, Vm); } -void ARMXEmitter::VABS(ARMReg Vd, ARMReg Vm){ WriteVFPDataOp(5, Vd, D0, Vm); } -void ARMXEmitter::VDIV(ARMReg Vd, ARMReg Vn, ARMReg Vm){ WriteVFPDataOp(6, Vd, Vn, Vm); } -void ARMXEmitter::VNEG(ARMReg Vd, ARMReg Vm){ WriteVFPDataOp(7, Vd, D1, Vm); } -void ARMXEmitter::VSQRT(ARMReg Vd, ARMReg Vm){ WriteVFPDataOp(8, Vd, D1, Vm); } -void ARMXEmitter::VCMP(ARMReg Vd, ARMReg Vm){ WriteVFPDataOp(9, Vd, D4, Vm); } -void ARMXEmitter::VCMPE(ARMReg Vd, ARMReg Vm){ WriteVFPDataOp(10, Vd, D4, Vm); } -void ARMXEmitter::VCMP(ARMReg Vd){ WriteVFPDataOp(9, Vd, D5, D0); } -void ARMXEmitter::VCMPE(ARMReg Vd){ WriteVFPDataOp(10, Vd, D5, D0); } +void ARMXEmitter::VNMLA(ARMReg Vd, ARMReg Vn, ARMReg Vm){ WriteVFPDataOp(1, Vd, Vn, Vm); } +void ARMXEmitter::VMLS(ARMReg Vd, ARMReg Vn, ARMReg Vm){ WriteVFPDataOp(2, Vd, Vn, Vm); } +void ARMXEmitter::VNMLS(ARMReg Vd, ARMReg Vn, ARMReg Vm){ WriteVFPDataOp(3, Vd, Vn, Vm); } +void ARMXEmitter::VADD(ARMReg Vd, ARMReg Vn, ARMReg Vm){ WriteVFPDataOp(4, Vd, Vn, Vm); } +void ARMXEmitter::VSUB(ARMReg Vd, ARMReg Vn, ARMReg Vm){ WriteVFPDataOp(5, Vd, Vn, Vm); } +void ARMXEmitter::VMUL(ARMReg Vd, ARMReg Vn, ARMReg Vm){ WriteVFPDataOp(6, Vd, Vn, Vm); } +void ARMXEmitter::VNMUL(ARMReg Vd, ARMReg Vn, ARMReg Vm){ WriteVFPDataOp(7, Vd, Vn, Vm); } +void ARMXEmitter::VABS(ARMReg Vd, ARMReg Vm){ WriteVFPDataOp(8, Vd, D0, Vm); } +void ARMXEmitter::VDIV(ARMReg Vd, ARMReg Vn, ARMReg Vm){ WriteVFPDataOp(9, Vd, Vn, Vm); } +void ARMXEmitter::VNEG(ARMReg Vd, ARMReg Vm){ WriteVFPDataOp(10, Vd, D1, Vm); } +void ARMXEmitter::VSQRT(ARMReg Vd, ARMReg Vm){ WriteVFPDataOp(11, Vd, D1, Vm); } +void ARMXEmitter::VCMP(ARMReg Vd, ARMReg Vm){ WriteVFPDataOp(12, Vd, D4, Vm); } +void ARMXEmitter::VCMPE(ARMReg Vd, ARMReg Vm){ WriteVFPDataOp(13, Vd, D4, Vm); } +void ARMXEmitter::VCMP(ARMReg Vd){ WriteVFPDataOp(12, Vd, D5, D0); } +void ARMXEmitter::VCMPE(ARMReg Vd){ WriteVFPDataOp(13, Vd, D5, D0); } void ARMXEmitter::VLDR(ARMReg Dest, ARMReg Base, s16 offset) { - _assert_msg_(DYNA_REC, Dest >= S0 && Dest <= D31, "Passed Invalid dest register to VLDR"); - _assert_msg_(DYNA_REC, Base <= R15, "Passed invalid Base register to VLDR"); + _dbg_assert_msg_(DYNA_REC, Dest >= S0 && Dest <= D31, "Passed Invalid dest register to VLDR"); + _dbg_assert_msg_(DYNA_REC, Base <= R15, "Passed invalid Base register to VLDR"); bool Add = offset >= 0 ? true : false; u32 imm = abs(offset); - _assert_msg_(DYNA_REC, (imm & 0xC03) == 0, "VLDR: Offset needs to be word aligned and small enough"); + _dbg_assert_msg_(DYNA_REC, (imm & 0xC03) == 0, "VLDR: Offset needs to be word aligned and small enough"); - if (imm & 0xC03) + if (imm & 0xC03) ERROR_LOG(DYNA_REC, "VLDR: Bad offset %08x", imm); bool single_reg = Dest < D0; @@ -1015,25 +1073,25 @@ void ARMXEmitter::VLDR(ARMReg Dest, ARMReg Base, s16 offset) if (single_reg) { Write32(condition | (0xD << 24) | (Add << 23) | ((Dest & 0x1) << 22) | (1 << 20) | (Base << 16) \ - | ((Dest & 0x1E) << 11) | (10 << 8) | (imm >> 2)); + | ((Dest & 0x1E) << 11) | (10 << 8) | (imm >> 2)); } else { Write32(condition | (0xD << 24) | (Add << 23) | ((Dest & 0x10) << 18) | (1 << 20) | (Base << 16) \ - | ((Dest & 0xF) << 12) | (11 << 8) | (imm >> 2)); + | ((Dest & 0xF) << 12) | (11 << 8) | (imm >> 2)); } } void ARMXEmitter::VSTR(ARMReg Src, ARMReg Base, s16 offset) { - _assert_msg_(DYNA_REC, Src >= S0 && Src <= D31, "Passed invalid src register to VSTR"); - _assert_msg_(DYNA_REC, Base <= R15, "Passed invalid base register to VSTR"); + _dbg_assert_msg_(DYNA_REC, Src >= S0 && Src <= D31, "Passed invalid src register to VSTR"); + _dbg_assert_msg_(DYNA_REC, Base <= R15, "Passed invalid base register to VSTR"); bool Add = offset >= 0 ? true : false; u32 imm = abs(offset); - _assert_msg_(DYNA_REC, (imm & 0xC03) == 0, "VSTR: Offset needs to be word aligned and small enough"); + _dbg_assert_msg_(DYNA_REC, (imm & 0xC03) == 0, "VSTR: Offset needs to be word aligned and small enough"); - if (imm & 0xC03) + if (imm & 0xC03) ERROR_LOG(DYNA_REC, "VSTR: Bad offset %08x", imm); bool single_reg = Src < D0; @@ -1043,12 +1101,12 @@ void ARMXEmitter::VSTR(ARMReg Src, ARMReg Base, s16 offset) if (single_reg) { Write32(condition | (0xD << 24) | (Add << 23) | ((Src & 0x1) << 22) | (Base << 16) \ - | ((Src & 0x1E) << 11) | (10 << 8) | (imm >> 2)); + | ((Src & 0x1E) << 11) | (10 << 8) | (imm >> 2)); } else { Write32(condition | (0xD << 24) | (Add << 23) | ((Src & 0x10) << 18) | (Base << 16) \ - | ((Src & 0xF) << 12) | (11 << 8) | (imm >> 2)); + | ((Src & 0xF) << 12) | (11 << 8) | (imm >> 2)); } } @@ -1063,15 +1121,20 @@ void ARMXEmitter::VMSR(ARMReg Rt) { } // VFP and ASIMD +void ARMXEmitter::VMOV(ARMReg Dest, Operand2 op2) +{ + _dbg_assert_msg_(DYNA_REC, cpu_info.bVFPv3, "VMOV #imm requires VFPv3"); + Write32(condition | (0xEB << 20) | EncodeVd(Dest) | (0xA << 8) | op2.Imm8VFP()); +} void ARMXEmitter::VMOV(ARMReg Dest, ARMReg Src, bool high) { - _assert_msg_(DYNA_REC, Src < S0, "This VMOV doesn't support SRC other than ARM Reg"); - _assert_msg_(DYNA_REC, Dest >= D0, "This VMOV doesn't support DEST other than VFP"); + _dbg_assert_msg_(DYNA_REC, Src < S0, "This VMOV doesn't support SRC other than ARM Reg"); + _dbg_assert_msg_(DYNA_REC, Dest >= D0, "This VMOV doesn't support DEST other than VFP"); Dest = SubBase(Dest); Write32(condition | (0xE << 24) | (high << 21) | ((Dest & 0xF) << 16) | (Src << 12) \ - | (11 << 8) | ((Dest & 0x10) << 3) | (1 << 4)); + | (0xB << 8) | ((Dest & 0x10) << 3) | (1 << 4)); } void ARMXEmitter::VMOV(ARMReg Dest, ARMReg Src) @@ -1091,7 +1154,7 @@ void ARMXEmitter::VMOV(ARMReg Dest, ARMReg Src) else { // Move 64bit from Arm reg - _assert_msg_(DYNA_REC, false, "This VMOV doesn't support moving 64bit ARM to NEON"); + _dbg_assert_msg_(DYNA_REC, false, "This VMOV doesn't support moving 64bit ARM to NEON"); return; } } @@ -1111,14 +1174,14 @@ void ARMXEmitter::VMOV(ARMReg Dest, ARMReg Src) else { // Move 64bit To Arm reg - _assert_msg_(DYNA_REC, false, "This VMOV doesn't support moving 64bit ARM From NEON"); + _dbg_assert_msg_(DYNA_REC, false, "This VMOV doesn't support moving 64bit ARM From NEON"); return; } } else { // Move Arm reg to Arm reg - _assert_msg_(DYNA_REC, false, "VMOV doesn't support moving ARM registers"); + _dbg_assert_msg_(DYNA_REC, false, "VMOV doesn't support moving ARM registers"); } } // Moving NEON registers @@ -1127,7 +1190,7 @@ void ARMXEmitter::VMOV(ARMReg Dest, ARMReg Src) bool Single = DestSize == 1; bool Quad = DestSize == 4; - _assert_msg_(DYNA_REC, SrcSize == DestSize, "VMOV doesn't support moving different register sizes"); + _dbg_assert_msg_(DYNA_REC, SrcSize == DestSize, "VMOV doesn't support moving different register sizes"); Dest = SubBase(Dest); Src = SubBase(Src); @@ -1142,7 +1205,7 @@ void ARMXEmitter::VMOV(ARMReg Dest, ARMReg Src) // Double and quad if (Quad) { - _assert_msg_(DYNA_REC, cpu_info.bNEON, "Trying to use quad registers when you don't support ASIMD."); + _dbg_assert_msg_(DYNA_REC, cpu_info.bNEON, "Trying to use quad registers when you don't support ASIMD."); // Gets encoded as a Double register Write32((0xF2 << 24) | ((Dest & 0x10) << 18) | (2 << 20) | ((Src & 0xF) << 16) \ | ((Dest & 0xF) << 12) | (1 << 8) | ((Src & 0x10) << 3) | (1 << 6) \ @@ -1160,13 +1223,39 @@ void ARMXEmitter::VMOV(ARMReg Dest, ARMReg Src) void ARMXEmitter::VCVT(ARMReg Dest, ARMReg Source, int flags) { bool single_reg = (Dest < D0) && (Source < D0); + bool single_double = !single_reg && (Source < D0 || Dest < D0); + bool single_to_double = Source < D0; int op = ((flags & TO_INT) ? (flags & ROUND_TO_ZERO) : (flags & IS_SIGNED)) ? 1 : 0; int op2 = ((flags & TO_INT) ? (flags & IS_SIGNED) : 0) ? 1 : 0; Dest = SubBase(Dest); Source = SubBase(Source); - if (single_reg) + if (single_double) { + // S32<->F64 + if ((flags & TO_INT) || (flags & TO_FLOAT)) + { + if (single_to_double) + { + Write32(condition | (0x1D << 23) | ((Dest & 0x10) << 18) | (0x7 << 19) \ + | ((Dest & 0xF) << 12) | (op << 7) | (0x2D << 6) | ((Source & 0x1) << 5) | (Source >> 1)); + } else { + Write32(condition | (0x1D << 23) | ((Dest & 0x1) << 22) | (0x7 << 19) | ((flags & TO_INT) << 18) | (op2 << 16) \ + | ((Dest & 0x1E) << 11) | (op << 7) | (0x2D << 6) | ((Source & 0x10) << 1) | (Source & 0xF)); + } + } + // F32<->F64 + else { + if (single_to_double) + { + Write32(condition | (0x1D << 23) | ((Dest & 0x10) << 18) | (0x3 << 20) | (0x7 << 16) \ + | ((Dest & 0xF) << 12) | (0x2B << 6) | ((Source & 0x1) << 5) | (Source >> 1)); + } else { + Write32(condition | (0x1D << 23) | ((Dest & 0x1) << 22) | (0x3 << 20) | (0x7 << 16) \ + | ((Dest & 0x1E) << 11) | (0x2F << 6) | ((Source & 0x10) << 1) | (Source & 0xF)); + } + } + } else if (single_reg) { Write32(condition | (0x1D << 23) | ((Dest & 0x1) << 22) | (0x7 << 19) | ((flags & TO_INT) << 18) | (op2 << 16) \ | ((Dest & 0x1E) << 11) | (op << 7) | (0x29 << 6) | ((Source & 0x1) << 5) | (Source >> 1)); } else { diff --git a/Source/Core/Common/Src/ArmEmitter.h b/Source/Core/Common/Src/ArmEmitter.h index b3fab39c40..1592da7d4f 100644 --- a/Source/Core/Common/Src/ArmEmitter.h +++ b/Source/Core/Common/Src/ArmEmitter.h @@ -365,7 +365,7 @@ private: u32 EncodeVn(ARMReg Vn); u32 EncodeVm(ARMReg Vm); void WriteVFPDataOp(u32 Op, ARMReg Vd, ARMReg Vn, ARMReg Vm); - + void Write4OpMultiply(u32 op, ARMReg destLo, ARMReg destHi, ARMReg rn, ARMReg rm); // New Ops @@ -431,6 +431,7 @@ public: void B (ARMReg src); void BL(const void *fnptr); void BL(ARMReg src); + bool BLInRange(const void *fnptr); void PUSH(const int num, ...); void POP(const int num, ...); @@ -453,6 +454,8 @@ public: void LSLS(ARMReg dest, ARMReg src, Operand2 op2); void LSLS(ARMReg dest, ARMReg src, ARMReg op2); void LSR (ARMReg dest, ARMReg src, Operand2 op2); + void ASR (ARMReg dest, ARMReg src, Operand2 op2); + void ASRS(ARMReg dest, ARMReg src, Operand2 op2); void SBC (ARMReg dest, ARMReg src, Operand2 op2); void SBCS(ARMReg dest, ARMReg src, Operand2 op2); void RBIT(ARMReg dest, ARMReg src); @@ -484,6 +487,7 @@ public: void MULS(ARMReg dest, ARMReg src, ARMReg op2); void UMULL(ARMReg destLo, ARMReg destHi, ARMReg rn, ARMReg rm); + void UMULLS(ARMReg destLo, ARMReg destHi, ARMReg rn, ARMReg rm); void SMULL(ARMReg destLo, ARMReg destHi, ARMReg rn, ARMReg rm); void UMLAL(ARMReg destLo, ARMReg destHi, ARMReg rn, ARMReg rm); @@ -530,6 +534,7 @@ public: // Subtracts the base from the register to give us the real one ARMReg SubBase(ARMReg Reg); // NEON Only + void VABD(IntegerSize Size, ARMReg Vd, ARMReg Vn, ARMReg Vm); void VADD(IntegerSize Size, ARMReg Vd, ARMReg Vn, ARMReg Vm); void VSUB(IntegerSize Size, ARMReg Vd, ARMReg Vn, ARMReg Vm); @@ -541,6 +546,10 @@ public: // Compares against zero void VCMP(ARMReg Vd); void VCMPE(ARMReg Vd); + + void VNMLA(ARMReg Vd, ARMReg Vn, ARMReg Vm); + void VNMLS(ARMReg Vd, ARMReg Vn, ARMReg Vm); + void VNMUL(ARMReg Vd, ARMReg Vn, ARMReg Vm); void VDIV(ARMReg Vd, ARMReg Vn, ARMReg Vm); void VSQRT(ARMReg Vd, ARMReg Vm); @@ -552,6 +561,7 @@ public: void VMUL(ARMReg Vd, ARMReg Vn, ARMReg Vm); void VMLA(ARMReg Vd, ARMReg Vn, ARMReg Vm); void VMLS(ARMReg Vd, ARMReg Vn, ARMReg Vm); + void VMOV(ARMReg Dest, Operand2 op2); void VMOV(ARMReg Dest, ARMReg Src, bool high); void VMOV(ARMReg Dest, ARMReg Src); void VCVT(ARMReg Dest, ARMReg Src, int flags); @@ -564,7 +574,7 @@ public: // Wrapper around MOVT/MOVW with fallbacks. void MOVI2R(ARMReg reg, u32 val, bool optimize = true); - void MOVI2F(ARMReg dest, float val, ARMReg tempReg); + void MOVI2F(ARMReg dest, float val, ARMReg tempReg, bool negate = false); void ADDI2R(ARMReg rd, ARMReg rs, u32 val, ARMReg scratch); void ANDI2R(ARMReg rd, ARMReg rs, u32 val, ARMReg scratch); @@ -624,7 +634,11 @@ public: // Start over if you need to change the code (call FreeCodeSpace(), AllocCodeSpace()). void WriteProtect() { - WriteProtectMemory(region, region_size, true); + WriteProtectMemory(region, region_size, true); + } + void UnWriteProtect() + { + UnWriteProtectMemory(region, region_size, false); } void ResetCodePtr() @@ -636,7 +650,23 @@ public: { return region_size - (GetCodePtr() - region); } + + u8 *GetBasePtr() { + return region; + } + + size_t GetOffset(u8 *ptr) { + return ptr - region; + } +}; + +// VFP Specific +struct VFPEnc { + s16 opc1; + s16 opc2; }; +extern const VFPEnc VFPOps[16][2]; +extern const char *VFPOpNames[16]; } // namespace diff --git a/Source/Core/Common/Src/ExtendedTrace.cpp b/Source/Core/Common/Src/ExtendedTrace.cpp index 85057639a5..08740c3c95 100644 --- a/Source/Core/Common/Src/ExtendedTrace.cpp +++ b/Source/Core/Common/Src/ExtendedTrace.cpp @@ -136,7 +136,6 @@ static BOOL GetModuleNameFromAddress( UINT address, LPTSTR lpszModule ) static BOOL GetFunctionInfoFromAddresses( ULONG fnAddress, ULONG stackAddress, LPTSTR lpszSymbol ) { BOOL ret = FALSE; - DWORD dwDisp = 0; DWORD dwSymSize = 10000; TCHAR lpszUnDSymbol[BUFFERSIZE]=_T("?"); CHAR lpszNonUnicodeUnDSymbol[BUFFERSIZE]="?"; @@ -153,9 +152,11 @@ static BOOL GetFunctionInfoFromAddresses( ULONG fnAddress, ULONG stackAddress, L // Get symbol info for IP #ifndef _M_X64 + DWORD dwDisp = 0; if ( SymGetSymFromAddr( GetCurrentProcess(), (ULONG)fnAddress, &dwDisp, pSym ) ) #else //makes it compile but hell im not sure if this works... + DWORD64 dwDisp = 0; if ( SymGetSymFromAddr( GetCurrentProcess(), (ULONG)fnAddress, (PDWORD64)&dwDisp, pSym ) ) #endif { diff --git a/Source/Core/Common/Src/IniFile.cpp b/Source/Core/Common/Src/IniFile.cpp index 0b265543de..2eca8df929 100644 --- a/Source/Core/Common/Src/IniFile.cpp +++ b/Source/Core/Common/Src/IniFile.cpp @@ -20,45 +20,30 @@ namespace { -static void ParseLine(const std::string& line, std::string* keyOut, std::string* valueOut, std::string* commentOut) +static void ParseLine(const std::string& line, std::string* keyOut, std::string* valueOut) { - int FirstEquals = (int)line.find("=", 0); - int FirstCommentChar = -1; - - // Comments - if (FirstCommentChar < 0) - FirstCommentChar = - (int)line.find("#", FirstEquals > 0 ? FirstEquals : 0); - if (FirstCommentChar < 0 && line[0] == ';') - FirstCommentChar = 0; + if (line[0] == '#') + return; - // Allow preservation of spacing before comment - if (FirstCommentChar > 0) - { - while (line[FirstCommentChar - 1] == ' ' || line[FirstCommentChar - 1] == 9) // 9 == tab - { - FirstCommentChar--; - } - } + int FirstEquals = (int)line.find("=", 0); - if ((FirstEquals >= 0) && ((FirstCommentChar < 0) || (FirstEquals < FirstCommentChar))) + if (FirstEquals >= 0) { // Yes, a valid line! *keyOut = StripSpaces(line.substr(0, FirstEquals)); - if (commentOut) *commentOut = FirstCommentChar > 0 ? line.substr(FirstCommentChar) : std::string(""); - if (valueOut) *valueOut = StripQuotes(StripSpaces(line.substr(FirstEquals + 1, FirstCommentChar - FirstEquals - 1))); + if (valueOut) *valueOut = StripQuotes(StripSpaces(line.substr(FirstEquals + 1, std::string::npos))); } } } -std::string* IniFile::Section::GetLine(const char* key, std::string* valueOut, std::string* commentOut) +std::string* IniFile::Section::GetLine(const char* key, std::string* valueOut) { for (std::vector<std::string>::iterator iter = lines.begin(); iter != lines.end(); ++iter) { std::string& line = *iter; std::string lineKey; - ParseLine(line, &lineKey, valueOut, commentOut); + ParseLine(line, &lineKey, valueOut); if (!strcasecmp(lineKey.c_str(), key)) return &line; } @@ -67,12 +52,12 @@ std::string* IniFile::Section::GetLine(const char* key, std::string* valueOut, s void IniFile::Section::Set(const char* key, const char* newValue) { - std::string value, commented; - std::string* line = GetLine(key, &value, &commented); + std::string value; + std::string* line = GetLine(key, &value); if (line) { // Change the value - keep the key and comment - *line = StripSpaces(key) + " = " + newValue + commented; + *line = StripSpaces(key) + " = " + newValue; } else { @@ -91,7 +76,7 @@ void IniFile::Section::Set(const char* key, const std::string& newValue, const s bool IniFile::Section::Get(const char* key, std::string* value, const char* defaultValue) { - std::string* line = GetLine(key, value, 0); + std::string* line = GetLine(key, value); if (!line) { if (defaultValue) @@ -224,7 +209,7 @@ bool IniFile::Section::Exists(const char *key) const for (std::vector<std::string>::const_iterator iter = lines.begin(); iter != lines.end(); ++iter) { std::string lineKey; - ParseLine(*iter, &lineKey, NULL, NULL); + ParseLine(*iter, &lineKey, NULL); if (!strcasecmp(lineKey.c_str(), key)) return true; } @@ -233,7 +218,7 @@ bool IniFile::Section::Exists(const char *key) const bool IniFile::Section::Delete(const char *key) { - std::string* line = GetLine(key, 0, 0); + std::string* line = GetLine(key, 0); for (std::vector<std::string>::iterator liter = lines.begin(); liter != lines.end(); ++liter) { if (line == &*liter) @@ -313,7 +298,7 @@ bool IniFile::DeleteKey(const char* sectionName, const char* key) Section* section = GetSection(sectionName); if (!section) return false; - std::string* line = section->GetLine(key, 0, 0); + std::string* line = section->GetLine(key, 0); for (std::vector<std::string>::iterator liter = section->lines.begin(); liter != section->lines.end(); ++liter) { if (line == &(*liter)) @@ -335,7 +320,7 @@ bool IniFile::GetKeys(const char* sectionName, std::vector<std::string>& keys) c for (std::vector<std::string>::const_iterator liter = section->lines.begin(); liter != section->lines.end(); ++liter) { std::string key; - ParseLine(*liter, &key, 0, 0); + ParseLine(*liter, &key, 0); keys.push_back(key); } return true; @@ -421,11 +406,6 @@ bool IniFile::Load(const char* filename) // New section! std::string sub = line.substr(1, endpos - 1); sections.push_back(Section(sub)); - - if (endpos + 1 < line.size()) - { - sections[sections.size() - 1].comment = line.substr(endpos + 1); - } } } else @@ -459,7 +439,7 @@ bool IniFile::Save(const char* filename) if (section.name != "") { - out << "[" << section.name << "]" << section.comment << std::endl; + out << "[" << section.name << "]" << std::endl; } for (std::vector<std::string>::const_iterator liter = section.lines.begin(); liter != section.lines.end(); ++liter) diff --git a/Source/Core/Common/Src/IniFile.h b/Source/Core/Common/Src/IniFile.h index 10e1cfdbb9..bad26ca090 100644 --- a/Source/Core/Common/Src/IniFile.h +++ b/Source/Core/Common/Src/IniFile.h @@ -25,7 +25,7 @@ public: bool Exists(const char *key) const; bool Delete(const char *key); - std::string* GetLine(const char* key, std::string* valueOut, std::string* commentOut); + std::string* GetLine(const char* key, std::string* valueOut); void Set(const char* key, const char* newValue); void Set(const char* key, const std::string& newValue, const std::string& defaultValue); @@ -70,7 +70,6 @@ public: protected: std::vector<std::string> lines; std::string name; - std::string comment; }; bool Load(const char* filename); diff --git a/Source/Core/Common/Src/MemArena.cpp b/Source/Core/Common/Src/MemArena.cpp index 487788dc45..b7400a978e 100644 --- a/Source/Core/Common/Src/MemArena.cpp +++ b/Source/Core/Common/Src/MemArena.cpp @@ -20,6 +20,7 @@ #include <linux/ashmem.h> #endif #endif +#include <set> #if defined(__APPLE__) static const char* ram_temp_file = "/tmp/gc_mem.tmp"; @@ -151,7 +152,11 @@ u8* MemArena::Find4GBBase() PanicAlert("Failed to map 1 GB of memory space: %s", strerror(errno)); return 0; } - munmap(base, 0x31000000); +#ifndef ANDROID + // Android 4.3 changes how munmap works which causes crashes. + // Keep the memory space after allocating it... + munmap(base, MemSize); +#endif return static_cast<u8*>(base); #endif #endif @@ -214,27 +219,7 @@ static bool Memory_TryBase(u8 *base, const MemoryView *views, int num_views, u32 bail: // Argh! ERROR! Free what we grabbed so far so we can try again. - for (int j = 0; j <= i; j++) - { - SKIP(flags, views[i].flags); - if (views[j].out_ptr_low && *views[j].out_ptr_low) - { - arena->ReleaseView(*views[j].out_ptr_low, views[j].size); - *views[j].out_ptr_low = NULL; - } - if (*views[j].out_ptr) - { -#ifdef _M_X64 - arena->ReleaseView(*views[j].out_ptr, views[j].size); -#else - if (!(views[j].flags & MV_MIRROR_PREVIOUS)) - { - arena->ReleaseView(*views[j].out_ptr, views[j].size); - } -#endif - *views[j].out_ptr = NULL; - } - } + MemoryMap_Shutdown(views, i+1, flags, arena); return false; } @@ -300,15 +285,20 @@ u8 *MemoryMap_Setup(const MemoryView *views, int num_views, u32 flags, MemArena void MemoryMap_Shutdown(const MemoryView *views, int num_views, u32 flags, MemArena *arena) { + std::set<void*> freeset; for (int i = 0; i < num_views; i++) { - SKIP(flags, views[i].flags); - if (views[i].out_ptr_low && *views[i].out_ptr_low) - arena->ReleaseView(*views[i].out_ptr_low, views[i].size); - if (*views[i].out_ptr && (views[i].out_ptr_low && *views[i].out_ptr != *views[i].out_ptr_low)) - arena->ReleaseView(*views[i].out_ptr, views[i].size); - *views[i].out_ptr = NULL; - if (views[i].out_ptr_low) - *views[i].out_ptr_low = NULL; + const MemoryView* view = &views[i]; + u8** outptrs[2] = {view->out_ptr_low, view->out_ptr}; + for (int j = 0; j < 2; j++) + { + u8** outptr = outptrs[j]; + if (outptr && *outptr && !freeset.count(*outptr)) + { + arena->ReleaseView(*outptr, view->size); + freeset.insert(*outptr); + *outptr = NULL; + } + } } } diff --git a/Source/Core/Common/Src/StringUtil.cpp b/Source/Core/Common/Src/StringUtil.cpp index 99bc2ae6ca..25885552ef 100644 --- a/Source/Core/Common/Src/StringUtil.cpp +++ b/Source/Core/Common/Src/StringUtil.cpp @@ -34,7 +34,39 @@ bool AsciiToHex(const char* _szValue, u32& result) bool CharArrayFromFormatV(char* out, int outsize, const char* format, va_list args) { - int writtenCount = vsnprintf(out, outsize, format, args); + int writtenCount; + +#ifdef _WIN32 + // You would think *printf are simple, right? Iterate on each character, + // if it's a format specifier handle it properly, etc. + // + // Nooooo. Not according to the C standard. + // + // According to the C99 standard (7.19.6.1 "The fprintf function") + // The format shall be a multibyte character sequence + // + // Because some character encodings might have '%' signs in the middle of + // a multibyte sequence (SJIS for example only specifies that the first + // byte of a 2 byte sequence is "high", the second byte can be anything), + // printf functions have to decode the multibyte sequences and try their + // best to not screw up. + // + // Unfortunately, on Windows, the locale for most languages is not UTF-8 + // as we would need. Notably, for zh_TW, Windows chooses EUC-CN as the + // locale, and completely fails when trying to decode UTF-8 as EUC-CN. + // + // On the other hand, the fix is simple: because we use UTF-8, no such + // multibyte handling is required as we can simply assume that no '%' char + // will be present in the middle of a multibyte sequence. + // + // This is why we lookup an ANSI (cp1252) locale here and use _vsnprintf_l. + static locale_t c_locale = NULL; + if (!c_locale) + c_locale = _create_locale(LC_ALL, ".1252"); + writtenCount = _vsnprintf_l(out, outsize, format, c_locale, args); +#else + writtenCount = vsnprintf(out, outsize, format, args); +#endif if (writtenCount > 0 && writtenCount < outsize) { @@ -58,10 +90,9 @@ std::string StringFromFormat(const char* format, ...) va_start(args, format); required = _vscprintf(format, args); buf = new char[required + 1]; - vsnprintf(buf, required, format, args); + CharArrayFromFormatV(buf, required + 1, format, args); va_end(args); - buf[required] = '\0'; std::string temp = buf; delete[] buf; #else diff --git a/Source/Core/Common/Src/x64CPUDetect.cpp b/Source/Core/Common/Src/x64CPUDetect.cpp index d225262f81..e4eac54ef1 100644 --- a/Source/Core/Common/Src/x64CPUDetect.cpp +++ b/Source/Core/Common/Src/x64CPUDetect.cpp @@ -72,6 +72,14 @@ static void __cpuid(int info[4], int x) #endif } +#define _XCR_XFEATURE_ENABLED_MASK 0 +static unsigned long long _xgetbv(unsigned int index) +{ + unsigned int eax, edx; + __asm__ __volatile__("xgetbv" : "=a"(eax), "=d"(edx) : "c"(index)); + return ((unsigned long long)edx << 32) | eax; +} + #endif #include "Common.h" @@ -149,8 +157,17 @@ void CPUInfo::Detect() if ((cpu_id[2] >> 9) & 1) bSSSE3 = true; if ((cpu_id[2] >> 19) & 1) bSSE4_1 = true; if ((cpu_id[2] >> 20) & 1) bSSE4_2 = true; - if ((cpu_id[2] >> 28) & 1) bAVX = true; if ((cpu_id[2] >> 25) & 1) bAES = true; + + // AVX support requires 3 separate checks: + // - Is the AVX bit set in CPUID? + // - Is the XSAVE bit set in CPUID? + // - XGETBV result has the XCR bit set. + if (((cpu_id[2] >> 28) & 1) && ((cpu_id[2] >> 27) & 1)) + { + if ((_xgetbv(_XCR_XFEATURE_ENABLED_MASK) & 0x6) == 0x6) + bAVX = true; + } } if (max_ex_fn >= 0x80000004) { // Extract brand string diff --git a/Source/Core/Common/make_scmrev.h.js b/Source/Core/Common/make_scmrev.h.js index 82f6394c2b..f2978987dc 100644 --- a/Source/Core/Common/make_scmrev.h.js +++ b/Source/Core/Common/make_scmrev.h.js @@ -58,8 +58,8 @@ var describe = GetFirstStdOutLine(gitexe + cmd_describe); var branch = GetFirstStdOutLine(gitexe + cmd_branch); var isMaster = +("master" == branch); -// remove hash from description -describe = describe.replace(/-[^-]+(-dirty)?$/, '$1'); +// remove hash (and trailing "-0" if needed) from description +describe = describe.replace(/(-0)?-[^-]+(-dirty)?$/, '$2'); var out_contents = "#define SCM_REV_STR \"" + revision + "\"\n" + diff --git a/Source/Core/Core/CMakeLists.txt b/Source/Core/Core/CMakeLists.txt index ece59b3610..072edded23 100644 --- a/Source/Core/Core/CMakeLists.txt +++ b/Source/Core/Core/CMakeLists.txt @@ -11,7 +11,6 @@ set(SRCS Src/ActionReplay.cpp Src/GeckoCodeConfig.cpp Src/GeckoCode.cpp Src/Movie.cpp - Src/NetPlay.cpp Src/NetPlayClient.cpp Src/NetPlayServer.cpp Src/PatchEngine.cpp @@ -215,6 +214,7 @@ if(_M_ARM) Src/PowerPC/JitArm32/JitArm_Integer.cpp Src/PowerPC/JitArm32/JitArm_LoadStore.cpp Src/PowerPC/JitArm32/JitArm_FloatingPoint.cpp + Src/PowerPC/JitArm32/JitArm_Paired.cpp Src/PowerPC/JitArm32/JitArm_SystemRegisters.cpp Src/PowerPC/JitArm32/JitArm_LoadStoreFloating.cpp) endif() diff --git a/Source/Core/Core/Core.vcxproj b/Source/Core/Core/Core.vcxproj index c419f10115..70941527d5 100644 --- a/Source/Core/Core/Core.vcxproj +++ b/Source/Core/Core/Core.vcxproj @@ -338,7 +338,6 @@ <ClCompile Include="Src\IPC_HLE\WII_Socket.cpp" /> <ClCompile Include="Src\x64MemTools.cpp" /> <ClCompile Include="Src\Movie.cpp" /> - <ClCompile Include="Src\NetPlay.cpp" /> <ClCompile Include="Src\NetPlayClient.cpp" /> <ClCompile Include="Src\NetPlayServer.cpp" /> <ClCompile Include="Src\PatchEngine.cpp" /> @@ -550,7 +549,9 @@ <ClInclude Include="Src\IPC_HLE\WII_Socket.h" /> <ClInclude Include="Src\MemTools.h" /> <ClInclude Include="Src\Movie.h" /> - <ClInclude Include="Src\NetPlay.h" /> + <ClInclude Include="Src\NetPlayClient.h" /> + <ClInclude Include="Src\NetPlayProto.h" /> + <ClInclude Include="Src\NetPlayServer.h" /> <ClInclude Include="Src\ec_wii.h" /> <ClInclude Include="Src\PatchEngine.h" /> <ClInclude Include="Src\DSPEmulator.h" /> diff --git a/Source/Core/Core/Core.vcxproj.filters b/Source/Core/Core/Core.vcxproj.filters index 65fc55bf04..7b3a436959 100644 --- a/Source/Core/Core/Core.vcxproj.filters +++ b/Source/Core/Core/Core.vcxproj.filters @@ -529,15 +529,6 @@ <ClCompile Include="Src\HW\Wiimote.cpp"> <Filter>HW %28Flipper/Hollywood%29\Wiimote</Filter> </ClCompile> - <ClCompile Include="Src\NetPlay.cpp"> - <Filter>NetPlay</Filter> - </ClCompile> - <ClCompile Include="Src\NetPlayServer.cpp"> - <Filter>NetPlay</Filter> - </ClCompile> - <ClCompile Include="Src\NetPlayClient.cpp"> - <Filter>NetPlay</Filter> - </ClCompile> <ClCompile Include="Src\BootManager.cpp" /> <ClCompile Include="Src\FifoPlayer\FifoDataFile.cpp"> <Filter>FifoPlayer</Filter> @@ -567,6 +558,8 @@ <ClCompile Include="Src\PowerPC\JitInterface.cpp"> <Filter>PowerPC</Filter> </ClCompile> + <ClCompile Include="Src\NetPlayClient.cpp" /> + <ClCompile Include="Src\NetPlayServer.cpp" /> <ClCompile Include="Src\IPC_HLE\ICMPWin.cpp"> <Filter>IPC HLE %28IOS/Starlet%29\Net</Filter> </ClCompile> @@ -1027,9 +1020,6 @@ <ClInclude Include="Src\PowerPC\CPUCoreBase.h"> <Filter>PowerPC</Filter> </ClInclude> - <ClInclude Include="Src\NetPlay.h"> - <Filter>NetPlay</Filter> - </ClInclude> <ClInclude Include="Src\BootManager.h" /> <ClInclude Include="Src\FifoPlayer\FifoDataFile.h"> <Filter>FifoPlayer</Filter> @@ -1059,6 +1049,9 @@ <ClInclude Include="Src\PowerPC\JitInterface.h"> <Filter>PowerPC</Filter> </ClInclude> + <ClInclude Include="Src\NetPlayClient.h" /> + <ClInclude Include="Src\NetPlayProto.h" /> + <ClInclude Include="Src\NetPlayServer.h" /> <ClInclude Include="Src\IPC_HLE\WII_IPC_HLE_Device_net_ssl.h"> <Filter>IPC HLE %28IOS/Starlet%29\Net</Filter> </ClInclude> @@ -1206,9 +1199,6 @@ <Filter Include="HW %28Flipper/Hollywood%29\Wiimote\Real"> <UniqueIdentifier>{1c21a3e1-b791-4a23-b0d5-ed2b2c34007f}</UniqueIdentifier> </Filter> - <Filter Include="NetPlay"> - <UniqueIdentifier>{231ceb02-1122-402a-87a8-094a9ed768c2}</UniqueIdentifier> - </Filter> <Filter Include="FifoPlayer"> <UniqueIdentifier>{ca7d56f7-4e84-4d15-9aea-7ae6fa7d6586}</UniqueIdentifier> </Filter> diff --git a/Source/Core/Core/Src/BootManager.cpp b/Source/Core/Core/Src/BootManager.cpp index 25e3c6396e..6454df49d5 100644 --- a/Source/Core/Core/Src/BootManager.cpp +++ b/Source/Core/Core/Src/BootManager.cpp @@ -34,7 +34,7 @@ #include "Host.h" #include "VideoBackendBase.h" #include "Movie.h" -#include "NetPlay.h" +#include "NetPlayClient.h" namespace BootManager { @@ -43,7 +43,7 @@ namespace BootManager // Apply fire liberally struct ConfigCache { - bool valid, bCPUThread, bSkipIdle, bEnableFPRF, bMMU, bDCBZOFF, m_EnableJIT, + bool valid, bCPUThread, bSkipIdle, bEnableFPRF, bMMU, bDCBZOFF, m_EnableJIT, bDSPThread, bVBeamSpeedHack, bSyncGPU, bFastDiscSpeed, bMergeBlocks, bDSPHLE, bHLE_BS2; int iTLBHack, iCPUCore; std::string strBackend; @@ -93,6 +93,7 @@ bool BootCore(const std::string& _rFilename) config_cache.strBackend = StartUp.m_strVideoBackend; config_cache.bHLE_BS2 = StartUp.bHLE_BS2; config_cache.m_EnableJIT = SConfig::GetInstance().m_EnableJIT; + config_cache.bDSPThread = StartUp.bDSPThread; // General settings game_ini.Get("Core", "CPUThread", &StartUp.bCPUThread, StartUp.bCPUThread); @@ -106,6 +107,7 @@ bool BootCore(const std::string& _rFilename) game_ini.Get("Core", "FastDiscSpeed", &StartUp.bFastDiscSpeed, StartUp.bFastDiscSpeed); game_ini.Get("Core", "BlockMerging", &StartUp.bMergeBlocks, StartUp.bMergeBlocks); game_ini.Get("Core", "DSPHLE", &StartUp.bDSPHLE, StartUp.bDSPHLE); + game_ini.Get("Core", "DSPThread", &StartUp.bDSPThread, StartUp.bDSPThread); game_ini.Get("Core", "GFXBackend", &StartUp.m_strVideoBackend, StartUp.m_strVideoBackend.c_str()); game_ini.Get("Core", "CPUCore", &StartUp.iCPUCore, StartUp.iCPUCore); game_ini.Get("Core", "HLE_BS2", &StartUp.bHLE_BS2, StartUp.bHLE_BS2); @@ -136,8 +138,9 @@ bool BootCore(const std::string& _rFilename) } } - if (NetPlay::GetNetPlayPtr()) + if (NetPlay::IsNetPlayRunning()) { + StartUp.bCPUThread = g_NetPlaySettings.m_CPUthread; StartUp.bDSPHLE = g_NetPlaySettings.m_DSPHLE; StartUp.bEnableMemcardSaving = g_NetPlaySettings.m_WriteToMemcard; SConfig::GetInstance().m_EnableJIT = g_NetPlaySettings.m_DSPEnableJIT; @@ -176,6 +179,7 @@ void Stop() StartUp.bFastDiscSpeed = config_cache.bFastDiscSpeed; StartUp.bMergeBlocks = config_cache.bMergeBlocks; StartUp.bDSPHLE = config_cache.bDSPHLE; + StartUp.bDSPThread = config_cache.bDSPThread; StartUp.m_strVideoBackend = config_cache.strBackend; VideoBackend::ActivateBackend(StartUp.m_strVideoBackend); StartUp.bHLE_BS2 = config_cache.bHLE_BS2; diff --git a/Source/Core/Core/Src/ConfigManager.cpp b/Source/Core/Core/Src/ConfigManager.cpp index 1447aaa5fa..53d5854b00 100644 --- a/Source/Core/Core/Src/ConfigManager.cpp +++ b/Source/Core/Core/Src/ConfigManager.cpp @@ -67,7 +67,12 @@ static const struct { { "Wiimote4Connect", 347 /* WXK_F8 */, 1 /* wxMOD_ALT */ }, { "BalanceBoardConnect",348 /* WXK_F9 */, 1 /* wxMOD_ALT */ }, #endif - + { "ToggleIR", 0, 0 /* wxMOD_NONE */ }, + { "ToggleAspectRatio", 0, 0 /* wxMOD_NONE */ }, + { "ToggleEFBCopies", 0, 0 /* wxMOD_NONE */ }, + { "ToggleFog", 0, 0 /* wxMOD_NONE */ }, + { "IncreaseFrameLimit", 0, 0 /* wxMOD_NONE */ }, + { "DecreaseFrameLimit", 0, 0 /* wxMOD_NONE */ }, { "LoadStateSlot1", 340 /* WXK_F1 */, 0 /* wxMOD_NONE */ }, { "LoadStateSlot2", 341 /* WXK_F2 */, 0 /* wxMOD_NONE */ }, { "LoadStateSlot3", 342 /* WXK_F3 */, 0 /* wxMOD_NONE */ }, @@ -76,6 +81,8 @@ static const struct { { "LoadStateSlot6", 345 /* WXK_F6 */, 0 /* wxMOD_NONE */ }, { "LoadStateSlot7", 346 /* WXK_F7 */, 0 /* wxMOD_NONE */ }, { "LoadStateSlot8", 347 /* WXK_F8 */, 0 /* wxMOD_NONE */ }, + { "LoadStateSlot9", 0, 0 /* wxMOD_NONE */ }, + { "LoadStateSlot10",0, 0 /* wxMOD_NONE */ }, { "SaveStateSlot1", 340 /* WXK_F1 */, 4 /* wxMOD_SHIFT */ }, { "SaveStateSlot2", 341 /* WXK_F2 */, 4 /* wxMOD_SHIFT */ }, @@ -85,6 +92,8 @@ static const struct { { "SaveStateSlot6", 345 /* WXK_F6 */, 4 /* wxMOD_SHIFT */ }, { "SaveStateSlot7", 346 /* WXK_F7 */, 4 /* wxMOD_SHIFT */ }, { "SaveStateSlot8", 347 /* WXK_F8 */, 4 /* wxMOD_SHIFT */ }, + { "SaveStateSlot9", 0, 0 /* wxMOD_NONE */ }, + { "SaveStateSlot10",0, 0 /* wxMOD_NONE */ }, { "LoadLastState1", 0, 0 /* wxMOD_NONE */ }, { "LoadLastState2", 0, 0 /* wxMOD_NONE */ }, @@ -270,6 +279,9 @@ void SConfig::SaveSettings() ini.Set("DSP", "Backend", sBackend); ini.Set("DSP", "Volume", m_Volume); + // Fifo Player + ini.Set("FifoPlayer", "LoopReplay", m_LocalCoreStartupParameter.bLoopFifoReplay); + ini.Save(File::GetUserPath(F_DOLPHINCONFIG_IDX)); m_SYSCONF->Save(); } @@ -445,6 +457,8 @@ void SConfig::LoadSettings() ini.Get("DSP", "Backend", &sBackend, BACKEND_NULLSOUND); #endif ini.Get("DSP", "Volume", &m_Volume, 100); + + ini.Get("FifoPlayer", "LoopReplay", &m_LocalCoreStartupParameter.bLoopFifoReplay, true); } m_SYSCONF = new SysConf(); diff --git a/Source/Core/Core/Src/Core.cpp b/Source/Core/Core/Src/Core.cpp index 6ff2588f45..0e936ddde4 100644 --- a/Source/Core/Core/Src/Core.cpp +++ b/Source/Core/Core/Src/Core.cpp @@ -79,8 +79,6 @@ void Callback_WiimoteInterruptChannel(int _number, u16 _channelID, const void* _ // Function declarations void EmuThread(); -void Stop(); - bool g_bStopping = false; bool g_bHwInit = false; bool g_bStarted = false; @@ -520,9 +518,6 @@ void SetState(EState _State) { switch (_State) { - case CORE_UNINITIALIZED: - Stop(); - break; case CORE_PAUSE: CCPU::EnableStepping(true); // Break Wiimote::Pause(); diff --git a/Source/Core/Core/Src/CoreParameter.cpp b/Source/Core/Core/Src/CoreParameter.cpp index 773fdbcd5f..58997407c6 100644 --- a/Source/Core/Core/Src/CoreParameter.cpp +++ b/Source/Core/Core/Src/CoreParameter.cpp @@ -20,6 +20,7 @@ SCoreStartupParameter::SCoreStartupParameter() : hInstance(0), + bEnableDebugging(false), bAutomaticStart(false), bBootToPause(false), bJITNoBlockCache(false), bJITBlockLinking(true), bJITOff(false), bJITLoadStoreOff(false), bJITLoadStorelXzOff(false), @@ -46,7 +47,8 @@ SCoreStartupParameter::SCoreStartupParameter() bRenderWindowAutoSize(false), bKeepWindowOnTop(false), bFullscreen(false), bRenderToMain(false), bProgressive(false), bDisableScreenSaver(false), - iPosX(100), iPosY(100), iWidth(800), iHeight(600) + iPosX(100), iPosY(100), iWidth(800), iHeight(600), + bLoopFifoReplay(true) { LoadDefaults(); } @@ -54,9 +56,13 @@ SCoreStartupParameter::SCoreStartupParameter() void SCoreStartupParameter::LoadDefaults() { bEnableDebugging = false; + bAutomaticStart = false; + bBootToPause = false; + #ifdef USE_GDBSTUB iGDBPort = -1; #endif + iCPUCore = 1; bCPUThread = false; bSkipIdle = false; @@ -84,6 +90,8 @@ void SCoreStartupParameter::LoadDefaults() iWidth = 800; iHeight = 600; + bLoopFifoReplay = true; + bJITOff = false; // debugger only settings bJITLoadStoreOff = false; bJITLoadStoreFloatingOff = false; @@ -314,7 +322,10 @@ bool SCoreStartupParameter::AutoSetup(EBootBS2 _BootBS2) m_strSRAM = File::GetUserPath(F_GCSRAM_IDX); if (!bWii) { - m_strBootROM = File::GetSysDirectory() + GC_SYS_DIR + DIR_SEP + Region + DIR_SEP GC_IPL; + m_strBootROM = File::GetUserPath(D_GCUSER_IDX) + DIR_SEP + Region + DIR_SEP GC_IPL; + if (!File::Exists(m_strBootROM)) + m_strBootROM = File::GetSysDirectory() + GC_SYS_DIR + DIR_SEP + Region + DIR_SEP GC_IPL; + if (!bHLE_BS2) { if (!File::Exists(m_strBootROM)) diff --git a/Source/Core/Core/Src/CoreParameter.h b/Source/Core/Core/Src/CoreParameter.h index edfb1141a1..5666049b2f 100644 --- a/Source/Core/Core/Src/CoreParameter.h +++ b/Source/Core/Core/Src/CoreParameter.h @@ -34,6 +34,14 @@ enum Hotkey HK_WIIMOTE4_CONNECT, HK_BALANCEBOARD_CONNECT, + HK_TOGGLE_IR, + HK_TOGGLE_AR, + HK_TOGGLE_EFBCOPIES, + HK_TOGGLE_FOG, + + HK_INCREASE_FRAME_LIMIT, + HK_DECREASE_FRAME_LIMIT, + HK_LOAD_STATE_SLOT_1, HK_LOAD_STATE_SLOT_2, HK_LOAD_STATE_SLOT_3, @@ -42,6 +50,8 @@ enum Hotkey HK_LOAD_STATE_SLOT_6, HK_LOAD_STATE_SLOT_7, HK_LOAD_STATE_SLOT_8, + HK_LOAD_STATE_SLOT_9, + HK_LOAD_STATE_SLOT_10, HK_SAVE_STATE_SLOT_1, HK_SAVE_STATE_SLOT_2, @@ -51,6 +61,8 @@ enum Hotkey HK_SAVE_STATE_SLOT_6, HK_SAVE_STATE_SLOT_7, HK_SAVE_STATE_SLOT_8, + HK_SAVE_STATE_SLOT_9, + HK_SAVE_STATE_SLOT_10, HK_LOAD_LAST_STATE_1, HK_LOAD_LAST_STATE_2, @@ -85,6 +97,7 @@ struct SCoreStartupParameter // 0 = Interpreter // 1 = Jit // 2 = JitIL + // 3 = JIT ARM int iCPUCore; // JIT (shared between JIT and JITIL) @@ -152,6 +165,9 @@ struct SCoreStartupParameter int iPosX, iPosY, iWidth, iHeight; + // Fifo Player related settings + bool bLoopFifoReplay; + enum EBootBS2 { BOOT_DEFAULT, diff --git a/Source/Core/Core/Src/FifoPlayer/FifoPlayer.cpp b/Source/Core/Core/Src/FifoPlayer/FifoPlayer.cpp index 45455683be..f660b41f9e 100644 --- a/Source/Core/Core/Src/FifoPlayer/FifoPlayer.cpp +++ b/Source/Core/Core/Src/FifoPlayer/FifoPlayer.cpp @@ -6,7 +6,10 @@ #include "FifoPlayer.h" #include "Common.h" +#include "ConfigManager.h" +#include "Core.h" #include "CoreTiming.h" +#include "Host.h" #include "HW/GPFifo.h" #include "HW/Memmap.h" @@ -68,10 +71,18 @@ bool FifoPlayer::Play() { if (m_CurrentFrame >= m_FrameRangeEnd) { - m_CurrentFrame = m_FrameRangeStart; - - CoreTiming::downcount = 0; - CoreTiming::Advance(); + if (m_Loop) + { + m_CurrentFrame = m_FrameRangeStart; + + CoreTiming::downcount = 0; + CoreTiming::Advance(); + } + else + { + PowerPC::Stop(); + Host_Message(WM_USER_STOP); + } } else { @@ -150,6 +161,7 @@ FifoPlayer::FifoPlayer() : m_FrameWrittenCb(NULL), m_File(NULL) { + m_Loop = SConfig::GetInstance().m_LocalCoreStartupParameter.bLoopFifoReplay; } void FifoPlayer::WriteFrame(const FifoFrameInfo &frame, const AnalyzedFrameInfo &info) diff --git a/Source/Core/Core/Src/FifoPlayer/FifoPlayer.h b/Source/Core/Core/Src/FifoPlayer/FifoPlayer.h index 5d23e109f8..bad936cca9 100644 --- a/Source/Core/Core/Src/FifoPlayer/FifoPlayer.h +++ b/Source/Core/Core/Src/FifoPlayer/FifoPlayer.h @@ -86,6 +86,8 @@ private: bool ShouldLoadBP(u8 address); + bool m_Loop; + u32 m_CurrentFrame; u32 m_FrameRangeStart; u32 m_FrameRangeEnd; diff --git a/Source/Core/Core/Src/HW/BBA-TAP/TAP_Win32.cpp b/Source/Core/Core/Src/HW/BBA-TAP/TAP_Win32.cpp index e5d2b7be64..a444ca63cb 100644 --- a/Source/Core/Core/Src/HW/BBA-TAP/TAP_Win32.cpp +++ b/Source/Core/Core/Src/HW/BBA-TAP/TAP_Win32.cpp @@ -193,7 +193,7 @@ bool CEXIETHERNET::Activate() } if (mHAdapter == INVALID_HANDLE_VALUE) { - ERROR_LOG(SP1, "Failed to open any TAP"); + PanicAlert("Failed to open any TAP"); return false; } diff --git a/Source/Core/Core/Src/HW/SI.cpp b/Source/Core/Core/Src/HW/SI.cpp index 85c84f92dd..9142919346 100644 --- a/Source/Core/Core/Src/HW/SI.cpp +++ b/Source/Core/Core/Src/HW/SI.cpp @@ -7,7 +7,7 @@ #include "../ConfigManager.h" #include "../CoreTiming.h" #include "../Movie.h" -#include "../NetPlay.h" +#include "../NetPlayClient.h" #include "SystemTimers.h" #include "ProcessorInterface.h" @@ -262,7 +262,7 @@ void Init() if (Movie::IsRecordingInput() || Movie::IsPlayingInput()) AddDevice(Movie::IsUsingPad(i) ? (Movie::IsUsingBongo(i) ? SIDEVICE_GC_TARUKONGA : SIDEVICE_GC_CONTROLLER) : SIDEVICE_NONE, i); - else if (NetPlay::GetNetPlayPtr()) + else if (NetPlay::IsNetPlayRunning()) AddDevice((SIDevices) g_NetPlaySettings.m_Controllers[i], i); else AddDevice(SConfig::GetInstance().m_SIDevice[i], i); @@ -644,10 +644,12 @@ void RunSIBuffer() int GetTicksToNextSIPoll() { // Poll for input at regular intervals (once per frame) when playing or recording a movie - if (Movie::IsPlayingInput() || Movie::IsRecordingInput() || NetPlay::GetNetPlayPtr()) + if (Movie::IsPlayingInput() || Movie::IsRecordingInput()) { return SystemTimers::GetTicksPerSecond() / VideoInterface::TargetRefreshRate; } + if (NetPlay::IsNetPlayRunning()) + return SystemTimers::GetTicksPerSecond() / VideoInterface::TargetRefreshRate / 2; if (!g_Poll.Y && g_Poll.X) return VideoInterface::GetTicksPerLine() * g_Poll.X; diff --git a/Source/Core/Core/Src/HW/Wiimote.cpp b/Source/Core/Core/Src/HW/Wiimote.cpp index 0bf10b343d..2061e80f2e 100644 --- a/Source/Core/Core/Src/HW/Wiimote.cpp +++ b/Source/Core/Core/Src/HW/Wiimote.cpp @@ -32,7 +32,7 @@ void Shutdown() delete *i; g_plugin.controllers.clear(); - WiimoteReal::Shutdown(); + WiimoteReal::Stop(); g_controller_interface.Shutdown(); } diff --git a/Source/Core/Core/Src/HW/Wiimote.h b/Source/Core/Core/Src/HW/Wiimote.h index 04c09c5ab5..be1de18bc9 100644 --- a/Source/Core/Core/Src/HW/Wiimote.h +++ b/Source/Core/Core/Src/HW/Wiimote.h @@ -54,6 +54,7 @@ namespace WiimoteReal { void Initialize(bool wait = false); +void Stop(); void Shutdown(); void Resume(); void Pause(); diff --git a/Source/Core/Core/Src/HW/WiimoteEmu/Attachment/Attachment.cpp b/Source/Core/Core/Src/HW/WiimoteEmu/Attachment/Attachment.cpp index 93e5a22a9e..bf4cacfea3 100644 --- a/Source/Core/Core/Src/HW/WiimoteEmu/Attachment/Attachment.cpp +++ b/Source/Core/Core/Src/HW/WiimoteEmu/Attachment/Attachment.cpp @@ -13,15 +13,17 @@ static const u8 nothing_id[] = { 0x00, 0x00, 0x00, 0x00, 0x2e, 0x2e }; // The id for a partially inserted extension static const u8 partially_id[] = { 0x00, 0x00, 0x00, 0x00, 0xff, 0xff }; -Attachment::Attachment( const char* const _name ) : name( _name ) +Attachment::Attachment( const char* const _name, WiimoteEmu::ExtensionReg& _reg ) + : name( _name ), reg( _reg ) { - reg.resize( WIIMOTE_REG_EXT_SIZE, 0); + memset(id, 0, sizeof(id)); + memset(calibration, 0, sizeof(calibration)); } -None::None() : Attachment( "None" ) +None::None( WiimoteEmu::ExtensionReg& _reg ) : Attachment( "None", _reg ) { // set up register - memcpy( ®[0xfa], nothing_id, sizeof(nothing_id) ); + memcpy(&id, nothing_id, sizeof(nothing_id)); } std::string Attachment::GetName() const @@ -29,6 +31,14 @@ std::string Attachment::GetName() const return name; } +void Attachment::Reset() +{ + // set up register + memset( ®, 0, WIIMOTE_REG_EXT_SIZE ); + memcpy( ®.constant_id, id, sizeof(id) ); + memcpy( ®.calibration, calibration, sizeof(calibration) ); +} + } void ControllerEmu::Extension::GetState( u8* const data, const bool focus ) diff --git a/Source/Core/Core/Src/HW/WiimoteEmu/Attachment/Attachment.h b/Source/Core/Core/Src/HW/WiimoteEmu/Attachment/Attachment.h index 777c0e158e..dfa292bf3b 100644 --- a/Source/Core/Core/Src/HW/WiimoteEmu/Attachment/Attachment.h +++ b/Source/Core/Core/Src/HW/WiimoteEmu/Attachment/Attachment.h @@ -14,19 +14,23 @@ namespace WiimoteEmu class Attachment : public ControllerEmu { public: - Attachment( const char* const _name ); + Attachment( const char* const _name, WiimoteEmu::ExtensionReg& _reg ); virtual void GetState( u8* const data, const bool focus = true ) {} + void Reset(); std::string GetName() const; - const char* const name; - std::vector<u8> reg; + const char* const name; + WiimoteEmu::ExtensionReg& reg; + + u8 id[6]; + u8 calibration[0x10]; }; class None : public Attachment { public: - None(); + None( WiimoteEmu::ExtensionReg& _reg ); }; } diff --git a/Source/Core/Core/Src/HW/WiimoteEmu/Attachment/Classic.cpp b/Source/Core/Core/Src/HW/WiimoteEmu/Attachment/Classic.cpp index 3de2951de3..5b0d962397 100644 --- a/Source/Core/Core/Src/HW/WiimoteEmu/Attachment/Classic.cpp +++ b/Source/Core/Core/Src/HW/WiimoteEmu/Attachment/Classic.cpp @@ -53,7 +53,7 @@ static const u16 classic_dpad_bitmasks[] = Classic::PAD_UP, Classic::PAD_DOWN, Classic::PAD_LEFT, Classic::PAD_RIGHT }; -Classic::Classic() : Attachment(_trans("Classic")) +Classic::Classic(WiimoteEmu::ExtensionReg& _reg) : Attachment(_trans("Classic"), _reg) { // buttons groups.push_back(m_buttons = new Buttons("Buttons")); @@ -76,9 +76,9 @@ Classic::Classic() : Attachment(_trans("Classic")) // set up register // calibration - memcpy(®[0x20], classic_calibration, sizeof(classic_calibration)); + memcpy(&calibration, classic_calibration, sizeof(classic_calibration)); // id - memcpy(®[0xfa], classic_id, sizeof(classic_id)); + memcpy(&id, classic_id, sizeof(classic_id)); } void Classic::GetState(u8* const data, const bool focus) diff --git a/Source/Core/Core/Src/HW/WiimoteEmu/Attachment/Classic.h b/Source/Core/Core/Src/HW/WiimoteEmu/Attachment/Classic.h index 852eb74b81..ac68b2ad77 100644 --- a/Source/Core/Core/Src/HW/WiimoteEmu/Attachment/Classic.h +++ b/Source/Core/Core/Src/HW/WiimoteEmu/Attachment/Classic.h @@ -10,7 +10,7 @@ namespace WiimoteEmu class Classic : public Attachment { public: - Classic(); + Classic(WiimoteEmu::ExtensionReg& _reg); void GetState( u8* const data, const bool focus ); enum diff --git a/Source/Core/Core/Src/HW/WiimoteEmu/Attachment/Drums.cpp b/Source/Core/Core/Src/HW/WiimoteEmu/Attachment/Drums.cpp index 066843b3e4..1ae774ba7d 100644 --- a/Source/Core/Core/Src/HW/WiimoteEmu/Attachment/Drums.cpp +++ b/Source/Core/Core/Src/HW/WiimoteEmu/Attachment/Drums.cpp @@ -32,7 +32,7 @@ static const u16 drum_button_bitmasks[] = Drums::BUTTON_PLUS, }; -Drums::Drums() : Attachment(_trans("Drums")) +Drums::Drums(WiimoteEmu::ExtensionReg& _reg) : Attachment(_trans("Drums"), _reg) { // pads groups.push_back(m_pads = new Buttons(_trans("Pads"))); @@ -49,7 +49,7 @@ Drums::Drums() : Attachment(_trans("Drums")) // set up register // id - memcpy(®[0xfa], drums_id, sizeof(drums_id)); + memcpy(&id, drums_id, sizeof(drums_id)); } void Drums::GetState(u8* const data, const bool focus) diff --git a/Source/Core/Core/Src/HW/WiimoteEmu/Attachment/Drums.h b/Source/Core/Core/Src/HW/WiimoteEmu/Attachment/Drums.h index fc0d4851a5..3771140f10 100644 --- a/Source/Core/Core/Src/HW/WiimoteEmu/Attachment/Drums.h +++ b/Source/Core/Core/Src/HW/WiimoteEmu/Attachment/Drums.h @@ -10,7 +10,7 @@ namespace WiimoteEmu class Drums : public Attachment { public: - Drums(); + Drums(WiimoteEmu::ExtensionReg& _reg); void GetState( u8* const data, const bool focus ); enum diff --git a/Source/Core/Core/Src/HW/WiimoteEmu/Attachment/Guitar.cpp b/Source/Core/Core/Src/HW/WiimoteEmu/Attachment/Guitar.cpp index 918236c10e..23a2f93054 100644 --- a/Source/Core/Core/Src/HW/WiimoteEmu/Attachment/Guitar.cpp +++ b/Source/Core/Core/Src/HW/WiimoteEmu/Attachment/Guitar.cpp @@ -36,7 +36,7 @@ static const u16 guitar_strum_bitmasks[] = Guitar::BAR_DOWN, }; -Guitar::Guitar() : Attachment(_trans("Guitar")) +Guitar::Guitar(WiimoteEmu::ExtensionReg& _reg) : Attachment(_trans("Guitar"), _reg) { // frets groups.push_back(m_frets = new Buttons(_trans("Frets"))); @@ -62,7 +62,7 @@ Guitar::Guitar() : Attachment(_trans("Guitar")) // set up register // id - memcpy(®[0xfa], guitar_id, sizeof(guitar_id)); + memcpy(&id, guitar_id, sizeof(guitar_id)); } void Guitar::GetState(u8* const data, const bool focus) diff --git a/Source/Core/Core/Src/HW/WiimoteEmu/Attachment/Guitar.h b/Source/Core/Core/Src/HW/WiimoteEmu/Attachment/Guitar.h index 8d1e718337..245ebabb90 100644 --- a/Source/Core/Core/Src/HW/WiimoteEmu/Attachment/Guitar.h +++ b/Source/Core/Core/Src/HW/WiimoteEmu/Attachment/Guitar.h @@ -10,7 +10,7 @@ namespace WiimoteEmu class Guitar : public Attachment { public: - Guitar(); + Guitar(WiimoteEmu::ExtensionReg& _reg); void GetState( u8* const data, const bool focus ); enum diff --git a/Source/Core/Core/Src/HW/WiimoteEmu/Attachment/Nunchuk.cpp b/Source/Core/Core/Src/HW/WiimoteEmu/Attachment/Nunchuk.cpp index 47cb95905e..63dd485ed7 100644 --- a/Source/Core/Core/Src/HW/WiimoteEmu/Attachment/Nunchuk.cpp +++ b/Source/Core/Core/Src/HW/WiimoteEmu/Attachment/Nunchuk.cpp @@ -31,7 +31,8 @@ static const u8 nunchuk_button_bitmasks[] = Nunchuk::BUTTON_Z, }; -Nunchuk::Nunchuk(UDPWrapper *wrp) : Attachment(_trans("Nunchuk")) , m_udpWrap(wrp) +Nunchuk::Nunchuk(UDPWrapper *wrp, WiimoteEmu::ExtensionReg& _reg) + : Attachment(_trans("Nunchuk"), _reg) , m_udpWrap(wrp) { // buttons groups.push_back(m_buttons = new Buttons("Buttons")); @@ -55,9 +56,9 @@ Nunchuk::Nunchuk(UDPWrapper *wrp) : Attachment(_trans("Nunchuk")) , m_udpWrap(wr // set up register // calibration - memcpy(®[0x20], nunchuck_calibration, sizeof(nunchuck_calibration)); + memcpy(&calibration, nunchuck_calibration, sizeof(nunchuck_calibration)); // id - memcpy(®[0xfa], nunchuck_id, sizeof(nunchuck_id)); + memcpy(&id, nunchuck_id, sizeof(nunchuck_id)); // this should get set to 0 on disconnect, but it isn't, o well memset(m_shake_step, 0, sizeof(m_shake_step)); @@ -68,11 +69,45 @@ void Nunchuk::GetState(u8* const data, const bool focus) wm_extension* const ncdata = (wm_extension*)data; ncdata->bt = 0; - // stick / not using calibration data for stick, o well - m_stick->GetState(&ncdata->jx, &ncdata->jy, 0x80, focus ? 127 : 0); - + // stick + ControlState state[2]; + m_stick->GetState(&state[0], &state[1], 0, 1); + + nu_cal &cal = *(nu_cal*)®.calibration; + nu_js cal_js[2]; + cal_js[0] = *&cal.jx; + cal_js[1] = *&cal.jy; + + for (int i = 0; i < 2; i++) { + ControlState &s = *&state[i]; + nu_js c = *&cal_js[i]; + if (s < 0) + s = s * abs(c.min - c.center) + c.center; + else if (s > 0) + s = s * abs(c.max - c.center) + c.center; + else + s = c.center; + } + + ncdata->jx = u8(trim(state[0])); + ncdata->jy = u8(trim(state[1])); + + if (ncdata->jx != cal.jx.center || ncdata->jy != cal.jy.center) + { + if (ncdata->jy == cal.jy.center) + ncdata->jy = cal.jy.center + 1; + if (ncdata->jx == cal.jx.center) + ncdata->jx = cal.jx.center + 1; + } + + if (!focus) + { + ncdata->jx = cal.jx.center; + ncdata->jy = cal.jy.center; + } + AccelData accel; - accel_cal* calib = (accel_cal*)®[0x20]; + accel_cal* calib = (accel_cal*)®.calibration[0]; // tilt EmulateTilt(&accel, m_tilt, focus); diff --git a/Source/Core/Core/Src/HW/WiimoteEmu/Attachment/Nunchuk.h b/Source/Core/Core/Src/HW/WiimoteEmu/Attachment/Nunchuk.h index b465283e61..3b720f73a7 100644 --- a/Source/Core/Core/Src/HW/WiimoteEmu/Attachment/Nunchuk.h +++ b/Source/Core/Core/Src/HW/WiimoteEmu/Attachment/Nunchuk.h @@ -15,7 +15,7 @@ namespace WiimoteEmu class Nunchuk : public Attachment { public: - Nunchuk(UDPWrapper * wrp); + Nunchuk(UDPWrapper * wrp, WiimoteEmu::ExtensionReg& _reg); virtual void GetState( u8* const data, const bool focus ); diff --git a/Source/Core/Core/Src/HW/WiimoteEmu/Attachment/Turntable.cpp b/Source/Core/Core/Src/HW/WiimoteEmu/Attachment/Turntable.cpp index 21489548fa..901ad27c9f 100644 --- a/Source/Core/Core/Src/HW/WiimoteEmu/Attachment/Turntable.cpp +++ b/Source/Core/Core/Src/HW/WiimoteEmu/Attachment/Turntable.cpp @@ -30,7 +30,7 @@ static const char* const turntable_button_names[] = "-", "+", _trans("Euphoria"), }; -Turntable::Turntable() : Attachment(_trans("Turntable")) +Turntable::Turntable(WiimoteEmu::ExtensionReg& _reg) : Attachment(_trans("Turntable"), _reg) { // buttons groups.push_back(m_buttons = new Buttons("Buttons")); @@ -53,7 +53,7 @@ Turntable::Turntable() : Attachment(_trans("Turntable")) // set up register // id - memcpy(®[0xfa], turntable_id, sizeof(turntable_id)); + memcpy(&id, turntable_id, sizeof(turntable_id)); } void Turntable::GetState(u8* const data, const bool focus) diff --git a/Source/Core/Core/Src/HW/WiimoteEmu/Attachment/Turntable.h b/Source/Core/Core/Src/HW/WiimoteEmu/Attachment/Turntable.h index b2d2458312..0960c272a8 100644 --- a/Source/Core/Core/Src/HW/WiimoteEmu/Attachment/Turntable.h +++ b/Source/Core/Core/Src/HW/WiimoteEmu/Attachment/Turntable.h @@ -10,7 +10,7 @@ namespace WiimoteEmu class Turntable : public Attachment { public: - Turntable(); + Turntable(WiimoteEmu::ExtensionReg& _reg); void GetState(u8* const data, const bool focus); enum diff --git a/Source/Core/Core/Src/HW/WiimoteEmu/EmuSubroutines.cpp b/Source/Core/Core/Src/HW/WiimoteEmu/EmuSubroutines.cpp index f1904e9534..235d5cb7f1 100644 --- a/Source/Core/Core/Src/HW/WiimoteEmu/EmuSubroutines.cpp +++ b/Source/Core/Core/Src/HW/WiimoteEmu/EmuSubroutines.cpp @@ -851,11 +851,8 @@ void Wiimote::HandleExtensionSwap() // set the wanted extension m_extension->active_extension = m_extension->switch_extension; - // set register, I hate this - const std::vector<u8> ® = ((WiimoteEmu::Attachment*)m_extension->attachments[m_extension->active_extension])->reg; - memset(&m_reg_ext, 0, WIIMOTE_REG_EXT_SIZE); - memcpy(&m_reg_ext, ®[0], reg.size()); - + // reset register + ((WiimoteEmu::Attachment*)m_extension->attachments[m_extension->active_extension])->Reset(); } } diff --git a/Source/Core/Core/Src/HW/WiimoteEmu/WiimoteEmu.cpp b/Source/Core/Core/Src/HW/WiimoteEmu/WiimoteEmu.cpp index 9645b735b7..eb5ebc2be5 100644 --- a/Source/Core/Core/Src/HW/WiimoteEmu/WiimoteEmu.cpp +++ b/Source/Core/Core/Src/HW/WiimoteEmu/WiimoteEmu.cpp @@ -286,12 +286,12 @@ Wiimote::Wiimote( const unsigned int index ) // extension groups.push_back(m_extension = new Extension(_trans("Extension"))); - m_extension->attachments.push_back(new WiimoteEmu::None()); - m_extension->attachments.push_back(new WiimoteEmu::Nunchuk(m_udp)); - m_extension->attachments.push_back(new WiimoteEmu::Classic()); - m_extension->attachments.push_back(new WiimoteEmu::Guitar()); - m_extension->attachments.push_back(new WiimoteEmu::Drums()); - m_extension->attachments.push_back(new WiimoteEmu::Turntable()); + m_extension->attachments.push_back(new WiimoteEmu::None(m_reg_ext)); + m_extension->attachments.push_back(new WiimoteEmu::Nunchuk(m_udp, m_reg_ext)); + m_extension->attachments.push_back(new WiimoteEmu::Classic(m_reg_ext)); + m_extension->attachments.push_back(new WiimoteEmu::Guitar(m_reg_ext)); + m_extension->attachments.push_back(new WiimoteEmu::Drums(m_reg_ext)); + m_extension->attachments.push_back(new WiimoteEmu::Turntable(m_reg_ext)); m_extension->settings.push_back(new ControlGroup::Setting(_trans("Motion Plus"), 0, 0, 1)); diff --git a/Source/Core/Core/Src/HW/WiimoteEmu/WiimoteEmu.h b/Source/Core/Core/Src/HW/WiimoteEmu/WiimoteEmu.h index 24b9357542..2fd471978e 100644 --- a/Source/Core/Core/Src/HW/WiimoteEmu/WiimoteEmu.h +++ b/Source/Core/Core/Src/HW/WiimoteEmu/WiimoteEmu.h @@ -17,7 +17,7 @@ #include <vector> #include <queue> -// Registry sizes +// Registry sizes #define WIIMOTE_EEPROM_SIZE (16*1024) #define WIIMOTE_EEPROM_FREE_SIZE 0x1700 #define WIIMOTE_REG_SPEAKER_SIZE 10 @@ -47,6 +47,30 @@ struct ADPCMState s32 predictor, step; }; +struct ExtensionReg +{ + u8 unknown1[0x08]; + + // address 0x08 + u8 controller_data[0x06]; + u8 unknown2[0x12]; + + // address 0x20 + u8 calibration[0x10]; + u8 unknown3[0x10]; + + // address 0x40 + u8 encryption_key[0x10]; + u8 unknown4[0xA0]; + + // address 0xF0 + u8 encryption; + u8 unknown5[0x9]; + + // address 0xFA + u8 constant_id[6]; +}; + extern const ReportFeatures reporting_mode_features[]; void EmulateShake(AccelData* const accel_data @@ -143,7 +167,7 @@ private: ControlGroup* m_rumble; Extension* m_extension; ControlGroup* m_options; - + // WiiMote accel data AccelData m_accel; @@ -151,7 +175,7 @@ private: const u8 m_index; double ir_sin, ir_cos; //for the low pass filter - + UDPWrapper* m_udp; bool m_rumble_on; @@ -201,30 +225,7 @@ private: } m_reg_ir; - struct ExtensionReg - { - u8 unknown1[0x08]; - - // address 0x08 - u8 controller_data[0x06]; - u8 unknown2[0x12]; - - // address 0x20 - u8 calibration[0x10]; - u8 unknown3[0x10]; - - // address 0x40 - u8 encryption_key[0x10]; - u8 unknown4[0xA0]; - - // address 0xF0 - u8 encryption; - u8 unknown5[0x9]; - - // address 0xFA - u8 constant_id[6]; - - } m_reg_ext; + ExtensionReg m_reg_ext; struct SpeakerReg { diff --git a/Source/Core/Core/Src/HW/WiimoteEmu/WiimoteHid.h b/Source/Core/Core/Src/HW/WiimoteEmu/WiimoteHid.h index 7c6d4de8a6..751c177f98 100644 --- a/Source/Core/Core/Src/HW/WiimoteEmu/WiimoteHid.h +++ b/Source/Core/Core/Src/HW/WiimoteEmu/WiimoteHid.h @@ -54,7 +54,7 @@ struct wm_ir_basic }; // Three bytes for one object -struct wm_ir_extended +struct wm_ir_extended { u8 x; u8 y; @@ -150,9 +150,9 @@ struct wm_turntable_extension struct wm_motionplus_data { u8 yaw1; - + u8 roll1; - + u8 pitch1; u8 yaw2 : 6; @@ -230,7 +230,7 @@ struct wm_status_report }; #define WM_WRITE_DATA 0x16 -struct wm_write_data +struct wm_write_data { u8 rumble : 1; u8 space : 2; //see WM_SPACE_* @@ -241,7 +241,7 @@ struct wm_write_data }; #define WM_ACK_DATA 0x22 -struct wm_acknowledge +struct wm_acknowledge { wm_core buttons; u8 reportID; @@ -276,7 +276,7 @@ struct wm_read_data_reply #define WM_RDERR_WOREG 7 #define WM_RDERR_NOMEM 8 - + // Data reports #define WM_REPORT_CORE 0x30 @@ -304,20 +304,20 @@ struct wm_report_core_accel_ir12 #define WM_REPORT_CORE_EXT19 0x34 #define WM_REPORT_CORE_ACCEL_EXT16 0x35 -struct wm_report_core_accel_ext16 +struct wm_report_core_accel_ext16 { wm_core c; wm_accel a; wm_extension ext; //wm_ir_basic ir[2]; u8 pad[10]; - + }; #define WM_REPORT_CORE_IR10_EXT9 0x36 #define WM_REPORT_CORE_ACCEL_IR10_EXT6 0x37 -struct wm_report_core_accel_ir10_ext6 +struct wm_report_core_accel_ir10_ext6 { wm_core c; wm_accel a; @@ -336,7 +336,7 @@ struct wm_report_ext21 #define WM_REPORT_INTERLEAVE2 0x3f #define WM_SPEAKER_ENABLE 0x14 -#define WM_SPEAKER_MUTE 0x19 +#define WM_SPEAKER_MUTE 0x19 #define WM_WRITE_SPEAKER_DATA 0x18 struct wm_speaker_data { @@ -383,9 +383,12 @@ struct cc_trigger struct nu_cal { wm_accel cal_zero; // zero calibration + u8 pad1; wm_accel cal_g; // g size + u8 pad2; nu_js jx; // nu_js jy; // + u8 sum[2]; }; struct cc_cal diff --git a/Source/Core/Core/Src/HW/WiimoteReal/WiimoteReal.cpp b/Source/Core/Core/Src/HW/WiimoteReal/WiimoteReal.cpp index b5297d8655..d2e7e2f57a 100644 --- a/Source/Core/Core/Src/HW/WiimoteReal/WiimoteReal.cpp +++ b/Source/Core/Core/Src/HW/WiimoteReal/WiimoteReal.cpp @@ -570,15 +570,17 @@ void Initialize(bool wait) g_real_wiimotes_initialized = true; } -void Shutdown(void) +// called on emulation shutdown +void Stop(void) { for (unsigned int i = 0; i < MAX_BBMOTES; ++i) if (g_wiimotes[i] && g_wiimotes[i]->IsConnected()) g_wiimotes[i]->EmuStop(); +} - // WiimoteReal is shutdown on app exit - return; - +// called when the dolphin app exits +void Shutdown(void) +{ g_wiimote_scanner.StopScanning(); std::lock_guard<std::recursive_mutex> lk(g_refresh_lock); diff --git a/Source/Core/Core/Src/IPC_HLE/WII_IPC_HLE_Device_usb.cpp b/Source/Core/Core/Src/IPC_HLE/WII_IPC_HLE_Device_usb.cpp index 9bef545257..39a6b46893 100644 --- a/Source/Core/Core/Src/IPC_HLE/WII_IPC_HLE_Device_usb.cpp +++ b/Source/Core/Core/Src/IPC_HLE/WII_IPC_HLE_Device_usb.cpp @@ -1256,8 +1256,6 @@ void CWII_IPC_HLE_Device_usb_oh1_57e_305::ExecuteHCICommandMessage(const SHCICom void CWII_IPC_HLE_Device_usb_oh1_57e_305::CommandInquiry(u8* _Input) { // Inquiry should not be called normally - PanicAlertT("HCI_CMD_INQUIRY is called, please report!"); - hci_inquiry_cp* pInquiry = (hci_inquiry_cp*)_Input; INFO_LOG(WII_IPC_WIIMOTE, "Command: HCI_CMD_INQUIRY:"); @@ -1863,8 +1861,6 @@ CWII_IPC_HLE_WiiMote* CWII_IPC_HLE_Device_usb_oh1_57e_305::AccessWiiMote(const b } ERROR_LOG(WII_IPC_WIIMOTE,"Can't find WiiMote by bd: %02x:%02x:%02x:%02x:%02x:%02x", - _rAddr.b[0], _rAddr.b[1], _rAddr.b[2], _rAddr.b[3], _rAddr.b[4], _rAddr.b[5]); - PanicAlertT("Can't find WiiMote by bd: %02x:%02x:%02x:%02x:%02x:%02x", _rAddr.b[0], _rAddr.b[1], _rAddr.b[2], _rAddr.b[3], _rAddr.b[4], _rAddr.b[5]); return NULL; } diff --git a/Source/Core/Core/Src/Movie.cpp b/Source/Core/Core/Src/Movie.cpp index 2b60b7558a..0be4bb8926 100644 --- a/Source/Core/Core/Src/Movie.cpp +++ b/Source/Core/Core/Src/Movie.cpp @@ -156,6 +156,7 @@ void Init() { ReadHeader(); std::thread md5thread(CheckMD5); + md5thread.detach(); if ((strncmp((char *)tmpHeader.gameID, Core::g_CoreStartupParameter.GetUniqueID().c_str(), 6))) { PanicAlert("The recorded game (%s) is not the same as the selected game (%s)", tmpHeader.gameID, Core::g_CoreStartupParameter.GetUniqueID().c_str()); @@ -167,6 +168,7 @@ void Init() { GetSettings(); std::thread md5thread(GetMD5); + md5thread.detach(); } g_frameSkipCounter = g_framesToSkip; diff --git a/Source/Core/Core/Src/NetPlay.cpp b/Source/Core/Core/Src/NetPlay.cpp deleted file mode 100644 index 45d1689abe..0000000000 --- a/Source/Core/Core/Src/NetPlay.cpp +++ /dev/null @@ -1,401 +0,0 @@ -// Copyright 2013 Dolphin Emulator Project -// Licensed under GPLv2 -// Refer to the license.txt file included. - -#include "NetPlay.h" - -// for wiimote -#include "IPC_HLE/WII_IPC_HLE_Device_usb.h" -#include "IPC_HLE/WII_IPC_HLE_WiiMote.h" -// for gcpad -#include "HW/SI_DeviceGCController.h" -#include "HW/SI_DeviceGCSteeringWheel.h" -#include "HW/SI_DeviceDanceMat.h" -// for gctime -#include "HW/EXI_DeviceIPL.h" -// for wiimote/ OSD messages -#include "Core.h" -#include "ConfigManager.h" - -std::mutex crit_netplay_ptr; -static NetPlay* netplay_ptr = NULL; -NetSettings g_NetPlaySettings; - -#define RPT_SIZE_HACK (1 << 16) - -// called from ---GUI--- thread -NetPlay::NetPlay(NetPlayUI* dialog) - : m_dialog(dialog), m_is_running(false), m_do_loop(true) -{ - m_target_buffer_size = 20; - ClearBuffers(); -} - -void NetPlay_Enable(NetPlay* const np) -{ - std::lock_guard<std::mutex> lk(crit_netplay_ptr); - netplay_ptr = np; -} - -void NetPlay_Disable() -{ - std::lock_guard<std::mutex> lk(crit_netplay_ptr); - netplay_ptr = NULL; -} - -// called from ---GUI--- thread -NetPlay::~NetPlay() -{ - std::lock_guard<std::mutex> lk(crit_netplay_ptr); - netplay_ptr = NULL; - - // not perfect - if (m_is_running) - StopGame(); -} - -NetPlay::Player::Player() -{ - memset(pad_map, -1, sizeof(pad_map)); -} - -// called from ---GUI--- thread -std::string NetPlay::Player::ToString() const -{ - std::ostringstream ss; - ss << name << '[' << (char)(pid+'0') << "] : " << revision << " |"; - for (unsigned int i=0; i<4; ++i) - ss << (pad_map[i]>=0 ? (char)(pad_map[i]+'1') : '-'); - ss << '|'; - return ss.str(); -} - -NetPad::NetPad() -{ - nHi = 0x00808080; - nLo = 0x80800000; -} - -NetPad::NetPad(const SPADStatus* const pad_status) -{ - nHi = (u32)((u8)pad_status->stickY); - nHi |= (u32)((u8)pad_status->stickX << 8); - nHi |= (u32)((u16)pad_status->button << 16); - nHi |= 0x00800000; - nLo = (u8)pad_status->triggerRight; - nLo |= (u32)((u8)pad_status->triggerLeft << 8); - nLo |= (u32)((u8)pad_status->substickY << 16); - nLo |= (u32)((u8)pad_status->substickX << 24); -} - -// called from ---NETPLAY--- thread -void NetPlay::ClearBuffers() -{ - // clear pad buffers, Clear method isn't thread safe - for (unsigned int i=0; i<4; ++i) - { - while (m_pad_buffer[i].Size()) - m_pad_buffer[i].Pop(); - - while (m_wiimote_buffer[i].Size()) - m_wiimote_buffer[i].Pop(); - - m_wiimote_input[i].clear(); - } -} - -// called from ---CPU--- thread -bool NetPlay::GetNetPads(const u8 pad_nb, const SPADStatus* const pad_status, NetPad* const netvalues) -{ - { - std::lock_guard<std::recursive_mutex> lkp(m_crit.players); - - // in game mapping for this local pad - unsigned int in_game_num = m_local_player->pad_map[pad_nb]; - - // does this local pad map in game? - if (in_game_num < 4) - { - NetPad np(pad_status); - - // adjust the buffer either up or down - // inserting multiple padstates or dropping states - while (m_pad_buffer[in_game_num].Size() <= m_target_buffer_size) - { - // add to buffer - m_pad_buffer[in_game_num].Push(np); - - // send - SendPadState(pad_nb, np); - } - } - - } // unlock players - - //Common::Timer bufftimer; - //bufftimer.Start(); - - // get padstate from buffer and send to game - while (!m_pad_buffer[pad_nb].Pop(*netvalues)) - { - // wait for receiving thread to push some data - Common::SleepCurrentThread(1); - - if (false == m_is_running) - return false; - - // TODO: check the time of bufftimer here, - // if it gets pretty high, ask the user if they want to disconnect - - } - - //u64 hangtime = bufftimer.GetTimeElapsed(); - //if (hangtime > 10) - //{ - // std::ostringstream ss; - // ss << "Pad " << (int)pad_nb << ": Had to wait " << hangtime << "ms for pad data. (increase pad Buffer maybe)"; - // Core::DisplayMessage(ss.str(), 1000); - //} - - return true; -} - -// called from ---CPU--- thread -void NetPlay::WiimoteInput(int _number, u16 _channelID, const void* _pData, u32 _Size) -{ - //// in game mapping for this local wiimote - unsigned int in_game_num = m_local_player->pad_map[_number]; // just using gc pad_map for now - - // does this local pad map in game? - if (in_game_num < 4) - { - m_wiimote_input[_number].resize(m_wiimote_input[_number].size() + 1); - m_wiimote_input[_number].back().assign((char*)_pData, (char*)_pData + _Size); - m_wiimote_input[_number].back().channel = _channelID; - } -} - -// called from ---CPU--- thread -void NetPlay::WiimoteUpdate(int _number) -{ - { - std::lock_guard<std::recursive_mutex> lkp(m_crit.players); - - // in game mapping for this local wiimote - unsigned int in_game_num = m_local_player->pad_map[_number]; // just using gc pad_map for now - - // does this local pad map in game? - if (in_game_num < 4) - { - m_wiimote_buffer[in_game_num].Push(m_wiimote_input[_number]); - - // TODO: send it - - m_wiimote_input[_number].clear(); - } - - } // unlock players - - if (0 == m_wiimote_buffer[_number].Size()) - { - //PanicAlert("PANIC"); - return; - } - - NetWiimote nw; - m_wiimote_buffer[_number].Pop(nw); - - NetWiimote::const_iterator - i = nw.begin(), e = nw.end(); - for ( ; i!=e; ++i) - Core::Callback_WiimoteInterruptChannel(_number, i->channel, &(*i)[0], (u32)i->size() + RPT_SIZE_HACK); -} - -// called from ---GUI--- thread -bool NetPlay::StartGame(const std::string &path) -{ - if (m_is_running) - { - PanicAlertT("Game is already running!"); - return false; - } - - m_dialog->AppendChat(" -- STARTING GAME -- "); - - m_is_running = true; - NetPlay_Enable(this); - - ClearBuffers(); - - // boot game - m_dialog->BootGame(path); - - // temporary - NetWiimote nw; - for (unsigned int i = 0; i<4; ++i) - for (unsigned int f = 0; f<2; ++f) - m_wiimote_buffer[i].Push(nw); - - return true; -} - -// called from ---GUI--- thread and ---NETPLAY--- thread (client side) -bool NetPlay::StopGame() -{ - std::lock_guard<std::recursive_mutex> lkg(m_crit.game); - - if (false == m_is_running) - { - PanicAlertT("Game isn't running!"); - return false; - } - - m_dialog->AppendChat(" -- STOPPING GAME -- "); - - m_is_running = false; - NetPlay_Disable(); - - // stop game - m_dialog->StopGame(); - - return true; -} - -void NetPlay::SetMemcardWriteEnabled(bool enabled) -{ - std::lock_guard<std::recursive_mutex> lkg(m_crit.game); - g_NetPlaySettings.m_WriteToMemcard = enabled; -} - -// called from ---CPU--- thread -u8 NetPlay::GetPadNum(u8 numPAD) -{ - // TODO: i don't like that this loop is running everytime there is rumble - unsigned int i = 0; - for (; i<4; ++i) - if (numPAD == m_local_player->pad_map[i]) - break; - - return i; -} - -void NetPlay::GetNetSettings() -{ - SConfig &instance = SConfig::GetInstance(); - g_NetPlaySettings.m_DSPHLE = instance.m_LocalCoreStartupParameter.bDSPHLE; - g_NetPlaySettings.m_DSPEnableJIT = instance.m_EnableJIT; - - for (unsigned int i = 0; i < 4; ++i) - g_NetPlaySettings.m_Controllers[i] = SConfig::GetInstance().m_SIDevice[i]; -} - -// stuff hacked into dolphin - -// called from ---CPU--- thread -// Actual Core function which is called on every frame -bool CSIDevice_GCController::NetPlay_GetInput(u8 numPAD, SPADStatus PadStatus, u32 *PADStatus) -{ - std::lock_guard<std::mutex> lk(crit_netplay_ptr); - - if (netplay_ptr) - return netplay_ptr->GetNetPads(numPAD, &PadStatus, (NetPad*)PADStatus); - else - return false; -} - -bool CSIDevice_GCSteeringWheel::NetPlay_GetInput(u8 numPAD, SPADStatus PadStatus, u32 *PADStatus) -{ - return CSIDevice_GCController::NetPlay_GetInput(numPAD, PadStatus, PADStatus); -} - -bool CSIDevice_DanceMat::NetPlay_GetInput(u8 numPAD, SPADStatus PadStatus, u32 *PADStatus) -{ - return CSIDevice_GCController::NetPlay_GetInput(numPAD, PadStatus, PADStatus); -} - -// called from ---CPU--- thread -// so all players' games get the same time -u32 CEXIIPL::NetPlay_GetGCTime() -{ - std::lock_guard<std::mutex> lk(crit_netplay_ptr); - - if (netplay_ptr) - return 1272737767; // watev - else - return 0; -} - -// called from ---CPU--- thread -// return the local pad num that should rumble given a ingame pad num -u8 CSIDevice_GCController::NetPlay_GetPadNum(u8 numPAD) -{ - std::lock_guard<std::mutex> lk(crit_netplay_ptr); - - if (netplay_ptr) - return netplay_ptr->GetPadNum(numPAD); - else - return numPAD; -} - -u8 CSIDevice_GCSteeringWheel::NetPlay_GetPadNum(u8 numPAD) -{ - return CSIDevice_GCController::NetPlay_GetPadNum(numPAD); -} - -u8 CSIDevice_DanceMat::NetPlay_GetPadNum(u8 numPAD) -{ - return CSIDevice_GCController::NetPlay_GetPadNum(numPAD); -} - -// called from ---CPU--- thread -// wiimote update / used for frame counting -//void CWII_IPC_HLE_Device_usb_oh1_57e_305::NetPlay_WiimoteUpdate(int _number) -void CWII_IPC_HLE_Device_usb_oh1_57e_305::NetPlay_WiimoteUpdate(int) -{ - //CritLocker crit(crit_netplay_ptr); - - //if (netplay_ptr) - // netplay_ptr->WiimoteUpdate(_number); -} - -// called from ---CPU--- thread -// -int CWII_IPC_HLE_WiiMote::NetPlay_GetWiimoteNum(int _number) -{ - //CritLocker crit(crit_netplay_ptr); - - //if (netplay_ptr) - // return netplay_ptr->GetPadNum(_number); // just using gcpad mapping for now - //else - return _number; -} - -// called from ---CPU--- thread -// intercept wiimote input callback -//bool CWII_IPC_HLE_WiiMote::NetPlay_WiimoteInput(int _number, u16 _channelID, const void* _pData, u32& _Size) -bool CWII_IPC_HLE_WiiMote::NetPlay_WiimoteInput(int, u16, const void*, u32&) -{ - std::lock_guard<std::mutex> lk(crit_netplay_ptr); - - if (netplay_ptr) - //{ - // if (_Size >= RPT_SIZE_HACK) - // { - // _Size -= RPT_SIZE_HACK; - // return false; - // } - // else - // { - // netplay_ptr->WiimoteInput(_number, _channelID, _pData, _Size); - // // don't use this packet - return true; - // } - //} - else - return false; -} - -NetPlay* NetPlay::GetNetPlayPtr() -{ - return netplay_ptr; -} diff --git a/Source/Core/Core/Src/NetPlay.h b/Source/Core/Core/Src/NetPlay.h deleted file mode 100644 index 222fb680cf..0000000000 --- a/Source/Core/Core/Src/NetPlay.h +++ /dev/null @@ -1,275 +0,0 @@ -// Copyright 2013 Dolphin Emulator Project -// Licensed under GPLv2 -// Refer to the license.txt file included. - -#ifndef _NETPLAY_H -#define _NETPLAY_H - -#include "Common.h" -#include "CommonTypes.h" -#include "Thread.h" -#include "Timer.h" - -#include <SFML/Network.hpp> - -#include "GCPadStatus.h" - -#include <functional> -#include <map> -#include <queue> -#include <sstream> - -#include "FifoQueue.h" - -class NetPad -{ -public: - NetPad(); - NetPad(const SPADStatus* const); - - u32 nHi; - u32 nLo; -}; - -struct NetSettings -{ - bool m_DSPHLE; - bool m_DSPEnableJIT; - bool m_WriteToMemcard; - u8 m_Controllers[4]; -}; -extern NetSettings g_NetPlaySettings; - -struct Rpt : public std::vector<u8> -{ - u16 channel; -}; - -typedef std::vector<Rpt> NetWiimote; - -#define NETPLAY_VERSION "Dolphin NetPlay 2013-07-22" - -// messages -enum -{ - NP_MSG_PLAYER_JOIN = 0x10, - NP_MSG_PLAYER_LEAVE = 0x11, - - NP_MSG_CHAT_MESSAGE = 0x30, - - NP_MSG_PAD_DATA = 0x60, - NP_MSG_PAD_MAPPING = 0x61, - NP_MSG_PAD_BUFFER = 0x62, - - NP_MSG_WIIMOTE_DATA = 0x70, - NP_MSG_WIIMOTE_MAPPING = 0x71, // just using pad mapping for now - - NP_MSG_START_GAME = 0xA0, - NP_MSG_CHANGE_GAME = 0xA1, - NP_MSG_STOP_GAME = 0xA2, - NP_MSG_DISABLE_GAME = 0xA3, - - NP_MSG_READY = 0xD0, - NP_MSG_NOT_READY = 0xD1, - - NP_MSG_PING = 0xE0, - NP_MSG_PONG = 0xE1, -}; - -typedef u8 MessageId; -typedef u8 PlayerId; -typedef s8 PadMapping; -typedef u32 FrameNum; - -enum -{ - CON_ERR_SERVER_FULL = 1, - CON_ERR_GAME_RUNNING, - CON_ERR_VERSION_MISMATCH -}; - -class NetPlayUI -{ -public: - virtual ~NetPlayUI() {}; - - virtual void BootGame(const std::string& filename) = 0; - virtual void StopGame() = 0; - - virtual void Update() = 0; - virtual void AppendChat(const std::string& msg) = 0; - - virtual void OnMsgChangeGame(const std::string& filename) = 0; - virtual void OnMsgStartGame() = 0; - virtual void OnMsgStopGame() = 0; -}; - -class NetPlay -{ -public: - NetPlay(NetPlayUI* _dialog); - virtual ~NetPlay(); - //virtual void ThreadFunc() = 0; - - bool is_connected; - - // Send and receive pads values - void WiimoteInput(int _number, u16 _channelID, const void* _pData, u32 _Size); - void WiimoteUpdate(int _number); - bool GetNetPads(const u8 pad_nb, const SPADStatus* const, NetPad* const netvalues); - virtual bool ChangeGame(const std::string& game) = 0; - virtual void GetPlayerList(std::string& list, std::vector<int>& pid_list) = 0; - virtual void SendChatMessage(const std::string& msg) = 0; - - virtual bool StartGame(const std::string &path); - virtual bool StopGame(); - - virtual void SetMemcardWriteEnabled(bool enabled); - //void PushPadStates(unsigned int count); - - u8 GetPadNum(u8 numPAD); - static NetPlay* GetNetPlayPtr(); - -protected: - //void GetBufferedPad(const u8 pad_nb, NetPad* const netvalues); - void ClearBuffers(); - void GetNetSettings(); - virtual void SendPadState(const PadMapping local_nb, const NetPad& np) = 0; - - struct - { - std::recursive_mutex game; - // lock order - std::recursive_mutex players, send; - } m_crit; - - class Player - { - public: - Player(); - std::string ToString() const; - - PlayerId pid; - std::string name; - PadMapping pad_map[4]; - std::string revision; - }; - - Common::FifoQueue<NetPad> m_pad_buffer[4]; - Common::FifoQueue<NetWiimote> m_wiimote_buffer[4]; - - NetWiimote m_wiimote_input[4]; - - NetPlayUI* m_dialog; - sf::SocketTCP m_socket; - std::thread m_thread; - sf::Selector<sf::SocketTCP> m_selector; - - std::string m_selected_game; - volatile bool m_is_running; - volatile bool m_do_loop; - - unsigned int m_target_buffer_size; - - Player* m_local_player; - - u32 m_current_game; -}; - -void NetPlay_Enable(NetPlay* const np); -void NetPlay_Disable(); - -class NetPlayServer : public NetPlay -{ -public: - void ThreadFunc(); - - NetPlayServer(const u16 port, const std::string& name, NetPlayUI* dialog); - ~NetPlayServer(); - - void GetPlayerList(std::string& list, std::vector<int>& pid_list); - - // Send and receive pads values - //bool GetNetPads(const u8 pad_nb, const SPADStatus* const, NetPad* const netvalues); - bool ChangeGame(const std::string& game); - void SendChatMessage(const std::string& msg); - - bool StartGame(const std::string &path); - bool StopGame(); - - bool GetPadMapping(const int pid, int map[]); - bool SetPadMapping(const int pid, const int map[]); - - u64 CalculateMinimumBufferTime(); - void AdjustPadBufferSize(unsigned int size); - -#ifdef USE_UPNP - void TryPortmapping(u16 port); -#endif - -private: - class Client : public Player - { - public: - Client() : ping(0), current_game(0) {} - - sf::SocketTCP socket; - u64 ping; - u32 current_game; - }; - - void SendPadState(const PadMapping local_nb, const NetPad& np); - void SendToClients(sf::Packet& packet, const PlayerId skip_pid = 0); - unsigned int OnConnect(sf::SocketTCP& socket); - unsigned int OnDisconnect(sf::SocketTCP& socket); - unsigned int OnData(sf::Packet& packet, sf::SocketTCP& socket); - void UpdatePadMapping(); - - std::map<sf::SocketTCP, Client> m_players; - - Common::Timer m_ping_timer; - u32 m_ping_key; - bool m_update_pings; - -#ifdef USE_UPNP - static void mapPortThread(const u16 port); - static void unmapPortThread(); - - static bool initUPnP(); - static bool UPnPMapPort(const std::string& addr, const u16 port); - static bool UPnPUnmapPort(const u16 port); - - static struct UPNPUrls m_upnp_urls; - static struct IGDdatas m_upnp_data; - static u16 m_upnp_mapped; - static bool m_upnp_inited; - static bool m_upnp_error; - static std::thread m_upnp_thread; -#endif -}; - -class NetPlayClient : public NetPlay -{ -public: - void ThreadFunc(); - - NetPlayClient(const std::string& address, const u16 port, NetPlayUI* dialog, const std::string& name); - ~NetPlayClient(); - - void GetPlayerList(std::string& list, std::vector<int>& pid_list); - - // Send and receive pads values - //bool GetNetPads(const u8 pad_nb, const SPADStatus* const, NetPad* const netvalues); - bool StartGame(const std::string &path); - bool ChangeGame(const std::string& game); - void SendChatMessage(const std::string& msg); - -private: - void SendPadState(const PadMapping local_nb, const NetPad& np); - unsigned int OnData(sf::Packet& packet); - - PlayerId m_pid; - std::map<PlayerId, Player> m_players; -}; - -#endif diff --git a/Source/Core/Core/Src/NetPlayClient.cpp b/Source/Core/Core/Src/NetPlayClient.cpp index 7163be001a..33f31a1815 100644 --- a/Source/Core/Core/Src/NetPlayClient.cpp +++ b/Source/Core/Core/Src/NetPlayClient.cpp @@ -2,21 +2,81 @@ // Licensed under GPLv2 // Refer to the license.txt file included. -#include "NetPlay.h" +#include "NetPlayClient.h" + +// for wiimote +#include "IPC_HLE/WII_IPC_HLE_Device_usb.h" +#include "IPC_HLE/WII_IPC_HLE_WiiMote.h" +// for gcpad +#include "HW/SI_DeviceGCController.h" +#include "HW/SI_DeviceGCSteeringWheel.h" +#include "HW/SI_DeviceDanceMat.h" +// for gctime +#include "HW/EXI_DeviceIPL.h" +// for wiimote/ OSD messages +#include "Core.h" +#include "ConfigManager.h" + +std::mutex crit_netplay_client; +static NetPlayClient * netplay_client = NULL; +NetSettings g_NetPlaySettings; + +#define RPT_SIZE_HACK (1 << 16) + +NetPlayClient::Player::Player() +{ + memset(pad_map, -1, sizeof(pad_map)); +} + +// called from ---GUI--- thread +std::string NetPlayClient::Player::ToString() const +{ + std::ostringstream ss; + ss << name << '[' << (char)(pid+'0') << "] : " << revision << " |"; + for (unsigned int i=0; i<4; ++i) + ss << (pad_map[i]>=0 ? (char)(pad_map[i]+'1') : '-'); + ss << " | " << ping << "ms"; + return ss.str(); +} + +NetPad::NetPad() +{ + nHi = 0x00808080; + nLo = 0x80800000; +} + +NetPad::NetPad(const SPADStatus* const pad_status) +{ + nHi = (u32)((u8)pad_status->stickY); + nHi |= (u32)((u8)pad_status->stickX << 8); + nHi |= (u32)((u16)pad_status->button << 16); + nHi |= 0x00800000; + nLo = (u8)pad_status->triggerRight; + nLo |= (u32)((u8)pad_status->triggerLeft << 8); + nLo |= (u32)((u8)pad_status->substickY << 16); + nLo |= (u32)((u8)pad_status->substickX << 24); +} // called from ---GUI--- thread NetPlayClient::~NetPlayClient() { + // not perfect + if (m_is_running) + StopGame(); + if (is_connected) { m_do_loop = false; m_thread.join(); - } + } } // called from ---GUI--- thread -NetPlayClient::NetPlayClient(const std::string& address, const u16 port, NetPlayUI* dialog, const std::string& name) : NetPlay(dialog) +NetPlayClient::NetPlayClient(const std::string& address, const u16 port, NetPlayUI* dialog, const std::string& name) : m_dialog(dialog), m_is_running(false), m_do_loop(true) { + m_target_buffer_size = 20; + ClearBuffers(); + is_connected = false; // why is false successful? documentation says true is @@ -193,6 +253,7 @@ unsigned int NetPlayClient::OnData(sf::Packet& packet) { std::lock_guard<std::recursive_mutex> lkg(m_crit.game); packet >> m_current_game; + packet >> g_NetPlaySettings.m_CPUthread; packet >> g_NetPlaySettings.m_DSPEnableJIT; packet >> g_NetPlaySettings.m_DSPHLE; packet >> g_NetPlaySettings.m_WriteToMemcard; @@ -233,6 +294,21 @@ unsigned int NetPlayClient::OnData(sf::Packet& packet) } break; + case NP_MSG_PLAYER_PING_DATA: + { + PlayerId pid; + packet >> pid; + + { + std::lock_guard<std::recursive_mutex> lkp(m_crit.players); + Player& player = m_players[pid]; + packet >> player.ping; + } + + m_dialog->Update(); + } + break; + default : PanicAlertT("Unknown message received with id : %d", mid); break; @@ -328,12 +404,31 @@ bool NetPlayClient::StartGame(const std::string &path) spac << m_current_game; spac << (char *)&g_NetPlaySettings; - if (false == NetPlay::StartGame(path)) - return false; - std::lock_guard<std::recursive_mutex> lks(m_crit.send); m_socket.Send(spac); + if (m_is_running) + { + PanicAlertT("Game is already running!"); + return false; + } + + m_dialog->AppendChat(" -- STARTING GAME -- "); + + m_is_running = true; + NetPlay_Enable(this); + + ClearBuffers(); + + // boot game + m_dialog->BootGame(path); + + // temporary + NetWiimote nw; + for (unsigned int i = 0; i<4; ++i) + for (unsigned int f = 0; f<2; ++f) + m_wiimote_buffer[i].Push(nw); + return true; } @@ -342,3 +437,283 @@ bool NetPlayClient::ChangeGame(const std::string&) { return true; } + +// called from ---NETPLAY--- thread +void NetPlayClient::ClearBuffers() +{ + // clear pad buffers, Clear method isn't thread safe + for (unsigned int i=0; i<4; ++i) + { + while (m_pad_buffer[i].Size()) + m_pad_buffer[i].Pop(); + + while (m_wiimote_buffer[i].Size()) + m_wiimote_buffer[i].Pop(); + + m_wiimote_input[i].clear(); + } +} + +// called from ---CPU--- thread +bool NetPlayClient::GetNetPads(const u8 pad_nb, const SPADStatus* const pad_status, NetPad* const netvalues) +{ + { + std::lock_guard<std::recursive_mutex> lkp(m_crit.players); + + // in game mapping for this local pad + unsigned int in_game_num = m_local_player->pad_map[pad_nb]; + + // does this local pad map in game? + if (in_game_num < 4) + { + NetPad np(pad_status); + + // adjust the buffer either up or down + // inserting multiple padstates or dropping states + while (m_pad_buffer[in_game_num].Size() <= m_target_buffer_size) + { + // add to buffer + m_pad_buffer[in_game_num].Push(np); + + // send + SendPadState(pad_nb, np); + } + } + + } // unlock players + + //Common::Timer bufftimer; + //bufftimer.Start(); + + // get padstate from buffer and send to game + while (!m_pad_buffer[pad_nb].Pop(*netvalues)) + { + // wait for receiving thread to push some data + Common::SleepCurrentThread(1); + + if (false == m_is_running) + return false; + + // TODO: check the time of bufftimer here, + // if it gets pretty high, ask the user if they want to disconnect + + } + + //u64 hangtime = bufftimer.GetTimeElapsed(); + //if (hangtime > 10) + //{ + // std::ostringstream ss; + // ss << "Pad " << (int)pad_nb << ": Had to wait " << hangtime << "ms for pad data. (increase pad Buffer maybe)"; + // Core::DisplayMessage(ss.str(), 1000); + //} + + return true; +} + +// called from ---CPU--- thread +void NetPlayClient::WiimoteInput(int _number, u16 _channelID, const void* _pData, u32 _Size) +{ + //// in game mapping for this local wiimote + unsigned int in_game_num = m_local_player->pad_map[_number]; // just using gc pad_map for now + + // does this local pad map in game? + if (in_game_num < 4) + { + m_wiimote_input[_number].resize(m_wiimote_input[_number].size() + 1); + m_wiimote_input[_number].back().assign((char*)_pData, (char*)_pData + _Size); + m_wiimote_input[_number].back().channel = _channelID; + } +} + +// called from ---CPU--- thread +void NetPlayClient::WiimoteUpdate(int _number) +{ + { + std::lock_guard<std::recursive_mutex> lkp(m_crit.players); + + // in game mapping for this local wiimote + unsigned int in_game_num = m_local_player->pad_map[_number]; // just using gc pad_map for now + + // does this local pad map in game? + if (in_game_num < 4) + { + m_wiimote_buffer[in_game_num].Push(m_wiimote_input[_number]); + + // TODO: send it + + m_wiimote_input[_number].clear(); + } + + } // unlock players + + if (0 == m_wiimote_buffer[_number].Size()) + { + //PanicAlert("PANIC"); + return; + } + + NetWiimote nw; + m_wiimote_buffer[_number].Pop(nw); + + NetWiimote::const_iterator + i = nw.begin(), e = nw.end(); + for ( ; i!=e; ++i) + Core::Callback_WiimoteInterruptChannel(_number, i->channel, &(*i)[0], (u32)i->size() + RPT_SIZE_HACK); +} + +// called from ---GUI--- thread and ---NETPLAY--- thread (client side) +bool NetPlayClient::StopGame() +{ + std::lock_guard<std::recursive_mutex> lkg(m_crit.game); + + if (false == m_is_running) + { + PanicAlertT("Game isn't running!"); + return false; + } + + m_dialog->AppendChat(" -- STOPPING GAME -- "); + + m_is_running = false; + NetPlay_Disable(); + + // stop game + m_dialog->StopGame(); + + return true; +} + +// called from ---CPU--- thread +u8 NetPlayClient::GetPadNum(u8 numPAD) +{ + // TODO: i don't like that this loop is running everytime there is rumble + unsigned int i = 0; + for (; i<4; ++i) + if (numPAD == m_local_player->pad_map[i]) + break; + + return i; +} + +// stuff hacked into dolphin + +// called from ---CPU--- thread +// Actual Core function which is called on every frame +bool CSIDevice_GCController::NetPlay_GetInput(u8 numPAD, SPADStatus PadStatus, u32 *PADStatus) +{ + std::lock_guard<std::mutex> lk(crit_netplay_client); + + if (netplay_client) + return netplay_client->GetNetPads(numPAD, &PadStatus, (NetPad*)PADStatus); + else + return false; +} + +bool CSIDevice_GCSteeringWheel::NetPlay_GetInput(u8 numPAD, SPADStatus PadStatus, u32 *PADStatus) +{ + return CSIDevice_GCController::NetPlay_GetInput(numPAD, PadStatus, PADStatus); +} + +bool CSIDevice_DanceMat::NetPlay_GetInput(u8 numPAD, SPADStatus PadStatus, u32 *PADStatus) +{ + return CSIDevice_GCController::NetPlay_GetInput(numPAD, PadStatus, PADStatus); +} + +// called from ---CPU--- thread +// so all players' games get the same time +u32 CEXIIPL::NetPlay_GetGCTime() +{ + std::lock_guard<std::mutex> lk(crit_netplay_client); + + if (netplay_client) + return 1272737767; // watev + else + return 0; +} + +// called from ---CPU--- thread +// return the local pad num that should rumble given a ingame pad num +u8 CSIDevice_GCController::NetPlay_GetPadNum(u8 numPAD) +{ + std::lock_guard<std::mutex> lk(crit_netplay_client); + + if (netplay_client) + return netplay_client->GetPadNum(numPAD); + else + return numPAD; +} + +u8 CSIDevice_GCSteeringWheel::NetPlay_GetPadNum(u8 numPAD) +{ + return CSIDevice_GCController::NetPlay_GetPadNum(numPAD); +} + +u8 CSIDevice_DanceMat::NetPlay_GetPadNum(u8 numPAD) +{ + return CSIDevice_GCController::NetPlay_GetPadNum(numPAD); +} + +// called from ---CPU--- thread +// wiimote update / used for frame counting +//void CWII_IPC_HLE_Device_usb_oh1_57e_305::NetPlay_WiimoteUpdate(int _number) +void CWII_IPC_HLE_Device_usb_oh1_57e_305::NetPlay_WiimoteUpdate(int) +{ + //CritLocker crit(crit_netplay_client); + + //if (netplay_client) + // netplay_client->WiimoteUpdate(_number); +} + +// called from ---CPU--- thread +// +int CWII_IPC_HLE_WiiMote::NetPlay_GetWiimoteNum(int _number) +{ + //CritLocker crit(crit_netplay_client); + + //if (netplay_client) + // return netplay_client->GetPadNum(_number); // just using gcpad mapping for now + //else + return _number; +} + +// called from ---CPU--- thread +// intercept wiimote input callback +//bool CWII_IPC_HLE_WiiMote::NetPlay_WiimoteInput(int _number, u16 _channelID, const void* _pData, u32& _Size) +bool CWII_IPC_HLE_WiiMote::NetPlay_WiimoteInput(int, u16, const void*, u32&) +{ + std::lock_guard<std::mutex> lk(crit_netplay_client); + + if (netplay_client) + //{ + // if (_Size >= RPT_SIZE_HACK) + // { + // _Size -= RPT_SIZE_HACK; + // return false; + // } + // else + // { + // netplay_client->WiimoteInput(_number, _channelID, _pData, _Size); + // // don't use this packet + return true; + // } + //} + else + return false; +} + +bool NetPlay::IsNetPlayRunning() +{ + return netplay_client != NULL; +} + +void NetPlay_Enable(NetPlayClient* const np) +{ + std::lock_guard<std::mutex> lk(crit_netplay_client); + netplay_client = np; +} + +void NetPlay_Disable() +{ + std::lock_guard<std::mutex> lk(crit_netplay_client); + netplay_client = NULL; +} diff --git a/Source/Core/Core/Src/NetPlayClient.h b/Source/Core/Core/Src/NetPlayClient.h new file mode 100644 index 0000000000..d44a4c84b8 --- /dev/null +++ b/Source/Core/Core/Src/NetPlayClient.h @@ -0,0 +1,135 @@ +// Copyright 2013 Dolphin Emulator Project +// Licensed under GPLv2 +// Refer to the license.txt file included. + +#ifndef _NETPLAY_H +#define _NETPLAY_H + +#include "Common.h" +#include "CommonTypes.h" +#include "Thread.h" +#include "Timer.h" + +#include <SFML/Network.hpp> + +#include "NetPlayProto.h" +#include "GCPadStatus.h" + +#include <functional> +#include <map> +#include <queue> +#include <sstream> + +#include "FifoQueue.h" + +class NetPad +{ +public: + NetPad(); + NetPad(const SPADStatus* const); + + u32 nHi; + u32 nLo; +}; + +class NetPlayUI +{ +public: + virtual ~NetPlayUI() {}; + + virtual void BootGame(const std::string& filename) = 0; + virtual void StopGame() = 0; + + virtual void Update() = 0; + virtual void AppendChat(const std::string& msg) = 0; + + virtual void OnMsgChangeGame(const std::string& filename) = 0; + virtual void OnMsgStartGame() = 0; + virtual void OnMsgStopGame() = 0; +}; + +extern NetSettings g_NetPlaySettings; + +class NetPlayClient +{ +public: + void ThreadFunc(); + + NetPlayClient(const std::string& address, const u16 port, NetPlayUI* dialog, const std::string& name); + ~NetPlayClient(); + + void GetPlayerList(std::string& list, std::vector<int>& pid_list); + + bool is_connected; + + bool StartGame(const std::string &path); + bool StopGame(); + bool ChangeGame(const std::string& game); + void SendChatMessage(const std::string& msg); + + // Send and receive pads values + void WiimoteInput(int _number, u16 _channelID, const void* _pData, u32 _Size); + void WiimoteUpdate(int _number); + bool GetNetPads(const u8 pad_nb, const SPADStatus* const, NetPad* const netvalues); + + u8 GetPadNum(u8 numPAD); + +protected: + void ClearBuffers(); + + struct + { + std::recursive_mutex game; + // lock order + std::recursive_mutex players, send; + } m_crit; + + class Player + { + public: + Player(); + std::string ToString() const; + + PlayerId pid; + std::string name; + PadMapping pad_map[4]; + std::string revision; + u32 ping; + }; + + Common::FifoQueue<NetPad> m_pad_buffer[4]; + Common::FifoQueue<NetWiimote> m_wiimote_buffer[4]; + + NetWiimote m_wiimote_input[4]; + + NetPlayUI* m_dialog; + sf::SocketTCP m_socket; + std::thread m_thread; + sf::Selector<sf::SocketTCP> m_selector; + + std::string m_selected_game; + volatile bool m_is_running; + volatile bool m_do_loop; + + unsigned int m_target_buffer_size; + + Player* m_local_player; + + u32 m_current_game; + +private: + void SendPadState(const PadMapping local_nb, const NetPad& np); + unsigned int OnData(sf::Packet& packet); + + PlayerId m_pid; + std::map<PlayerId, Player> m_players; +}; + +namespace NetPlay { + bool IsNetPlayRunning(); +}; + +void NetPlay_Enable(NetPlayClient* const np); +void NetPlay_Disable(); + +#endif diff --git a/Source/Core/Core/Src/NetPlayProto.h b/Source/Core/Core/Src/NetPlayProto.h new file mode 100644 index 0000000000..d4abf60cb8 --- /dev/null +++ b/Source/Core/Core/Src/NetPlayProto.h @@ -0,0 +1,69 @@ +// Copyright 2013 Dolphin Emulator Project +// Licensed under GPLv2 +// Refer to the license.txt file included. + +#ifndef _NETPLAY_PROTO_H +#define _NETPLAY_PROTO_H + +#include "Common.h" +#include "CommonTypes.h" + +struct NetSettings +{ + bool m_CPUthread; + bool m_DSPHLE; + bool m_DSPEnableJIT; + bool m_WriteToMemcard; + u8 m_Controllers[4]; +}; + +struct Rpt : public std::vector<u8> +{ + u16 channel; +}; + +typedef std::vector<Rpt> NetWiimote; + +#define NETPLAY_VERSION "Dolphin NetPlay 2013-08-18" + +// messages +enum +{ + NP_MSG_PLAYER_JOIN = 0x10, + NP_MSG_PLAYER_LEAVE = 0x11, + + NP_MSG_CHAT_MESSAGE = 0x30, + + NP_MSG_PAD_DATA = 0x60, + NP_MSG_PAD_MAPPING = 0x61, + NP_MSG_PAD_BUFFER = 0x62, + + NP_MSG_WIIMOTE_DATA = 0x70, + NP_MSG_WIIMOTE_MAPPING = 0x71, // just using pad mapping for now + + NP_MSG_START_GAME = 0xA0, + NP_MSG_CHANGE_GAME = 0xA1, + NP_MSG_STOP_GAME = 0xA2, + NP_MSG_DISABLE_GAME = 0xA3, + + NP_MSG_READY = 0xD0, + NP_MSG_NOT_READY = 0xD1, + + NP_MSG_PING = 0xE0, + NP_MSG_PONG = 0xE1, + NP_MSG_PLAYER_PING_DATA = 0xE2, +}; + +typedef u8 MessageId; +typedef u8 PlayerId; +typedef s8 PadMapping; +typedef u32 FrameNum; + +enum +{ + CON_ERR_SERVER_FULL = 1, + CON_ERR_GAME_RUNNING, + CON_ERR_VERSION_MISMATCH +}; + +#endif diff --git a/Source/Core/Core/Src/NetPlayServer.cpp b/Source/Core/Core/Src/NetPlayServer.cpp index db3a41a398..134045c5bf 100644 --- a/Source/Core/Core/Src/NetPlayServer.cpp +++ b/Source/Core/Core/Src/NetPlayServer.cpp @@ -2,15 +2,20 @@ // Licensed under GPLv2 // Refer to the license.txt file included. -#include "NetPlay.h" +#include "NetPlayServer.h" + +NetPlayServer::Client::Client() +{ + memset(pad_map, -1, sizeof(pad_map)); +} -// called from ---GUI--- thread NetPlayServer::~NetPlayServer() { if (is_connected) { m_do_loop = false; m_thread.join(); + m_socket.Close(); } #ifdef USE_UPNP @@ -22,35 +27,15 @@ NetPlayServer::~NetPlayServer() } // called from ---GUI--- thread -NetPlayServer::NetPlayServer(const u16 port, const std::string& name, NetPlayUI* dialog) : NetPlay(dialog) +NetPlayServer::NetPlayServer(const u16 port) : is_connected(false), m_is_running(false) { - m_update_pings = true; - if (m_socket.Listen(port)) { - Client player; - player.pid = 0; - player.revision = netplay_dolphin_ver; - player.socket = m_socket; - player.name = name; - - // map local pad 1 to game pad 1 - player.pad_map[0] = 0; - - // add self to player list - m_players[m_socket] = player; - m_local_player = &m_players[m_socket]; - //PanicAlertT("Listening"); - - m_dialog->Update(); - is_connected = true; - + m_do_loop = true; m_selector.Add(m_socket); m_thread = std::thread(std::mem_fun(&NetPlayServer::ThreadFunc), this); } - else - is_connected = false; } // called from ---NETPLAY--- thread @@ -258,8 +243,6 @@ unsigned int NetPlayServer::OnConnect(sf::SocketTCP& socket) // add client to selector/ used for receiving m_selector.Add(socket); - m_dialog->Update(); - return 0; } @@ -271,7 +254,6 @@ unsigned int NetPlayServer::OnDisconnect(sf::SocketTCP& socket) PanicAlertT("Client disconnect while game is running!! NetPlay is disabled. You must manually stop the game."); std::lock_guard<std::recursive_mutex> lkg(m_crit.game); m_is_running = false; - NetPlay_Disable(); sf::Packet spac; spac << (MessageId)NP_MSG_DISABLE_GAME; @@ -293,8 +275,6 @@ unsigned int NetPlayServer::OnDisconnect(sf::SocketTCP& socket) std::lock_guard<std::recursive_mutex> lks(m_crit.send); SendToClients(spac); - m_dialog->Update(); - return 0; } @@ -357,8 +337,6 @@ bool NetPlayServer::SetPadMapping(const int pid, const int map[]) std::lock_guard<std::recursive_mutex> lks(m_crit.send); UpdatePadMapping(); // sync pad mappings with everyone - m_dialog->Update(); - return true; } @@ -381,29 +359,6 @@ void NetPlayServer::UpdatePadMapping() } // called from ---GUI--- thread and ---NETPLAY--- thread -u64 NetPlayServer::CalculateMinimumBufferTime() -{ - std::lock_guard<std::recursive_mutex> lkp(m_crit.players); - - std::map<sf::SocketTCP, Client>::const_iterator - i = m_players.begin(), - e = m_players.end(); - std::priority_queue<unsigned int> pings; - for ( ;i!=e; ++i) - pings.push(i->second.ping/2); - - unsigned int required_ms = pings.top(); - // if there is more than 1 client, buffersize must be >= (2 highest ping times combined) - if (pings.size() > 1) - { - pings.pop(); - required_ms += pings.top(); - } - - return required_ms; -} - -// called from ---GUI--- thread and ---NETPLAY--- thread void NetPlayServer::AdjustPadBufferSize(unsigned int size) { std::lock_guard<std::recursive_mutex> lkg(m_crit.game); @@ -447,12 +402,6 @@ unsigned int NetPlayServer::OnData(sf::Packet& packet, sf::SocketTCP& socket) std::lock_guard<std::recursive_mutex> lks(m_crit.send); SendToClients(spac, player.pid); } - - // add to gui - std::ostringstream ss; - ss << player.name << '[' << (char)(player.pid+'0') << "]: " << msg; - - m_dialog->AppendChat(ss.str()); } break; @@ -463,8 +412,8 @@ unsigned int NetPlayServer::OnData(sf::Packet& packet, sf::SocketTCP& socket) break; PadMapping map = 0; - NetPad np; - packet >> map >> np.nHi >> np.nLo; + int hi, lo; + packet >> map >> hi >> lo; // check if client's pad indeed maps in game if (map >= 0 && map < 4) @@ -477,14 +426,12 @@ unsigned int NetPlayServer::OnData(sf::Packet& packet, sf::SocketTCP& socket) if (map < 0) return 1; - // add to pad buffer - m_pad_buffer[(unsigned)map].Push(np); // relay to clients sf::Packet spac; spac << (MessageId)NP_MSG_PAD_DATA; spac << map; // in game mapping - spac << np.nHi << np.nLo; + spac << hi << lo; std::lock_guard<std::recursive_mutex> lks(m_crit.send); SendToClients(spac, player.pid); @@ -498,11 +445,15 @@ unsigned int NetPlayServer::OnData(sf::Packet& packet, sf::SocketTCP& socket) packet >> ping_key; if (m_ping_key == ping_key) - { - //PanicAlertT("Good pong"); player.ping = ping; - } - m_dialog->Update(); + + sf::Packet spac; + spac << (MessageId)NP_MSG_PLAYER_PING_DATA; + spac << player.pid; + spac << player.ping; + + std::lock_guard<std::recursive_mutex> lks(m_crit.send); + SendToClients(spac); } break; @@ -522,25 +473,6 @@ unsigned int NetPlayServer::OnData(sf::Packet& packet, sf::SocketTCP& socket) return 0; } -// called from ---GUI--- thread -void NetPlayServer::GetPlayerList(std::string& list, std::vector<int>& pid_list) -{ - std::lock_guard<std::recursive_mutex> lkp(m_crit.players); - - std::ostringstream ss; - - std::map<sf::SocketTCP, Client>::const_iterator - i = m_players.begin(), - e = m_players.end(); - for ( ; i!=e; ++i) - { - ss << i->second.ToString() << " " << i->second.ping << "ms\n"; - pid_list.push_back(i->second.pid); - } - - list = ss.str(); -} - // called from ---GUI--- thread / and ---NETPLAY--- thread void NetPlayServer::SendChatMessage(const std::string& msg) { @@ -573,29 +505,16 @@ bool NetPlayServer::ChangeGame(const std::string &game) return true; } -// called from ---CPU--- thread -void NetPlayServer::SendPadState(const PadMapping local_nb, const NetPad& np) +// called from ---GUI--- thread +void NetPlayServer::SetNetSettings(const NetSettings &settings) { - // send to server - sf::Packet spac; - spac << (MessageId)NP_MSG_PAD_DATA; - spac << m_local_player->pad_map[local_nb]; // in-game pad num - spac << np.nHi << np.nLo; - - std::lock_guard<std::recursive_mutex> lks(m_crit.send); - SendToClients(spac); + m_settings = settings; } // called from ---GUI--- thread bool NetPlayServer::StartGame(const std::string &path) { std::lock_guard<std::recursive_mutex> lkg(m_crit.game); - - GetNetSettings(); - if (false == NetPlay::StartGame(path)) - return false; - - // TODO: i dont like this here m_current_game = Common::Timer::GetTimeMs(); // no change, just update with clients @@ -604,17 +523,20 @@ bool NetPlayServer::StartGame(const std::string &path) // tell clients to start game sf::Packet spac; spac << (MessageId)NP_MSG_START_GAME; - spac << NetPlay::m_current_game; - spac << g_NetPlaySettings.m_DSPEnableJIT; - spac << g_NetPlaySettings.m_DSPHLE; - spac << g_NetPlaySettings.m_WriteToMemcard; + spac << m_current_game; + spac << m_settings.m_CPUthread; + spac << m_settings.m_DSPEnableJIT; + spac << m_settings.m_DSPHLE; + spac << m_settings.m_WriteToMemcard; for (unsigned int i = 0; i < 4; ++i) - spac << g_NetPlaySettings.m_Controllers[i]; + spac << m_settings.m_Controllers[i]; std::lock_guard<std::recursive_mutex> lkp(m_crit.players); std::lock_guard<std::recursive_mutex> lks(m_crit.send); SendToClients(spac); + m_is_running = true; + return true; } @@ -622,9 +544,6 @@ bool NetPlayServer::StartGame(const std::string &path) // called from ---GUI--- thread bool NetPlayServer::StopGame() { - if (false == NetPlay::StopGame()) - return false; - // tell clients to stop game sf::Packet spac; spac << (MessageId)NP_MSG_STOP_GAME; @@ -633,6 +552,8 @@ bool NetPlayServer::StopGame() std::lock_guard<std::recursive_mutex> lks(m_crit.send); SendToClients(spac); + m_is_running = false; + return true; } diff --git a/Source/Core/Core/Src/NetPlayServer.h b/Source/Core/Core/Src/NetPlayServer.h new file mode 100644 index 0000000000..4ef601bf06 --- /dev/null +++ b/Source/Core/Core/Src/NetPlayServer.h @@ -0,0 +1,113 @@ +// Copyright 2013 Dolphin Emulator Project +// Licensed under GPLv2 +// Refer to the license.txt file included. + +#ifndef _NETPLAY_SERVER_H +#define _NETPLAY_SERVER_H + +#include "Common.h" +#include "CommonTypes.h" +#include "Thread.h" +#include "Timer.h" + +#include <SFML/Network.hpp> + +#include "NetPlayProto.h" + +#include <functional> +#include <map> +#include <queue> +#include <sstream> + +class NetPlayServer +{ +public: + void ThreadFunc(); + + NetPlayServer(const u16 port); + ~NetPlayServer(); + + bool ChangeGame(const std::string& game); + void SendChatMessage(const std::string& msg); + + void SetNetSettings(const NetSettings &settings); + + bool StartGame(const std::string &path); + bool StopGame(); + + bool GetPadMapping(const int pid, int map[]); + bool SetPadMapping(const int pid, const int map[]); + + void AdjustPadBufferSize(unsigned int size); + + bool is_connected; + +#ifdef USE_UPNP + void TryPortmapping(u16 port); +#endif + +private: + class Client + { + public: + Client(); + + PlayerId pid; + std::string name; + PadMapping pad_map[4]; + std::string revision; + + sf::SocketTCP socket; + u32 ping; + u32 current_game; + }; + + void SendToClients(sf::Packet& packet, const PlayerId skip_pid = 0); + unsigned int OnConnect(sf::SocketTCP& socket); + unsigned int OnDisconnect(sf::SocketTCP& socket); + unsigned int OnData(sf::Packet& packet, sf::SocketTCP& socket); + void UpdatePadMapping(); + + NetSettings m_settings; + + bool m_is_running; + bool m_do_loop; + Common::Timer m_ping_timer; + u32 m_ping_key; + bool m_update_pings; + u32 m_current_game; + unsigned int m_target_buffer_size; + + std::map<sf::SocketTCP, Client> m_players; + + struct + { + std::recursive_mutex game; + // lock order + std::recursive_mutex players, send; + } m_crit; + + std::string m_selected_game; + + sf::SocketTCP m_socket; + std::thread m_thread; + sf::Selector<sf::SocketTCP> m_selector; + +#ifdef USE_UPNP + static void mapPortThread(const u16 port); + static void unmapPortThread(); + + static bool initUPnP(); + static bool UPnPMapPort(const std::string& addr, const u16 port); + static bool UPnPUnmapPort(const u16 port); + + static struct UPNPUrls m_upnp_urls; + static struct IGDdatas m_upnp_data; + static u16 m_upnp_mapped; + static bool m_upnp_inited; + static bool m_upnp_error; + static std::thread m_upnp_thread; +#endif +}; + +#endif diff --git a/Source/Core/Core/Src/PowerPC/JitArm32/Jit.cpp b/Source/Core/Core/Src/PowerPC/JitArm32/Jit.cpp index a4988f7c17..cd5f90d129 100644 --- a/Source/Core/Core/Src/PowerPC/JitArm32/Jit.cpp +++ b/Source/Core/Core/Src/PowerPC/JitArm32/Jit.cpp @@ -48,15 +48,10 @@ void JitArm::Init() AllocCodeSpace(CODE_SIZE); blocks.Init(); asm_routines.Init(); - // TODO: Investigate why the register cache crashes when only doing Init with - // the pointer to this. Seems for some reason it doesn't set the emitter pointer - // In the class for some reason? gpr.Init(this); - gpr.SetEmitter(this); fpr.Init(this); - fpr.SetEmitter(this); jo.enableBlocklink = true; - jo.optimizeGatherPipe = false; + jo.optimizeGatherPipe = true; } void JitArm::ClearCache() @@ -137,7 +132,11 @@ static void ImHere() void JitArm::Cleanup() { if (jo.optimizeGatherPipe && js.fifoBytesThisBlock > 0) + { + PUSH(4, R0, R1, R2, R3); QuickCallFunction(R14, (void*)&GPFifo::CheckGatherPipe); + POP(4, R0, R1, R2, R3); + } } void JitArm::DoDownCount() { @@ -290,9 +289,9 @@ void STACKALIGN JitArm::Jit(u32 em_address) ClearCache(); } - int block_num = blocks.AllocateBlock(em_address); + int block_num = blocks.AllocateBlock(PowerPC::ppcState.pc); JitBlock *b = blocks.GetBlock(block_num); - const u8* BlockPtr = DoJit(em_address, &code_buffer, b); + const u8* BlockPtr = DoJit(PowerPC::ppcState.pc, &code_buffer, b); blocks.FinalizeBlock(block_num, jo.enableBlocklink, BlockPtr); } void JitArm::Break(UGeckoInstruction inst) @@ -360,13 +359,13 @@ const u8* JitArm::DoJit(u32 em_address, PPCAnalyst::CodeBuffer *code_buf, JitBlo // Downcount flag check, Only valid for linked blocks { - FixupBranch skip = B_CC(CC_PL); + SetCC(CC_MI); ARMReg rA = gpr.GetReg(false); MOVI2R(rA, js.blockStart); STR(rA, R9, PPCSTATE_OFF(pc)); MOVI2R(rA, (u32)asm_routines.doTiming); B(rA); - SetJumpTarget(skip); + SetCC(); } const u8 *normalEntry = GetCodePtr(); @@ -384,11 +383,11 @@ const u8* JitArm::DoJit(u32 em_address, PPCAnalyst::CodeBuffer *code_buf, JitBlo MOVI2R(C, js.blockStart); // R3 LDR(A, R9, PPCSTATE_OFF(msr)); TST(A, Shift); - FixupBranch b1 = B_CC(CC_NEQ); + SetCC(CC_EQ); STR(C, R9, PPCSTATE_OFF(pc)); MOVI2R(A, (u32)asm_routines.fpException); B(A); - SetJumpTarget(b1); + SetCC(); gpr.Unlock(A, C); } // Conditionally add profiling code. @@ -451,8 +450,9 @@ const u8* JitArm::DoJit(u32 em_address, PPCAnalyst::CodeBuffer *code_buf, JitBlo if (jo.optimizeGatherPipe && js.fifoBytesThisBlock >= 32) { js.fifoBytesThisBlock -= 32; - // TODO: This needs thunkmanager for ARM - //ARMABI_CallFunction(thunks.ProtectFunction((void *)&GPFifo::CheckGatherPipe, 0)); + PUSH(4, R0, R1, R2, R3); + QuickCallFunction(R14, (void*)&GPFifo::CheckGatherPipe); + POP(4, R0, R1, R2, R3); } if (Core::g_CoreStartupParameter.bEnableDebugging) { diff --git a/Source/Core/Core/Src/PowerPC/JitArm32/Jit.h b/Source/Core/Core/Src/PowerPC/JitArm32/Jit.h index e5a07b3bac..be203868e5 100644 --- a/Source/Core/Core/Src/PowerPC/JitArm32/Jit.h +++ b/Source/Core/Core/Src/PowerPC/JitArm32/Jit.h @@ -116,10 +116,11 @@ public: void GenerateRC(int cr = 0); void ComputeRC(int cr = 0); + void ComputeRC(s32 value, int cr); - // TODO: This shouldn't be here - void StoreFromReg(ARMReg dest, ARMReg value, int accessSize, s32 offset); - void LoadToReg(ARMReg dest, ARMReg addr, int accessSize, s32 offset); + void ComputeCarry(); + void GetCarryAndClear(ARMReg reg); + void FinalizeCarry(ARMReg reg); // OPCODES void unknown_instruction(UGeckoInstruction _inst); @@ -147,18 +148,27 @@ public: void addi(UGeckoInstruction _inst); void addis(UGeckoInstruction _inst); void addx(UGeckoInstruction _inst); + void addcx(UGeckoInstruction _inst); + void addex(UGeckoInstruction _inst); void cmp (UGeckoInstruction _inst); void cmpi(UGeckoInstruction _inst); + void cmpl(UGeckoInstruction _inst); void cmpli(UGeckoInstruction _inst); void negx(UGeckoInstruction _inst); void mulli(UGeckoInstruction _inst); + void mullwx(UGeckoInstruction _inst); + void mulhwux(UGeckoInstruction _inst); void ori(UGeckoInstruction _inst); void oris(UGeckoInstruction _inst); void orx(UGeckoInstruction _inst); void xorx(UGeckoInstruction _inst); + void andx(UGeckoInstruction _inst); + void andi_rc(UGeckoInstruction _inst); + void andis_rc(UGeckoInstruction _inst); void rlwimix(UGeckoInstruction _inst); void rlwinmx(UGeckoInstruction _inst); void subfx(UGeckoInstruction _inst); + void srawix(UGeckoInstruction _inst); void extshx(UGeckoInstruction inst); void extsbx(UGeckoInstruction inst); @@ -171,8 +181,10 @@ public: // LoadStore void icbi(UGeckoInstruction _inst); + void dcbst(UGeckoInstruction _inst); void lbz(UGeckoInstruction _inst); void lhz(UGeckoInstruction _inst); + void lha(UGeckoInstruction _inst); void lwz(UGeckoInstruction _inst); void lwzx(UGeckoInstruction _inst); void stb(UGeckoInstruction _inst); @@ -184,12 +196,24 @@ public: // Floating point void fabsx(UGeckoInstruction _inst); + void faddsx(UGeckoInstruction _inst); void faddx(UGeckoInstruction _inst); + void fsubsx(UGeckoInstruction _inst); + void fsubx(UGeckoInstruction _inst); + void fmulsx(UGeckoInstruction _inst); + void fmulx(UGeckoInstruction _inst); void fmrx(UGeckoInstruction _inst); // Floating point loadStore void lfs(UGeckoInstruction _inst); void lfd(UGeckoInstruction _inst); + + // Paired Singles + void ps_add(UGeckoInstruction _inst); + void ps_sum0(UGeckoInstruction _inst); + void ps_madd(UGeckoInstruction _inst); + void ps_sub(UGeckoInstruction _inst); + void ps_mul(UGeckoInstruction _inst); }; #endif // _JIT64_H diff --git a/Source/Core/Core/Src/PowerPC/JitArm32/JitArm_FloatingPoint.cpp b/Source/Core/Core/Src/PowerPC/JitArm32/JitArm_FloatingPoint.cpp index c82c7d3877..85ab5f3cae 100644 --- a/Source/Core/Core/Src/PowerPC/JitArm32/JitArm_FloatingPoint.cpp +++ b/Source/Core/Core/Src/PowerPC/JitArm32/JitArm_FloatingPoint.cpp @@ -51,6 +51,21 @@ void JitArm::fabsx(UGeckoInstruction inst) if (inst.Rc) Helper_UpdateCR1(vD); } +void JitArm::faddsx(UGeckoInstruction inst) +{ + INSTRUCTION_START + JITDISABLE(FloatingPoint) + + ARMReg vA = fpr.R0(inst.FA); + ARMReg vB = fpr.R0(inst.FB); + ARMReg vD0 = fpr.R0(inst.FD); + ARMReg vD1 = fpr.R1(inst.FD); + + VADD(vD0, vA, vB); + VMOV(vD1, vD0); + if (inst.Rc) Helper_UpdateCR1(vD0); +} + void JitArm::faddx(UGeckoInstruction inst) { INSTRUCTION_START @@ -64,6 +79,63 @@ void JitArm::faddx(UGeckoInstruction inst) if (inst.Rc) Helper_UpdateCR1(vD); } +void JitArm::fsubsx(UGeckoInstruction inst) +{ + INSTRUCTION_START + JITDISABLE(FloatingPoint) + + ARMReg vA = fpr.R0(inst.FA); + ARMReg vB = fpr.R0(inst.FB); + ARMReg vD0 = fpr.R0(inst.FD); + ARMReg vD1 = fpr.R1(inst.FD); + + VSUB(vD0, vA, vB); + VMOV(vD1, vD0); + if (inst.Rc) Helper_UpdateCR1(vD0); +} + +void JitArm::fsubx(UGeckoInstruction inst) +{ + INSTRUCTION_START + JITDISABLE(FloatingPoint) + + ARMReg vD = fpr.R0(inst.FD); + ARMReg vA = fpr.R0(inst.FA); + ARMReg vB = fpr.R0(inst.FB); + + VSUB(vD, vA, vB); + if (inst.Rc) Helper_UpdateCR1(vD); +} + +// Breaks Animal Crossing +void JitArm::fmulsx(UGeckoInstruction inst) +{ + INSTRUCTION_START + JITDISABLE(FloatingPoint) + + Default(inst); return; + + ARMReg vA = fpr.R0(inst.FA); + ARMReg vC = fpr.R0(inst.FC); + ARMReg vD0 = fpr.R0(inst.FD); + ARMReg vD1 = fpr.R1(inst.FD); + + VMUL(vD0, vA, vC); + VMOV(vD1, vD0); + if (inst.Rc) Helper_UpdateCR1(vD0); +} +void JitArm::fmulx(UGeckoInstruction inst) +{ + INSTRUCTION_START + JITDISABLE(FloatingPoint) + + ARMReg vD0 = fpr.R0(inst.FD); + ARMReg vA = fpr.R0(inst.FA); + ARMReg vC = fpr.R0(inst.FC); + + VMUL(vD0, vA, vC); + if (inst.Rc) Helper_UpdateCR1(vD0); +} void JitArm::fmrx(UGeckoInstruction inst) { INSTRUCTION_START diff --git a/Source/Core/Core/Src/PowerPC/JitArm32/JitArm_Integer.cpp b/Source/Core/Core/Src/PowerPC/JitArm32/JitArm_Integer.cpp index e19112c1b5..e840d4dd49 100644 --- a/Source/Core/Core/Src/PowerPC/JitArm32/JitArm_Integer.cpp +++ b/Source/Core/Core/Src/PowerPC/JitArm32/JitArm_Integer.cpp @@ -54,82 +54,234 @@ void JitArm::ComputeRC(int cr) { STRB(rB, R9, PPCSTATE_OFF(cr_fast) + cr); gpr.Unlock(rB); } +void JitArm::ComputeRC(s32 value, int cr) { + ARMReg rB = gpr.GetReg(); + + if (value < 0) + MOV(rB, 0x8); + else if (value > 0) + MOV(rB, 0x4); + else + MOV(rB, 0x2); + + STRB(rB, R9, PPCSTATE_OFF(cr_fast) + cr); + gpr.Unlock(rB); +} + +void JitArm::ComputeCarry() +{ + ARMReg tmp = gpr.GetReg(); + Operand2 mask = Operand2(2, 2); // XER_CA_MASK + LDR(tmp, R9, PPCSTATE_OFF(spr[SPR_XER])); + SetCC(CC_CS); + ORR(tmp, tmp, mask); + SetCC(CC_CC); + BIC(tmp, tmp, mask); + SetCC(); + STR(tmp, R9, PPCSTATE_OFF(spr[SPR_XER])); + gpr.Unlock(tmp); +} + +void JitArm::GetCarryAndClear(ARMReg reg) +{ + ARMReg tmp = gpr.GetReg(); + Operand2 mask = Operand2(2, 2); // XER_CA_MASK + LDR(tmp, R9, PPCSTATE_OFF(spr[SPR_XER])); + AND(reg, tmp, mask); + BIC(tmp, tmp, mask); + STR(tmp, R9, PPCSTATE_OFF(spr[SPR_XER])); + gpr.Unlock(tmp); +} + +void JitArm::FinalizeCarry(ARMReg reg) +{ + ARMReg tmp = gpr.GetReg(); + Operand2 mask = Operand2(2, 2); // XER_CA_MASK + SetCC(CC_CS); + ORR(reg, reg, mask); + SetCC(); + LDR(tmp, R9, PPCSTATE_OFF(spr[SPR_XER])); + ORR(tmp, tmp, reg); + STR(tmp, R9, PPCSTATE_OFF(spr[SPR_XER])); + gpr.Unlock(tmp); +} void JitArm::addi(UGeckoInstruction inst) { INSTRUCTION_START JITDISABLE(Integer) - ARMReg RD = gpr.R(inst.RD); - - if (inst.RA) + u32 d = inst.RD, a = inst.RA; + if (a) { + if (gpr.IsImm(a)) + { + gpr.SetImmediate(d, gpr.GetImm(a) + inst.SIMM_16); + return; + } ARMReg rA = gpr.GetReg(false); - ARMReg RA = gpr.R(inst.RA); + ARMReg RA = gpr.R(a); + ARMReg RD = gpr.R(d); MOVI2R(rA, (u32)inst.SIMM_16); ADD(RD, RA, rA); } else - MOVI2R(RD, inst.SIMM_16); + gpr.SetImmediate(d, inst.SIMM_16); } void JitArm::addis(UGeckoInstruction inst) { INSTRUCTION_START JITDISABLE(Integer) - - ARMReg RD = gpr.R(inst.RD); - if (inst.RA) + + u32 d = inst.RD, a = inst.RA; + if (a) { + if (gpr.IsImm(a)) + { + gpr.SetImmediate(d, gpr.GetImm(a) + (inst.SIMM_16 << 16)); + return; + } ARMReg rA = gpr.GetReg(false); - ARMReg RA = gpr.R(inst.RA); + ARMReg RA = gpr.R(a); + ARMReg RD = gpr.R(d); MOVI2R(rA, inst.SIMM_16 << 16); ADD(RD, RA, rA); } else - MOVI2R(RD, inst.SIMM_16 << 16); + gpr.SetImmediate(d, inst.SIMM_16 << 16); } void JitArm::addx(UGeckoInstruction inst) { INSTRUCTION_START JITDISABLE(Integer) + u32 a = inst.RA, b = inst.RB, d = inst.RD; + + if (gpr.IsImm(a) && gpr.IsImm(b)) + { + gpr.SetImmediate(d, gpr.GetImm(a) + gpr.GetImm(b)); + if (inst.Rc) ComputeRC(gpr.GetImm(d), 0); + return; + } + ARMReg RA = gpr.R(a); + ARMReg RB = gpr.R(b); + ARMReg RD = gpr.R(d); + ADDS(RD, RA, RB); + if (inst.Rc) ComputeRC(); +} - ARMReg RA = gpr.R(inst.RA); - ARMReg RB = gpr.R(inst.RB); - ARMReg RD = gpr.R(inst.RD); +void JitArm::addcx(UGeckoInstruction inst) +{ + INSTRUCTION_START + JITDISABLE(Integer) + u32 a = inst.RA, b = inst.RB, d = inst.RD; + + ARMReg RA = gpr.R(a); + ARMReg RB = gpr.R(b); + ARMReg RD = gpr.R(d); + ADDS(RD, RA, RB); + ComputeCarry(); + if (inst.Rc) ComputeRC(); +} +void JitArm::addex(UGeckoInstruction inst) +{ + INSTRUCTION_START + JITDISABLE(Integer) + u32 a = inst.RA, b = inst.RB, d = inst.RD; + Default(inst); return; + ARMReg RA = gpr.R(a); + ARMReg RB = gpr.R(b); + ARMReg RD = gpr.R(d); + ARMReg rA = gpr.GetReg(); + GetCarryAndClear(rA); ADDS(RD, RA, RB); + FinalizeCarry(rA); if (inst.Rc) ComputeRC(); + gpr.Unlock(rA); } + void JitArm::subfx(UGeckoInstruction inst) { INSTRUCTION_START JITDISABLE(Integer) - ARMReg RA = gpr.R(inst.RA); - ARMReg RB = gpr.R(inst.RB); - ARMReg RD = gpr.R(inst.RD); - SUBS(RD, RB, RA); + u32 a = inst.RA, b = inst.RB, d = inst.RD; + if (inst.OE) PanicAlert("OE: subfx"); + + if (gpr.IsImm(a) && gpr.IsImm(b)) + { + gpr.SetImmediate(d, gpr.GetImm(b) - gpr.GetImm(a)); + if (inst.Rc) ComputeRC(gpr.GetImm(d), 0); + return; + } + ARMReg RA = gpr.R(a); + ARMReg RB = gpr.R(b); + ARMReg RD = gpr.R(d); + SUBS(RD, RB, RA); if (inst.Rc) GenerateRC(); } void JitArm::mulli(UGeckoInstruction inst) { INSTRUCTION_START JITDISABLE(Integer) + u32 a = inst.RA, d = inst.RD; - ARMReg RA = gpr.R(inst.RA); - ARMReg RD = gpr.R(inst.RD); + if (gpr.IsImm(a)) + { + gpr.SetImmediate(d, gpr.GetImm(a) * inst.SIMM_16); + return; + } + ARMReg RA = gpr.R(a); + ARMReg RD = gpr.R(d); ARMReg rA = gpr.GetReg(); MOVI2R(rA, inst.SIMM_16); MUL(RD, RA, rA); gpr.Unlock(rA); } -void JitArm::ori(UGeckoInstruction inst) + +void JitArm::mullwx(UGeckoInstruction inst) { INSTRUCTION_START JITDISABLE(Integer) - ARMReg RA = gpr.R(inst.RA); - ARMReg RS = gpr.R(inst.RS); + u32 a = inst.RA, b = inst.RB, d = inst.RD; + + ARMReg RA = gpr.R(a); + ARMReg RB = gpr.R(b); + ARMReg RD = gpr.R(d); + MULS(RD, RA, RB); + if (inst.OE) PanicAlert("OE: mullwx"); + if (inst.Rc) ComputeRC(); +} + +void JitArm::mulhwux(UGeckoInstruction inst) +{ + INSTRUCTION_START + JITDISABLE(Integer) + + u32 a = inst.RA, b = inst.RB, d = inst.RD; + + ARMReg RA = gpr.R(a); + ARMReg RB = gpr.R(b); + ARMReg RD = gpr.R(d); + ARMReg rA = gpr.GetReg(false); + UMULLS(rA, RD, RA, RB); + if (inst.Rc) ComputeRC(); +} + +void JitArm::ori(UGeckoInstruction inst) +{ + INSTRUCTION_START + JITDISABLE(Integer) + u32 a = inst.RA, s = inst.RS; + + if (gpr.IsImm(s)) + { + gpr.SetImmediate(a, gpr.GetImm(s) | inst.UIMM); + return; + } + ARMReg RA = gpr.R(a); + ARMReg RS = gpr.R(s); ARMReg rA = gpr.GetReg(); MOVI2R(rA, inst.UIMM); ORR(RA, RS, rA); @@ -139,9 +291,15 @@ void JitArm::oris(UGeckoInstruction inst) { INSTRUCTION_START JITDISABLE(Integer) + u32 a = inst.RA, s = inst.RS; - ARMReg RA = gpr.R(inst.RA); - ARMReg RS = gpr.R(inst.RS); + if (gpr.IsImm(s)) + { + gpr.SetImmediate(a, gpr.GetImm(s) | (inst.UIMM << 16)); + return; + } + ARMReg RA = gpr.R(a); + ARMReg RS = gpr.R(s); ARMReg rA = gpr.GetReg(); MOVI2R(rA, inst.UIMM << 16); ORR(RA, RS, rA); @@ -152,10 +310,17 @@ void JitArm::orx(UGeckoInstruction inst) { INSTRUCTION_START JITDISABLE(Integer) + u32 a = inst.RA, b = inst.RB, s = inst.RS; - ARMReg rA = gpr.R(inst.RA); - ARMReg rS = gpr.R(inst.RS); - ARMReg rB = gpr.R(inst.RB); + if (gpr.IsImm(b) && gpr.IsImm(s)) + { + gpr.SetImmediate(a, gpr.GetImm(s) | gpr.GetImm(b)); + if (inst.Rc) ComputeRC(gpr.GetImm(a), 0); + return; + } + ARMReg rA = gpr.R(a); + ARMReg rB = gpr.R(b); + ARMReg rS = gpr.R(s); ORRS(rA, rS, rB); if (inst.Rc) ComputeRC(); @@ -166,23 +331,100 @@ void JitArm::xorx(UGeckoInstruction inst) INSTRUCTION_START JITDISABLE(Integer) - ARMReg rA = gpr.R(inst.RA); - ARMReg rS = gpr.R(inst.RS); - ARMReg rB = gpr.R(inst.RB); + u32 a = inst.RA, b = inst.RB, s = inst.RS; + + if (gpr.IsImm(b) && gpr.IsImm(s)) + { + gpr.SetImmediate(a, gpr.GetImm(s) ^ gpr.GetImm(b)); + if (inst.Rc) ComputeRC(gpr.GetImm(a), 0); + return; + } + ARMReg rA = gpr.R(a); + ARMReg rB = gpr.R(b); + ARMReg rS = gpr.R(s); EORS(rA, rS, rB); if (inst.Rc) ComputeRC(); } + +void JitArm::andx(UGeckoInstruction inst) +{ + u32 a = inst.RA, b = inst.RB, s = inst.RS; + + if (gpr.IsImm(s) && gpr.IsImm(b)) + { + gpr.SetImmediate(a, gpr.GetImm(s) & gpr.GetImm(b)); + if (inst.Rc) ComputeRC(gpr.GetImm(a), 0); + return; + } + ARMReg rA = gpr.R(a); + ARMReg rB = gpr.R(b); + ARMReg rS = gpr.R(s); + + ANDS(rA, rS, rB); + + if (inst.Rc) ComputeRC(); +} + +void JitArm::andi_rc(UGeckoInstruction inst) +{ + u32 a = inst.RA, s = inst.RS; + + if (gpr.IsImm(s)) + { + gpr.SetImmediate(a, gpr.GetImm(s) & inst.UIMM); + ComputeRC(gpr.GetImm(a), 0); + return; + } + ARMReg rA = gpr.R(a); + ARMReg rS = gpr.R(s); + ARMReg RA = gpr.GetReg(); + + MOVI2R(RA, inst.UIMM); + ANDS(rA, rS, RA); + + ComputeRC(); + gpr.Unlock(RA); +} + +void JitArm::andis_rc(UGeckoInstruction inst) +{ + u32 a = inst.RA, s = inst.RS; + + if (gpr.IsImm(s)) + { + gpr.SetImmediate(a, gpr.GetImm(s) & ((u32)inst.UIMM << 16)); + ComputeRC(gpr.GetImm(a), 0); + return; + } + ARMReg rA = gpr.R(a); + ARMReg rS = gpr.R(s); + ARMReg RA = gpr.GetReg(); + + MOVI2R(RA, (u32)inst.UIMM << 16); + ANDS(rA, rS, RA); + + ComputeRC(); + gpr.Unlock(RA); +} + void JitArm::extshx(UGeckoInstruction inst) { INSTRUCTION_START JITDISABLE(Integer) - ARMReg RA, RS; - RA = gpr.R(inst.RA); - RS = gpr.R(inst.RS); - SXTH(RA, RS); + u32 a = inst.RA, s = inst.RS; + + if (gpr.IsImm(s)) + { + gpr.SetImmediate(a, (u32)(s32)(s16)gpr.GetImm(s)); + if (inst.Rc) ComputeRC(gpr.GetImm(a), 0); + return; + } + ARMReg rA = gpr.R(a); + ARMReg rS = gpr.R(s); + SXTH(rA, rS); if (inst.Rc){ - CMP(RA, 0); + CMP(rA, 0); ComputeRC(); } } @@ -190,12 +432,19 @@ void JitArm::extsbx(UGeckoInstruction inst) { INSTRUCTION_START JITDISABLE(Integer) - ARMReg RA, RS; - RA = gpr.R(inst.RA); - RS = gpr.R(inst.RS); - SXTB(RA, RS); + u32 a = inst.RA, s = inst.RS; + + if (gpr.IsImm(s)) + { + gpr.SetImmediate(a, (u32)(s32)(s8)gpr.GetImm(s)); + if (inst.Rc) ComputeRC(gpr.GetImm(a), 0); + return; + } + ARMReg rA = gpr.R(a); + ARMReg rS = gpr.R(s); + SXTB(rA, rS); if (inst.Rc){ - CMP(RA, 0); + CMP(rA, 0); ComputeRC(); } } @@ -204,32 +453,66 @@ void JitArm::cmp (UGeckoInstruction inst) INSTRUCTION_START JITDISABLE(Integer) - ARMReg RA = gpr.R(inst.RA); - ARMReg RB = gpr.R(inst.RB); int crf = inst.CRFD; + u32 a = inst.RA, b = inst.RB; + + if (gpr.IsImm(a) && gpr.IsImm(b)) + { + ComputeRC((s32)gpr.GetImm(a) - (s32)gpr.GetImm(b), crf); + return; + } + + ARMReg RA = gpr.R(a); + ARMReg RB = gpr.R(b); CMP(RA, RB); + ComputeRC(crf); } void JitArm::cmpi(UGeckoInstruction inst) { INSTRUCTION_START JITDISABLE(Integer) - - ARMReg RA = gpr.R(inst.RA); + u32 a = inst.RA; int crf = inst.CRFD; - if (inst.SIMM_16 >= 0 && inst.SIMM_16 < 256) - { - CMP(RA, inst.SIMM_16); - } + if (gpr.IsImm(a)) + ComputeRC((s32)gpr.GetImm(a) - inst.SIMM_16, crf); else { - ARMReg rA = gpr.GetReg(); - MOVI2R(rA, inst.SIMM_16); - CMP(RA, rA); - gpr.Unlock(rA); + ARMReg RA = gpr.R(a); + if (inst.SIMM_16 >= 0 && inst.SIMM_16 < 256) + CMP(RA, inst.SIMM_16); + else + { + ARMReg rA = gpr.GetReg(); + MOVI2R(rA, inst.SIMM_16); + CMP(RA, rA); + gpr.Unlock(rA); + } + ComputeRC(crf); } - ComputeRC(crf); } +void JitArm::cmpl(UGeckoInstruction inst) +{ + INSTRUCTION_START + JITDISABLE(Integer) + + ARMReg RA = gpr.R(inst.RA); + ARMReg RB = gpr.R(inst.RB); + ARMReg rA = gpr.GetReg(); + int crf = inst.CRFD; + + CMP(RA, RB); + // Unsigned GenerateRC() + + MOV(rA, 0x2); // Result == 0 + SetCC(CC_LO); MOV(rA, 0x8); // Result < 0 + SetCC(CC_HI); MOV(rA, 0x4); // Result > 0 + SetCC(); + + STRB(rA, R9, PPCSTATE_OFF(cr_fast) + crf); + gpr.Unlock(rA); +} + void JitArm::cmpli(UGeckoInstruction inst) { INSTRUCTION_START @@ -259,7 +542,7 @@ void JitArm::cmpli(UGeckoInstruction inst) gpr.Unlock(rA); } -// Wrong - 27/10/2012 + void JitArm::negx(UGeckoInstruction inst) { INSTRUCTION_START @@ -330,4 +613,49 @@ void JitArm::rlwinmx(UGeckoInstruction inst) //m_GPR[inst.RA] = _rotl(m_GPR[inst.RS],inst.SH) & mask; } +void JitArm::srawix(UGeckoInstruction inst) +{ + INSTRUCTION_START + JITDISABLE(Integer) + int a = inst.RA; + int s = inst.RS; + int amount = inst.SH; + if (amount != 0) + { + Default(inst); return; + ARMReg RA = gpr.R(a); + ARMReg RS = gpr.R(s); + ARMReg tmp = gpr.GetReg(); + Operand2 mask = Operand2(2, 2); // XER_CA_MASK + + MOV(tmp, RS); + ASRS(RA, RS, amount); + if (inst.Rc) + GenerateRC(); + LSL(tmp, tmp, 32 - amount); + TST(tmp, RA); + + LDR(tmp, R9, PPCSTATE_OFF(spr[SPR_XER])); + BIC(tmp, tmp, mask); + SetCC(CC_EQ); + ORR(tmp, tmp, mask); + SetCC(); + STR(tmp, R9, PPCSTATE_OFF(spr[SPR_XER])); + gpr.Unlock(tmp); + } + else + { + ARMReg RA = gpr.R(a); + ARMReg RS = gpr.R(s); + MOV(RA, RS); + + ARMReg tmp = gpr.GetReg(); + Operand2 mask = Operand2(2, 2); // XER_CA_MASK + LDR(tmp, R9, PPCSTATE_OFF(spr[SPR_XER])); + BIC(tmp, tmp, mask); + STR(tmp, R9, PPCSTATE_OFF(spr[SPR_XER])); + gpr.Unlock(tmp); + + } +} diff --git a/Source/Core/Core/Src/PowerPC/JitArm32/JitArm_LoadStore.cpp b/Source/Core/Core/Src/PowerPC/JitArm32/JitArm_LoadStore.cpp index bd13100695..2efb6d5c7c 100644 --- a/Source/Core/Core/Src/PowerPC/JitArm32/JitArm_LoadStore.cpp +++ b/Source/Core/Core/Src/PowerPC/JitArm32/JitArm_LoadStore.cpp @@ -31,36 +31,12 @@ #include "JitRegCache.h" #include "JitAsm.h" -#ifdef ANDROID -#define FASTMEM 0 -#else -#define FASTMEM 0 -#endif void JitArm::stb(UGeckoInstruction inst) { INSTRUCTION_START JITDISABLE(LoadStore) ARMReg RS = gpr.R(inst.RS); -#if 0 // FASTMEM - // R10 contains the dest address - ARMReg Value = R11; - ARMReg RA; - if (inst.RA) - RA = gpr.R(inst.RA); - MOV(Value, RS); - if (inst.RA) - { - MOVI2R(R10, inst.SIMM_16, false); - ADD(R10, R10, RA); - } - else - { - MOVI2R(R10, (u32)inst.SIMM_16, false); - NOP(1); - } - StoreFromReg(R10, Value, 16, 0); -#else ARMReg ValueReg = gpr.GetReg(); ARMReg Addr = gpr.GetReg(); ARMReg Function = gpr.GetReg(); @@ -82,7 +58,6 @@ void JitArm::stb(UGeckoInstruction inst) BL(Function); POP(4, R0, R1, R2, R3); gpr.Unlock(ValueReg, Addr, Function); -#endif } void JitArm::stbu(UGeckoInstruction inst) @@ -122,25 +97,6 @@ void JitArm::sth(UGeckoInstruction inst) JITDISABLE(LoadStore) ARMReg RS = gpr.R(inst.RS); -#if 0 // FASTMEM - // R10 contains the dest address - ARMReg Value = R11; - ARMReg RA; - if (inst.RA) - RA = gpr.R(inst.RA); - MOV(Value, RS); - if (inst.RA) - { - MOVI2R(R10, inst.SIMM_16, false); - ADD(R10, R10, RA); - } - else - { - MOVI2R(R10, (u32)inst.SIMM_16, false); - NOP(1); - } - StoreFromReg(R10, Value, 16, 0); -#else ARMReg ValueReg = gpr.GetReg(); ARMReg Addr = gpr.GetReg(); ARMReg Function = gpr.GetReg(); @@ -162,7 +118,6 @@ void JitArm::sth(UGeckoInstruction inst) BL(Function); POP(4, R0, R1, R2, R3); gpr.Unlock(ValueReg, Addr, Function); -#endif } void JitArm::sthu(UGeckoInstruction inst) { @@ -203,29 +158,6 @@ void JitArm::stw(UGeckoInstruction inst) JITDISABLE(LoadStore) ARMReg RS = gpr.R(inst.RS); -#if FASTMEM - // R10 contains the dest address - if (Core::g_CoreStartupParameter.bFastmem) - { - ARMReg Value = R11; - ARMReg RA; - if (inst.RA) - RA = gpr.R(inst.RA); - MOV(Value, RS); - if (inst.RA) - { - MOVI2R(R10, inst.SIMM_16, false); - ADD(R10, R10, RA); - } - else - { - MOVI2R(R10, (u32)inst.SIMM_16, false); - NOP(1); - } - StoreFromReg(R10, Value, 32, 0); - } - else -#endif { ARMReg ValueReg = gpr.GetReg(); ARMReg Addr = gpr.GetReg(); @@ -282,79 +214,6 @@ void JitArm::stwu(UGeckoInstruction inst) gpr.Unlock(ValueReg, Addr, Function); } -void JitArm::StoreFromReg(ARMReg dest, ARMReg value, int accessSize, s32 offset) -{ - ARMReg rA = gpr.GetReg(); - - // All this gets replaced on backpatch - MOVI2R(rA, Memory::MEMVIEW32_MASK, false); // 1-2 - AND(dest, dest, rA); // 3 - MOVI2R(rA, (u32)Memory::base, false); // 4-5 - ADD(dest, dest, rA); // 6 - switch (accessSize) - { - case 32: - REV(value, value); // 7 - break; - case 16: - REV16(value, value); - break; - case 8: - NOP(1); - break; - } - switch (accessSize) - { - case 32: - STR(value, dest); // 8 - break; - case 16: - STRH(value, dest); - break; - case 8: - STRB(value, dest); - break; - } - gpr.Unlock(rA); -} -void JitArm::LoadToReg(ARMReg dest, ARMReg addr, int accessSize, s32 offset) -{ - ARMReg rA = gpr.GetReg(); - MOVI2R(rA, offset, false); // -3 - ADD(addr, addr, rA); // - 1 - - // All this gets replaced on backpatch - MOVI2R(rA, Memory::MEMVIEW32_MASK, false); // 2 - AND(addr, addr, rA); // 3 - MOVI2R(rA, (u32)Memory::base, false); // 5 - ADD(addr, addr, rA); // 6 - switch (accessSize) - { - case 32: - LDR(dest, addr); // 7 - break; - case 16: - LDRH(dest, addr); - break; - case 8: - LDRB(dest, addr); - break; - } - switch (accessSize) - { - case 32: - REV(dest, dest); // 9 - break; - case 16: - REV16(dest, dest); - break; - case 8: - NOP(1); - break; - - } - gpr.Unlock(rA); -} void JitArm::lbz(UGeckoInstruction inst) { INSTRUCTION_START @@ -366,24 +225,6 @@ void JitArm::lbz(UGeckoInstruction inst) LDR(rA, R9, PPCSTATE_OFF(Exceptions)); CMP(rA, EXCEPTION_DSI); FixupBranch DoNotLoad = B_CC(CC_EQ); -#if FASTMEM - // Backpatch route - // Gets loaded in to RD - // Address is in R10 - if (Core::g_CoreStartupParameter.bFastmem) - { - gpr.Unlock(rA, rB); - if (inst.RA) - { - ARMReg RA = gpr.R(inst.RA); - MOV(R10, RA); // - 4 - } - else - MOV(R10, 0); // - 4 - LoadToReg(RD, R10, 8, inst.SIMM_16); - } - else -#endif { if (inst.RA) { @@ -417,21 +258,36 @@ void JitArm::lhz(UGeckoInstruction inst) LDR(rA, R9, PPCSTATE_OFF(Exceptions)); CMP(rA, EXCEPTION_DSI); FixupBranch DoNotLoad = B_CC(CC_EQ); -#if 0 // FASTMEM - // Backpatch route - // Gets loaded in to RD - // Address is in R10 - gpr.Unlock(rA, rB); if (inst.RA) { + MOVI2R(rB, inst.SIMM_16); ARMReg RA = gpr.R(inst.RA); - MOV(R10, RA); // - 4 + ADD(rB, rB, RA); } - else - MOV(R10, 0); // - 4 + else + MOVI2R(rB, (u32)inst.SIMM_16); + + MOVI2R(rA, (u32)&Memory::Read_U16); + PUSH(4, R0, R1, R2, R3); + MOV(R0, rB); + BL(rA); + MOV(rA, R0); + POP(4, R0, R1, R2, R3); + MOV(RD, rA); + gpr.Unlock(rA, rB); + SetJumpTarget(DoNotLoad); +} +void JitArm::lha(UGeckoInstruction inst) +{ + INSTRUCTION_START + JITDISABLE(LoadStore) - LoadToReg(RD, R10, 16, (u32)inst.SIMM_16); -#else + ARMReg rA = gpr.GetReg(); + ARMReg rB = gpr.GetReg(); + ARMReg RD = gpr.R(inst.RD); + LDR(rA, R9, PPCSTATE_OFF(Exceptions)); + CMP(rA, EXCEPTION_DSI); + FixupBranch DoNotLoad = B_CC(CC_EQ); if (inst.RA) { @@ -447,12 +303,13 @@ void JitArm::lhz(UGeckoInstruction inst) MOV(R0, rB); BL(rA); MOV(rA, R0); + SXTH(rA, rA); POP(4, R0, R1, R2, R3); MOV(RD, rA); gpr.Unlock(rA, rB); -#endif SetJumpTarget(DoNotLoad); } + void JitArm::lwz(UGeckoInstruction inst) { INSTRUCTION_START @@ -464,25 +321,6 @@ void JitArm::lwz(UGeckoInstruction inst) LDR(rA, R9, PPCSTATE_OFF(Exceptions)); CMP(rA, EXCEPTION_DSI); FixupBranch DoNotLoad = B_CC(CC_EQ); - -#if FASTMEM - // Backpatch route - // Gets loaded in to RD - // Address is in R10 - if (Core::g_CoreStartupParameter.bFastmem) - { - gpr.Unlock(rA, rB); - if (inst.RA) - { - ARMReg RA = gpr.R(inst.RA); - MOV(R10, RA); // - 4 - } - else - MOV(R10, 0); // - 4 - LoadToReg(RD, R10, 32, (u32)inst.SIMM_16); - } - else -#endif { if (inst.RA) { @@ -543,24 +381,6 @@ void JitArm::lwzx(UGeckoInstruction inst) LDR(rA, R9, PPCSTATE_OFF(Exceptions)); CMP(rA, EXCEPTION_DSI); FixupBranch DoNotLoad = B_CC(CC_EQ); -#if FASTMEM - // Backpatch route - // Gets loaded in to RD - // Address is in R10 - if (Core::g_CoreStartupParameter.bFastmem) - { - gpr.Unlock(rA, rB); - if (inst.RA) - { - ARMReg RA = gpr.R(inst.RA); - ADD(R10, RA, RB); // - 4 - } - else - MOV(R10, RB); // -4 - LoadToReg(RD, R10, 32, 0); - } - else -#endif { if (inst.RA) { @@ -582,6 +402,21 @@ void JitArm::lwzx(UGeckoInstruction inst) SetJumpTarget(DoNotLoad); //// u32 temp = Memory::Read_U32(_inst.RA ? (m_GPR[_inst.RA] + m_GPR[_inst.RB]) : m_GPR[_inst.RB]); } + +void JitArm::dcbst(UGeckoInstruction inst) +{ + INSTRUCTION_START + JITDISABLE(LoadStore) + + // If the dcbst instruction is preceded by dcbt, it is flushing a prefetched + // memory location. Do not invalidate the JIT cache in this case as the memory + // will be the same. + // dcbt = 0x7c00022c + if ((Memory::ReadUnchecked_U32(js.compilerPC - 4) & 0x7c00022c) != 0x7c00022c) + { + Default(inst); return; + } +} void JitArm::icbi(UGeckoInstruction inst) { Default(inst); diff --git a/Source/Core/Core/Src/PowerPC/JitArm32/JitArm_LoadStoreFloating.cpp b/Source/Core/Core/Src/PowerPC/JitArm32/JitArm_LoadStoreFloating.cpp index 708aff9022..f764717a15 100644 --- a/Source/Core/Core/Src/PowerPC/JitArm32/JitArm_LoadStoreFloating.cpp +++ b/Source/Core/Core/Src/PowerPC/JitArm32/JitArm_LoadStoreFloating.cpp @@ -36,8 +36,8 @@ void JitArm::lfs(UGeckoInstruction inst) { INSTRUCTION_START JITDISABLE(LoadStoreFloating) - Default(inst); return; + Default(inst); return; ARMReg rA = gpr.GetReg(); ARMReg rB = gpr.GetReg(); LDR(rA, R9, PPCSTATE_OFF(Exceptions)); @@ -53,16 +53,15 @@ void JitArm::lfs(UGeckoInstruction inst) else MOVI2R(rB, (u32)inst.SIMM_16); - ARMReg v0 = fpr.R0(inst.FD, false); - ARMReg v1 = fpr.R1(inst.FD, false); + ARMReg v0 = fpr.R0(inst.FD); + ARMReg v1 = fpr.R1(inst.FD); MOVI2R(rA, (u32)&Memory::Read_F32); PUSH(4, R0, R1, R2, R3); MOV(R0, rB); BL(rA); - // XXX: Need to use VCVT here. - VMOV(v0, D0); - VMOV(v1, D0); + VCVT(v0, S0, 0); + VCVT(v1, S0, 0); POP(4, R0, R1, R2, R3); gpr.Unlock(rA, rB); @@ -73,6 +72,7 @@ void JitArm::lfd(UGeckoInstruction inst) { INSTRUCTION_START JITDISABLE(LoadStoreFloating) + Default(inst); return; ARMReg rA = gpr.GetReg(); ARMReg rB = gpr.GetReg(); @@ -89,7 +89,7 @@ void JitArm::lfd(UGeckoInstruction inst) else MOVI2R(rB, (u32)inst.SIMM_16); - ARMReg v0 = fpr.R0(inst.FD, false); + ARMReg v0 = fpr.R0(inst.FD); MOVI2R(rA, (u32)&Memory::Read_F64); PUSH(4, R0, R1, R2, R3); diff --git a/Source/Core/Core/Src/PowerPC/JitArm32/JitArm_Paired.cpp b/Source/Core/Core/Src/PowerPC/JitArm32/JitArm_Paired.cpp new file mode 100644 index 0000000000..279ed10a48 --- /dev/null +++ b/Source/Core/Core/Src/PowerPC/JitArm32/JitArm_Paired.cpp @@ -0,0 +1,149 @@ +// Copyright (C) 2003 Dolphin Project. + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, version 2.0. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License 2.0 for more details. + +// A copy of the GPL 2.0 should have been included with the program. +// If not, see http://www.gnu.org/licenses/ + +// Official SVN repository and contact information can be found at +// http://code.google.com/p/dolphin-emu/ +#include "Common.h" +#include "Thunk.h" + +#include "../../Core.h" +#include "../PowerPC.h" +#include "../../CoreTiming.h" +#include "../PPCTables.h" +#include "ArmEmitter.h" + +#include "Jit.h" +#include "JitRegCache.h" +#include "JitAsm.h" + +// Wrong, THP videos like SMS and Ikaruga show artifacts +void JitArm::ps_add(UGeckoInstruction inst) +{ + INSTRUCTION_START + JITDISABLE(Paired) + + Default(inst); return; + + u32 a = inst.FA, b = inst.FB, d = inst.FD; + if (inst.Rc){ + Default(inst); return; + } + ARMReg vA0 = fpr.R0(a); + ARMReg vA1 = fpr.R1(a); + ARMReg vB0 = fpr.R0(b); + ARMReg vB1 = fpr.R1(b); + ARMReg vD0 = fpr.R0(d); + ARMReg vD1 = fpr.R1(d); + + VADD(vD0, vA0, vB0); + VADD(vD1, vA1, vB1); +} + +// Wrong, THP videos like SMS and Ikaruga show artifacts +void JitArm::ps_madd(UGeckoInstruction inst) +{ + INSTRUCTION_START + JITDISABLE(Paired) + + Default(inst); return; + + u32 a = inst.FA, b = inst.FB, c = inst.FC, d = inst.FD; + + if (inst.Rc) { + Default(inst); return; + } + ARMReg vA0 = fpr.R0(a); + ARMReg vA1 = fpr.R1(a); + ARMReg vB0 = fpr.R0(b); + ARMReg vB1 = fpr.R1(b); + ARMReg vC0 = fpr.R0(c); + ARMReg vC1 = fpr.R1(c); + ARMReg vD0 = fpr.R0(d); + ARMReg vD1 = fpr.R1(d); + + ARMReg V0 = fpr.GetReg(); + ARMReg V1 = fpr.GetReg(); + + VMOV(V0, vC0); + VMOV(V1, vC1); + + VMLA(V0, vA0, vB0); + VMLA(V1, vA1, vB1); + + VMOV(vD0, V0); + VMOV(vD1, V1); + + fpr.Unlock(V0); + fpr.Unlock(V1); +} + +void JitArm::ps_sum0(UGeckoInstruction inst) +{ + INSTRUCTION_START + JITDISABLE(Paired) + + u32 a = inst.FA, b = inst.FB, c = inst.FC, d = inst.FD; + + if (inst.Rc) { + Default(inst); return; + } + ARMReg vA0 = fpr.R0(a); + ARMReg vB1 = fpr.R1(b); + ARMReg vC1 = fpr.R1(c); + ARMReg vD0 = fpr.R0(d); + ARMReg vD1 = fpr.R1(d); + + VADD(vD0, vA0, vB1); + VMOV(vD1, vC1); +} + +void JitArm::ps_sub(UGeckoInstruction inst) +{ + INSTRUCTION_START + JITDISABLE(Paired) + + u32 a = inst.FA, b = inst.FB, d = inst.FD; + if (inst.Rc){ + Default(inst); return; + } + ARMReg vA0 = fpr.R0(a); + ARMReg vA1 = fpr.R1(a); + ARMReg vB0 = fpr.R0(b); + ARMReg vB1 = fpr.R1(b); + ARMReg vD0 = fpr.R0(d); + ARMReg vD1 = fpr.R1(d); + + VSUB(vD0, vA0, vB0); + VSUB(vD1, vA1, vB1); +} + +void JitArm::ps_mul(UGeckoInstruction inst) +{ + INSTRUCTION_START + JITDISABLE(Paired) + u32 a = inst.FA, c = inst.FC, d = inst.FD; + if (inst.Rc){ + Default(inst); return; + } + ARMReg vA0 = fpr.R0(a); + ARMReg vA1 = fpr.R1(a); + ARMReg vC0 = fpr.R0(c); + ARMReg vC1 = fpr.R1(c); + ARMReg vD0 = fpr.R0(d); + ARMReg vD1 = fpr.R1(d); + + VMUL(vD0, vA0, vC0); + VMUL(vD1, vA1, vC1); +} + diff --git a/Source/Core/Core/Src/PowerPC/JitArm32/JitArm_SystemRegisters.cpp b/Source/Core/Core/Src/PowerPC/JitArm32/JitArm_SystemRegisters.cpp index cf7535136f..0c58b43ff3 100644 --- a/Source/Core/Core/Src/PowerPC/JitArm32/JitArm_SystemRegisters.cpp +++ b/Source/Core/Core/Src/PowerPC/JitArm32/JitArm_SystemRegisters.cpp @@ -33,7 +33,6 @@ void JitArm::mtspr(UGeckoInstruction inst) JITDISABLE(SystemRegisters) u32 iIndex = (inst.SPRU << 5) | (inst.SPRL & 0x1F); - ARMReg RD = gpr.R(inst.RD); switch (iIndex) { @@ -70,6 +69,7 @@ void JitArm::mtspr(UGeckoInstruction inst) } // OK, this is easy. + ARMReg RD = gpr.R(inst.RD); STR(RD, R9, PPCSTATE_OFF(spr) + iIndex * 4); } void JitArm::mftb(UGeckoInstruction inst) @@ -105,13 +105,16 @@ void JitArm::mtmsr(UGeckoInstruction inst) //JITDISABLE(SystemRegisters) STR(gpr.R(inst.RS), R9, PPCSTATE_OFF(msr)); + + gpr.Flush(); + fpr.Flush(); + WriteExit(js.compilerPC + 4, 0); } void JitArm::mfmsr(UGeckoInstruction inst) { INSTRUCTION_START JITDISABLE(SystemRegisters) - Default(inst); return; LDR(gpr.R(inst.RD), R9, PPCSTATE_OFF(msr)); } diff --git a/Source/Core/Core/Src/PowerPC/JitArm32/JitArm_Tables.cpp b/Source/Core/Core/Src/PowerPC/JitArm32/JitArm_Tables.cpp index 3b97640ff2..fe822179ed 100644 --- a/Source/Core/Core/Src/PowerPC/JitArm32/JitArm_Tables.cpp +++ b/Source/Core/Core/Src/PowerPC/JitArm32/JitArm_Tables.cpp @@ -75,8 +75,8 @@ static GekkoOPTemplate primarytable[] = {25, &JitArm::oris}, //"oris", OPTYPE_INTEGER, FL_OUT_A | FL_IN_S}}, {26, &JitArm::Default}, //"xori", OPTYPE_INTEGER, FL_OUT_A | FL_IN_S}}, {27, &JitArm::Default}, //"xoris", OPTYPE_INTEGER, FL_OUT_A | FL_IN_S}}, - {28, &JitArm::Default}, //"andi_rc", OPTYPE_INTEGER, FL_OUT_A | FL_IN_S | FL_SET_CR0}}, - {29, &JitArm::Default}, //"andis_rc", OPTYPE_INTEGER, FL_OUT_A | FL_IN_S | FL_SET_CR0}}, + {28, &JitArm::andi_rc}, //"andi_rc", OPTYPE_INTEGER, FL_OUT_A | FL_IN_S | FL_SET_CR0}}, + {29, &JitArm::andis_rc}, //"andis_rc", OPTYPE_INTEGER, FL_OUT_A | FL_IN_S | FL_SET_CR0}}, {32, &JitArm::lwz}, //"lwz", OPTYPE_LOAD, FL_OUT_D | FL_IN_A}}, {33, &JitArm::Default}, //"lwzu", OPTYPE_LOAD, FL_OUT_D | FL_OUT_A | FL_IN_A}}, @@ -84,7 +84,7 @@ static GekkoOPTemplate primarytable[] = {35, &JitArm::Default}, //"lbzu", OPTYPE_LOAD, FL_OUT_D | FL_OUT_A | FL_IN_A}}, {40, &JitArm::lhz}, //"lhz", OPTYPE_LOAD, FL_OUT_D | FL_IN_A}}, {41, &JitArm::Default}, //"lhzu", OPTYPE_LOAD, FL_OUT_D | FL_OUT_A | FL_IN_A}}, - {42, &JitArm::Default}, //"lha", OPTYPE_LOAD, FL_OUT_D | FL_IN_A}}, + {42, &JitArm::lha}, //"lha", OPTYPE_LOAD, FL_OUT_D | FL_IN_A}}, {43, &JitArm::Default}, //"lhau", OPTYPE_LOAD, FL_OUT_D | FL_OUT_A | FL_IN_A}}, {44, &JitArm::sth}, //"sth", OPTYPE_STORE, FL_IN_A | FL_IN_S}}, @@ -143,21 +143,21 @@ static GekkoOPTemplate table4[] = static GekkoOPTemplate table4_2[] = { - {10, &JitArm::Default}, //"ps_sum0", OPTYPE_PS, 0}}, + {10, &JitArm::ps_sum0}, //"ps_sum0", OPTYPE_PS, 0}}, {11, &JitArm::Default}, //"ps_sum1", OPTYPE_PS, 0}}, {12, &JitArm::Default}, //"ps_muls0", OPTYPE_PS, 0}}, {13, &JitArm::Default}, //"ps_muls1", OPTYPE_PS, 0}}, {14, &JitArm::Default}, //"ps_madds0", OPTYPE_PS, 0}}, {15, &JitArm::Default}, //"ps_madds1", OPTYPE_PS, 0}}, {18, &JitArm::Default}, //"ps_div", OPTYPE_PS, 0, 16}}, - {20, &JitArm::Default}, //"ps_sub", OPTYPE_PS, 0}}, - {21, &JitArm::Default}, //"ps_add", OPTYPE_PS, 0}}, + {20, &JitArm::ps_sub}, //"ps_sub", OPTYPE_PS, 0}}, + {21, &JitArm::ps_add}, //"ps_add", OPTYPE_PS, 0}}, {23, &JitArm::Default}, //"ps_sel", OPTYPE_PS, 0}}, {24, &JitArm::Default}, //"ps_res", OPTYPE_PS, 0}}, - {25, &JitArm::Default}, //"ps_mul", OPTYPE_PS, 0}}, + {25, &JitArm::ps_mul}, //"ps_mul", OPTYPE_PS, 0}}, {26, &JitArm::Default}, //"ps_rsqrte", OPTYPE_PS, 0, 1}}, {28, &JitArm::Default}, //"ps_msub", OPTYPE_PS, 0}}, - {29, &JitArm::Default}, //"ps_madd", OPTYPE_PS, 0}}, + {29, &JitArm::ps_madd}, //"ps_madd", OPTYPE_PS, 0}}, {30, &JitArm::Default}, //"ps_nmsub", OPTYPE_PS, 0}}, {31, &JitArm::Default}, //"ps_nmadd", OPTYPE_PS, 0}}, }; @@ -194,7 +194,7 @@ static GekkoOPTemplate table19[] = static GekkoOPTemplate table31[] = { - {28, &JitArm::Default}, //"andx", OPTYPE_INTEGER, FL_OUT_A | FL_IN_SB | FL_RC_BIT}}, + {28, &JitArm::andx}, //"andx", OPTYPE_INTEGER, FL_OUT_A | FL_IN_SB | FL_RC_BIT}}, {60, &JitArm::Default}, //"andcx", OPTYPE_INTEGER, FL_OUT_A | FL_IN_SB | FL_RC_BIT}}, {444, &JitArm::orx}, //"orx", OPTYPE_INTEGER, FL_OUT_A | FL_IN_SB | FL_RC_BIT}}, {124, &JitArm::Default}, //"norx", OPTYPE_INTEGER, FL_OUT_A | FL_IN_SB | FL_RC_BIT}}, @@ -203,16 +203,16 @@ static GekkoOPTemplate table31[] = {476, &JitArm::Default}, //"nandx", OPTYPE_INTEGER, FL_OUT_A | FL_IN_SB | FL_RC_BIT}}, {284, &JitArm::Default}, //"eqvx", OPTYPE_INTEGER, FL_OUT_A | FL_IN_SB | FL_RC_BIT}}, {0, &JitArm::cmp}, //"cmp", OPTYPE_INTEGER, FL_IN_AB | FL_SET_CRn}}, - {32, &JitArm::Default}, //"cmpl", OPTYPE_INTEGER, FL_IN_AB | FL_SET_CRn}}, + {32, &JitArm::cmpl}, //"cmpl", OPTYPE_INTEGER, FL_IN_AB | FL_SET_CRn}}, {26, &JitArm::Default}, //"cntlzwx",OPTYPE_INTEGER, FL_OUT_A | FL_IN_S | FL_RC_BIT}}, {922, &JitArm::extshx}, //"extshx", OPTYPE_INTEGER, FL_OUT_A | FL_IN_S | FL_RC_BIT}}, {954, &JitArm::extsbx}, //"extsbx", OPTYPE_INTEGER, FL_OUT_A | FL_IN_S | FL_RC_BIT}}, {536, &JitArm::Default}, //"srwx", OPTYPE_INTEGER, FL_OUT_A | FL_IN_B | FL_IN_S | FL_RC_BIT}}, {792, &JitArm::Default}, //"srawx", OPTYPE_INTEGER, FL_OUT_A | FL_IN_B | FL_IN_S | FL_RC_BIT}}, - {824, &JitArm::Default}, //"srawix", OPTYPE_INTEGER, FL_OUT_A | FL_IN_B | FL_IN_S | FL_RC_BIT}}, + {824, &JitArm::srawix}, //"srawix", OPTYPE_INTEGER, FL_OUT_A | FL_IN_B | FL_IN_S | FL_RC_BIT}}, {24, &JitArm::Default}, //"slwx", OPTYPE_INTEGER, FL_OUT_A | FL_IN_B | FL_IN_S | FL_RC_BIT}}, - {54, &JitArm::Default}, //"dcbst", OPTYPE_DCACHE, 0, 4}}, + {54, &JitArm::dcbst}, //"dcbst", OPTYPE_DCACHE, 0, 4}}, {86, &JitArm::Default}, //"dcbf", OPTYPE_DCACHE, 0, 4}}, {246, &JitArm::Default}, //"dcbtst", OPTYPE_DCACHE, 0, 1}}, {278, &JitArm::Default}, //"dcbt", OPTYPE_DCACHE, 0, 1}}, @@ -309,8 +309,8 @@ static GekkoOPTemplate table31_2[] = { {266, &JitArm::addx}, //"addx", OPTYPE_INTEGER, FL_OUT_D | FL_IN_AB | FL_RC_BIT}}, {778, &JitArm::addx}, //"addx", OPTYPE_INTEGER, FL_OUT_D | FL_IN_AB | FL_RC_BIT}}, - {10, &JitArm::Default}, //"addcx", OPTYPE_INTEGER, FL_OUT_D | FL_IN_AB | FL_SET_CA | FL_RC_BIT}}, - {138, &JitArm::Default}, //"addex", OPTYPE_INTEGER, FL_OUT_D | FL_IN_AB | FL_READ_CA | FL_SET_CA | FL_RC_BIT}}, + {10, &JitArm::addcx}, //"addcx", OPTYPE_INTEGER, FL_OUT_D | FL_IN_AB | FL_SET_CA | FL_RC_BIT}}, + {138, &JitArm::addex}, //"addex", OPTYPE_INTEGER, FL_OUT_D | FL_IN_AB | FL_READ_CA | FL_SET_CA | FL_RC_BIT}}, {234, &JitArm::Default}, //"addmex", OPTYPE_INTEGER, FL_OUT_D | FL_IN_AB | FL_READ_CA | FL_SET_CA | FL_RC_BIT}}, {202, &JitArm::Default}, //"addzex", OPTYPE_INTEGER, FL_OUT_D | FL_IN_AB | FL_READ_CA | FL_SET_CA | FL_RC_BIT}}, {491, &JitArm::Default}, //"divwx", OPTYPE_INTEGER, FL_OUT_D | FL_IN_AB | FL_RC_BIT, 39}}, @@ -318,8 +318,8 @@ static GekkoOPTemplate table31_2[] = {459, &JitArm::Default}, //"divwux", OPTYPE_INTEGER, FL_OUT_D | FL_IN_AB | FL_RC_BIT, 39}}, {971, &JitArm::Default}, //"divwuox", OPTYPE_INTEGER, FL_OUT_D | FL_IN_AB | FL_RC_BIT, 39}}, {75, &JitArm::Default}, //"mulhwx", OPTYPE_INTEGER, FL_OUT_D | FL_IN_AB | FL_RC_BIT, 4}}, - {11, &JitArm::Default}, //"mulhwux", OPTYPE_INTEGER, FL_OUT_D | FL_IN_AB | FL_RC_BIT, 4}}, - {235, &JitArm::Default}, //"mullwx", OPTYPE_INTEGER, FL_OUT_D | FL_IN_AB | FL_RC_BIT, 4}}, + {11, &JitArm::mulhwux}, //"mulhwux", OPTYPE_INTEGER, FL_OUT_D | FL_IN_AB | FL_RC_BIT, 4}}, + {235, &JitArm::mullwx}, //"mullwx", OPTYPE_INTEGER, FL_OUT_D | FL_IN_AB | FL_RC_BIT, 4}}, {747, &JitArm::Default}, //"mullwox", OPTYPE_INTEGER, FL_OUT_D | FL_IN_AB | FL_RC_BIT, 4}}, {104, &JitArm::negx}, //"negx", OPTYPE_INTEGER, FL_OUT_D | FL_IN_AB | FL_RC_BIT}}, {40, &JitArm::subfx}, //"subfx", OPTYPE_INTEGER, FL_OUT_D | FL_IN_AB | FL_RC_BIT}}, @@ -333,11 +333,11 @@ static GekkoOPTemplate table31_2[] = static GekkoOPTemplate table59[] = { {18, &JitArm::Default}, //{"fdivsx", OPTYPE_FPU, FL_RC_BIT_F, 16}}, - {20, &JitArm::Default}, //"fsubsx", OPTYPE_FPU, FL_RC_BIT_F}}, - {21, &JitArm::Default}, //"faddsx", OPTYPE_FPU, FL_RC_BIT_F}}, + {20, &JitArm::fsubsx}, //"fsubsx", OPTYPE_FPU, FL_RC_BIT_F}}, + {21, &JitArm::faddsx}, //"faddsx", OPTYPE_FPU, FL_RC_BIT_F}}, // {22, &JitArm::Default}, //"fsqrtsx", OPTYPE_FPU, FL_RC_BIT_F}}, // Not implemented on gekko {24, &JitArm::Default}, //"fresx", OPTYPE_FPU, FL_RC_BIT_F}}, - {25, &JitArm::Default}, //"fmulsx", OPTYPE_FPU, FL_RC_BIT_F}}, + {25, &JitArm::fmulsx}, //"fmulsx", OPTYPE_FPU, FL_RC_BIT_F}}, {28, &JitArm::Default}, //"fmsubsx", OPTYPE_FPU, FL_RC_BIT_F}}, {29, &JitArm::Default}, //"fmaddsx", OPTYPE_FPU, FL_RC_BIT_F}}, {30, &JitArm::Default}, //"fnmsubsx", OPTYPE_FPU, FL_RC_BIT_F}}, @@ -367,11 +367,11 @@ static GekkoOPTemplate table63[] = static GekkoOPTemplate table63_2[] = { {18, &JitArm::Default}, //"fdivx", OPTYPE_FPU, FL_RC_BIT_F, 30}}, - {20, &JitArm::Default}, //"fsubx", OPTYPE_FPU, FL_RC_BIT_F}}, + {20, &JitArm::fsubx}, //"fsubx", OPTYPE_FPU, FL_RC_BIT_F}}, {21, &JitArm::faddx}, //"faddx", OPTYPE_FPU, FL_RC_BIT_F}}, {22, &JitArm::Default}, //"fsqrtx", OPTYPE_FPU, FL_RC_BIT_F}}, {23, &JitArm::Default}, //"fselx", OPTYPE_FPU, FL_RC_BIT_F}}, - {25, &JitArm::Default}, //"fmulx", OPTYPE_FPU, FL_RC_BIT_F}}, + {25, &JitArm::fmulx}, //"fmulx", OPTYPE_FPU, FL_RC_BIT_F}}, {26, &JitArm::Default}, //"frsqrtex", OPTYPE_FPU, FL_RC_BIT_F}}, {28, &JitArm::Default}, //"fmsubx", OPTYPE_FPU, FL_RC_BIT_F}}, {29, &JitArm::Default}, //"fmaddx", OPTYPE_FPU, FL_RC_BIT_F}}, diff --git a/Source/Core/Core/Src/PowerPC/JitArm32/JitAsm.cpp b/Source/Core/Core/Src/PowerPC/JitArm32/JitAsm.cpp index aa999c9a39..851d8b7706 100644 --- a/Source/Core/Core/Src/PowerPC/JitArm32/JitAsm.cpp +++ b/Source/Core/Core/Src/PowerPC/JitArm32/JitAsm.cpp @@ -65,34 +65,30 @@ void JitArmAsmRoutineManager::Generate() // It runs though to the compiling portion if it isn't found LDR(R12, R9, PPCSTATE_OFF(pc));// Load the current PC into R12 - MOVI2R(R14, JIT_ICACHE_MASK); // Potential for optimization - AND(R12, R12, R14); // R12 contains PC & JIT_ICACHE_MASK here. - // Confirmed good to this point 08-03-12 + Operand2 iCacheMask = Operand2(0xE, 2); // JIT_ICACHE_MASK + BIC(R12, R12, iCacheMask); // R12 contains PC & JIT_ICACHE_MASK here. MOVI2R(R14, (u32)jit->GetBlockCache()->GetICache()); - // Confirmed That this loads the base iCache Location correctly 08-04-12 LDR(R12, R14, R12); // R12 contains iCache[PC & JIT_ICACHE_MASK] here // R12 Confirmed this is the correct iCache Location loaded. TST(R12, 0xFC); // Test to see if it is a JIT block. - SetCC(CC_EQ); // Only run next part if R12 is zero - // Success, it is our Jitblock. - MOVI2R(R14, (u32)jit->GetBlockCache()->GetCodePointers()); - // LDR R14 right here to get CodePointers()[0] pointer. - REV(R12, R12); // Reversing this gives us our JITblock. - LSL(R12, R12, 2); // Multiply by four because address locations are u32 in size - LDR(R14, R14, R12); // Load the block address in to R14 + SetCC(CC_EQ); + // Success, it is our Jitblock. + MOVI2R(R14, (u32)jit->GetBlockCache()->GetCodePointers()); + // LDR R14 right here to get CodePointers()[0] pointer. + REV(R12, R12); // Reversing this gives us our JITblock. + LSL(R12, R12, 2); // Multiply by four because address locations are u32 in size + LDR(R14, R14, R12); // Load the block address in to R14 - B(R14); - - FixupBranch NextBlock = B(); // Jump to end so we can start a new block - SetCC(); // Return to always executing codes + B(R14); + // No need to jump anywhere after here, the block will go back to dispatcher start + SetCC(); // If we get to this point, that means that we don't have the block cached to execute // So call ArmJit to compile the block and then execute it. MOVI2R(R14, (u32)&Jit); - LDR(R0, R9, PPCSTATE_OFF(pc)); BL(R14); B(dispatcherNoCheck); @@ -129,7 +125,6 @@ void JitArmAsmRoutineManager::Generate() TST(R0, R1); FixupBranch Exit = B_CC(CC_NEQ); - SetJumpTarget(NextBlock); B(dispatcher); SetJumpTarget(Exit); diff --git a/Source/Core/Core/Src/PowerPC/JitArm32/JitFPRCache.cpp b/Source/Core/Core/Src/PowerPC/JitArm32/JitFPRCache.cpp index cdc13c48e2..359c497b3c 100644 --- a/Source/Core/Core/Src/PowerPC/JitArm32/JitFPRCache.cpp +++ b/Source/Core/Core/Src/PowerPC/JitArm32/JitFPRCache.cpp @@ -35,6 +35,7 @@ void ArmFPRCache::Init(ARMXEmitter *emitter) ArmCRegs[a].Reg = PPCRegs[a]; ArmCRegs[a].LastLoad = 0; ArmCRegs[a].PS1 = false; + ArmCRegs[a].Away = true; } for(u8 a = 0; a < NUMARMREG; ++a) { @@ -117,30 +118,40 @@ ARMReg ArmFPRCache::GetPPCReg(u32 preg, bool PS1, bool preLoad) if (ArmCRegs[a].PPCReg == preg && ArmCRegs[a].PS1 == PS1) { ArmCRegs[a].LastLoad = 0; + // Check if the value is actually in the reg + if (ArmCRegs[a].Away && preLoad) + { + // Load it now since we want it + s16 offset = PPCSTATE_OFF(ps) + (preg * 16) + (PS1 ? 8 : 0); + emit->VLDR(ArmCRegs[a].Reg, R9, offset); + ArmCRegs[a].Away = false; + } return ArmCRegs[a].Reg; } // Check if we have a free register for (u8 a = 0; a < NUMPPCREG; ++a) if (ArmCRegs[a].PPCReg == 33) { - u16 offset = PPCSTATE_OFF(ps) + (preg * 16) + (PS1 ? 8 : 0); + s16 offset = PPCSTATE_OFF(ps) + (preg * 16) + (PS1 ? 8 : 0); if (preLoad) emit->VLDR(ArmCRegs[a].Reg, R9, offset); ArmCRegs[a].PPCReg = preg; ArmCRegs[a].LastLoad = 0; ArmCRegs[a].PS1 = PS1; + ArmCRegs[a].Away = !preLoad; return ArmCRegs[a].Reg; } // Alright, we couldn't get a free space, dump that least used register - u16 offsetOld = PPCSTATE_OFF(ps) + (ArmCRegs[Num].PPCReg * 16) + (ArmCRegs[Num].PS1 ? 8 : 0); + s16 offsetOld = PPCSTATE_OFF(ps) + (ArmCRegs[Num].PPCReg * 16) + (ArmCRegs[Num].PS1 ? 8 : 0); emit->VSTR(ArmCRegs[Num].Reg, R9, offsetOld); - u16 offsetNew = PPCSTATE_OFF(ps) + (preg * 16) + (PS1 ? 8 : 0); + s16 offsetNew = PPCSTATE_OFF(ps) + (preg * 16) + (PS1 ? 8 : 0); if (preLoad) emit->VLDR(ArmCRegs[Num].Reg, R9, offsetNew); ArmCRegs[Num].PPCReg = preg; ArmCRegs[Num].LastLoad = 0; ArmCRegs[Num].PS1 = PS1; + ArmCRegs[Num].Away = !preLoad; return ArmCRegs[Num].Reg; } @@ -160,10 +171,11 @@ void ArmFPRCache::Flush() for(u8 a = 0; a < NUMPPCREG; ++a) if (ArmCRegs[a].PPCReg != 33) { - u16 offset = PPCSTATE_OFF(ps) + (ArmCRegs[a].PPCReg * 16) + (ArmCRegs[a].PS1 ? 8 : 0); + s16 offset = PPCSTATE_OFF(ps) + (ArmCRegs[a].PPCReg * 16) + (ArmCRegs[a].PS1 ? 8 : 0); emit->VSTR(ArmCRegs[a].Reg, R9, offset); ArmCRegs[a].PPCReg = 33; ArmCRegs[a].LastLoad = 0; + ArmCRegs[a].Away = true; } } diff --git a/Source/Core/Core/Src/PowerPC/JitArm32/JitRegCache.cpp b/Source/Core/Core/Src/PowerPC/JitArm32/JitRegCache.cpp index 2a9aa2154f..be79bd4b71 100644 --- a/Source/Core/Core/Src/PowerPC/JitArm32/JitRegCache.cpp +++ b/Source/Core/Core/Src/PowerPC/JitArm32/JitRegCache.cpp @@ -28,13 +28,7 @@ void ArmRegCache::Init(ARMXEmitter *emitter) emit = emitter; ARMReg *PPCRegs = GetPPCAllocationOrder(NUMPPCREG); ARMReg *Regs = GetAllocationOrder(NUMARMREG); - for(u8 a = 0; a < 32; ++a) - { - // This gives us the memory locations of the gpr registers so we can - // load them. - regs[a].location = (u8*)&PowerPC::ppcState.gpr[a]; - regs[a].UsesLeft = 0; - } + for(u8 a = 0; a < NUMPPCREG; ++a) { ArmCRegs[a].PPCReg = 33; @@ -49,14 +43,8 @@ void ArmRegCache::Init(ARMXEmitter *emitter) } void ArmRegCache::Start(PPCAnalyst::BlockRegStats &stats) { - for(u8 a = 0; a < NUMPPCREG; ++a) - { - ArmCRegs[a].PPCReg = 33; - ArmCRegs[a].LastLoad = 0; - } - for(u8 a = 0; a < 32; ++a) - regs[a].UsesLeft = stats.GetTotalNumAccesses(a); } + ARMReg *ArmRegCache::GetPPCAllocationOrder(int &count) { // This will return us the allocation order of the registers we can use on @@ -94,16 +82,7 @@ ARMReg ArmRegCache::GetReg(bool AutoLock) _assert_msg_(_DYNA_REC_, false, "All available registers are locked dumb dumb"); return R0; } -void ArmRegCache::Lock(ARMReg Reg) -{ - for(u8 RegNum = 0; RegNum < NUMARMREG; ++RegNum) - if(ArmRegs[RegNum].Reg == Reg) - { - _assert_msg_(_DYNA_REC, ArmRegs[RegNum].free, "This register is already locked"); - ArmRegs[RegNum].free = false; - } - _assert_msg_(_DYNA_REC, false, "Register %d can't be used with lock", Reg); -} + void ArmRegCache::Unlock(ARMReg R0, ARMReg R1, ARMReg R2, ARMReg R3) { for(u8 RegNum = 0; RegNum < NUMARMREG; ++RegNum) @@ -118,51 +97,130 @@ void ArmRegCache::Unlock(ARMReg R0, ARMReg R1, ARMReg R2, ARMReg R3) if( R3 != INVALID_REG && ArmRegs[RegNum].Reg == R3) ArmRegs[RegNum].free = true; } } - -ARMReg ArmRegCache::R(u32 preg) +u32 ArmRegCache::GetLeastUsedRegister(bool increment) { u32 HighestUsed = 0; - u8 Num = 0; + u8 lastRegIndex = 0; for(u8 a = 0; a < NUMPPCREG; ++a){ - ++ArmCRegs[a].LastLoad; + if (increment) + ++ArmCRegs[a].LastLoad; if (ArmCRegs[a].LastLoad > HighestUsed) { HighestUsed = ArmCRegs[a].LastLoad; - Num = a; + lastRegIndex = a; } } - // Check if already Loaded - for(u8 a = 0; a < NUMPPCREG; ++a) - if (ArmCRegs[a].PPCReg == preg) - { - ArmCRegs[a].LastLoad = 0; - return ArmCRegs[a].Reg; - } - // Check if we have a free register + return lastRegIndex; +} +bool ArmRegCache::FindFreeRegister(u32 ®index) +{ for (u8 a = 0; a < NUMPPCREG; ++a) if (ArmCRegs[a].PPCReg == 33) { - emit->LDR(ArmCRegs[a].Reg, R9, PPCSTATE_OFF(gpr) + preg * 4); - ArmCRegs[a].PPCReg = preg; - ArmCRegs[a].LastLoad = 0; - return ArmCRegs[a].Reg; + regindex = a; + return true; } + return false; +} + +ARMReg ArmRegCache::R(u32 preg) +{ + if (regs[preg].GetType() == REG_IMM) + { + return BindToRegister(preg); + //asm ("bkpt #1;"); + } + u32 lastRegIndex = GetLeastUsedRegister(true); + + // Check if already Loaded + if(regs[preg].GetType() == REG_REG) + { + u8 a = regs[preg].GetRegIndex(); + ArmCRegs[a].LastLoad = 0; + return ArmCRegs[a].Reg; + } + + // Check if we have a free register + u32 regindex; + if (FindFreeRegister(regindex)) + { + emit->LDR(ArmCRegs[regindex].Reg, R9, PPCSTATE_OFF(gpr) + preg * 4); + ArmCRegs[regindex].PPCReg = preg; + ArmCRegs[regindex].LastLoad = 0; + + regs[preg].LoadToReg(regindex); + return ArmCRegs[regindex].Reg; + } + // Alright, we couldn't get a free space, dump that least used register - emit->STR(ArmCRegs[Num].Reg, R9, PPCSTATE_OFF(gpr) + ArmCRegs[Num].PPCReg * 4); - emit->LDR(ArmCRegs[Num].Reg, R9, PPCSTATE_OFF(gpr) + preg * 4); - ArmCRegs[Num].PPCReg = preg; - ArmCRegs[Num].LastLoad = 0; - return ArmCRegs[Num].Reg; + emit->STR(ArmCRegs[lastRegIndex].Reg, R9, PPCSTATE_OFF(gpr) + ArmCRegs[lastRegIndex].PPCReg * 4); + emit->LDR(ArmCRegs[lastRegIndex].Reg, R9, PPCSTATE_OFF(gpr) + preg * 4); + + regs[ArmCRegs[lastRegIndex].PPCReg].Flush(); + + ArmCRegs[lastRegIndex].PPCReg = preg; + ArmCRegs[lastRegIndex].LastLoad = 0; + + regs[preg].LoadToReg(lastRegIndex); + + return ArmCRegs[lastRegIndex].Reg; +} + +ARMReg ArmRegCache::BindToRegister(u32 preg) +{ + _assert_msg_(DYNA_REC, regs[preg].GetType() == REG_IMM, "Can't BindToRegister with a REG"); + u32 lastRegIndex = GetLeastUsedRegister(false); + u32 freeRegIndex; + if (FindFreeRegister(freeRegIndex)) + { + emit->MOVI2R(ArmCRegs[freeRegIndex].Reg, regs[preg].GetImm()); + ArmCRegs[freeRegIndex].PPCReg = preg; + ArmCRegs[freeRegIndex].LastLoad = 0; + regs[preg].LoadToReg(freeRegIndex); + return ArmCRegs[freeRegIndex].Reg; + } + else + { + emit->STR(ArmCRegs[lastRegIndex].Reg, R9, PPCSTATE_OFF(gpr) + ArmCRegs[lastRegIndex].PPCReg * 4); + emit->MOVI2R(ArmCRegs[lastRegIndex].Reg, regs[preg].GetImm()); + + regs[ArmCRegs[lastRegIndex].PPCReg].Flush(); + + ArmCRegs[lastRegIndex].PPCReg = preg; + ArmCRegs[lastRegIndex].LastLoad = 0; + + regs[preg].LoadToReg(lastRegIndex); + return ArmCRegs[lastRegIndex].Reg; + } +} + +void ArmRegCache::SetImmediate(u32 preg, u32 imm) +{ + if (regs[preg].GetType() == REG_REG) + { + // Dump real reg at this point + u32 regindex = regs[preg].GetRegIndex(); + ArmCRegs[regindex].PPCReg = 33; + ArmCRegs[regindex].LastLoad = 0; + } + regs[preg].LoadToImm(imm); } void ArmRegCache::Flush() { - for(u8 a = 0; a < NUMPPCREG; ++a) - if (ArmCRegs[a].PPCReg != 33) + for (u8 a = 0; a < 32; ++a) + { + if (regs[a].GetType() == REG_IMM) + BindToRegister(a); + if (regs[a].GetType() == REG_REG) { - emit->STR(ArmCRegs[a].Reg, R9, PPCSTATE_OFF(gpr) + ArmCRegs[a].PPCReg * 4); - ArmCRegs[a].PPCReg = 33; - ArmCRegs[a].LastLoad = 0; + u32 regindex = regs[a].GetRegIndex(); + emit->STR(ArmCRegs[regindex].Reg, R9, PPCSTATE_OFF(gpr) + a * 4); + ArmCRegs[regindex].PPCReg = 33; + ArmCRegs[regindex].LastLoad = 0; } + + regs[a].Flush(); + } } diff --git a/Source/Core/Core/Src/PowerPC/JitArm32/JitRegCache.h b/Source/Core/Core/Src/PowerPC/JitArm32/JitRegCache.h index 7292ce1581..9eac9eeee8 100644 --- a/Source/Core/Core/Src/PowerPC/JitArm32/JitRegCache.h +++ b/Source/Core/Core/Src/PowerPC/JitArm32/JitRegCache.h @@ -35,17 +35,68 @@ using namespace ArmGen; // it // So we have R14, R12, R11, R10 to work with instructions -struct PPCCachedReg +enum RegType { - const u8 *location; - u32 UsesLeft; + REG_NOTLOADED = 0, + REG_REG, + REG_IMM, }; + +class OpArg +{ + private: + class Reg{ + public: + RegType m_type; + u8 m_reg; // index to register + u32 m_value; + Reg() + { + m_type = REG_NOTLOADED; + m_reg = 33; + m_value = 0; + } + } Reg; + + public: + OpArg(){} + + RegType GetType() + { + return Reg.m_type; + } + + u8 GetRegIndex() + { + return Reg.m_reg; + } + u32 GetImm() + { + return Reg.m_value; + } + void LoadToReg(u8 reg) + { + Reg.m_type = REG_REG; + Reg.m_reg = reg; + } + void LoadToImm(u32 imm) + { + Reg.m_type = REG_IMM; + Reg.m_value = imm; + } + void Flush() + { + Reg.m_type = REG_NOTLOADED; + } +}; + struct JRCPPC { u32 PPCReg; // Tied to which PPC Register bool PS1; ARMReg Reg; // Tied to which ARM Register u32 LastLoad; + bool Away; // Only used in FPR cache }; struct JRCReg { @@ -55,7 +106,7 @@ struct JRCReg class ArmRegCache { private: - PPCCachedReg regs[32]; + OpArg regs[32]; JRCPPC ArmCRegs[ARMREGS]; JRCReg ArmRegs[ARMREGS]; // Four registers remaining @@ -64,7 +115,9 @@ private: ARMReg *GetAllocationOrder(int &count); ARMReg *GetPPCAllocationOrder(int &count); - + + u32 GetLeastUsedRegister(bool increment); + bool FindFreeRegister(u32 ®index); protected: ARMXEmitter *emit; @@ -74,16 +127,16 @@ public: void Init(ARMXEmitter *emitter); void Start(PPCAnalyst::BlockRegStats &stats); - - void SetEmitter(ARMXEmitter *emitter) {emit = emitter;} ARMReg GetReg(bool AutoLock = true); // Return a ARM register we can use. - void Lock(ARMReg reg); void Unlock(ARMReg R0, ARMReg R1 = INVALID_REG, ARMReg R2 = INVALID_REG, ARMReg R3 = INVALID_REG); void Flush(); ARMReg R(u32 preg); // Returns a cached register - + bool IsImm(u32 preg) { return regs[preg].GetType() == REG_IMM; } + u32 GetImm(u32 preg) { return regs[preg].GetImm(); } + void SetImmediate(u32 preg, u32 imm); + ARMReg BindToRegister(u32 preg); }; diff --git a/Source/Core/Core/Src/PowerPC/JitCommon/JitCache.cpp b/Source/Core/Core/Src/PowerPC/JitCommon/JitCache.cpp index 889c51520c..7923fbf274 100644 --- a/Source/Core/Core/Src/PowerPC/JitCommon/JitCache.cpp +++ b/Source/Core/Core/Src/PowerPC/JitCommon/JitCache.cpp @@ -120,10 +120,12 @@ bool JitBlock::ContainsAddress(u32 em_address) // is full and when saving and loading states. void JitBaseBlockCache::Clear() { +#if defined(_DEBUG) || defined(DEBUGFAST) if (IsFull()) Core::DisplayMessage("Clearing block cache.", 3000); else Core::DisplayMessage("Clearing code cache.", 3000); +#endif for (int i = 0; i < num_blocks; i++) { diff --git a/Source/Core/Core/Src/PowerPC/PPCTables.cpp b/Source/Core/Core/Src/PowerPC/PPCTables.cpp index 9b3d74ffff..6599a58d4f 100644 --- a/Source/Core/Core/Src/PowerPC/PPCTables.cpp +++ b/Source/Core/Core/Src/PowerPC/PPCTables.cpp @@ -213,7 +213,7 @@ void LogCompiledInstructions() { if (m_allInstructions[i]->compileCount > 0) { - fprintf(f.GetHandle(), "%s\t%i\t%i\t%08x\n", m_allInstructions[i]->opname, + fprintf(f.GetHandle(), "%s\t%i\t%lld\t%08x\n", m_allInstructions[i]->opname, m_allInstructions[i]->compileCount, m_allInstructions[i]->runCount, m_allInstructions[i]->lastUse); } } @@ -223,7 +223,7 @@ void LogCompiledInstructions() { if (m_allInstructions[i]->compileCount == 0) { - fprintf(f.GetHandle(), "%s\t%i\t%i\n", m_allInstructions[i]->opname, + fprintf(f.GetHandle(), "%s\t%i\t%lld\n", m_allInstructions[i]->opname, m_allInstructions[i]->compileCount, m_allInstructions[i]->runCount); } } diff --git a/Source/Core/Core/Src/PowerPC/PPCTables.h b/Source/Core/Core/Src/PowerPC/PPCTables.h index 5b4fb5d11c..4a32f5515c 100644 --- a/Source/Core/Core/Src/PowerPC/PPCTables.h +++ b/Source/Core/Core/Src/PowerPC/PPCTables.h @@ -77,11 +77,7 @@ struct GekkoOPInfo int type; int flags; int numCyclesMinusOne; -#ifdef _M_ARM u64 runCount; -#else - int runCount; -#endif int compileCount; u32 lastUse; }; diff --git a/Source/Core/Core/Src/PowerPC/PowerPC.cpp b/Source/Core/Core/Src/PowerPC/PowerPC.cpp index 4f45d08ede..b082960175 100644 --- a/Source/Core/Core/Src/PowerPC/PowerPC.cpp +++ b/Source/Core/Core/Src/PowerPC/PowerPC.cpp @@ -127,17 +127,6 @@ void Init(int cpu_core) ppcState.itlb_last = 0; memset(ppcState.itlb_va, 0, sizeof(ppcState.itlb_va)); memset(ppcState.itlb_pa, 0, sizeof(ppcState.itlb_pa)); - - memset(ppcState.mojs, 0, sizeof(ppcState.mojs)); - memset(ppcState.sr, 0, sizeof(ppcState.sr)); - ppcState.DebugCount = 0; - ppcState.dtlb_last = 0; - ppcState.dtlb_last = 0; - memset(ppcState.dtlb_va, 0, sizeof(ppcState.dtlb_va)); - memset(ppcState.dtlb_pa, 0, sizeof(ppcState.dtlb_pa)); - ppcState.itlb_last = 0; - memset(ppcState.itlb_va, 0, sizeof(ppcState.itlb_va)); - memset(ppcState.itlb_pa, 0, sizeof(ppcState.itlb_pa)); ppcState.pagetable_base = 0; ppcState.pagetable_hashmask = 0; diff --git a/Source/Core/Core/Src/State.h b/Source/Core/Core/Src/State.h index 302e25d617..8da3a4d537 100644 --- a/Source/Core/Core/Src/State.h +++ b/Source/Core/Core/Src/State.h @@ -15,7 +15,7 @@ namespace State { // number of states -static const u32 NUM_STATES = 8; +static const u32 NUM_STATES = 10; struct StateHeader { diff --git a/Source/Core/DolphinWX/CMakeLists.txt b/Source/Core/DolphinWX/CMakeLists.txt index 524a14f13c..62ce9808a2 100644 --- a/Source/Core/DolphinWX/CMakeLists.txt +++ b/Source/Core/DolphinWX/CMakeLists.txt @@ -170,6 +170,7 @@ if(USE_UPNP) endif() if(ANDROID) + set(DOLPHIN_EXE main) add_library(${DOLPHIN_EXE} SHARED ${SRCS}) target_link_libraries(${DOLPHIN_EXE} log @@ -181,9 +182,12 @@ if(ANDROID) if (${CMAKE_SYSTEM_PROCESSOR} MATCHES "mips") set (SO_TARGET "mips") endif() - if (${CMAKE_SYSTEM_PROCESSOR} MATCHES "^arm") + if (${CMAKE_SYSTEM_PROCESSOR} MATCHES "armv7-a") set (SO_TARGET "armeabi-v7a") endif() + if(${CMAKE_SYSTEM_PROCESSOR} MATCHES "armv5te") + set (SO_TARGET "armeabi") + endif() if (${CMAKE_SYSTEM_PROCESSOR} MATCHES "i686") set (SO_TARGET "x86") endif() @@ -196,6 +200,9 @@ if(ANDROID) add_custom_command(TARGET ${DOLPHIN_EXE} POST_BUILD COMMAND cp ARGS ${CMAKE_SOURCE_DIR}/Data/Sys/GC/* ${CMAKE_SOURCE_DIR}/Source/Android/assets/ ) + add_custom_command(TARGET ${DOLPHIN_EXE} POST_BUILD + COMMAND cp ARGS ${CMAKE_SOURCE_DIR}/Data/Sys/Wii/* ${CMAKE_SOURCE_DIR}/Source/Android/assets/ + ) else() add_executable(${DOLPHIN_EXE} ${SRCS}) target_link_libraries(${DOLPHIN_EXE} ${LIBS} ${WXLIBS}) diff --git a/Source/Core/DolphinWX/Dolphin.vcxproj b/Source/Core/DolphinWX/Dolphin.vcxproj index f094d0e12c..5b9563293b 100644 --- a/Source/Core/DolphinWX/Dolphin.vcxproj +++ b/Source/Core/DolphinWX/Dolphin.vcxproj @@ -238,7 +238,6 @@ xcopy "$(SolutionDir)..\Externals\SDL\$(PlatformName)\*.dll" "$(TargetDir)" /e / <ClCompile Include="Src\FrameAui.cpp" /> <ClCompile Include="Src\FrameTools.cpp" /> <ClCompile Include="Src\GameListCtrl.cpp" /> - <ClCompile Include="Src\GCMicDlg.cpp" /> <ClCompile Include="Src\GeckoCodeDiag.cpp" /> <ClCompile Include="Src\HotkeyDlg.cpp" /> <ClCompile Include="Src\InputConfigDiag.cpp" /> @@ -301,7 +300,6 @@ xcopy "$(SolutionDir)..\Externals\SDL\$(PlatformName)\*.dll" "$(TargetDir)" /e / <ClInclude Include="Src\FifoPlayerDlg.h" /> <ClInclude Include="Src\Frame.h" /> <ClInclude Include="Src\GameListCtrl.h" /> - <ClInclude Include="Src\GCMicDlg.h" /> <ClInclude Include="Src\GeckoCodeDiag.h" /> <ClInclude Include="Src\Globals.h" /> <ClInclude Include="Src\HotkeyDlg.h" /> diff --git a/Source/Core/DolphinWX/Dolphin.vcxproj.filters b/Source/Core/DolphinWX/Dolphin.vcxproj.filters index 5cbfd9d982..6c1f530015 100644 --- a/Source/Core/DolphinWX/Dolphin.vcxproj.filters +++ b/Source/Core/DolphinWX/Dolphin.vcxproj.filters @@ -132,9 +132,6 @@ <ClCompile Include="Src\TASInputDlg.cpp"> <Filter>GUI</Filter> </ClCompile> - <ClCompile Include="Src\GCMicDlg.cpp"> - <Filter>GUI</Filter> - </ClCompile> <ClCompile Include="Src\GLInterface\WGL.cpp" /> </ItemGroup> <ItemGroup> @@ -262,9 +259,6 @@ <ClInclude Include="Src\TASInputDlg.h"> <Filter>GUI</Filter> </ClInclude> - <ClInclude Include="Src\GCMicDlg.h"> - <Filter>GUI</Filter> - </ClInclude> <ClInclude Include="Src\GLInterface.h" /> <ClInclude Include="Src\GLInterface\InterfaceBase.h" /> <ClInclude Include="Src\GLInterface\WGL.h" /> diff --git a/Source/Core/DolphinWX/Info.plist.in b/Source/Core/DolphinWX/Info.plist.in index c23ae1e40e..f08863a5d9 100644 --- a/Source/Core/DolphinWX/Info.plist.in +++ b/Source/Core/DolphinWX/Info.plist.in @@ -28,7 +28,7 @@ <key>CFBundleIconFile</key> <string>Dolphin.icns</string> <key>CFBundleIdentifier</key> - <string>com.dolphin-emulator.dolphin</string> + <string>org.dolphin-emu.dolphin</string> <key>CFBundleDevelopmentRegion</key> <string>English</string> <key>CFBundleLocalizations</key> diff --git a/Source/Core/DolphinWX/Src/Frame.cpp b/Source/Core/DolphinWX/Src/Frame.cpp index af71066314..613cdc35ab 100644 --- a/Source/Core/DolphinWX/Src/Frame.cpp +++ b/Source/Core/DolphinWX/Src/Frame.cpp @@ -213,9 +213,9 @@ EVT_MENU(IDM_UNDOSAVESTATE, CFrame::OnUndoSaveState) EVT_MENU(IDM_LOADSTATEFILE, CFrame::OnLoadStateFromFile) EVT_MENU(IDM_SAVESTATEFILE, CFrame::OnSaveStateToFile) -EVT_MENU_RANGE(IDM_LOADSLOT1, IDM_LOADSLOT8, CFrame::OnLoadState) +EVT_MENU_RANGE(IDM_LOADSLOT1, IDM_LOADSLOT10, CFrame::OnLoadState) EVT_MENU_RANGE(IDM_LOADLAST1, IDM_LOADLAST8, CFrame::OnLoadLastState) -EVT_MENU_RANGE(IDM_SAVESLOT1, IDM_SAVESLOT8, CFrame::OnSaveState) +EVT_MENU_RANGE(IDM_SAVESLOT1, IDM_SAVESLOT10, CFrame::OnSaveState) EVT_MENU_RANGE(IDM_FRAMESKIP0, IDM_FRAMESKIP9, CFrame::OnFrameSkip) EVT_MENU_RANGE(IDM_DRIVE1, IDM_DRIVE24, CFrame::OnBootDrive) EVT_MENU_RANGE(IDM_CONNECT_WIIMOTE1, IDM_CONNECT_BALANCEBOARD, CFrame::OnConnectWiimote) @@ -756,6 +756,8 @@ int GetCmdForHotkey(unsigned int key) case HK_LOAD_STATE_SLOT_6: return IDM_LOADSLOT6; case HK_LOAD_STATE_SLOT_7: return IDM_LOADSLOT7; case HK_LOAD_STATE_SLOT_8: return IDM_LOADSLOT8; + case HK_LOAD_STATE_SLOT_9: return IDM_LOADSLOT9; + case HK_LOAD_STATE_SLOT_10: return IDM_LOADSLOT10; case HK_SAVE_STATE_SLOT_1: return IDM_SAVESLOT1; case HK_SAVE_STATE_SLOT_2: return IDM_SAVESLOT2; @@ -765,6 +767,8 @@ int GetCmdForHotkey(unsigned int key) case HK_SAVE_STATE_SLOT_6: return IDM_SAVESLOT6; case HK_SAVE_STATE_SLOT_7: return IDM_SAVESLOT7; case HK_SAVE_STATE_SLOT_8: return IDM_SAVESLOT8; + case HK_SAVE_STATE_SLOT_9: return IDM_SAVESLOT9; + case HK_SAVE_STATE_SLOT_10: return IDM_SAVESLOT10; case HK_LOAD_LAST_STATE_1: return IDM_LOADLAST1; case HK_LOAD_LAST_STATE_2: return IDM_LOADLAST2; @@ -846,6 +850,48 @@ void CFrame::OnKeyDown(wxKeyEvent& event) WiimoteId = 3; else if (IsHotkey(event, HK_BALANCEBOARD_CONNECT)) WiimoteId = 4; + else if (IsHotkey(event, HK_TOGGLE_IR)) + { + OSDChoice = 1; + // Toggle native resolution + if (++g_Config.iEFBScale > SCALE_4X) + g_Config.iEFBScale = SCALE_AUTO; + } + else if (IsHotkey(event, HK_TOGGLE_AR)) + { + OSDChoice = 2; + // Toggle aspect ratio + g_Config.iAspectRatio = (g_Config.iAspectRatio + 1) & 3; + } + else if (IsHotkey(event, HK_TOGGLE_EFBCOPIES)) + { + OSDChoice = 3; + // Toggle EFB copy + if (!g_Config.bEFBCopyEnable || g_Config.bCopyEFBToTexture) + { + g_Config.bEFBCopyEnable ^= true; + g_Config.bCopyEFBToTexture = false; + } + else + { + g_Config.bCopyEFBToTexture = !g_Config.bCopyEFBToTexture; + } + } + else if (IsHotkey(event, HK_TOGGLE_FOG)) + { + OSDChoice = 4; + g_Config.bDisableFog = !g_Config.bDisableFog; + } + else if (IsHotkey(event, HK_INCREASE_FRAME_LIMIT)) + { + if (++SConfig::GetInstance().m_Framelimit > 0x19) + SConfig::GetInstance().m_Framelimit = 0; + } + else if (IsHotkey(event, HK_DECREASE_FRAME_LIMIT)) + { + if (--SConfig::GetInstance().m_Framelimit > 0x19) + SConfig::GetInstance().m_Framelimit = 0x19; + } else { unsigned int i = NUM_HOTKEYS; @@ -891,43 +937,6 @@ void CFrame::OnKeyDown(wxKeyEvent& event) ConnectWiimote(WiimoteId, connect); } - if (g_Config.bOSDHotKey && event.GetModifiers() == wxMOD_NONE) - { - switch (event.GetKeyCode()) - { - case '3': - OSDChoice = 1; - // Toggle native resolution - g_Config.iEFBScale = g_Config.iEFBScale + 1; - if (g_Config.iEFBScale > 7) g_Config.iEFBScale = 0; - break; - case '4': - OSDChoice = 2; - // Toggle aspect ratio - g_Config.iAspectRatio = (g_Config.iAspectRatio + 1) & 3; - break; - case '5': - OSDChoice = 3; - // Toggle EFB copy - if (!g_Config.bEFBCopyEnable || g_Config.bCopyEFBToTexture) - { - g_Config.bEFBCopyEnable ^= true; - g_Config.bCopyEFBToTexture = false; - } - else - { - g_Config.bCopyEFBToTexture = !g_Config.bCopyEFBToTexture; - } - break; - case '6': - OSDChoice = 4; - g_Config.bDisableFog = !g_Config.bDisableFog; - break; - default: - break; - } - } - if (g_Config.bFreeLook && event.GetModifiers() == wxMOD_SHIFT) { static float debugSpeed = 1.0f; diff --git a/Source/Core/DolphinWX/Src/FrameTools.cpp b/Source/Core/DolphinWX/Src/FrameTools.cpp index 1c70b4e715..dcca6ccf66 100644 --- a/Source/Core/DolphinWX/Src/FrameTools.cpp +++ b/Source/Core/DolphinWX/Src/FrameTools.cpp @@ -382,6 +382,8 @@ wxString CFrame::GetMenuLabel(int Id) case HK_LOAD_STATE_SLOT_6: case HK_LOAD_STATE_SLOT_7: case HK_LOAD_STATE_SLOT_8: + case HK_LOAD_STATE_SLOT_9: + case HK_LOAD_STATE_SLOT_10: Label = wxString::Format(_("Slot %i"), Id - HK_LOAD_STATE_SLOT_1 + 1); break; @@ -394,6 +396,8 @@ wxString CFrame::GetMenuLabel(int Id) case HK_SAVE_STATE_SLOT_6: case HK_SAVE_STATE_SLOT_7: case HK_SAVE_STATE_SLOT_8: + case HK_SAVE_STATE_SLOT_9: + case HK_SAVE_STATE_SLOT_10: Label = wxString::Format(_("Slot %i"), Id - HK_SAVE_STATE_SLOT_1 + 1); break; @@ -1006,6 +1010,8 @@ void CFrame::DoPause() // Stop the emulation void CFrame::DoStop() { + if (!Core::IsRunningAndStarted()) + return; if (confirmStop) return; @@ -1045,6 +1051,7 @@ void CFrame::DoStop() DoRecordingSave(); if(Movie::IsPlayingInput() || Movie::IsRecordingInput()) Movie::EndPlayInput(false); + NetPlay::StopGame(); wxBeginBusyCursor(); BootManager::Stop(); @@ -1581,7 +1588,11 @@ void CFrame::UpdateGUI() // Update Menu Accelerators for (unsigned int i = 0; i < NUM_HOTKEYS; i++) + { + if (GetCmdForHotkey(i) == -1) + continue; GetMenuBar()->FindItem(GetCmdForHotkey(i))->SetItemLabel(GetMenuLabel(i)); + } GetMenuBar()->FindItem(IDM_LOADSTATE)->Enable(Initialized); GetMenuBar()->FindItem(IDM_SAVESTATE)->Enable(Initialized); diff --git a/Source/Core/DolphinWX/Src/GCMicDlg.cpp b/Source/Core/DolphinWX/Src/GCMicDlg.cpp deleted file mode 100644 index 8edc86d667..0000000000 --- a/Source/Core/DolphinWX/Src/GCMicDlg.cpp +++ /dev/null @@ -1,274 +0,0 @@ -// Copyright 2013 Dolphin Emulator Project -// Licensed under GPLv2 -// Refer to the license.txt file included. - -#include <wx/notebook.h> - -#include "GCMicDlg.h" -#include "ConfigManager.h" - -BEGIN_EVENT_TABLE(GCMicDialog,wxDialog) - EVT_COMMAND_RANGE(0, NUM_HOTKEYS - 1, - wxEVT_COMMAND_BUTTON_CLICKED, GCMicDialog::OnButtonClick) - EVT_TIMER(wxID_ANY, GCMicDialog::OnButtonTimer) -END_EVENT_TABLE() - -GCMicDialog::GCMicDialog(wxWindow *parent, wxWindowID id, const wxString &title, - const wxPoint &position, const wxSize& size, long style) -: wxDialog(parent, id, title, position, size, style) -{ - CreateHotkeyGUIControls(); - -#if wxUSE_TIMER - m_ButtonMappingTimer = new wxTimer(this, wxID_ANY); - g_Pressed = 0; - g_Modkey = 0; - ClickedButton = NULL; - GetButtonWaitingID = 0; - GetButtonWaitingTimer = 0; -#endif -} - -GCMicDialog::~GCMicDialog() -{ - delete m_ButtonMappingTimer; -} - -// Save keyboard key mapping -void GCMicDialog::SaveButtonMapping(int Id, int Key, int Modkey) -{ - SConfig::GetInstance().m_LocalCoreStartupParameter.iHotkey[Id] = Key; - SConfig::GetInstance().m_LocalCoreStartupParameter.iHotkeyModifier[Id] = Modkey; -} - -void GCMicDialog::EndGetButtons(void) -{ - wxTheApp->Unbind(wxEVT_KEY_DOWN, &GCMicDialog::OnKeyDown, this); - m_ButtonMappingTimer->Stop(); - GetButtonWaitingTimer = 0; - GetButtonWaitingID = 0; - ClickedButton = NULL; - SetEscapeId(wxID_ANY); -} - -void GCMicDialog::OnKeyDown(wxKeyEvent& event) -{ - if(ClickedButton != NULL) - { - // Save the key - g_Pressed = event.GetKeyCode(); - g_Modkey = event.GetModifiers(); - - // Don't allow modifier keys - if (g_Pressed == WXK_CONTROL || g_Pressed == WXK_ALT || - g_Pressed == WXK_SHIFT || g_Pressed == WXK_COMMAND) - return; - - // Use the space key to set a blank key - if (g_Pressed == WXK_SPACE) - { - SaveButtonMapping(ClickedButton->GetId(), -1, 0); - SetButtonText(ClickedButton->GetId(), wxString()); - } - else - { - SetButtonText(ClickedButton->GetId(), - InputCommon::WXKeyToString(g_Pressed), - InputCommon::WXKeymodToString(g_Modkey)); - SaveButtonMapping(ClickedButton->GetId(), g_Pressed, g_Modkey); - } - EndGetButtons(); - } -} - -// Update the textbox for the buttons -void GCMicDialog::SetButtonText(int id, const wxString &keystr, const wxString &modkeystr) -{ - m_Button_Hotkeys[id]->SetLabel(modkeystr + keystr); -} - -void GCMicDialog::DoGetButtons(int _GetId) -{ - // Values used in this function - const int Seconds = 4; // Seconds to wait for - const int TimesPerSecond = 40; // How often to run the check - - // If the Id has changed or the timer is not running we should start one - if( GetButtonWaitingID != _GetId || !m_ButtonMappingTimer->IsRunning() ) - { - if(m_ButtonMappingTimer->IsRunning()) - m_ButtonMappingTimer->Stop(); - - // Save the button Id - GetButtonWaitingID = _GetId; - GetButtonWaitingTimer = 0; - - // Start the timer - #if wxUSE_TIMER - m_ButtonMappingTimer->Start(1000 / TimesPerSecond); - #endif - } - - // Process results - // Count each time - GetButtonWaitingTimer++; - - // This is run every second - if (GetButtonWaitingTimer % TimesPerSecond == 0) - { - // Current time - int TmpTime = Seconds - (GetButtonWaitingTimer / TimesPerSecond); - // Update text - SetButtonText(_GetId, wxString::Format(wxT("[ %d ]"), TmpTime)); - } - - // Time's up - if (GetButtonWaitingTimer / TimesPerSecond >= Seconds) - { - // Revert back to old label - SetButtonText(_GetId, OldLabel); - EndGetButtons(); - } -} - -// Input button clicked -void GCMicDialog::OnButtonClick(wxCommandEvent& event) -{ - event.Skip(); - - if (m_ButtonMappingTimer->IsRunning()) - return; - - wxTheApp->Bind(wxEVT_KEY_DOWN, &GCMicDialog::OnKeyDown, this); - - // Get the button - ClickedButton = (wxButton *)event.GetEventObject(); - SetEscapeId(wxID_CANCEL); - // Save old label so we can revert back - OldLabel = ClickedButton->GetLabel(); - ClickedButton->SetWindowStyle(wxWANTS_CHARS); - ClickedButton->SetLabel(_("<Press Key>")); - DoGetButtons(ClickedButton->GetId()); -} - -#define HOTKEY_NUM_COLUMNS 2 - -void GCMicDialog::CreateHotkeyGUIControls(void) -{ - const wxString pageNames[] = - { - _("General"), - _("State Saves") - }; - - const wxString hkText[] = - { - _("Open"), - _("Change Disc"), - _("Refresh List"), - - _("Play/Pause"), - _("Stop"), - _("Reset"), - _("Frame Advance"), - - _("Start Recording"), - _("Play Recording"), - _("Export Recording"), - _("Read-only mode"), - - _("Toggle Fullscreen"), - _("Take Screenshot"), - - _("Connect Wiimote 1"), - _("Connect Wiimote 2"), - _("Connect Wiimote 3"), - _("Connect Wiimote 4"), - - _("Load State Slot 1"), - _("Load State Slot 2"), - _("Load State Slot 3"), - _("Load State Slot 4"), - _("Load State Slot 5"), - _("Load State Slot 6"), - _("Load State Slot 7"), - _("Load State Slot 8"), - - _("Save State Slot 1"), - _("Save State Slot 2"), - _("Save State Slot 3"), - _("Save State Slot 4"), - _("Save State Slot 5"), - _("Save State Slot 6"), - _("Save State Slot 7"), - _("Save State Slot 8") - }; - - const int page_breaks[3] = {HK_OPEN, HK_LOAD_STATE_SLOT_1, NUM_HOTKEYS}; - - // Configuration controls sizes - wxSize size(100,20); - // A small type font - wxFont m_SmallFont(7, wxFONTFAMILY_DEFAULT, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_NORMAL); - - wxNotebook *Notebook = new wxNotebook(this, wxID_ANY, wxDefaultPosition, wxDefaultSize); - - for (int j = 0; j < 2; j++) - { - wxPanel *Page = new wxPanel(Notebook, wxID_ANY, wxDefaultPosition, wxDefaultSize); - Notebook->AddPage(Page, pageNames[j]); - - wxGridBagSizer *sHotkeys = new wxGridBagSizer(); - - // Header line - for (int i = 0; i < HOTKEY_NUM_COLUMNS; i++) - { - wxBoxSizer *HeaderSizer = new wxBoxSizer(wxHORIZONTAL); - wxStaticText *StaticTextHeader = new wxStaticText(Page, wxID_ANY, _("Action")); - HeaderSizer->Add(StaticTextHeader, 1, wxALL, 2); - StaticTextHeader = new wxStaticText(Page, wxID_ANY, _("Key"), wxDefaultPosition, size); - HeaderSizer->Add(StaticTextHeader, 0, wxALL, 2); - sHotkeys->Add(HeaderSizer, wxGBPosition(0, i), wxDefaultSpan, wxEXPAND | wxLEFT, (i > 0) ? 30 : 1); - } - - int column_break = (page_breaks[j+1] + page_breaks[j] + 1) / 2; - - for (int i = page_breaks[j]; i < page_breaks[j+1]; i++) - { - // Text for the action - wxStaticText *stHotkeys = new wxStaticText(Page, wxID_ANY, hkText[i]); - - // Key selection button - m_Button_Hotkeys[i] = new wxButton(Page, i, wxEmptyString, - wxDefaultPosition, size); - m_Button_Hotkeys[i]->SetFont(m_SmallFont); - m_Button_Hotkeys[i]->SetToolTip(_("Left click to detect hotkeys.\nEnter space to clear.")); - SetButtonText(i, - InputCommon::WXKeyToString(SConfig::GetInstance().m_LocalCoreStartupParameter.iHotkey[i]), - InputCommon::WXKeymodToString( - SConfig::GetInstance().m_LocalCoreStartupParameter.iHotkeyModifier[i])); - - wxBoxSizer *sHotkey = new wxBoxSizer(wxHORIZONTAL); - sHotkey->Add(stHotkeys, 1, wxALIGN_LEFT | wxALIGN_CENTER_VERTICAL | wxALL, 2); - sHotkey->Add(m_Button_Hotkeys[i], 0, wxALL, 2); - sHotkeys->Add(sHotkey, - wxGBPosition((i < column_break) ? i - page_breaks[j] + 1 : i - column_break + 1, - (i < column_break) ? 0 : 1), - wxDefaultSpan, wxEXPAND | wxLEFT, (i < column_break) ? 1 : 30); - } - - wxStaticBoxSizer *sHotkeyBox = new wxStaticBoxSizer(wxVERTICAL, Page, _("Hotkeys")); - sHotkeyBox->Add(sHotkeys); - - wxBoxSizer* const sPage = new wxBoxSizer(wxVERTICAL); - sPage->Add(sHotkeyBox, 0, wxEXPAND | wxALL, 5); - Page->SetSizer(sPage); - } - - wxBoxSizer *sMainSizer = new wxBoxSizer(wxVERTICAL); - sMainSizer->Add(Notebook, 0, wxEXPAND | wxALL, 5); - sMainSizer->Add(CreateButtonSizer(wxOK), 0, wxEXPAND | wxLEFT | wxRIGHT | wxDOWN, 5); - SetSizerAndFit(sMainSizer); - SetFocus(); -} - diff --git a/Source/Core/DolphinWX/Src/GCMicDlg.h b/Source/Core/DolphinWX/Src/GCMicDlg.h deleted file mode 100644 index 7d5d88b6dd..0000000000 --- a/Source/Core/DolphinWX/Src/GCMicDlg.h +++ /dev/null @@ -1,61 +0,0 @@ -// Copyright 2013 Dolphin Emulator Project -// Licensed under GPLv2 -// Refer to the license.txt file included. - -#ifndef __GCMICDIALOG_h__ -#define __GCMICDIALOG_h__ - -#include <wx/wx.h> -#include <wx/textctrl.h> -#include <wx/button.h> -#include <wx/stattext.h> -#include <wx/combobox.h> -#include <wx/checkbox.h> -#include <wx/gbsizer.h> - -#include "Common.h" -#include "CoreParameter.h" -#include "WXInputBase.h" - -#if defined(HAVE_X11) && HAVE_X11 -#include "X11InputBase.h" -#include <X11/Xlib.h> -#include <X11/keysym.h> -#endif - -class GCMicDialog : public wxDialog -{ - public: - GCMicDialog(wxWindow *parent, - wxWindowID id = 1, - const wxString &title = _("GCMic Configuration"), - const wxPoint& pos = wxDefaultPosition, - const wxSize& size = wxDefaultSize, - long style = wxDEFAULT_DIALOG_STYLE); - virtual ~GCMicDialog(); - - private: - DECLARE_EVENT_TABLE(); - - wxString OldLabel; - - wxButton *ClickedButton, - *m_Button_Hotkeys[NUM_HOTKEYS]; - - wxTimer *m_ButtonMappingTimer; - - void OnButtonTimer(wxTimerEvent& WXUNUSED(event)) { DoGetButtons(GetButtonWaitingID); } - void OnButtonClick(wxCommandEvent& event); - void OnKeyDown(wxKeyEvent& event); - void SaveButtonMapping(int Id, int Key, int Modkey); - void CreateHotkeyGUIControls(void); - - void SetButtonText(int id, const wxString &keystr, const wxString &modkeystr = wxString()); - - void DoGetButtons(int id); - void EndGetButtons(void); - - int GetButtonWaitingID, GetButtonWaitingTimer, g_Pressed, g_Modkey; -}; -#endif - diff --git a/Source/Core/DolphinWX/Src/GLInterface/EGL.cpp b/Source/Core/DolphinWX/Src/GLInterface/EGL.cpp index b5560d1ed7..b8276ae546 100644 --- a/Source/Core/DolphinWX/Src/GLInterface/EGL.cpp +++ b/Source/Core/DolphinWX/Src/GLInterface/EGL.cpp @@ -132,17 +132,6 @@ bool cInterfaceEGL::Create(void *&window_handle) exit(1); } - if (!eglMakeCurrent(GLWin.egl_dpy, GLWin.egl_surf, GLWin.egl_surf, GLWin.egl_ctx)) { - - INFO_LOG(VIDEO, "Error: eglMakeCurrent() failed\n"); - return false; - } - - INFO_LOG(VIDEO, "GL_VENDOR: %s\n", glGetString(GL_VENDOR)); - INFO_LOG(VIDEO, "GL_RENDERER: %s\n", glGetString(GL_RENDERER)); - INFO_LOG(VIDEO, "GL_VERSION: %s\n", glGetString(GL_VERSION)); - INFO_LOG(VIDEO, "GL_EXTENSIONS: %s\n", glGetString(GL_EXTENSIONS)); - Platform.ToggleFullscreen(SConfig::GetInstance().m_LocalCoreStartupParameter.bFullscreen); window_handle = (void *)GLWin.native_window; diff --git a/Source/Core/DolphinWX/Src/Globals.h b/Source/Core/DolphinWX/Src/Globals.h index ded510028d..5930427620 100644 --- a/Source/Core/DolphinWX/Src/Globals.h +++ b/Source/Core/DolphinWX/Src/Globals.h @@ -38,6 +38,8 @@ enum IDM_SAVESLOT6, IDM_SAVESLOT7, IDM_SAVESLOT8, + IDM_SAVESLOT9, + IDM_SAVESLOT10, IDM_LOADSLOT1, IDM_LOADSLOT2, IDM_LOADSLOT3, @@ -46,6 +48,8 @@ enum IDM_LOADSLOT6, IDM_LOADSLOT7, IDM_LOADSLOT8, + IDM_LOADSLOT9, + IDM_LOADSLOT10, IDM_LOADLAST1, IDM_LOADLAST2, IDM_LOADLAST3, diff --git a/Source/Core/DolphinWX/Src/HotkeyDlg.cpp b/Source/Core/DolphinWX/Src/HotkeyDlg.cpp index fad602f19e..67d540b16e 100644 --- a/Source/Core/DolphinWX/Src/HotkeyDlg.cpp +++ b/Source/Core/DolphinWX/Src/HotkeyDlg.cpp @@ -187,6 +187,13 @@ void HotkeyConfigDialog::CreateHotkeyGUIControls(void) _("Connect Wiimote 4"), _("Connect Balance Board"), + _("Toggle IR"), + _("Toggle Aspect Ratio"), + _("Toggle EFB Copies"), + _("Toggle Fog"), + _("Increase Frame limit"), + _("Decrease Frame limit"), + _("Load State Slot 1"), _("Load State Slot 2"), _("Load State Slot 3"), @@ -195,6 +202,8 @@ void HotkeyConfigDialog::CreateHotkeyGUIControls(void) _("Load State Slot 6"), _("Load State Slot 7"), _("Load State Slot 8"), + _("Load State Slot 9"), + _("Load State Slot 10"), _("Save State Slot 1"), _("Save State Slot 2"), @@ -204,6 +213,8 @@ void HotkeyConfigDialog::CreateHotkeyGUIControls(void) _("Save State Slot 6"), _("Save State Slot 7"), _("Save State Slot 8"), + _("Save State Slot 9"), + _("Save State Slot 10"), _("Load State Last 1"), _("Load State Last 2"), diff --git a/Source/Core/DolphinWX/Src/Main.cpp b/Source/Core/DolphinWX/Src/Main.cpp index 0cbfab1031..be1f1b7802 100644 --- a/Source/Core/DolphinWX/Src/Main.cpp +++ b/Source/Core/DolphinWX/Src/Main.cpp @@ -263,6 +263,9 @@ bool DolphinApp::OnInit() File::CreateFullPath(File::GetUserPath(D_SCREENSHOTS_IDX)); File::CreateFullPath(File::GetUserPath(D_STATESAVES_IDX)); File::CreateFullPath(File::GetUserPath(D_MAILLOGS_IDX)); + File::CreateFullPath(File::GetUserPath(D_GCUSER_IDX) + USA_DIR DIR_SEP); + File::CreateFullPath(File::GetUserPath(D_GCUSER_IDX) + EUR_DIR DIR_SEP); + File::CreateFullPath(File::GetUserPath(D_GCUSER_IDX) + JAP_DIR DIR_SEP); LogManager::Init(); SConfig::Init(); diff --git a/Source/Core/DolphinWX/Src/MainAndroid.cpp b/Source/Core/DolphinWX/Src/MainAndroid.cpp index 295d13ccef..5fc616d5ac 100644 --- a/Source/Core/DolphinWX/Src/MainAndroid.cpp +++ b/Source/Core/DolphinWX/Src/MainAndroid.cpp @@ -47,6 +47,9 @@ #include <android/native_window_jni.h> ANativeWindow* surf; int g_width, g_height; +std::string g_filename; +static std::thread g_run_thread; + #define LOGI(...) ((void)__android_log_print(ANDROID_LOG_INFO, "Dolphinemu", __VA_ARGS__)) void Host_NotifyMapLoaded() {} @@ -66,7 +69,10 @@ void* Host_GetRenderHandle() void* Host_GetInstance() { return NULL; } -void Host_UpdateTitle(const char* title){}; +void Host_UpdateTitle(const char* title) +{ + LOGI(title); +}; void Host_UpdateLogDisplay(){} @@ -297,12 +303,23 @@ JNIEXPORT void JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_SetConfig(JN env->ReleaseStringUTFChars(jDefault, Default); } -JNIEXPORT void JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_Run(JNIEnv *env, jobject obj, jstring jFile, jobject _surf, jint _width, jint _height) +JNIEXPORT void JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_SetFilename(JNIEnv *env, jobject obj, jstring jFile) +{ + const char *File = env->GetStringUTFChars(jFile, NULL); + + g_filename = std::string(File); + + env->ReleaseStringUTFChars(jFile, File); +} +JNIEXPORT void JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_SetDimensions(JNIEnv *env, jobject obj, jint _width, jint _height) { - surf = ANativeWindow_fromSurface(env, _surf); g_width = (int)_width; g_height = (int)_height; +} +JNIEXPORT void JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_Run(JNIEnv *env, jobject obj, jobject _surf) +{ + surf = ANativeWindow_fromSurface(env, _surf); // Install our callbacks OSD::AddCallback(OSD::OSD_INIT, OSDCallbacks, 0); OSD::AddCallback(OSD::OSD_SHUTDOWN, OSDCallbacks, 2); @@ -322,9 +339,8 @@ JNIEXPORT void JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_Run(JNIEnv * if (onscreencontrols) OSD::AddCallback(OSD::OSD_ONFRAME, OSDCallbacks, 1); - const char *File = env->GetStringUTFChars(jFile, NULL); // No use running the loop when booting fails - if ( BootManager::BootCore( File ) ) + if ( BootManager::BootCore( g_filename.c_str() ) ) while (PowerPC::GetState() != PowerPC::CPU_POWERDOWN) updateMainFrameEvent.Wait(); @@ -333,7 +349,8 @@ JNIEXPORT void JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_Run(JNIEnv * SConfig::Shutdown(); LogManager::Shutdown(); } - + + #ifdef __cplusplus } #endif diff --git a/Source/Core/DolphinWX/Src/NetWindow.cpp b/Source/Core/DolphinWX/Src/NetWindow.cpp index 22cd588236..7f1b7c6866 100644 --- a/Source/Core/DolphinWX/Src/NetWindow.cpp +++ b/Source/Core/DolphinWX/Src/NetWindow.cpp @@ -6,21 +6,25 @@ #include <IniFile.h> #include "WxUtils.h" -#include "NetPlay.h" +#include "NetPlayClient.h" +#include "NetPlayServer.h" #include "NetWindow.h" #include "Frame.h" #include "Core.h" +#include "ConfigManager.h" #include <sstream> #include <string> #define NETPLAY_TITLEBAR "Dolphin NetPlay" +#define INITIAL_PAD_BUFFER_SIZE 20 BEGIN_EVENT_TABLE(NetPlayDiag, wxFrame) EVT_COMMAND(wxID_ANY, wxEVT_THREAD, NetPlayDiag::OnThread) END_EVENT_TABLE() -static NetPlay* netplay_ptr = NULL; +static NetPlayServer* netplay_server = NULL; +static NetPlayClient* netplay_client = NULL; extern CFrame* main_frame; NetPlayDiag *NetPlayDiag::npd = NULL; @@ -200,6 +204,28 @@ NetPlaySetupDiag::~NetPlaySetupDiag() main_frame->g_NetPlaySetupDiag = NULL; } +void NetPlaySetupDiag::MakeNetPlayDiag(int port, const std::string &game, bool is_hosting) +{ + NetPlayDiag *&npd = NetPlayDiag::GetInstance(); + std::string ip; + npd = new NetPlayDiag(m_parent, m_game_list, game, is_hosting); + if (is_hosting) + ip = "127.0.0.1"; + else + ip = WxStrToStr(m_connect_ip_text->GetValue()); + + netplay_client = new NetPlayClient(ip, (u16)port, npd, WxStrToStr(m_nickname_text->GetValue())); + if (netplay_client->is_connected) + { + npd->Show(); + Destroy(); + } + else + { + npd->Destroy(); + } +} + void NetPlaySetupDiag::OnHost(wxCommandEvent&) { NetPlayDiag *&npd = NetPlayDiag::GetInstance(); @@ -217,25 +243,20 @@ void NetPlaySetupDiag::OnHost(wxCommandEvent&) std::string game(WxStrToStr(m_game_lbox->GetStringSelection())); - npd = new NetPlayDiag(m_parent, m_game_list, game, true); unsigned long port = 0; m_host_port_text->GetValue().ToULong(&port); - netplay_ptr = new NetPlayServer(u16(port), WxStrToStr(m_nickname_text->GetValue()), npd); - netplay_ptr->ChangeGame(game); - if (netplay_ptr->is_connected) + netplay_server = new NetPlayServer(u16(port)); + netplay_server->ChangeGame(game); + netplay_server->AdjustPadBufferSize(INITIAL_PAD_BUFFER_SIZE); + if (netplay_server->is_connected) { #ifdef USE_UPNP if(m_upnp_chk->GetValue()) - ((NetPlayServer*)netplay_ptr)->TryPortmapping(port); + netplay_server->TryPortmapping(port); #endif - npd->Show(); - Destroy(); - } - else - { - PanicAlertT("Failed to Listen!!"); - npd->Destroy(); } + + MakeNetPlayDiag(port, game, true); } void NetPlaySetupDiag::OnJoin(wxCommandEvent&) @@ -247,20 +268,9 @@ void NetPlaySetupDiag::OnJoin(wxCommandEvent&) return; } - npd = new NetPlayDiag(m_parent, m_game_list, ""); unsigned long port = 0; m_connect_port_text->GetValue().ToULong(&port); - netplay_ptr = new NetPlayClient(WxStrToStr(m_connect_ip_text->GetValue()) - , (u16)port, npd, WxStrToStr(m_nickname_text->GetValue())); - if (netplay_ptr->is_connected) - { - npd->Show(); - Destroy(); - } - else - { - npd->Destroy(); - } + MakeNetPlayDiag(port, "", false); } void NetPlaySetupDiag::OnQuit(wxCommandEvent&) @@ -272,6 +282,7 @@ NetPlayDiag::NetPlayDiag(wxWindow* const parent, const CGameListCtrl* const game const std::string& game, const bool is_hosting) : wxFrame(parent, wxID_ANY, wxT(NETPLAY_TITLEBAR), wxDefaultPosition, wxDefaultSize) , m_selected_game(game) + , m_start_btn(NULL) , m_game_list(game_list) { wxPanel* const panel = new wxPanel(this); @@ -330,22 +341,19 @@ NetPlayDiag::NetPlayDiag(wxWindow* const parent, const CGameListCtrl* const game wxBoxSizer* const bottom_szr = new wxBoxSizer(wxHORIZONTAL); if (is_hosting) { - wxButton* const start_btn = new wxButton(panel, wxID_ANY, _("Start")); - start_btn->Bind(wxEVT_COMMAND_BUTTON_CLICKED, &NetPlayDiag::OnStart, this); - bottom_szr->Add(start_btn); - wxButton* const stop_btn = new wxButton(panel, wxID_ANY, _("Stop")); - stop_btn->Bind(wxEVT_COMMAND_BUTTON_CLICKED, &NetPlayDiag::OnStop, this); - bottom_szr->Add(stop_btn); + m_start_btn = new wxButton(panel, wxID_ANY, _("Start")); + m_start_btn->Bind(wxEVT_COMMAND_BUTTON_CLICKED, &NetPlayDiag::OnStart, this); + bottom_szr->Add(m_start_btn); + bottom_szr->Add(new wxStaticText(panel, wxID_ANY, _("Buffer:")), 0, wxLEFT | wxCENTER, 5 ); wxSpinCtrl* const padbuf_spin = new wxSpinCtrl(panel, wxID_ANY, wxT("20") - , wxDefaultPosition, wxSize(64, -1), wxSP_ARROW_KEYS, 0, 200, 20); + , wxDefaultPosition, wxSize(64, -1), wxSP_ARROW_KEYS, 0, 200, INITIAL_PAD_BUFFER_SIZE); padbuf_spin->Bind(wxEVT_COMMAND_SPINCTRL_UPDATED, &NetPlayDiag::OnAdjustBuffer, this); bottom_szr->Add(padbuf_spin, 0, wxCENTER); - } - m_memcard_write = new wxCheckBox(panel, wxID_ANY, _("Write memcards (GC)")); - m_memcard_write->Bind(wxEVT_COMMAND_CHECKBOX_CLICKED, &NetPlayDiag::OnMemcardWriteCheck, this); - bottom_szr->Add(m_memcard_write, 0, wxCENTER); + m_memcard_write = new wxCheckBox(panel, wxID_ANY, _("Write memcards (GC)")); + bottom_szr->Add(m_memcard_write, 0, wxCENTER); + } bottom_szr->AddStretchSpacer(1); bottom_szr->Add(quit_btn); @@ -366,10 +374,15 @@ NetPlayDiag::NetPlayDiag(wxWindow* const parent, const CGameListCtrl* const game NetPlayDiag::~NetPlayDiag() { - if (netplay_ptr) + if (netplay_client) { - delete netplay_ptr; - netplay_ptr = NULL; + delete netplay_client; + netplay_client = NULL; + } + if (netplay_server) + { + delete netplay_server; + netplay_server = NULL; } npd = NULL; } @@ -380,37 +393,45 @@ void NetPlayDiag::OnChat(wxCommandEvent&) if (s.Length()) { - netplay_ptr->SendChatMessage(WxStrToStr(s)); + netplay_client->SendChatMessage(WxStrToStr(s)); m_chat_text->AppendText(s.Prepend(wxT(" >> ")).Append(wxT('\n'))); m_chat_msg_text->Clear(); } } -void NetPlayDiag::OnStart(wxCommandEvent&) +void NetPlayDiag::GetNetSettings(NetSettings &settings) +{ + SConfig &instance = SConfig::GetInstance(); + settings.m_DSPHLE = instance.m_LocalCoreStartupParameter.bDSPHLE; + settings.m_DSPEnableJIT = instance.m_EnableJIT; + settings.m_WriteToMemcard = m_memcard_write->GetValue(); + + for (unsigned int i = 0; i < 4; ++i) + settings.m_Controllers[i] = SConfig::GetInstance().m_SIDevice[i]; +} + +std::string NetPlayDiag::FindGame() { // find path for selected game, sloppy.. for (u32 i = 0 ; auto game = m_game_list->GetISO(i); ++i) - { if (m_selected_game == BuildGameName(*game)) - { - netplay_ptr->StartGame(game->GetFileName()); - return; - } - } + return game->GetFileName(); PanicAlertT("Game not found!"); + return ""; } -void NetPlayDiag::OnStop(wxCommandEvent&) +void NetPlayDiag::OnStart(wxCommandEvent&) { - netplay_ptr->StopGame(); + NetSettings settings; + GetNetSettings(settings); + netplay_server->SetNetSettings(settings); + netplay_server->StartGame(FindGame()); } void NetPlayDiag::BootGame(const std::string& filename) { main_frame->BootGame(filename); - - Core::g_CoreStartupParameter.bEnableMemcardSaving = m_memcard_write->GetValue(); } void NetPlayDiag::StopGame() @@ -444,27 +465,26 @@ void NetPlayDiag::OnMsgStartGame() { wxCommandEvent evt(wxEVT_THREAD, NP_GUI_EVT_START_GAME); GetEventHandler()->AddPendingEvent(evt); + if (m_start_btn) + m_start_btn->Disable(); } void NetPlayDiag::OnMsgStopGame() { wxCommandEvent evt(wxEVT_THREAD, NP_GUI_EVT_STOP_GAME); GetEventHandler()->AddPendingEvent(evt); -} - -void NetPlayDiag::OnMemcardWriteCheck(wxCommandEvent &event) -{ - netplay_ptr->SetMemcardWriteEnabled(m_memcard_write->GetValue()); + if (m_start_btn) + m_start_btn->Enable(); } void NetPlayDiag::OnAdjustBuffer(wxCommandEvent& event) { const int val = ((wxSpinCtrl*)event.GetEventObject())->GetValue(); - ((NetPlayServer*)netplay_ptr)->AdjustPadBufferSize(val); + netplay_server->AdjustPadBufferSize(val); std::ostringstream ss; ss << "< Pad Buffer: " << val << " >"; - netplay_ptr->SendChatMessage(ss.str()); + netplay_client->SendChatMessage(ss.str()); m_chat_text->AppendText(StrToWxStr(ss.str()).Append(wxT('\n'))); } @@ -479,7 +499,7 @@ void NetPlayDiag::OnThread(wxCommandEvent& event) // player list m_playerids.clear(); std::string tmps; - netplay_ptr->GetPlayerList(tmps, m_playerids); + netplay_client->GetPlayerList(tmps, m_playerids); const int selection = m_player_lbox->GetSelection(); @@ -502,15 +522,13 @@ void NetPlayDiag::OnThread(wxCommandEvent& event) case NP_GUI_EVT_START_GAME : // client start game :/ { - wxCommandEvent evt; - OnStart(evt); + netplay_client->StartGame(FindGame()); } break; case NP_GUI_EVT_STOP_GAME : // client stop game { - wxCommandEvent evt; - OnStop(evt); + netplay_client->StopGame(); } break; } @@ -534,7 +552,7 @@ void NetPlayDiag::OnChangeGame(wxCommandEvent&) if (game_name.length()) { m_selected_game = WxStrToStr(game_name); - netplay_ptr->ChangeGame(m_selected_game); + netplay_server->ChangeGame(m_selected_game); m_game_btn->SetLabel(game_name.Prepend(_(" Game : "))); } } @@ -549,13 +567,13 @@ void NetPlayDiag::OnConfigPads(wxCommandEvent&) return; pid = m_playerids.at(pid); - if (false == ((NetPlayServer*)netplay_ptr)->GetPadMapping(pid, mapping)) + if (false == netplay_server->GetPadMapping(pid, mapping)) return; PadMapDiag pmd(this, mapping); pmd.ShowModal(); - if (false == ((NetPlayServer*)netplay_ptr)->SetPadMapping(pid, mapping)) + if (false == netplay_server->SetPadMapping(pid, mapping)) PanicAlertT("Could not set pads. The player left or the game is currently running!\n" "(setting pads while the game is running is not yet supported)"); } @@ -641,3 +659,11 @@ void PadMapDiag::OnAdjust(wxCommandEvent& event) for (unsigned int i=0; i<4; ++i) m_mapping[i] = m_map_cbox[i]->GetSelection() - 1; } + +void NetPlay::StopGame() +{ + if (netplay_server != NULL) + netplay_server->StopGame(); + + // TODO: allow non-hosting clients to close the window +} diff --git a/Source/Core/DolphinWX/Src/NetWindow.h b/Source/Core/DolphinWX/Src/NetWindow.h index 76fbc03431..75f9964e9d 100644 --- a/Source/Core/DolphinWX/Src/NetWindow.h +++ b/Source/Core/DolphinWX/Src/NetWindow.h @@ -23,7 +23,7 @@ #include "FifoQueue.h" -#include "NetPlay.h" +#include "NetPlayClient.h" enum { @@ -42,6 +42,8 @@ private: void OnHost(wxCommandEvent& event); void OnQuit(wxCommandEvent& event); + void MakeNetPlayDiag(int port, const std::string &game, bool is_hosting); + wxTextCtrl *m_nickname_text, *m_host_port_text, *m_connect_port_text, @@ -65,7 +67,6 @@ public: Common::FifoQueue<std::string> chat_msgs; void OnStart(wxCommandEvent& event); - void OnStop(wxCommandEvent& event); // implementation of NetPlayUI methods void BootGame(const std::string& filename); @@ -85,11 +86,12 @@ private: void OnChat(wxCommandEvent& event); void OnQuit(wxCommandEvent& event); - void OnMemcardWriteCheck(wxCommandEvent& event); void OnThread(wxCommandEvent& event); void OnChangeGame(wxCommandEvent& event); void OnAdjustBuffer(wxCommandEvent& event); void OnConfigPads(wxCommandEvent& event); + void GetNetSettings(NetSettings &settings); + std::string FindGame(); wxListBox* m_player_lbox; wxTextCtrl* m_chat_text; @@ -98,6 +100,7 @@ private: std::string m_selected_game; wxButton* m_game_btn; + wxButton* m_start_btn; std::vector<int> m_playerids; @@ -130,5 +133,10 @@ private: int* const m_mapping; }; +namespace NetPlay +{ + void StopGame(); +} + #endif // _NETWINDOW_H_ diff --git a/Source/Core/DolphinWX/Src/VideoConfigDiag.cpp b/Source/Core/DolphinWX/Src/VideoConfigDiag.cpp index 5a7d11f96e..a606bf413e 100644 --- a/Source/Core/DolphinWX/Src/VideoConfigDiag.cpp +++ b/Source/Core/DolphinWX/Src/VideoConfigDiag.cpp @@ -86,7 +86,7 @@ wxString af_desc = wxTRANSLATE("Enable anisotropic filtering.\nEnhances visual q wxString aa_desc = wxTRANSLATE("Reduces the amount of aliasing caused by rasterizing 3D graphics.\nThis makes the rendered picture look less blocky.\nHeavily decreases emulation speed and sometimes causes issues.\n\nIf unsure, select None."); wxString scaled_efb_copy_desc = wxTRANSLATE("Greatly increases quality of textures generated using render to texture effects.\nRaising the internal resolution will improve the effect of this setting.\nSlightly decreases performance and possibly causes issues (although unlikely).\n\nIf unsure, leave this checked."); wxString pixel_lighting_desc = wxTRANSLATE("Calculate lighting of 3D graphics per-pixel rather than per vertex.\nDecreases emulation speed by some percent (depending on your GPU).\nThis usually is a safe enhancement, but might cause issues sometimes.\n\nIf unsure, leave this unchecked."); -wxString hacked_buffer_upload_desc = wxTRANSLATE("Use a hacked upload strategy to stream vertices.\nThis usually speed up, but is forbidden by OpenGL specification and may causes heavy glitches.\n\nIf unsure, leave this unchecked."); +wxString hacked_buffer_upload_desc = wxTRANSLATE("Speed up vertex streaming by using unsafe OpenGL code. Enabling this option might cause heavy glitches or even crash the emulator.\n\nIf unsure, leave this unchecked."); wxString fast_depth_calc_desc = wxTRANSLATE("Use a less accurate algorithm to calculate depth values.\nCauses issues in a few games but might give a decent speedup.\n\nIf unsure, leave this checked."); wxString force_filtering_desc = wxTRANSLATE("Force texture filtering even if the emulated game explicitly disabled it.\nImproves texture quality slightly but causes glitches in some games.\n\nIf unsure, leave this unchecked."); wxString _3d_vision_desc = wxTRANSLATE("Enable 3D effects via stereoscopy using Nvidia 3D Vision technology if it's supported by your GPU.\nPossibly causes issues.\nRequires fullscreen to work.\n\nIf unsure, leave this unchecked."); @@ -121,7 +121,6 @@ wxString crop_desc = wxTRANSLATE("Crop the picture from 4:3 to 5:4 or from 16:9 wxString opencl_desc = wxTRANSLATE("[EXPERIMENTAL]\nAims to speed up emulation by offloading texture decoding to the GPU using the OpenCL framework.\nHowever, right now it's known to cause texture defects in various games. Also it's slower than regular CPU texture decoding in most cases.\n\nIf unsure, leave this unchecked."); wxString dlc_desc = wxTRANSLATE("[EXPERIMENTAL]\nSpeeds up emulation a bit by caching display lists.\nPossibly causes issues though.\n\nIf unsure, leave this unchecked."); wxString omp_desc = wxTRANSLATE("Use multiple threads to decode textures.\nMight result in a speedup (especially on CPUs with more than two cores).\n\nIf unsure, leave this unchecked."); -wxString hotkeys_desc = wxTRANSLATE("Allows toggling certain options via the hotkeys 3 (Internal Resolution), 4 (Aspect Ratio), 5 (Copy EFB) and 6 (Fog) within the emulation window.\n\nIf unsure, leave this unchecked."); wxString ppshader_desc = wxTRANSLATE("Apply a post-processing effect after finishing a frame.\n\nIf unsure, select (off)."); wxString cache_efb_copies_desc = wxTRANSLATE("Slightly speeds up EFB to RAM copies by sacrificing emulation accuracy.\nSometimes also increases visual quality.\nIf you're experiencing any issues, try raising texture cache accuracy or disable this option.\n\nIf unsure, leave this unchecked."); wxString shader_errors_desc = wxTRANSLATE("Usually if shader compilation fails, an error message is displayed.\nHowever, one may skip the popups to allow interruption free gameplay by checking this option.\n\nIf unsure, leave this unchecked."); @@ -503,7 +502,7 @@ VideoConfigDiag::VideoConfigDiag(wxWindow* parent, const std::string &title, con szr_other->Add(CreateCheckBox(page_hacks, _("OpenCL Texture Decoder"), wxGetTranslation(opencl_desc), vconfig.bEnableOpenCL)); szr_other->Add(CreateCheckBox(page_hacks, _("OpenMP Texture Decoder"), wxGetTranslation(omp_desc), vconfig.bOMPDecoder)); szr_other->Add(CreateCheckBox(page_hacks, _("Fast Depth Calculation"), wxGetTranslation(fast_depth_calc_desc), vconfig.bFastDepthCalc)); - szr_other->Add(hacked_buffer_upload = CreateCheckBox(page_hacks, _("Hacked Buffer Upload"), wxGetTranslation(hacked_buffer_upload_desc), vconfig.bHackedBufferUpload)); + szr_other->Add(hacked_buffer_upload = CreateCheckBox(page_hacks, _("Vertex Streaming Hack"), wxGetTranslation(hacked_buffer_upload_desc), vconfig.bHackedBufferUpload)); wxStaticBoxSizer* const group_other = new wxStaticBoxSizer(wxVERTICAL, page_hacks, _("Other")); group_other->Add(szr_other, 1, wxEXPAND | wxLEFT | wxRIGHT | wxBOTTOM, 5); @@ -559,7 +558,6 @@ VideoConfigDiag::VideoConfigDiag(wxWindow* parent, const std::string &title, con szr_misc->Add(CreateCheckBox(page_advanced, _("Show Input Display"), wxGetTranslation(show_input_display_desc), vconfig.bShowInputDisplay)); szr_misc->Add(CreateCheckBox(page_advanced, _("Crop"), wxGetTranslation(crop_desc), vconfig.bCrop)); - szr_misc->Add(CreateCheckBox(page_advanced, _("Enable Hotkeys"), wxGetTranslation(hotkeys_desc), vconfig.bOSDHotKey)); // Progressive Scan { diff --git a/Source/Core/InputCommon/Src/ControllerInterface/SDL/SDL.cpp b/Source/Core/InputCommon/Src/ControllerInterface/SDL/SDL.cpp index 006b82d4ac..40c822c577 100644 --- a/Source/Core/InputCommon/Src/ControllerInterface/SDL/SDL.cpp +++ b/Source/Core/InputCommon/Src/ControllerInterface/SDL/SDL.cpp @@ -131,12 +131,14 @@ Joystick::Joystick(SDL_Joystick* const joystick, const int sdl_index, const unsi AddOutput(new SineEffect(m_state_out.back())); } +#ifdef SDL_HAPTIC_SQUARE // square effect if (supported_effects & SDL_HAPTIC_SQUARE) { m_state_out.push_back(EffectIDState()); AddOutput(new SquareEffect(m_state_out.back())); } +#endif // defined(SDL_HAPTIC_SQUARE) // triangle effect if (supported_effects & SDL_HAPTIC_TRIANGLE) @@ -187,10 +189,12 @@ std::string Joystick::SineEffect::GetName() const return "Sine"; } +#ifdef SDL_HAPTIC_SQUARE std::string Joystick::SquareEffect::GetName() const { return "Square"; } +#endif // defined(SDL_HAPTIC_SQUARE) std::string Joystick::TriangleEffect::GetName() const { @@ -255,6 +259,7 @@ void Joystick::SineEffect::SetState(const ControlState state) m_effect.changed = true; } +#ifdef SDL_HAPTIC_SQUARE void Joystick::SquareEffect::SetState(const ControlState state) { if (state) @@ -276,6 +281,7 @@ void Joystick::SquareEffect::SetState(const ControlState state) if (old != m_effect.effect.periodic.magnitude) m_effect.changed = true; } +#endif // defined(SDL_HAPTIC_SQUARE) void Joystick::TriangleEffect::SetState(const ControlState state) { diff --git a/Source/Core/InputCommon/Src/ControllerInterface/SDL/SDL.h b/Source/Core/InputCommon/Src/ControllerInterface/SDL/SDL.h index 6a65efeedb..9b9794c481 100644 --- a/Source/Core/InputCommon/Src/ControllerInterface/SDL/SDL.h +++ b/Source/Core/InputCommon/Src/ControllerInterface/SDL/SDL.h @@ -106,6 +106,7 @@ private: EffectIDState& m_effect; }; +#ifdef SDL_HAPTIC_SQUARE class SquareEffect : public Output { public: @@ -115,6 +116,7 @@ private: private: EffectIDState& m_effect; }; +#endif // defined(SDL_HAPTIC_SQUARE) class TriangleEffect : public Output { diff --git a/Source/Core/VideoCommon/CMakeLists.txt b/Source/Core/VideoCommon/CMakeLists.txt index a4dad8293b..8503377779 100644 --- a/Source/Core/VideoCommon/CMakeLists.txt +++ b/Source/Core/VideoCommon/CMakeLists.txt @@ -33,6 +33,7 @@ set(SRCS Src/BPFunctions.cpp Src/VertexManagerBase.cpp Src/VertexShaderGen.cpp Src/VertexShaderManager.cpp + Src/VideoBackendBase.cpp Src/VideoConfig.cpp Src/VideoState.cpp Src/XFMemory.cpp diff --git a/Source/Core/VideoCommon/Src/BPMemory.cpp b/Source/Core/VideoCommon/Src/BPMemory.cpp index 77f2f6bab3..7272ed0993 100644 --- a/Source/Core/VideoCommon/Src/BPMemory.cpp +++ b/Source/Core/VideoCommon/Src/BPMemory.cpp @@ -299,38 +299,3 @@ void GetBPRegInfo(const u8* data, char* name, size_t name_size, char* desc, size #undef SetRegName } } - -AlphaTest::TEST_RESULT AlphaTest::TestResult() -{ - switch(logic) - { - case 0: // AND - if (comp0 == ALPHACMP_ALWAYS && comp1 == ALPHACMP_ALWAYS) - return PASS; - if (comp0 == ALPHACMP_NEVER || comp1 == ALPHACMP_NEVER) - return FAIL; - break; - - case 1: // OR - if (comp0 == ALPHACMP_ALWAYS || comp1 == ALPHACMP_ALWAYS) - return PASS; - if (comp0 == ALPHACMP_NEVER && comp1 == ALPHACMP_NEVER) - return FAIL; - break; - - case 2: // XOR - if ((comp0 == ALPHACMP_ALWAYS && comp1 == ALPHACMP_NEVER) || (comp0 == ALPHACMP_NEVER && comp1 == ALPHACMP_ALWAYS)) - return PASS; - if ((comp0 == ALPHACMP_ALWAYS && comp1 == ALPHACMP_ALWAYS) || (comp0 == ALPHACMP_NEVER && comp1 == ALPHACMP_NEVER)) - return FAIL; - break; - - case 3: // XNOR - if ((comp0 == ALPHACMP_ALWAYS && comp1 == ALPHACMP_NEVER) || (comp0 == ALPHACMP_NEVER && comp1 == ALPHACMP_ALWAYS)) - return FAIL; - if ((comp0 == ALPHACMP_ALWAYS && comp1 == ALPHACMP_ALWAYS) || (comp0 == ALPHACMP_NEVER && comp1 == ALPHACMP_NEVER)) - return PASS; - break; - } - return UNDETERMINED; -} diff --git a/Source/Core/VideoCommon/Src/BPMemory.h b/Source/Core/VideoCommon/Src/BPMemory.h index 90fffc6c6c..83dbefed50 100644 --- a/Source/Core/VideoCommon/Src/BPMemory.h +++ b/Source/Core/VideoCommon/Src/BPMemory.h @@ -805,6 +805,7 @@ union PE_CONTROL u32 unused : 17; u32 rid : 8; }; + u32 hex; }; @@ -884,7 +885,40 @@ union AlphaTest PASS = 2, }; - TEST_RESULT TestResult(); + inline TEST_RESULT TestResult() const + { + switch(logic) + { + case 0: // AND + if (comp0 == ALPHACMP_ALWAYS && comp1 == ALPHACMP_ALWAYS) + return PASS; + if (comp0 == ALPHACMP_NEVER || comp1 == ALPHACMP_NEVER) + return FAIL; + break; + + case 1: // OR + if (comp0 == ALPHACMP_ALWAYS || comp1 == ALPHACMP_ALWAYS) + return PASS; + if (comp0 == ALPHACMP_NEVER && comp1 == ALPHACMP_NEVER) + return FAIL; + break; + + case 2: // XOR + if ((comp0 == ALPHACMP_ALWAYS && comp1 == ALPHACMP_NEVER) || (comp0 == ALPHACMP_NEVER && comp1 == ALPHACMP_ALWAYS)) + return PASS; + if ((comp0 == ALPHACMP_ALWAYS && comp1 == ALPHACMP_ALWAYS) || (comp0 == ALPHACMP_NEVER && comp1 == ALPHACMP_NEVER)) + return FAIL; + break; + + case 3: // XNOR + if ((comp0 == ALPHACMP_ALWAYS && comp1 == ALPHACMP_NEVER) || (comp0 == ALPHACMP_NEVER && comp1 == ALPHACMP_ALWAYS)) + return FAIL; + if ((comp0 == ALPHACMP_ALWAYS && comp1 == ALPHACMP_ALWAYS) || (comp0 == ALPHACMP_NEVER && comp1 == ALPHACMP_NEVER)) + return PASS; + break; + } + return UNDETERMINED; + } }; union UPE_Copy @@ -1005,6 +1039,9 @@ struct BPMemory TevKSel tevksel[8];//0xf6,0xf7,f8,f9,fa,fb,fc,fd u32 bpMask; //0xFE u32 unknown18; //ff + + bool UseEarlyDepthTest() const { return zcontrol.early_ztest && zmode.testenable; } + bool UseLateDepthTest() const { return !zcontrol.early_ztest && zmode.testenable; } }; #pragma pack() diff --git a/Source/Core/VideoCommon/Src/BPStructs.cpp b/Source/Core/VideoCommon/Src/BPStructs.cpp index ce0346b523..00cecf0082 100644 --- a/Source/Core/VideoCommon/Src/BPStructs.cpp +++ b/Source/Core/VideoCommon/Src/BPStructs.cpp @@ -153,7 +153,10 @@ void BPWritten(const BPCmd& bp) bpmem.genMode.numtexgens, bpmem.genMode.numcolchans, bpmem.genMode.multisampling, bpmem.genMode.numtevstages+1, bpmem.genMode.cullmode, bpmem.genMode.numindstages, bpmem.genMode.zfreeze); - SetGenerationMode(); + + // Only call SetGenerationMode when cull mode changes. + if (bp.changes & 0xC000) + SetGenerationMode(); break; } case BPMEM_IND_MTXA: // Index Matrix Changed diff --git a/Source/Core/VideoCommon/Src/DriverDetails.cpp b/Source/Core/VideoCommon/Src/DriverDetails.cpp index 153a07226f..85b7d3a47f 100644 --- a/Source/Core/VideoCommon/Src/DriverDetails.cpp +++ b/Source/Core/VideoCommon/Src/DriverDetails.cpp @@ -20,6 +20,7 @@ namespace DriverDetails // Local members Vendor m_vendor = VENDOR_UNKNOWN; + Driver m_driver = DRIVER_UNKNOWN; u32 m_devfamily = 0; double m_version = 0.0; @@ -29,10 +30,6 @@ namespace DriverDetails {BUG_NODYNUBOACCESS, 300, 14.0, -1.0}, {BUG_BROKENCENTROID, 300, 14.0, -1.0}, {BUG_BROKENINFOLOG, 300, -1.0, -1.0}, - {BUG_BROKENBUFFERS, 300, 14.0, -1.0}, - }; - BugInfo m_armbugs[] = { - {BUG_MALIBROKENBUFFERS, 600, -1.0, -1.0}, }; std::map<std::pair<Vendor, Bug>, BugInfo> m_bugs; @@ -40,26 +37,52 @@ namespace DriverDetails // Private function void InitBugMap() { - switch(m_vendor) + switch(m_driver) { - case VENDOR_QUALCOMM: + case DRIVER_QUALCOMM: for (unsigned int a = 0; a < (sizeof(m_qualcommbugs) / sizeof(BugInfo)); ++a) m_bugs[std::make_pair(m_vendor, m_qualcommbugs[a].m_bug)] = m_qualcommbugs[a]; break; - case VENDOR_ARM: - for (unsigned int a = 0; a < (sizeof(m_armbugs) / sizeof(BugInfo)); ++a) - m_bugs[std::make_pair(m_vendor, m_armbugs[a].m_bug)] = m_armbugs[a]; default: break; } } - void Init(Vendor vendor, const u32 devfamily, const double version) + void Init(Vendor vendor, Driver driver, const u32 devfamily, const double version) { m_vendor = vendor; + m_driver = driver; m_devfamily = devfamily; m_version = version; - InitBugMap(); + InitBugMap(); + if (driver == DRIVER_UNKNOWN) + switch(vendor) + { + case VENDOR_NVIDIA: + case VENDOR_TEGRA: + m_driver = DRIVER_NVIDIA; + break; + case VENDOR_ATI: + m_driver = DRIVER_ATI; + break; + case VENDOR_INTEL: + m_driver = DRIVER_INTEL; + break; + case VENDOR_ARM: + m_driver = DRIVER_ARM; + break; + case VENDOR_QUALCOMM: + m_driver = DRIVER_QUALCOMM; + break; + case VENDOR_IMGTEC: + m_driver = DRIVER_IMGTEC; + break; + case VENDOR_VIVANTE: + m_driver = DRIVER_VIVANTE; + break; + default: + break; + } for (auto it = m_bugs.begin(); it != m_bugs.end(); ++it) if (it->second.m_devfamily == m_devfamily) diff --git a/Source/Core/VideoCommon/Src/DriverDetails.h b/Source/Core/VideoCommon/Src/DriverDetails.h index bf67abe9eb..cb8b104eea 100644 --- a/Source/Core/VideoCommon/Src/DriverDetails.h +++ b/Source/Core/VideoCommon/Src/DriverDetails.h @@ -21,6 +21,23 @@ namespace DriverDetails VENDOR_UNKNOWN }; + // Enum of known drivers + enum Driver + { + DRIVER_NVIDIA = 0, // Official Nvidia, including mobile GPU + DRIVER_NOUVEAU, // OSS nouveau + DRIVER_ATI, // Official ATI + DRIVER_RADEONHD, // OSS Radeon + DRIVER_INTEL, // Official Intel + DRIVER_ARM, // Official Mali driver + DRIVER_LIMA, // OSS Mali driver + DRIVER_QUALCOMM, // Official Adreno driver + DRIVER_FREEDRENO, // OSS Adreno driver + DRIVER_IMGTEC, // OSS PowerVR driver + DRIVER_VIVANTE, // Official vivante driver + DRIVER_UNKNOWN // Unknown driver, default to official hardware driver + }; + // Enum of known bugs // These can be vendor specific, but we put them all in here // For putting a new bug in here, make sure to put a detailed comment above the enum @@ -52,30 +69,10 @@ namespace DriverDetails // Adreno devices /always/ return 0 when querying GL_INFO_LOG_LENGTH // They also max out at 1024 bytes(1023 characters + null terminator) for the log BUG_BROKENINFOLOG, - // Bug: Uploading data with rendering causes issues - // Affected devices: Qualcomm/Adreno - // Started Version: 14 - // Ended Version: -1 - // When drawing our elements, the instruction buffer on Adreno devices - // becomes too long, causing the device to quickly run out of RAM - // I've watched the kernel module go up to ~700MB of RAM in a few seconds - // The "workaround" is calling swapbuffers every single time we flush - // This causes flickering, but it is the only known way to work around it - BUG_BROKENBUFFERS, - // Bug: Uploading data without swapping causes issues - // Affected devices: Mali-T6xx - // Started Version: -1 - // Ended Version: -1 - // This is similar to the Adreno rendering bug where uploading the data - // to the GPU causes the device to quickly run out of RAM. - // Unlike the Adreno workaround though, this can be fixed by calling - // either glFlush() or glFinish() after flushing. - // glFlush tends to take 0-1Ms on each call - BUG_MALIBROKENBUFFERS, }; // Initializes our internal vendor, device family, and driver version - void Init(Vendor vendor, const u32 devfamily, const double version); + void Init(Vendor vendor, Driver driver, const u32 devfamily, const double version); // Once Vendor and driver version is set, this will return if it has the applicable bug passed to it. bool HasBug(Bug bug); diff --git a/Source/Core/VideoCommon/Src/Fifo.cpp b/Source/Core/VideoCommon/Src/Fifo.cpp index 5114e3fc2b..a00e531fa4 100644 --- a/Source/Core/VideoCommon/Src/Fifo.cpp +++ b/Source/Core/VideoCommon/Src/Fifo.cpp @@ -151,9 +151,6 @@ void RunGpuLoop() // check if we are able to run this buffer while (GpuRunningState && !CommandProcessor::interruptWaiting && fifo.bFF_GPReadEnable && fifo.CPReadWriteDistance && !AtBreakpoint()) { - if (!GpuRunningState) - break; - fifo.isGpuReadingData = true; CommandProcessor::isPossibleWaitingSetDrawDone = fifo.bFF_GPLinkEnable ? true : false; diff --git a/Source/Core/VideoCommon/Src/LightingShaderGen.h b/Source/Core/VideoCommon/Src/LightingShaderGen.h index 031dce44bd..fc107a2e2b 100644 --- a/Source/Core/VideoCommon/Src/LightingShaderGen.h +++ b/Source/Core/VideoCommon/Src/LightingShaderGen.h @@ -9,40 +9,22 @@ #include "NativeVertexFormat.h" #include "XFMemory.h" -static const char* LightCol(const char* lightsName, unsigned int index, const char* swizzle) -{ - static char result[32]; - snprintf(result, sizeof(result), "%s[5*%d].%s", lightsName, index, swizzle); - return result; -} -static const char* LightCosAtt(const char* lightsName, unsigned int index) -{ - static char result[32]; - snprintf(result, sizeof(result), "%s[5*%d+1]", lightsName, index); - return result; -} +#define LIGHT_COL "%s[5*%d].%s" +#define LIGHT_COL_PARAMS(lightsName, index, swizzle) (lightsName), (index), (swizzle) -static const char* LightDistAtt(const char* lightsName, unsigned int index) -{ - static char result[32]; - snprintf(result, sizeof(result), "%s[5*%d+2]", lightsName, index); - return result; -} +#define LIGHT_COSATT "%s[5*%d+1]" +#define LIGHT_COSATT_PARAMS(lightsName, index) (lightsName), (index) -static const char* LightPos(const char* lightsName, unsigned int index) -{ - static char result[32]; - snprintf(result, sizeof(result), "%s[5*%d+3]", lightsName, index); - return result; -} +#define LIGHT_DISTATT "%s[5*%d+2]" +#define LIGHT_DISTATT_PARAMS(lightsName, index) (lightsName), (index) + +#define LIGHT_POS "%s[5*%d+3]" +#define LIGHT_POS_PARAMS(lightsName, index) (lightsName), (index) + +#define LIGHT_DIR "%s[5*%d+4]" +#define LIGHT_DIR_PARAMS(lightsName, index) (lightsName), (index) -static const char* LightDir(const char* lightsName, unsigned int index) -{ - static char result[32]; - snprintf(result, sizeof(result), "%s[5*%d+4]", lightsName, index); - return result; -} template<class T> static void GenerateLightShader(T& object, LightingUidData& uid_data, int index, int litchan_index, const char* lightsName, int coloralpha) @@ -62,13 +44,13 @@ static void GenerateLightShader(T& object, LightingUidData& uid_data, int index, switch (chan.diffusefunc) { case LIGHTDIF_NONE: - object.Write("lacc.%s += %s;\n", swizzle, LightCol(lightsName, index, swizzle)); + object.Write("lacc.%s += " LIGHT_COL";\n", swizzle, LIGHT_COL_PARAMS(lightsName, index, swizzle)); break; case LIGHTDIF_SIGN: case LIGHTDIF_CLAMP: - object.Write("ldir = normalize(%s.xyz - pos.xyz);\n", LightPos(lightsName, index)); - object.Write("lacc.%s += %sdot(ldir, _norm0)) * %s;\n", - swizzle, chan.diffusefunc != LIGHTDIF_SIGN ? "max(0.0f," :"(", LightCol(lightsName, index, swizzle)); + object.Write("ldir = normalize(" LIGHT_POS".xyz - pos.xyz);\n", LIGHT_POS_PARAMS(lightsName, index)); + object.Write("lacc.%s += %sdot(ldir, _norm0)) * " LIGHT_COL";\n", + swizzle, chan.diffusefunc != LIGHTDIF_SIGN ? "max(0.0f," :"(", LIGHT_COL_PARAMS(lightsName, index, swizzle)); break; default: _assert_(0); } @@ -77,31 +59,34 @@ static void GenerateLightShader(T& object, LightingUidData& uid_data, int index, { if (chan.attnfunc == 3) { // spot - object.Write("ldir = %s.xyz - pos.xyz;\n", LightPos(lightsName, index)); + object.Write("ldir = " LIGHT_POS".xyz - pos.xyz;\n", LIGHT_POS_PARAMS(lightsName, index)); object.Write("dist2 = dot(ldir, ldir);\n" "dist = sqrt(dist2);\n" "ldir = ldir / dist;\n" - "attn = max(0.0f, dot(ldir, %s.xyz));\n", LightDir(lightsName, index)); - object.Write("attn = max(0.0f, dot(%s.xyz, float3(1.0f, attn, attn*attn))) / dot(%s.xyz, float3(1.0f,dist,dist2));\n", LightCosAtt(lightsName, index), LightDistAtt(lightsName, index)); + "attn = max(0.0f, dot(ldir, " LIGHT_DIR".xyz));\n", + LIGHT_DIR_PARAMS(lightsName, index)); + object.Write("attn = max(0.0f, dot(" LIGHT_COSATT".xyz, float3(1.0f, attn, attn*attn))) / dot(" LIGHT_DISTATT".xyz, float3(1.0f,dist,dist2));\n", + LIGHT_COSATT_PARAMS(lightsName, index), LIGHT_DISTATT_PARAMS(lightsName, index)); } else if (chan.attnfunc == 1) { // specular - object.Write("ldir = normalize(%s.xyz);\n", LightPos(lightsName, index)); - object.Write("attn = (dot(_norm0,ldir) >= 0.0f) ? max(0.0f, dot(_norm0, %s.xyz)) : 0.0f;\n", LightDir(lightsName, index)); - object.Write("attn = max(0.0f, dot(%s.xyz, float3(1,attn,attn*attn))) / dot(%s.xyz, float3(1,attn,attn*attn));\n", LightCosAtt(lightsName, index), LightDistAtt(lightsName, index)); + object.Write("ldir = normalize(" LIGHT_POS".xyz);\n", LIGHT_POS_PARAMS(lightsName, index)); + object.Write("attn = (dot(_norm0,ldir) >= 0.0f) ? max(0.0f, dot(_norm0, " LIGHT_DIR".xyz)) : 0.0f;\n", LIGHT_DIR_PARAMS(lightsName, index)); + object.Write("attn = max(0.0f, dot(" LIGHT_COSATT".xyz, float3(1,attn,attn*attn))) / dot(" LIGHT_DISTATT".xyz, float3(1,attn,attn*attn));\n", + LIGHT_COSATT_PARAMS(lightsName, index), LIGHT_DISTATT_PARAMS(lightsName, index)); } switch (chan.diffusefunc) { case LIGHTDIF_NONE: - object.Write("lacc.%s += attn * %s;\n", swizzle, LightCol(lightsName, index, swizzle)); + object.Write("lacc.%s += attn * " LIGHT_COL";\n", swizzle, LIGHT_COL_PARAMS(lightsName, index, swizzle)); break; case LIGHTDIF_SIGN: case LIGHTDIF_CLAMP: - object.Write("lacc.%s += attn * %sdot(ldir, _norm0)) * %s;\n", + object.Write("lacc.%s += attn * %sdot(ldir, _norm0)) * " LIGHT_COL";\n", swizzle, chan.diffusefunc != LIGHTDIF_SIGN ? "max(0.0f," :"(", - LightCol(lightsName, index, swizzle)); + LIGHT_COL_PARAMS(lightsName, index, swizzle)); break; default: _assert_(0); } @@ -150,7 +135,10 @@ static void GenerateLightingShader(T& object, LightingUidData& uid_data, int com else if (components & VB_HAS_COL0 ) object.Write("lacc = %s0;\n", inColorName); else - object.Write("lacc = float4(0.0f, 0.0f, 0.0f, 0.0f);\n"); + // TODO: this isn't verified. Here we want to read the ambient from the vertex, + // but the vertex itself has no color. So we don't know which value to read. + // Returing 1.0 is the same as disabled lightning, so this could be fine + object.Write("lacc = float4(1.0f, 1.0f, 1.0f, 1.0f);\n"); } else // from color { @@ -191,7 +179,8 @@ static void GenerateLightingShader(T& object, LightingUidData& uid_data, int com else if (components & VB_HAS_COL0 ) object.Write("lacc.w = %s0.w;\n", inColorName); else - object.Write("lacc.w = 0.0f;\n"); + // TODO: The same for alpha: We want to read from vertex, but the vertex has no color + object.Write("lacc.w = 1.0f;\n"); } else // from color { diff --git a/Source/Core/VideoCommon/Src/PerfQueryBase.cpp b/Source/Core/VideoCommon/Src/PerfQueryBase.cpp index c537d176f6..af8bfa72e5 100644 --- a/Source/Core/VideoCommon/Src/PerfQueryBase.cpp +++ b/Source/Core/VideoCommon/Src/PerfQueryBase.cpp @@ -1,3 +1,9 @@ #include "PerfQueryBase.h" +#include "VideoConfig.h" PerfQueryBase* g_perf_query = 0; + +bool PerfQueryBase::ShouldEmulate() const +{ + return g_ActiveConfig.bPerfQueriesEnable; +} diff --git a/Source/Core/VideoCommon/Src/PerfQueryBase.h b/Source/Core/VideoCommon/Src/PerfQueryBase.h index b979449edb..bf5474b4db 100644 --- a/Source/Core/VideoCommon/Src/PerfQueryBase.h +++ b/Source/Core/VideoCommon/Src/PerfQueryBase.h @@ -25,9 +25,12 @@ enum PerfQueryGroup class PerfQueryBase { public: - PerfQueryBase() {}; + PerfQueryBase() {} virtual ~PerfQueryBase() {} + // Checks if performance queries are enabled in the gameini configuration. + bool ShouldEmulate() const; + // Begin querying the specified value for the following host GPU commands virtual void EnableQuery(PerfQueryGroup type) {} diff --git a/Source/Core/VideoCommon/Src/PixelShaderGen.cpp b/Source/Core/VideoCommon/Src/PixelShaderGen.cpp index 9e831541bd..b4ad513d37 100644 --- a/Source/Core/VideoCommon/Src/PixelShaderGen.cpp +++ b/Source/Core/VideoCommon/Src/PixelShaderGen.cpp @@ -216,7 +216,7 @@ static char swapModeTable[4][5]; static char text[16384]; -static void BuildSwapModeTable() +static inline void BuildSwapModeTable() { static const char *swapColors = "rgba"; for (int i = 0; i < 4; i++) @@ -229,13 +229,13 @@ static void BuildSwapModeTable() } } -template<class T> static void WriteStage(T& out, pixel_shader_uid_data& uid_data, int n, API_TYPE ApiType, RegisterState RegisterStates[4]); -template<class T> static void SampleTexture(T& out, const char *destination, const char *texcoords, const char *texswap, int texmap, API_TYPE ApiType); -template<class T> static void WriteAlphaTest(T& out, pixel_shader_uid_data& uid_data, API_TYPE ApiType,DSTALPHA_MODE dstAlphaMode, bool per_pixel_depth); -template<class T> static void WriteFog(T& out, pixel_shader_uid_data& uid_data); +template<class T> static inline void WriteStage(T& out, pixel_shader_uid_data& uid_data, int n, API_TYPE ApiType, RegisterState RegisterStates[4]); +template<class T> static inline void SampleTexture(T& out, const char *texcoords, const char *texswap, int texmap, API_TYPE ApiType); +template<class T> static inline void WriteAlphaTest(T& out, pixel_shader_uid_data& uid_data, API_TYPE ApiType,DSTALPHA_MODE dstAlphaMode, bool per_pixel_depth); +template<class T> static inline void WriteFog(T& out, pixel_shader_uid_data& uid_data); template<class T> -static void GeneratePixelShader(T& out, DSTALPHA_MODE dstAlphaMode, API_TYPE ApiType, u32 components) +static inline void GeneratePixelShader(T& out, DSTALPHA_MODE dstAlphaMode, API_TYPE ApiType, u32 components) { // Non-uid template parameters will write to the dummy data (=> gets optimized out) pixel_shader_uid_data dummy_data; @@ -243,23 +243,25 @@ static void GeneratePixelShader(T& out, DSTALPHA_MODE dstAlphaMode, API_TYPE Api ? out.template GetUidData<pixel_shader_uid_data>() : dummy_data; out.SetBuffer(text); + const bool is_writing_shadercode = (out.GetBuffer() != NULL); #ifndef ANDROID locale_t locale; locale_t old_locale; - if (out.GetBuffer() != NULL) + if (is_writing_shadercode) { locale = newlocale(LC_NUMERIC_MASK, "C", NULL); // New locale for compilation old_locale = uselocale(locale); // Apply the locale for this thread } #endif - text[sizeof(text) - 1] = 0x7C; // canary + if (is_writing_shadercode) + text[sizeof(text) - 1] = 0x7C; // canary unsigned int numStages = bpmem.genMode.numtevstages + 1; unsigned int numTexgen = bpmem.genMode.numtexgens; - const bool forced_early_z = g_ActiveConfig.backend_info.bSupportsEarlyZ && bpmem.zcontrol.early_ztest && (g_ActiveConfig.bFastDepthCalc || bpmem.alpha_test.TestResult() == AlphaTest::UNDETERMINED); - const bool per_pixel_depth = (bpmem.ztex2.op != ZTEXTURE_DISABLE && !bpmem.zcontrol.early_ztest && bpmem.zmode.testenable) || (!g_ActiveConfig.bFastDepthCalc && !forced_early_z); + const bool forced_early_z = g_ActiveConfig.backend_info.bSupportsEarlyZ && bpmem.UseEarlyDepthTest() && (g_ActiveConfig.bFastDepthCalc || bpmem.alpha_test.TestResult() == AlphaTest::UNDETERMINED); + const bool per_pixel_depth = (bpmem.ztex2.op != ZTEXTURE_DISABLE && bpmem.UseLateDepthTest()) || (!g_ActiveConfig.bFastDepthCalc && bpmem.zmode.testenable && !forced_early_z); out.Write("//Pixel Shader for TEV stages\n"); out.Write("//%i TEV stages, %i texgens, %i IND stages\n", @@ -331,7 +333,7 @@ static void GeneratePixelShader(T& out, DSTALPHA_MODE dstAlphaMode, API_TYPE Api out.Write("VARYIN float4 colors_02;\n"); out.Write("VARYIN float4 colors_12;\n"); - + // compute window position if needed because binding semantic WPOS is not widely supported // Let's set up attributes if (xfregs.numTexGen.numTexGens < 7) @@ -365,18 +367,37 @@ static void GeneratePixelShader(T& out, DSTALPHA_MODE dstAlphaMode, API_TYPE Api } out.Write("float4 clipPos;\n"); } - + if (forced_early_z) { // HACK: This doesn't force the driver to write to depth buffer if alpha test fails. // It just allows it, but it seems that all drivers do. out.Write("layout(early_fragment_tests) in;\n"); } - + else if (bpmem.UseEarlyDepthTest() && (g_ActiveConfig.bFastDepthCalc || bpmem.alpha_test.TestResult() == AlphaTest::UNDETERMINED) && is_writing_shadercode) + { + static bool warn_once = true; + if (warn_once) + WARN_LOG(VIDEO, "Early z test enabled but not possible to emulate with current configuration. Make sure to use the D3D11 or OpenGL backend and enable fast depth calculations. If this message still shows up your hardware isn't able to emulate the feature properly (a GPU which supports D3D 11.0 / OGL 4.2 is required)."); + warn_once = false; + } + out.Write("void main()\n{\n"); } else { + if (forced_early_z) + { + out.Write("[earlydepthstencil]\n"); + } + else if (bpmem.UseEarlyDepthTest() && (g_ActiveConfig.bFastDepthCalc || bpmem.alpha_test.TestResult() == AlphaTest::UNDETERMINED) && is_writing_shadercode) + { + static bool warn_once = true; + if (warn_once) + WARN_LOG(VIDEO, "Early z test enabled but not possible to emulate with current configuration. Make sure to use the D3D11 or OpenGL backend and enable fast depth calculations. If this message still shows up your hardware isn't able to emulate the feature properly (a GPU which supports D3D 11.0 / OGL 4.2 is required)."); + warn_once = false; + } + out.Write("void main(\n"); if(ApiType != API_D3D11) { @@ -481,7 +502,6 @@ static void GeneratePixelShader(T& out, DSTALPHA_MODE dstAlphaMode, API_TYPE Api if (g_ActiveConfig.bEnablePixelLighting && g_ActiveConfig.backend_info.bSupportsPixelLighting) { - uid_data.xfregs_numTexGen_numTexGens = xfregs.numTexGen.numTexGens; if (xfregs.numTexGen.numTexGens < 7) { out.Write("\tfloat3 _norm0 = normalize(Normal.xyz);\n\n"); @@ -558,9 +578,8 @@ static void GeneratePixelShader(T& out, DSTALPHA_MODE dstAlphaMode, API_TYPE Api else out.Write("\ttempcoord = float2(0.0f, 0.0f);\n"); - char buffer[32]; - sprintf(buffer, "float3 indtex%d", i); - SampleTexture<T>(out, buffer, "tempcoord", "abg", texmap, ApiType); + out.Write("float3 indtex%d = ", i); + SampleTexture<T>(out, "tempcoord", "abg", texmap, ApiType); } } @@ -608,7 +627,10 @@ static void GeneratePixelShader(T& out, DSTALPHA_MODE dstAlphaMode, API_TYPE Api AlphaTest::TEST_RESULT Pretest = bpmem.alpha_test.TestResult(); uid_data.Pretest = Pretest; - if (Pretest == AlphaTest::UNDETERMINED) + + // NOTE: Fragment may not be discarded if alpha test always fails and early depth test is enabled + // (in this case we need to write a depth value if depth test passes regardless of the alpha testing result) + if (Pretest == AlphaTest::UNDETERMINED || (Pretest == AlphaTest::FAIL && bpmem.UseLateDepthTest())) WriteAlphaTest<T>(out, uid_data, ApiType, dstAlphaMode, per_pixel_depth); @@ -631,11 +653,11 @@ static void GeneratePixelShader(T& out, DSTALPHA_MODE dstAlphaMode, API_TYPE Api uid_data.per_pixel_depth = per_pixel_depth; uid_data.forced_early_z = forced_early_z; uid_data.fast_depth_calc = g_ActiveConfig.bFastDepthCalc; - uid_data.early_ztest = bpmem.zcontrol.early_ztest; + uid_data.early_ztest = bpmem.UseEarlyDepthTest(); uid_data.fog_fsel = bpmem.fog.c_proj_fsel.fsel; // Note: z-textures are not written to depth buffer if early depth test is used - if (per_pixel_depth && bpmem.zcontrol.early_ztest) + if (per_pixel_depth && bpmem.UseEarlyDepthTest()) out.Write("depth = zCoord;\n"); // Note: depth texture output is only written to depth buffer if late depth test is used @@ -653,7 +675,7 @@ static void GeneratePixelShader(T& out, DSTALPHA_MODE dstAlphaMode, API_TYPE Api out.Write("zCoord = zCoord * (16777216.0f/16777215.0f);\n"); } - if (per_pixel_depth && !bpmem.zcontrol.early_ztest) + if (per_pixel_depth && bpmem.UseLateDepthTest()) out.Write("depth = zCoord;\n"); if (dstAlphaMode == DSTALPHA_ALPHA_PASS) @@ -688,16 +710,16 @@ static void GeneratePixelShader(T& out, DSTALPHA_MODE dstAlphaMode, API_TYPE Api out.Write("}\n"); - if (text[sizeof(text) - 1] != 0x7C) - PanicAlert("PixelShader generator - buffer too small, canary has been eaten!"); + if (is_writing_shadercode) + { + if (text[sizeof(text) - 1] != 0x7C) + PanicAlert("PixelShader generator - buffer too small, canary has been eaten!"); #ifndef ANDROID - if (out.GetBuffer() != NULL) - { uselocale(old_locale); // restore locale freelocale(locale); - } #endif + } } @@ -745,7 +767,7 @@ static const char *TEVCMPAlphaOPTable[16] = }; template<class T> -static void WriteStage(T& out, pixel_shader_uid_data& uid_data, int n, API_TYPE ApiType, RegisterState RegisterStates[4]) +static inline void WriteStage(T& out, pixel_shader_uid_data& uid_data, int n, API_TYPE ApiType, RegisterState RegisterStates[4]) { int texcoord = bpmem.tevorders[n/2].getTexCoord(n&1); bool bHasTexCoord = (u32)texcoord < bpmem.genMode.numtexgens; @@ -888,7 +910,9 @@ static void WriteStage(T& out, pixel_shader_uid_data& uid_data, int n, API_TYPE char *texswap = swapModeTable[bpmem.combiners[n].alphaC.tswap]; int texmap = bpmem.tevorders[n/2].getTexMap(n&1); uid_data.SetTevindrefTexmap(i, texmap); - SampleTexture<T>(out, "textemp", "tevcoord", texswap, texmap, ApiType); + + out.Write("textemp = "); + SampleTexture<T>(out, "tevcoord", texswap, texmap, ApiType); } else { @@ -1110,13 +1134,14 @@ static void WriteStage(T& out, pixel_shader_uid_data& uid_data, int n, API_TYPE } template<class T> -void SampleTexture(T& out, const char *destination, const char *texcoords, const char *texswap, int texmap, API_TYPE ApiType) +void SampleTexture(T& out, const char *texcoords, const char *texswap, int texmap, API_TYPE ApiType) { out.SetConstantsUsed(C_TEXDIMS+texmap,C_TEXDIMS+texmap); + if (ApiType == API_D3D11) - out.Write("%s=Tex%d.Sample(samp%d,%s.xy * " I_TEXDIMS"[%d].xy).%s;\n", destination, texmap,texmap, texcoords, texmap, texswap); + out.Write("Tex%d.Sample(samp%d,%s.xy * " I_TEXDIMS"[%d].xy).%s;\n", texmap,texmap, texcoords, texmap, texswap); else - out.Write("%s=%s(samp%d,%s.xy * " I_TEXDIMS"[%d].xy).%s;\n", destination, ApiType == API_OPENGL ? "texture" : "tex2D", texmap, texcoords, texmap, texswap); + out.Write("%s(samp%d,%s.xy * " I_TEXDIMS"[%d].xy).%s;\n", ApiType == API_OPENGL ? "texture" : "tex2D", texmap, texcoords, texmap, texswap); } static const char *tevAlphaFuncsTable[] = @@ -1140,7 +1165,7 @@ static const char *tevAlphaFunclogicTable[] = }; template<class T> -static void WriteAlphaTest(T& out, pixel_shader_uid_data& uid_data, API_TYPE ApiType, DSTALPHA_MODE dstAlphaMode, bool per_pixel_depth) +static inline void WriteAlphaTest(T& out, pixel_shader_uid_data& uid_data, API_TYPE ApiType, DSTALPHA_MODE dstAlphaMode, bool per_pixel_depth) { static const char *alphaRef[2] = { @@ -1183,11 +1208,11 @@ static void WriteAlphaTest(T& out, pixel_shader_uid_data& uid_data, API_TYPE Api // We implement "depth test before texturing" by disabling alpha test when early-z is in use. // It seems to be less buggy than not to update the depth buffer if alpha test fails, // but both ways wouldn't be accurate. - + // OpenGL 4.2 has a flag which allows the driver to still update the depth buffer // if alpha test fails. The driver doesn't have to, but I assume they all do because // it's the much faster code path for the GPU. - uid_data.alpha_test_use_zcomploc_hack = bpmem.zcontrol.early_ztest && bpmem.zmode.updateenable && !g_ActiveConfig.backend_info.bSupportsEarlyZ; + uid_data.alpha_test_use_zcomploc_hack = bpmem.UseEarlyDepthTest() && bpmem.zmode.updateenable && !g_ActiveConfig.backend_info.bSupportsEarlyZ; if (!uid_data.alpha_test_use_zcomploc_hack) { out.Write("\t\tdiscard;\n"); @@ -1211,7 +1236,7 @@ static const char *tevFogFuncsTable[] = }; template<class T> -static void WriteFog(T& out, pixel_shader_uid_data& uid_data) +static inline void WriteFog(T& out, pixel_shader_uid_data& uid_data) { uid_data.fog_fsel = bpmem.fog.c_proj_fsel.fsel; if(bpmem.fog.c_proj_fsel.fsel == 0) @@ -1253,7 +1278,7 @@ static void WriteFog(T& out, pixel_shader_uid_data& uid_data) } else { - if (bpmem.fog.c_proj_fsel.fsel != 2) + if (bpmem.fog.c_proj_fsel.fsel != 2 && out.GetBuffer() != NULL) WARN_LOG(VIDEO, "Unknown Fog Type! %08x", bpmem.fog.c_proj_fsel.fsel); } diff --git a/Source/Core/VideoCommon/Src/PixelShaderGen.h b/Source/Core/VideoCommon/Src/PixelShaderGen.h index c1ca009438..7763cbd574 100644 --- a/Source/Core/VideoCommon/Src/PixelShaderGen.h +++ b/Source/Core/VideoCommon/Src/PixelShaderGen.h @@ -63,18 +63,30 @@ struct pixel_shader_uid_data u32 num_values; // TODO: Shouldn't be a u32 u32 NumValues() const { return num_values; } - u32 components; + u32 components : 23; u32 dstAlphaMode : 2; u32 Pretest : 2; + u32 nIndirectStagesUsed : 4; + u32 pad0 : 1; u32 genMode_numtexgens : 4; u32 genMode_numtevstages : 4; u32 genMode_numindstages : 3; - - u32 nIndirectStagesUsed : 8; + u32 alpha_test_comp0 : 3; + u32 alpha_test_comp1 : 3; + u32 alpha_test_logic : 2; + u32 alpha_test_use_zcomploc_hack : 1; + u32 fog_proj : 1; + u32 fog_fsel : 3; + u32 fog_RangeBaseEnabled : 1; + u32 ztex_op : 2; + u32 fast_depth_calc : 1; + u32 per_pixel_depth : 1; + u32 forced_early_z : 1; + u32 early_ztest : 1; + u32 pad1 : 1; u32 texMtxInfo_n_projection : 8; // 8x1 bit - u32 tevindref_bi0 : 3; u32 tevindref_bc0 : 3; u32 tevindref_bi1 : 3; @@ -83,6 +95,7 @@ struct pixel_shader_uid_data u32 tevindref_bc3 : 3; u32 tevindref_bi4 : 3; u32 tevindref_bc4 : 3; + inline void SetTevindrefValues(int index, u32 texcoord, u32 texmap) { if (index == 0) { tevindref_bc0 = texcoord; tevindref_bi0 = texmap; } @@ -98,25 +111,6 @@ struct pixel_shader_uid_data else if (index == 3) { tevindref_bi4 = texmap; } } - u32 alpha_test_comp0 : 3; - u32 alpha_test_comp1 : 3; - u32 alpha_test_logic : 2; - - u32 alpha_test_use_zcomploc_hack : 1; - - u32 fog_proj : 1; - u32 fog_fsel : 3; - u32 fog_RangeBaseEnabled : 1; - - u32 ztex_op : 2; - - u32 fast_depth_calc : 1; - u32 per_pixel_depth : 1; - u32 forced_early_z : 1; - u32 early_ztest : 1; - - u32 xfregs_numTexGen_numTexGens : 4; - struct { // TODO: Can save a lot space by removing the padding bits u32 cc : 24; diff --git a/Source/Core/VideoCommon/Src/RenderBase.cpp b/Source/Core/VideoCommon/Src/RenderBase.cpp index f514af0422..e4e330d6f5 100644 --- a/Source/Core/VideoCommon/Src/RenderBase.cpp +++ b/Source/Core/VideoCommon/Src/RenderBase.cpp @@ -254,9 +254,6 @@ void Renderer::SetScreenshot(const char *filename) // Create On-Screen-Messages void Renderer::DrawDebugText() { - if (!g_Config.bOSDHotKey) - return; - // OSD Menu messages if (OSDChoice > 0) { diff --git a/Source/Core/VideoCommon/Src/ShaderGenCommon.h b/Source/Core/VideoCommon/Src/ShaderGenCommon.h index ec4fe27416..a804c08f13 100644 --- a/Source/Core/VideoCommon/Src/ShaderGenCommon.h +++ b/Source/Core/VideoCommon/Src/ShaderGenCommon.h @@ -173,7 +173,7 @@ private: }; template<class T> -static void WriteRegister(T& object, API_TYPE ApiType, const char *prefix, const u32 num) +static inline void WriteRegister(T& object, API_TYPE ApiType, const char *prefix, const u32 num) { if (ApiType == API_OPENGL) return; // Nothing to do here @@ -182,7 +182,7 @@ static void WriteRegister(T& object, API_TYPE ApiType, const char *prefix, const } template<class T> -static void WriteLocation(T& object, API_TYPE ApiType, bool using_ubos) +static inline void WriteLocation(T& object, API_TYPE ApiType, bool using_ubos) { if (using_ubos) return; @@ -191,7 +191,7 @@ static void WriteLocation(T& object, API_TYPE ApiType, bool using_ubos) } template<class T> -static void DeclareUniform(T& object, API_TYPE api_type, bool using_ubos, const u32 num, const char* type, const char* name) +static inline void DeclareUniform(T& object, API_TYPE api_type, bool using_ubos, const u32 num, const char* type, const char* name) { WriteLocation(object, api_type, using_ubos); object.Write("%s %s ", type, name); diff --git a/Source/Core/VideoCommon/Src/VertexShaderGen.cpp b/Source/Core/VideoCommon/Src/VertexShaderGen.cpp index a682b4ea21..ad090fb839 100644 --- a/Source/Core/VideoCommon/Src/VertexShaderGen.cpp +++ b/Source/Core/VideoCommon/Src/VertexShaderGen.cpp @@ -38,7 +38,7 @@ static void DefineVSOutputStructMember(T& object, API_TYPE api_type, const char* } template<class T> -static void GenerateVSOutputStruct(T& object, u32 components, API_TYPE api_type) +static inline void GenerateVSOutputStruct(T& object, u32 components, API_TYPE api_type) { object.Write("struct VS_OUTPUT {\n"); DefineVSOutputStructMember(object, api_type, "float4", "pos", -1, "POSITION"); @@ -67,7 +67,7 @@ static void GenerateVSOutputStruct(T& object, u32 components, API_TYPE api_type) } template<class T> -static void GenerateVertexShader(T& out, u32 components, API_TYPE api_type) +static inline void GenerateVertexShader(T& out, u32 components, API_TYPE api_type) { // Non-uid template parameters will write to the dummy data (=> gets optimized out) vertex_shader_uid_data dummy_data; @@ -75,22 +75,23 @@ static void GenerateVertexShader(T& out, u32 components, API_TYPE api_type) ? out.template GetUidData<vertex_shader_uid_data>() : dummy_data; out.SetBuffer(text); + const bool is_writing_shadercode = (out.GetBuffer() != NULL); #ifndef ANDROID locale_t locale; locale_t old_locale; - if (out.GetBuffer() != NULL) + if (is_writing_shadercode) { locale = newlocale(LC_NUMERIC_MASK, "C", NULL); // New locale for compilation old_locale = uselocale(locale); // Apply the locale for this thread } #endif - text[sizeof(text) - 1] = 0x7C; // canary + + if (is_writing_shadercode) + text[sizeof(text) - 1] = 0x7C; // canary _assert_(bpmem.genMode.numtexgens == xfregs.numTexGen.numTexGens); _assert_(bpmem.genMode.numcolchans == xfregs.numChan.numColorChans); - bool is_d3d = (api_type & API_D3D9 || api_type == API_D3D11); - // uniforms if (g_ActiveConfig.backend_info.bSupportsGLSLUBO) out.Write("layout(std140) uniform VSBlock {\n"); @@ -174,19 +175,9 @@ static void GenerateVertexShader(T& out, u32 components, API_TYPE api_type) if (components & VB_HAS_NRM0) out.Write(" float3 rawnorm0 : NORMAL0,\n"); if (components & VB_HAS_NRM1) - { - if (is_d3d) - out.Write(" float3 rawnorm1 : NORMAL1,\n"); - else - out.Write(" float3 rawnorm1 : ATTR%d,\n", SHADER_NORM1_ATTRIB); - } + out.Write(" float3 rawnorm1 : NORMAL1,\n"); if (components & VB_HAS_NRM2) - { - if (is_d3d) - out.Write(" float3 rawnorm2 : NORMAL2,\n"); - else - out.Write(" float3 rawnorm2 : ATTR%d,\n", SHADER_NORM2_ATTRIB); - } + out.Write(" float3 rawnorm2 : NORMAL2,\n"); if (components & VB_HAS_COL0) out.Write(" float4 color0 : COLOR0,\n"); if (components & VB_HAS_COL1) @@ -198,12 +189,7 @@ static void GenerateVertexShader(T& out, u32 components, API_TYPE api_type) out.Write(" float%d tex%d : TEXCOORD%d,\n", hastexmtx ? 3 : 2, i, i); } if (components & VB_HAS_POSMTXIDX) - { - if (is_d3d) - out.Write(" float4 blend_indices : BLENDINDICES,\n"); - else - out.Write(" float fposmtx : ATTR%d,\n", SHADER_POSMTX_ATTRIB); - } + out.Write(" float4 blend_indices : BLENDINDICES,\n"); out.Write(" float4 rawpos : POSITION) {\n"); } out.Write("VS_OUTPUT o;\n"); @@ -225,7 +211,7 @@ static void GenerateVertexShader(T& out, u32 components, API_TYPE api_type) out.Write("int posmtx = int(fposmtx);\n"); } - if (DriverDetails::HasBug(DriverDetails::BUG_NODYNUBOACCESS)) + if (is_writing_shadercode && DriverDetails::HasBug(DriverDetails::BUG_NODYNUBOACCESS)) { // This'll cause issues, but it can't be helped out.Write("float4 pos = float4(dot(" I_TRANSFORMMATRICES"[0], rawpos), dot(" I_TRANSFORMMATRICES"[1], rawpos), dot(" I_TRANSFORMMATRICES"[2], rawpos), 1);\n"); @@ -353,7 +339,7 @@ static void GenerateVertexShader(T& out, u32 components, API_TYPE api_type) // transform the light dir into tangent space uid_data.texMtxInfo[i].embosslightshift = xfregs.texMtxInfo[i].embosslightshift; uid_data.texMtxInfo[i].embosssourceshift = xfregs.texMtxInfo[i].embosssourceshift; - out.Write("ldir = normalize(%s.xyz - pos.xyz);\n", LightPos(I_LIGHTS, texinfo.embosslightshift)); + out.Write("ldir = normalize(" LIGHT_POS".xyz - pos.xyz);\n", LIGHT_POS_PARAMS(I_LIGHTS, texinfo.embosslightshift)); out.Write("o.tex%d.xyz = o.tex%d.xyz + float3(dot(ldir, _norm1), dot(ldir, _norm2), 0.0f);\n", i, texinfo.embosssourceshift); } else @@ -468,7 +454,7 @@ static void GenerateVertexShader(T& out, u32 components, API_TYPE api_type) //write the true depth value, if the game uses depth textures pixel shaders will override with the correct values //if not early z culling will improve speed - if (is_d3d) + if (api_type & API_D3D9 || api_type == API_D3D11) { out.Write("o.pos.z = " I_DEPTHPARAMS".x * o.pos.w + o.pos.z * " I_DEPTHPARAMS".y;\n"); } @@ -547,16 +533,16 @@ static void GenerateVertexShader(T& out, u32 components, API_TYPE api_type) out.Write("return o;\n}\n"); } - if (text[sizeof(text) - 1] != 0x7C) - PanicAlert("VertexShader generator - buffer too small, canary has been eaten!"); + if (is_writing_shadercode) + { + if (text[sizeof(text) - 1] != 0x7C) + PanicAlert("VertexShader generator - buffer too small, canary has been eaten!"); #ifndef ANDROID - if (out.GetBuffer() != NULL) - { uselocale(old_locale); // restore locale freelocale(locale); - } #endif + } } void GetVertexShaderUid(VertexShaderUid& object, u32 components, API_TYPE api_type) diff --git a/Source/Core/VideoCommon/Src/VertexShaderGen.h b/Source/Core/VideoCommon/Src/VertexShaderGen.h index eef0646e6f..ab9a378107 100644 --- a/Source/Core/VideoCommon/Src/VertexShaderGen.h +++ b/Source/Core/VideoCommon/Src/VertexShaderGen.h @@ -69,12 +69,12 @@ struct vertex_shader_uid_data { u32 NumValues() const { return sizeof(vertex_shader_uid_data); } - u32 components; - u32 numColorChans : 2; + u32 components : 23; u32 numTexGens : 4; - + u32 numColorChans : 2; u32 dualTexTrans_enabled : 1; u32 pixel_lighting : 1; + u32 pad0 : 1; u32 texMtxInfo_n_projection : 16; // Stored separately to guarantee that the texMtxInfo struct is 8 bits wide struct { diff --git a/Source/Core/Common/Src/VideoBackendBase.cpp b/Source/Core/VideoCommon/Src/VideoBackendBase.cpp index 99bce01156..4769ede3a0 100644 --- a/Source/Core/Common/Src/VideoBackendBase.cpp +++ b/Source/Core/VideoCommon/Src/VideoBackendBase.cpp @@ -19,6 +19,8 @@ VideoBackend* g_video_backend = NULL; static VideoBackend* s_default_backend = NULL; #ifdef _WIN32 +#include <windows.h> + // http://msdn.microsoft.com/en-us/library/ms725491.aspx static bool IsGteVista() { diff --git a/Source/Core/Common/Src/VideoBackendBase.h b/Source/Core/VideoCommon/Src/VideoBackendBase.h index 9c591d05a5..9c591d05a5 100644 --- a/Source/Core/Common/Src/VideoBackendBase.h +++ b/Source/Core/VideoCommon/Src/VideoBackendBase.h diff --git a/Source/Core/VideoCommon/Src/VideoConfig.cpp b/Source/Core/VideoCommon/Src/VideoConfig.cpp index 7827c0008a..6b6c796015 100644 --- a/Source/Core/VideoCommon/Src/VideoConfig.cpp +++ b/Source/Core/VideoCommon/Src/VideoConfig.cpp @@ -11,6 +11,7 @@ #include "FileUtil.h" #include "Core.h" #include "Movie.h" +#include "OnScreenDisplay.h" VideoConfig g_Config; VideoConfig g_ActiveConfig; @@ -92,7 +93,6 @@ void VideoConfig::Load(const char *ini_file) iniFile.Get("Hacks", "EFBAccessEnable", &bEFBAccessEnable, true); iniFile.Get("Hacks", "DlistCachingEnable", &bDlistCachingEnable,false); iniFile.Get("Hacks", "EFBCopyEnable", &bEFBCopyEnable, true); - iniFile.Get("Hacks", "EFBCopyDisableHotKey", &bOSDHotKey, 0); iniFile.Get("Hacks", "EFBToTextureEnable", &bCopyEFBToTexture, true); iniFile.Get("Hacks", "EFBScaledCopy", &bCopyEFBScaled, true); iniFile.Get("Hacks", "EFBCopyCacheEnable", &bEFBCopyCacheEnable, false); @@ -105,6 +105,18 @@ void VideoConfig::Load(const char *ini_file) bool bTmp; iniFile.Get("Interface", "UsePanicHandlers", &bTmp, true); SetEnableAlert(bTmp); + + // Shader Debugging causes a huge slowdown and it's easy to forget about it + // since it's not exposed in the settings dialog. It's only used by + // developers, so displaying an obnoxious message avoids some confusion and + // is not too annoying/confusing for users. + // + // XXX(delroth): This is kind of a bad place to put this, but the current + // VideoCommon is a mess and we don't have a central initialization + // function to do these kind of checks. Instead, the init code is + // triplicated for each video backend. + if (bEnableShaderDebugging) + OSD::AddMessage("Warning: Shader Debugging is enabled, performance will suffer heavily", 15000); } void VideoConfig::GameIniLoad(const char *ini_file) @@ -182,6 +194,7 @@ void VideoConfig::GameIniLoad(const char *ini_file) iniFile.GetIfExists("Video", "PH_ZFar", &sPhackvalue[1]); iniFile.GetIfExists("Video", "ZTPSpeedupHack", &bZTPSpeedHack); iniFile.GetIfExists("Video", "UseBBox", &bUseBBox); + iniFile.GetIfExists("Video", "PerfQueriesEnable", &bPerfQueriesEnable); } void VideoConfig::VerifyValidity() @@ -248,7 +261,6 @@ void VideoConfig::Save(const char *ini_file) iniFile.Set("Hacks", "EFBAccessEnable", bEFBAccessEnable); iniFile.Set("Hacks", "DlistCachingEnable", bDlistCachingEnable); iniFile.Set("Hacks", "EFBCopyEnable", bEFBCopyEnable); - iniFile.Set("Hacks", "EFBCopyDisableHotKey", bOSDHotKey); iniFile.Set("Hacks", "EFBToTextureEnable", bCopyEFBToTexture); iniFile.Set("Hacks", "EFBScaledCopy", bCopyEFBScaled); iniFile.Set("Hacks", "EFBCopyCacheEnable", bEFBCopyCacheEnable); diff --git a/Source/Core/VideoCommon/Src/VideoConfig.h b/Source/Core/VideoCommon/Src/VideoConfig.h index 741521c728..b856683595 100644 --- a/Source/Core/VideoCommon/Src/VideoConfig.h +++ b/Source/Core/VideoCommon/Src/VideoConfig.h @@ -108,11 +108,11 @@ struct VideoConfig // Hacks bool bEFBAccessEnable; bool bDlistCachingEnable; + bool bPerfQueriesEnable; bool bEFBCopyEnable; bool bEFBCopyCacheEnable; bool bEFBEmulateFormatChanges; - bool bOSDHotKey; bool bCopyEFBToTexture; bool bCopyEFBScaled; int iSafeTextureCache_ColorSamples; diff --git a/Source/Core/VideoCommon/Src/XFStructs.cpp b/Source/Core/VideoCommon/Src/XFStructs.cpp index 98bef38f00..a2f2097e07 100644 --- a/Source/Core/VideoCommon/Src/XFStructs.cpp +++ b/Source/Core/VideoCommon/Src/XFStructs.cpp @@ -172,7 +172,7 @@ void XFRegWritten(int transferSize, u32 baseAddress, u32 *pData) case 0x104d: case 0x104e: case 0x104f: - DEBUG_LOG(VIDEO, "Possible Normal Mtx XF reg?: %x=%x\n", address, newValue); + DEBUG_LOG(VIDEO, "Possible Normal Mtx XF reg?: %x=%x", address, newValue); break; case 0x1013: @@ -182,7 +182,7 @@ void XFRegWritten(int transferSize, u32 baseAddress, u32 *pData) case 0x1017: default: - WARN_LOG(VIDEO, "Unknown XF Reg: %x=%x\n", address, newValue); + WARN_LOG(VIDEO, "Unknown XF Reg: %x=%x", address, newValue); break; } @@ -199,7 +199,7 @@ void LoadXFReg(u32 transferSize, u32 baseAddress, u32 *pData) // do not allow writes past registers if (baseAddress + transferSize > 0x1058) { - INFO_LOG(VIDEO, "XF load exceeds address space: %x %d bytes\n", baseAddress, transferSize); + INFO_LOG(VIDEO, "XF load exceeds address space: %x %d bytes", baseAddress, transferSize); if (baseAddress >= 0x1058) transferSize = 0; diff --git a/Source/Core/VideoCommon/VideoCommon.vcxproj b/Source/Core/VideoCommon/VideoCommon.vcxproj index 1e7a56f578..c5896af1a6 100644 --- a/Source/Core/VideoCommon/VideoCommon.vcxproj +++ b/Source/Core/VideoCommon/VideoCommon.vcxproj @@ -213,6 +213,7 @@ <ClCompile Include="Src\VertexManagerBase.cpp" /> <ClCompile Include="Src\VertexShaderGen.cpp" /> <ClCompile Include="Src\VertexShaderManager.cpp" /> + <ClCompile Include="Src\VideoBackendBase.cpp" /> <ClCompile Include="Src\VideoConfig.cpp" /> <ClCompile Include="Src\VideoState.cpp" /> <ClCompile Include="Src\x64DLCache.cpp" /> @@ -266,6 +267,7 @@ <ClInclude Include="Src\VertexShaderGen.h" /> <ClInclude Include="Src\VertexShaderManager.h" /> <ClInclude Include="Src\VideoCommon.h" /> + <ClInclude Include="Src\VideoBackendBase.h" /> <ClInclude Include="Src\VideoConfig.h" /> <ClInclude Include="Src\VideoState.h" /> <ClInclude Include="Src\XFMemory.h" /> diff --git a/Source/Core/VideoCommon/VideoCommon.vcxproj.filters b/Source/Core/VideoCommon/VideoCommon.vcxproj.filters index 785e55877f..3f864b0e7e 100644 --- a/Source/Core/VideoCommon/VideoCommon.vcxproj.filters +++ b/Source/Core/VideoCommon/VideoCommon.vcxproj.filters @@ -4,6 +4,7 @@ <ClCompile Include="Src\CommandProcessor.cpp" /> <ClCompile Include="Src\memcpy_amd.cpp" /> <ClCompile Include="Src\PixelEngine.cpp" /> + <ClCompile Include="Src\VideoBackendBase.cpp" /> <ClCompile Include="Src\VideoConfig.cpp" /> <ClCompile Include="Src\VertexLoader.cpp"> <Filter>Vertex Loading</Filter> @@ -128,6 +129,7 @@ <ClInclude Include="Src\NativeVertexFormat.h" /> <ClInclude Include="Src\PixelEngine.h" /> <ClInclude Include="Src\VideoCommon.h" /> + <ClInclude Include="Src\VideoBackendBase.h" /> <ClInclude Include="Src\VideoConfig.h" /> <ClInclude Include="Src\DataReader.h"> <Filter>Vertex Loading</Filter> |
