diff options
| author | degasus <wickmarkus@web.de> | 2012-12-27 10:36:54 +0100 |
|---|---|---|
| committer | degasus <wickmarkus@web.de> | 2012-12-27 10:36:54 +0100 |
| commit | 316a33d1e68ab47b2870345a04bb9dfd4f383f28 (patch) | |
| tree | 03b40807def9787df30976ecb53f09d6c6084c13 /Source/Core | |
| parent | 53398ca5d8bc6e73a726c9d803db5a956c22cf6a (diff) | |
| parent | 94116bf89c917309b7e7b2a2b46bf2f43f3219db (diff) | |
Merge branch 'master' into GLSL-master
Conflicts:
Source/Core/DolphinWX/Src/VideoConfigDiag.h
Source/Plugins/Plugin_VideoOGL/Src/GLUtil.h
Source/Plugins/Plugin_VideoOGL/Src/Render.cpp
Source/Plugins/Plugin_VideoOGL/Src/TextureCache.cpp
Source/Plugins/Plugin_VideoOGL/Src/TextureConverter.cpp
Diffstat (limited to 'Source/Core')
148 files changed, 4973 insertions, 1662 deletions
diff --git a/Source/Core/AudioCommon/Src/AudioCommon.cpp b/Source/Core/AudioCommon/Src/AudioCommon.cpp index b73757cad5..8a568448a3 100644 --- a/Source/Core/AudioCommon/Src/AudioCommon.cpp +++ b/Source/Core/AudioCommon/Src/AudioCommon.cpp @@ -26,6 +26,7 @@ #include "CoreAudioSoundStream.h" #include "OpenALStream.h" #include "PulseAudioStream.h" +#include "../../Core/Src/Movie.h" namespace AudioCommon { @@ -115,7 +116,12 @@ namespace AudioCommon return backends; } - bool UseJIT() { + bool UseJIT() + { + if (!Movie::IsDSPHLE() && Movie::IsPlayingInput() && Movie::IsConfigSaved()) + { + return true; + } return ac_Config.m_EnableJIT; } diff --git a/Source/Core/AudioCommon/Src/CoreAudioSoundStream.cpp b/Source/Core/AudioCommon/Src/CoreAudioSoundStream.cpp index d09bce85f9..f6d5d31bed 100644 --- a/Source/Core/AudioCommon/Src/CoreAudioSoundStream.cpp +++ b/Source/Core/AudioCommon/Src/CoreAudioSoundStream.cpp @@ -87,6 +87,13 @@ bool CoreAudioSound::Start() return false; } + err = AudioUnitSetParameter(audioUnit, + kHALOutputParam_Volume, + kAudioUnitParameterFlag_Output, 0, + m_volume / 100., 0); + if (err != noErr) + ERROR_LOG(AUDIO, "error setting volume"); + err = AudioUnitInitialize(audioUnit); if (err != noErr) { ERROR_LOG(AUDIO, "error initializing audiounit"); @@ -105,6 +112,7 @@ bool CoreAudioSound::Start() void CoreAudioSound::SetVolume(int volume) { OSStatus err; + m_volume = volume; err = AudioUnitSetParameter(audioUnit, kHALOutputParam_Volume, diff --git a/Source/Core/AudioCommon/Src/CoreAudioSoundStream.h b/Source/Core/AudioCommon/Src/CoreAudioSoundStream.h index b7f7d96f53..581e4aabd8 100644 --- a/Source/Core/AudioCommon/Src/CoreAudioSoundStream.h +++ b/Source/Core/AudioCommon/Src/CoreAudioSoundStream.h @@ -47,6 +47,7 @@ public: private: AudioUnit audioUnit; + int m_volume; static OSStatus callback(void *inRefCon, AudioUnitRenderActionFlags *ioActionFlags, diff --git a/Source/Core/AudioCommon/Src/OpenALStream.cpp b/Source/Core/AudioCommon/Src/OpenALStream.cpp index 99220f0ed2..2abd357782 100644 --- a/Source/Core/AudioCommon/Src/OpenALStream.cpp +++ b/Source/Core/AudioCommon/Src/OpenALStream.cpp @@ -123,7 +123,6 @@ void OpenALStream::SoundLoop() { Common::SetCurrentThreadName("Audio thread - openal"); - ALenum err; u32 ulFrequency = m_mixer->GetSampleRate(); memset(uiBuffers, 0, OAL_NUM_BUFFERS * sizeof(ALuint)); @@ -144,8 +143,8 @@ void OpenALStream::SoundLoop() // Set the default sound volume as saved in the config file. alSourcef(uiSource, AL_GAIN, fVolume); - err = alGetError(); // TODO: Error handling + //ALenum err = alGetError(); ALint iBuffersFilled = 0; ALint iBuffersProcessed = 0; diff --git a/Source/Core/Common/Src/CDUtils.cpp b/Source/Core/Common/Src/CDUtils.cpp index 4496302e46..42aa9bfe34 100644 --- a/Source/Core/Common/Src/CDUtils.cpp +++ b/Source/Core/Common/Src/CDUtils.cpp @@ -3,6 +3,7 @@ #include "CDUtils.h" #include "Common.h" +#include <memory> // for std::unique_ptr #ifdef _WIN32 #include <windows.h> #elif __APPLE__ diff --git a/Source/Core/Common/Src/CPUDetect.cpp b/Source/Core/Common/Src/CPUDetect.cpp index 93e9d25087..65cd6dbd0b 100644 --- a/Source/Core/Common/Src/CPUDetect.cpp +++ b/Source/Core/Common/Src/CPUDetect.cpp @@ -173,9 +173,7 @@ void CPUInfo::Detect() if (max_ex_fn >= 0x80000001) { // Check for more features. __cpuid(cpu_id, 0x80000001); - bool cmp_legacy = false; if (cpu_id[2] & 1) bLAHFSAHF64 = true; - if (cpu_id[2] & 2) cmp_legacy = true; //wtf is this? if ((cpu_id[3] >> 29) & 1) bLongMode = true; } diff --git a/Source/Core/Common/Src/Common.h b/Source/Core/Common/Src/Common.h index 960bf75559..884a1e6c16 100644 --- a/Source/Core/Common/Src/Common.h +++ b/Source/Core/Common/Src/Common.h @@ -60,11 +60,6 @@ private: #undef STACKALIGN #define STACKALIGN __attribute__((__force_align_arg_pointer__)) #endif -// We use wxWidgets on OS X only if it is version 2.9+ with Cocoa support. -#ifdef __WXOSX_COCOA__ -#define HAVE_WX 1 -#define USE_WX 1 // Use wxGLCanvas -#endif #elif defined _WIN32 diff --git a/Source/Core/Common/Src/CommonPaths.h b/Source/Core/Common/Src/CommonPaths.h index decf2aef97..430a0c0cd8 100644 --- a/Source/Core/Common/Src/CommonPaths.h +++ b/Source/Core/Common/Src/CommonPaths.h @@ -128,6 +128,7 @@ #define WII_EUR_SETTING "setting-eur.txt" #define WII_USA_SETTING "setting-usa.txt" #define WII_JAP_SETTING "setting-jpn.txt" +#define WII_KOR_SETTING "setting-kor.txt" #define GECKO_CODE_HANDLER "codehandler.bin" diff --git a/Source/Core/Common/Src/DebugInterface.h b/Source/Core/Common/Src/DebugInterface.h index 15c58e4f57..317cd0bb43 100644 --- a/Source/Core/Common/Src/DebugInterface.h +++ b/Source/Core/Common/Src/DebugInterface.h @@ -30,7 +30,7 @@ public: virtual void step() {} virtual void runToBreakpoint() {} virtual void breakNow() {} - virtual void insertBLR(unsigned int /*address*/, unsigned int) {} + virtual void insertBLR(unsigned int /*address*/, unsigned int /*value*/) {} virtual void showJitResults(unsigned int /*address*/) {}; virtual int getColor(unsigned int /*address*/){return 0xFFFFFFFF;} virtual std::string getDescription(unsigned int /*address*/) = 0; diff --git a/Source/Core/Common/Src/FileUtil.cpp b/Source/Core/Common/Src/FileUtil.cpp index 4650c6e1ba..77290528a6 100644 --- a/Source/Core/Common/Src/FileUtil.cpp +++ b/Source/Core/Common/Src/FileUtil.cpp @@ -299,7 +299,7 @@ bool Copy(const std::string &srcFilename, const std::string &destFilename) ERROR_LOG(COMMON, "Copy: failed reading from source, %s --> %s: %s", srcFilename.c_str(), destFilename.c_str(), GetLastErrorMsg()); - return false; + goto bail; } } @@ -310,13 +310,19 @@ bool Copy(const std::string &srcFilename, const std::string &destFilename) ERROR_LOG(COMMON, "Copy: failed writing to output, %s --> %s: %s", srcFilename.c_str(), destFilename.c_str(), GetLastErrorMsg()); - return false; + goto bail; } } // close flushs fclose(input); fclose(output); return true; +bail: + if (input) + fclose(input); + if (output) + fclose(output); + return false; #endif } @@ -643,13 +649,12 @@ std::string &GetUserPath(const unsigned int DirIDX, const std::string &newPath) if (paths[D_USER_IDX].empty()) { #ifdef _WIN32 - // TODO: use GetExeDirectory() here instead of ROOT_DIR so that if the cwd is changed we still have the correct paths? - paths[D_USER_IDX] = ROOT_DIR DIR_SEP USERDATA_DIR DIR_SEP; + paths[D_USER_IDX] = GetExeDirectory() + DIR_SEP USERDATA_DIR DIR_SEP; #else if (File::Exists(ROOT_DIR DIR_SEP USERDATA_DIR)) paths[D_USER_IDX] = ROOT_DIR DIR_SEP USERDATA_DIR DIR_SEP; else - paths[D_USER_IDX] = std::string(getenv("HOME")) + DIR_SEP DOLPHIN_DATA_DIR DIR_SEP; + paths[D_USER_IDX] = std::string(getenv("HOME") ? getenv("HOME") : getenv("PWD")) + DIR_SEP DOLPHIN_DATA_DIR DIR_SEP; #endif INFO_LOG(COMMON, "GetUserPath: Setting user directory to %s:", paths[D_USER_IDX].c_str()); diff --git a/Source/Core/Common/Src/MathUtil.h b/Source/Core/Common/Src/MathUtil.h index a6290ff602..c5f613ada1 100644 --- a/Source/Core/Common/Src/MathUtil.h +++ b/Source/Core/Common/Src/MathUtil.h @@ -117,6 +117,8 @@ struct Rectangle Rectangle(T theLeft, T theTop, T theRight, T theBottom) : left(theLeft), top(theTop), right(theRight), bottom(theBottom) { } + + bool operator==(const Rectangle& r) { return left==r.left && top==r.top && right==r.right && bottom==r.bottom; } T GetWidth() const { return abs(right - left); } T GetHeight() const { return abs(bottom - top); } diff --git a/Source/Core/Common/Src/Setup.h b/Source/Core/Common/Src/Setup.h deleted file mode 100644 index c0faec3059..0000000000 --- a/Source/Core/Common/Src/Setup.h +++ /dev/null @@ -1,41 +0,0 @@ -// 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/ - -#ifndef _SETUP_H_ -#define _SETUP_H_ - -// ----------------------------------------------------------------------------------------------------- -// File description: -// Compilation settings. I avoid placing this in Common.h or some place where lots of files needs -// to be rebuilt if any of these settings are changed. I'd rather have it in as few files as possible. -// This file can be kept on the ignore list in your SVN program. It allows local optional settings -// depending on what works on your computer. -// ----------------------------------------------------------------------------------------------------- - -// ----------------------------------------------------------------------------------------------------- -// Settings: - -// This may remove sound artifacts in Wario Land Shake It and perhaps other games -//#define SETUP_AVOID_SOUND_ARTIFACTS - -// Build with playback rerecording options -//#define RERECORDING - -// ----------------------------------------------------------------------------------------------------- - -#endif // _SETUP_H_ - diff --git a/Source/Core/Common/Src/Thread.cpp b/Source/Core/Common/Src/Thread.cpp index ce91aac651..73f83c204f 100644 --- a/Source/Core/Common/Src/Thread.cpp +++ b/Source/Core/Common/Src/Thread.cpp @@ -15,7 +15,6 @@ // Official SVN repository and contact information can be found at // http://code.google.com/p/dolphin-emu/ -#include "Setup.h" #include "Thread.h" #include "Common.h" diff --git a/Source/Core/Common/Src/Timer.cpp b/Source/Core/Common/Src/Timer.cpp index 087f8fcead..b1beed2066 100644 --- a/Source/Core/Common/Src/Timer.cpp +++ b/Source/Core/Common/Src/Timer.cpp @@ -97,12 +97,6 @@ void Timer::AddTimeDifference() m_StartTime += GetTimeDifference(); } -// Wind back the starting time to a custom time -void Timer::WindBackStartingTime(u64 WindBack) -{ - m_StartTime += WindBack; -} - // Get the time elapsed since the Start() u64 Timer::GetTimeElapsed() { diff --git a/Source/Core/Common/Src/Timer.h b/Source/Core/Common/Src/Timer.h index a638920409..152d4c60e6 100644 --- a/Source/Core/Common/Src/Timer.h +++ b/Source/Core/Common/Src/Timer.h @@ -35,7 +35,6 @@ public: // The time difference is always returned in milliseconds, regardless of alternative internal representation u64 GetTimeDifference(); void AddTimeDifference(); - void WindBackStartingTime(u64 WindBack); static void IncreaseResolution(); static void RestoreResolution(); diff --git a/Source/Core/Common/Src/VideoBackendBase.cpp b/Source/Core/Common/Src/VideoBackendBase.cpp index 339cb016c1..62bb42997f 100644 --- a/Source/Core/Common/Src/VideoBackendBase.cpp +++ b/Source/Core/Common/Src/VideoBackendBase.cpp @@ -22,7 +22,9 @@ #include "../../../Plugins/Plugin_VideoDX9/Src/VideoBackend.h" #include "../../../Plugins/Plugin_VideoDX11/Src/VideoBackend.h" #endif +#ifndef USE_GLES #include "../../../Plugins/Plugin_VideoOGL/Src/VideoBackend.h" +#endif #include "../../../Plugins/Plugin_VideoSoftware/Src/VideoBackend.h" std::vector<VideoBackend*> g_available_video_backends; @@ -41,7 +43,7 @@ static bool IsGteVista() VER_SET_CONDITION(dwlConditionMask, VER_MAJORVERSION, VER_GREATER_EQUAL); - return VerifyVersionInfo(&osvi, VER_MAJORVERSION, dwlConditionMask); + return VerifyVersionInfo(&osvi, VER_MAJORVERSION, dwlConditionMask) != FALSE; } #endif @@ -52,7 +54,9 @@ void VideoBackend::PopulateList() if (IsGteVista()) g_available_video_backends.push_back(new DX11::VideoBackend); #endif +#ifndef USE_GLES g_available_video_backends.push_back(new OGL::VideoBackend); +#endif g_available_video_backends.push_back(new SW::VideoSoftware); g_video_backend = g_available_video_backends.front(); diff --git a/Source/Core/Common/Src/VideoBackendBase.h b/Source/Core/Common/Src/VideoBackendBase.h index d09288ebc7..311fa66104 100644 --- a/Source/Core/Common/Src/VideoBackendBase.h +++ b/Source/Core/Common/Src/VideoBackendBase.h @@ -137,6 +137,8 @@ public: // the implementation needs not do synchronization logic, because calls to it are surrounded by PauseAndLock now virtual void DoState(PointerWrap &p) = 0; + + virtual void CheckInvalidState() = 0; }; extern std::vector<VideoBackend*> g_available_video_backends; @@ -176,9 +178,15 @@ class VideoBackendHardware : public VideoBackend void PauseAndLock(bool doLock, bool unpauseOnUnlock=true); void DoState(PointerWrap &p); + + bool m_invalid; + +public: + void CheckInvalidState(); protected: void InitializeShared(); + void InvalidState(); }; #endif diff --git a/Source/Core/Common/Src/x64Analyzer.cpp b/Source/Core/Common/Src/x64Analyzer.cpp index 2ea3e9a512..66a2fe217f 100644 --- a/Source/Core/Common/Src/x64Analyzer.cpp +++ b/Source/Core/Common/Src/x64Analyzer.cpp @@ -31,12 +31,9 @@ bool DisassembleMov(const unsigned char *codePtr, InstructionInfo &info, int acc info.hasImmediate = false; info.isMemoryWrite = false; - int addressSize = 8; u8 modRMbyte = 0; u8 sibByte = 0; bool hasModRM = false; - bool hasSIBbyte = false; - bool hasDisplacement = false; int displacementSize = 0; @@ -47,7 +44,6 @@ bool DisassembleMov(const unsigned char *codePtr, InstructionInfo &info, int acc } else if (*codePtr == 0x67) { - addressSize = 4; codePtr++; } @@ -113,7 +109,6 @@ bool DisassembleMov(const unsigned char *codePtr, InstructionInfo &info, int acc info.otherReg = (sibByte & 7); if (rex & 2) info.scaledReg += 8; if (rex & 1) info.otherReg += 8; - hasSIBbyte = true; } else { @@ -122,7 +117,6 @@ bool DisassembleMov(const unsigned char *codePtr, InstructionInfo &info, int acc } if (mrm.mod == 1 || mrm.mod == 2) { - hasDisplacement = true; if (mrm.mod == 1) displacementSize = 1; else diff --git a/Source/Core/Common/Src/x64Emitter.cpp b/Source/Core/Common/Src/x64Emitter.cpp index d4bd1adabf..19e96478d1 100644 --- a/Source/Core/Common/Src/x64Emitter.cpp +++ b/Source/Core/Common/Src/x64Emitter.cpp @@ -870,7 +870,6 @@ void XEmitter::BTC(int bits, OpArg dest, OpArg index) {WriteBitTest(bits, dest, //shift can be either imm8 or cl void XEmitter::SHRD(int bits, OpArg dest, OpArg src, OpArg shift) { - bool writeImm = false; if (dest.IsImm()) { _assert_msg_(DYNA_REC, 0, "SHRD - can't use imms as destination"); @@ -901,7 +900,6 @@ void XEmitter::SHRD(int bits, OpArg dest, OpArg src, OpArg shift) void XEmitter::SHLD(int bits, OpArg dest, OpArg src, OpArg shift) { - bool writeImm = false; if (dest.IsImm()) { _assert_msg_(DYNA_REC, 0, "SHLD - can't use imms as destination"); diff --git a/Source/Core/Core/CMakeLists.txt b/Source/Core/Core/CMakeLists.txt index 734d966781..124d7aa879 100644 --- a/Source/Core/Core/CMakeLists.txt +++ b/Source/Core/Core/CMakeLists.txt @@ -5,7 +5,6 @@ set(SRCS Src/ActionReplay.cpp Src/Console.cpp Src/Core.cpp Src/CoreParameter.cpp - Src/CoreRerecording.cpp Src/CoreTiming.cpp Src/DSPEmulator.cpp Src/GeckoCodeConfig.cpp @@ -71,7 +70,8 @@ set(SRCS Src/ActionReplay.cpp Src/HW/CPU.cpp Src/HW/DSP.cpp Src/HW/DSPHLE/UCodes/UCode_AX.cpp - Src/HW/DSPHLE/UCodes/UCode_AXWii.cpp + Src/HW/DSPHLE/UCodes/UCode_AXWii.cpp + Src/HW/DSPHLE/UCodes/UCode_NewAXWii.cpp Src/HW/DSPHLE/UCodes/UCode_CARD.cpp Src/HW/DSPHLE/UCodes/UCode_InitAudioSystem.cpp Src/HW/DSPHLE/UCodes/UCode_ROM.cpp @@ -192,7 +192,11 @@ set(SRCS Src/ActionReplay.cpp Src/PowerPC/JitCommon/JitCache.cpp Src/PowerPC/JitCommon/Jit_Util.cpp) -set(LIBS bdisasm inputcommon videoogl videosoftware sfml-network) +set(LIBS bdisasm inputcommon videosoftware sfml-network) + +if(NOT USE_GLES) + set(LIBS ${LIBS} videoogl) +endif() if(WIN32) set(SRCS ${SRCS} Src/HW/BBA-TAP/TAP_Win32.cpp Src/stdafx.cpp diff --git a/Source/Core/Core/Core.vcxproj b/Source/Core/Core/Core.vcxproj index e03d40e43a..e626ccd033 100644 --- a/Source/Core/Core/Core.vcxproj +++ b/Source/Core/Core/Core.vcxproj @@ -207,7 +207,6 @@ <ClCompile Include="Src\Console.cpp" /> <ClCompile Include="Src\Core.cpp" /> <ClCompile Include="Src\CoreParameter.cpp" /> - <ClCompile Include="Src\CoreRerecording.cpp" /> <ClCompile Include="Src\CoreTiming.cpp" /> <ClCompile Include="Src\Debugger\Debugger_SymbolMap.cpp" /> <ClCompile Include="Src\Debugger\Dump.cpp" /> @@ -262,6 +261,7 @@ <ClCompile Include="Src\HW\DSPHLE\UCodes\UCodes.cpp" /> <ClCompile Include="Src\HW\DSPHLE\UCodes\UCode_AX.cpp" /> <ClCompile Include="Src\HW\DSPHLE\UCodes\UCode_AXWii.cpp" /> + <ClCompile Include="Src\HW\DSPHLE\UCodes\UCode_NewAXWii.cpp" /> <ClCompile Include="Src\HW\DSPHLE\UCodes\UCode_CARD.cpp" /> <ClCompile Include="Src\HW\DSPHLE\UCodes\UCode_GBA.cpp" /> <ClCompile Include="Src\HW\DSPHLE\UCodes\UCode_InitAudioSystem.cpp" /> @@ -385,7 +385,11 @@ <ClCompile Include="Src\PowerPC\PPCTables.cpp" /> <ClCompile Include="Src\PowerPC\Profiler.cpp" /> <ClCompile Include="Src\PowerPC\SignatureDB.cpp" /> - <ClCompile Include="Src\State.cpp" /> + <ClCompile Include="Src\State.cpp"> + <OpenMPSupport Condition="'$(Configuration)|$(Platform)'=='DebugFast|Win32'">false</OpenMPSupport> + <OpenMPSupport Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">false</OpenMPSupport> + <OpenMPSupport Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">false</OpenMPSupport> + </ClCompile> <ClCompile Include="Src\stdafx.cpp"> <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Create</PrecompiledHeader> <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Create</PrecompiledHeader> @@ -459,9 +463,11 @@ <ClInclude Include="Src\HW\DSPHLE\MailHandler.h" /> <ClInclude Include="Src\HW\DSPHLE\UCodes\UCodes.h" /> <ClInclude Include="Src\HW\DSPHLE\UCodes\UCode_AX.h" /> - <ClInclude Include="Src\HW\DSPHLE\UCodes\UCode_AXStructs.h" /> + <ClInclude Include="Src\HW\DSPHLE\UCodes\UCode_AX_Structs.h" /> <ClInclude Include="Src\HW\DSPHLE\UCodes\UCode_AXWii.h" /> - <ClInclude Include="Src\HW\DSPHLE\UCodes\UCode_AX_ADPCM.h" /> + <ClInclude Include="Src\HW\DSPHLE\UCodes\UCode_AXWii_Structs.h" /> + <ClInclude Include="Src\HW\DSPHLE\UCodes\UCode_AXWii_Voice.h" /> + <ClInclude Include="Src\HW\DSPHLE\UCodes\UCode_NewAXWii.h" /> <ClInclude Include="Src\HW\DSPHLE\UCodes\UCode_AX_Voice.h" /> <ClInclude Include="Src\HW\DSPHLE\UCodes\UCode_CARD.h" /> <ClInclude Include="Src\HW\DSPHLE\UCodes\UCode_GBA.h" /> @@ -592,4 +598,4 @@ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" /> <ImportGroup Label="ExtensionTargets"> </ImportGroup> -</Project>
\ No newline at end of file +</Project> diff --git a/Source/Core/Core/Core.vcxproj.filters b/Source/Core/Core/Core.vcxproj.filters index 020cf76ad0..ad6db227d5 100644 --- a/Source/Core/Core/Core.vcxproj.filters +++ b/Source/Core/Core/Core.vcxproj.filters @@ -197,6 +197,9 @@ <ClCompile Include="Src\HW\DSPHLE\UCodes\UCode_AXWii.cpp"> <Filter>HW %28Flipper/Hollywood%29\DSP Interface + HLE\HLE\uCodes</Filter> </ClCompile> + <ClCompile Include="Src\HW\DSPHLE\UCodes\UCode_NewAXWii.cpp"> + <Filter>HW %28Flipper/Hollywood%29\DSP Interface + HLE\HLE\uCodes</Filter> + </ClCompile> <ClCompile Include="Src\HW\DSPHLE\UCodes\UCode_CARD.cpp"> <Filter>HW %28Flipper/Hollywood%29\DSP Interface + HLE\HLE\uCodes</Filter> </ClCompile> @@ -727,18 +730,24 @@ <ClInclude Include="Src\HW\DSPHLE\UCodes\UCode_AX.h"> <Filter>HW %28Flipper/Hollywood%29\DSP Interface + HLE\HLE\uCodes</Filter> </ClInclude> - <ClInclude Include="Src\HW\DSPHLE\UCodes\UCode_AX_ADPCM.h"> - <Filter>HW %28Flipper/Hollywood%29\DSP Interface + HLE\HLE\uCodes</Filter> - </ClInclude> <ClInclude Include="Src\HW\DSPHLE\UCodes\UCode_AX_Voice.h"> <Filter>HW %28Flipper/Hollywood%29\DSP Interface + HLE\HLE\uCodes</Filter> </ClInclude> - <ClInclude Include="Src\HW\DSPHLE\UCodes\UCode_AXStructs.h"> + <ClInclude Include="Src\HW\DSPHLE\UCodes\UCode_AX_Structs.h"> <Filter>HW %28Flipper/Hollywood%29\DSP Interface + HLE\HLE\uCodes</Filter> </ClInclude> <ClInclude Include="Src\HW\DSPHLE\UCodes\UCode_AXWii.h"> <Filter>HW %28Flipper/Hollywood%29\DSP Interface + HLE\HLE\uCodes</Filter> </ClInclude> + <ClInclude Include="Src\HW\DSPHLE\UCodes\UCode_AXWii_Structs.h"> + <Filter>HW %28Flipper/Hollywood%29\DSP Interface + HLE\HLE\uCodes</Filter> + </ClInclude> + <ClInclude Include="Src\HW\DSPHLE\UCodes\UCode_AXWii_Voice.h"> + <Filter>HW %28Flipper/Hollywood%29\DSP Interface + HLE\HLE\uCodes</Filter> + </ClInclude> + <ClInclude Include="Src\HW\DSPHLE\UCodes\UCode_NewAXWii.h"> + <Filter>HW %28Flipper/Hollywood%29\DSP Interface + HLE\HLE\uCodes</Filter> + </ClInclude> <ClInclude Include="Src\HW\DSPHLE\UCodes\UCode_CARD.h"> <Filter>HW %28Flipper/Hollywood%29\DSP Interface + HLE\HLE\uCodes</Filter> </ClInclude> @@ -1174,4 +1183,4 @@ <UniqueIdentifier>{3e9e6e83-c1bf-45f9-aeff-231f98f60d29}</UniqueIdentifier> </Filter> </ItemGroup> -</Project>
\ No newline at end of file +</Project> diff --git a/Source/Core/Core/Src/ActionReplay.cpp b/Source/Core/Core/Src/ActionReplay.cpp index 1ef6ca81bc..77f5778061 100644 --- a/Source/Core/Core/Src/ActionReplay.cpp +++ b/Source/Core/Core/Src/ActionReplay.cpp @@ -285,7 +285,6 @@ bool RunCode(const ARCode &arcode) // used for conditional codes int skip_count = 0; - u32 addr_last = 0; u32 val_last = 0; current_code = &arcode; @@ -394,7 +393,6 @@ bool RunCode(const ARCode &arcode) { LogInfo("ZCode: Memory Copy"); doMemoryCopy = true; - addr_last = addr; val_last = data; } else diff --git a/Source/Core/Core/Src/Boot/Boot_BS2Emu.cpp b/Source/Core/Core/Src/Boot/Boot_BS2Emu.cpp index 788b8c317c..bd789fa82b 100644 --- a/Source/Core/Core/Src/Boot/Boot_BS2Emu.cpp +++ b/Source/Core/Core/Src/Boot/Boot_BS2Emu.cpp @@ -187,8 +187,10 @@ bool CBoot::SetupWiiMemory(unsigned int _CountryCode) switch((DiscIO::IVolume::ECountry)_CountryCode) { case DiscIO::IVolume::COUNTRY_KOREA: + region_filename = File::GetSysDirectory() + WII_SYS_DIR + DIR_SEP + WII_KOR_SETTING; + break; case DiscIO::IVolume::COUNTRY_TAIWAN: - // TODO: Determine if Korea / Taiwan have their own specific settings. + // TODO: Determine if Taiwan has their own specific settings. case DiscIO::IVolume::COUNTRY_JAPAN: region_filename = File::GetSysDirectory() + WII_SYS_DIR + DIR_SEP + WII_JAP_SETTING; break; diff --git a/Source/Core/Core/Src/BootManager.cpp b/Source/Core/Core/Src/BootManager.cpp index 120355f029..e0fac1da87 100644 --- a/Source/Core/Core/Src/BootManager.cpp +++ b/Source/Core/Core/Src/BootManager.cpp @@ -45,6 +45,7 @@ #include "Core.h" #include "Host.h" #include "VideoBackendBase.h" +#include "Movie.h" namespace BootManager @@ -115,6 +116,19 @@ bool BootCore(const std::string& _rFilename) game_ini.Get("Core", "GFXBackend", &StartUp.m_strVideoBackend, StartUp.m_strVideoBackend.c_str()); VideoBackend::ActivateBackend(StartUp.m_strVideoBackend); + if (Movie::IsPlayingInput() && Movie::IsConfigSaved()) + { + StartUp.bCPUThread = Movie::IsDualCore(); + StartUp.bSkipIdle = Movie::IsSkipIdle(); + StartUp.bDSPHLE = Movie::IsDSPHLE(); + StartUp.bProgressive = Movie::IsProgressive(); + StartUp.bFastDiscSpeed = Movie::IsFastDiscSpeed(); + if (Movie::IsUsingMemcard() && Movie::IsStartingFromClearSave() && !StartUp.bWii) + { + if (File::Exists("Movie.raw")) + File::Delete("Movie.raw"); + } + } // Wii settings if (StartUp.bWii) { diff --git a/Source/Core/Core/Src/ConfigManager.cpp b/Source/Core/Core/Src/ConfigManager.cpp index 0c4fa04566..180e6c981d 100644 --- a/Source/Core/Core/Src/ConfigManager.cpp +++ b/Source/Core/Core/Src/ConfigManager.cpp @@ -131,6 +131,7 @@ void SConfig::SaveSettings() // General ini.Set("General", "LastFilename", m_LastFilename); + ini.Set("General", "ShowLag", m_ShowLag); // ISO folders // clear removed folders @@ -155,10 +156,12 @@ void SConfig::SaveSettings() ini.Set("General", "RecursiveGCMPaths", m_RecursiveISOFolder); ini.Set("General", "NANDRoot", m_NANDPath); + ini.Set("General", "WirelessMac", m_WirelessMac); // Interface ini.Set("Interface", "ConfirmStop", m_LocalCoreStartupParameter.bConfirmStop); ini.Set("Interface", "UsePanicHandlers", m_LocalCoreStartupParameter.bUsePanicHandlers); + ini.Set("Interface", "OnScreenDisplayMessages", m_LocalCoreStartupParameter.bOnScreenDisplayMessages); ini.Set("Interface", "HideCursor", m_LocalCoreStartupParameter.bHideCursor); ini.Set("Interface", "AutoHideCursor", m_LocalCoreStartupParameter.bAutoHideCursor); ini.Set("Interface", "Theme", m_LocalCoreStartupParameter.iTheme); @@ -208,6 +211,8 @@ void SConfig::SaveSettings() ini.Set("GameList", "ListKorea", m_ListKorea); ini.Set("GameList", "ListTaiwan", m_ListTaiwan); ini.Set("GameList", "ListUnknown", m_ListUnknown); + ini.Set("GameList", "ListSort", m_ListSort); + ini.Set("GameList", "ListSortSecondary", m_ListSort2); // Core ini.Set("Core", "HLE_BS2", m_LocalCoreStartupParameter.bHLE_BS2); @@ -246,6 +251,10 @@ void SConfig::SaveSettings() // GFX Backend ini.Set("Core", "GFXBackend", m_LocalCoreStartupParameter.m_strVideoBackend); + // Movie + ini.Set("Movie", "PauseMovie", m_PauseMovie); + ini.Set("Movie", "Author", m_strMovieAuthor); + ini.Save(File::GetUserPath(F_DOLPHINCONFIG_IDX)); m_SYSCONF->Save(); } @@ -260,6 +269,7 @@ void SConfig::LoadSettings() // General { ini.Get("General", "LastFilename", &m_LastFilename); + ini.Get("General", "ShowLag", &m_ShowLag, false); m_ISOFolder.clear(); int numGCMPaths; @@ -282,12 +292,14 @@ void SConfig::LoadSettings() m_NANDPath = File::GetUserPath(D_WIIROOT_IDX, m_NANDPath); DiscIO::cUIDsys::AccessInstance().UpdateLocation(); DiscIO::CSharedContent::AccessInstance().UpdateLocation(); + ini.Get("General", "WirelessMac", &m_WirelessMac); } { // Interface ini.Get("Interface", "ConfirmStop", &m_LocalCoreStartupParameter.bConfirmStop, false); ini.Get("Interface", "UsePanicHandlers", &m_LocalCoreStartupParameter.bUsePanicHandlers, true); + ini.Get("Interface", "OnScreenDisplayMessages", &m_LocalCoreStartupParameter.bOnScreenDisplayMessages, true); ini.Get("Interface", "HideCursor", &m_LocalCoreStartupParameter.bHideCursor, false); ini.Get("Interface", "AutoHideCursor", &m_LocalCoreStartupParameter.bAutoHideCursor, false); ini.Get("Interface", "Theme", &m_LocalCoreStartupParameter.iTheme, 0); @@ -334,11 +346,13 @@ void SConfig::LoadSettings() ini.Get("GameList", "ListPal", &m_ListPal, true); ini.Get("GameList", "ListUsa", &m_ListUsa, true); - ini.Get("GameList", "ListFrance", &m_ListFrance, true); - ini.Get("GameList", "ListItaly", &m_ListItaly, true); - ini.Get("GameList", "ListKorea", &m_ListKorea, true); - ini.Get("GameList", "ListTaiwan", &m_ListTaiwan, true); - ini.Get("GameList", "ListUnknown", &m_ListUnknown, true); + ini.Get("GameList", "ListFrance", &m_ListFrance, true); + ini.Get("GameList", "ListItaly", &m_ListItaly, true); + ini.Get("GameList", "ListKorea", &m_ListKorea, true); + ini.Get("GameList", "ListTaiwan", &m_ListTaiwan, true); + ini.Get("GameList", "ListUnknown", &m_ListUnknown, true); + ini.Get("GameList", "ListSort", &m_ListSort, 3); + ini.Get("GameList", "ListSortSecondary",&m_ListSort2, 0); // Core ini.Get("Core", "HLE_BS2", &m_LocalCoreStartupParameter.bHLE_BS2, false); @@ -384,6 +398,10 @@ void SConfig::LoadSettings() // GFX Backend ini.Get("Core", "GFXBackend", &m_LocalCoreStartupParameter.m_strVideoBackend, ""); + + // Movie + ini.Get("General", "PauseMovie", &m_PauseMovie, false); + ini.Get("Movie", "Author", &m_strMovieAuthor, ""); } m_SYSCONF = new SysConf(); diff --git a/Source/Core/Core/Src/ConfigManager.h b/Source/Core/Core/Src/ConfigManager.h index 0c8f3f1af1..cbe1b4d1cb 100644 --- a/Source/Core/Core/Src/ConfigManager.h +++ b/Source/Core/Core/Src/ConfigManager.h @@ -75,6 +75,13 @@ struct SConfig : NonCopyable bool m_ListKorea; bool m_ListTaiwan; bool m_ListUnknown; + int m_ListSort; + int m_ListSort2; + + std::string m_WirelessMac; + bool m_PauseMovie; + bool m_ShowLag; + std::string m_strMovieAuthor; SysConf* m_SYSCONF; diff --git a/Source/Core/Core/Src/Core.cpp b/Source/Core/Core/Src/Core.cpp index ec3d0e8f70..e92b9088bc 100644 --- a/Source/Core/Core/Src/Core.cpp +++ b/Source/Core/Core/Src/Core.cpp @@ -18,9 +18,9 @@ #ifdef _WIN32 #include <windows.h> +#include "EmuWindow.h" #endif -#include "Setup.h" // Common #include "Atomic.h" #include "Thread.h" #include "Timer.h" @@ -61,9 +61,6 @@ #include "VideoBackendBase.h" #include "AudioCommon.h" #include "OnScreenDisplay.h" -#ifdef _WIN32 -#include "EmuWindow.h" -#endif #include "VolumeHandler.h" #include "FileMonitor.h" @@ -293,7 +290,7 @@ void Stop() // - Hammertime! SConfig::GetInstance().m_SYSCONF->Reload(); INFO_LOG(CONSOLE, "Stop [Main Thread]\t\t---- Shutdown complete ----"); - Movie::g_currentInputCount = 0; + Movie::Shutdown(); g_bStopping = false; } @@ -434,7 +431,7 @@ void EmuThread() CBoot::BootUp(); // Setup our core, but can't use dynarec if we are compare server - if (_CoreParameter.iCPUCore && (!_CoreParameter.bRunCompareServer || + if (Movie::GetCPUMode() && (!_CoreParameter.bRunCompareServer || _CoreParameter.bRunCompareClient)) PowerPC::SetMode(PowerPC::MODE_JIT); else diff --git a/Source/Core/Core/Src/Core.h b/Source/Core/Core/Src/Core.h index 448bd55bb6..312c446744 100644 --- a/Source/Core/Core/Src/Core.h +++ b/Source/Core/Core/Src/Core.h @@ -95,21 +95,6 @@ void RequestRefreshInfo(); // the return value of the first call should be passed in as the second argument of the second call. bool PauseAndLock(bool doLock, bool unpauseOnUnlock=true); -#ifdef RERECORDING - -void FrameUpdate(); -void FrameAdvance(); -void FrameStepOnOff(); -void WriteStatus(); -void RerecordingStart(); -void RerecordingStop(); -void WindBack(int Counter); - -extern int g_FrameCounter,g_InputCounter; -extern bool g_FrameStep; - -#endif - } // namespace #endif diff --git a/Source/Core/Core/Src/CoreParameter.cpp b/Source/Core/Core/Src/CoreParameter.cpp index ba72d47ffb..dee2452cb3 100644 --- a/Source/Core/Core/Src/CoreParameter.cpp +++ b/Source/Core/Core/Src/CoreParameter.cpp @@ -53,7 +53,7 @@ SCoreStartupParameter::SCoreStartupParameter() bFastDiscSpeed(false), SelectedLanguage(0), bWii(false), bDisableWiimoteSpeaker(false), bConfirmStop(false), bHideCursor(false), - bAutoHideCursor(false), bUsePanicHandlers(true), + bAutoHideCursor(false), bUsePanicHandlers(true), bOnScreenDisplayMessages(true), iRenderWindowXPos(-1), iRenderWindowYPos(-1), iRenderWindowWidth(640), iRenderWindowHeight(480), bRenderWindowAutoSize(false), bKeepWindowOnTop(false), diff --git a/Source/Core/Core/Src/CoreParameter.h b/Source/Core/Core/Src/CoreParameter.h index 2eb261b589..e67935906b 100644 --- a/Source/Core/Core/Src/CoreParameter.h +++ b/Source/Core/Core/Src/CoreParameter.h @@ -122,7 +122,7 @@ struct SCoreStartupParameter bool bDisableWiimoteSpeaker; // Interface settings - bool bConfirmStop, bHideCursor, bAutoHideCursor, bUsePanicHandlers; + bool bConfirmStop, bHideCursor, bAutoHideCursor, bUsePanicHandlers, bOnScreenDisplayMessages; // Hotkeys int iHotkey[NUM_HOTKEYS]; diff --git a/Source/Core/Core/Src/CoreRerecording.cpp b/Source/Core/Core/Src/CoreRerecording.cpp deleted file mode 100644 index 3064ed37ad..0000000000 --- a/Source/Core/Core/Src/CoreRerecording.cpp +++ /dev/null @@ -1,248 +0,0 @@ -// 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 "Setup.h" -#ifndef RERECORDING -bool rerecording = false; -#else - -// Include -// -------------- -#ifdef _WIN32 - #include <windows.h> -#endif - -#include "Thread.h" // Common - -#include "Timer.h" -#include "Common.h" - -#include "Console.h" -#include "Core.h" -#include "CPUDetect.h" -#include "CoreTiming.h" -#include "Boot/Boot.h" -#include "PatchEngine.h" - -#include "HW/Memmap.h" -#include "HW/ProcessorInterface.h" -#include "HW/GPFifo.h" -#include "HW/CPU.h" -#include "HW/HW.h" -#include "HW/DSP.h" -#include "HW/GPFifo.h" -#include "HW/AudioInterface.h" -#include "HW/VideoInterface.h" -#include "HW/CommandProcessor.h" -#include "HW/PixelEngine.h" -#include "HW/SystemTimers.h" - -#include "PowerPC/PowerPC.h" - -#include "ConfigManager.h" - -#include "MemTools.h" -#include "Host.h" -#include "LogManager.h" - - - - - -// File description: Rerecording Functions -/* --------------- - -How the timer works: We measure the time between drawn frames, not when the game is paused. So time -should be a fairly comparable measure of the time it took to play the game. However the time it takes -to draw a frame will be lower on a fast computer. Therefore we could perhaps measure time as an -internal game time that is adjusted by the average time it takes to draw a frame. Also if it only takes -ten or twenty milliseconds to draw a frame I'm not certain about how accurate the mmsystem timers are for -such short periods. - -//////////////////////////////////////*/ - - - -namespace Core -{ - - - -// Declarations and definitions -// --------------- -int g_FrameCounter = 0; -bool g_FrameStep = false; -Common::Timer ReRecTimer; - - - - -// Control Run, Pause, Stop and the Timer. -// --------------- - -// Subtract the paused time when we run again -void Run() -{ - ReRecTimer.AddTimeDifference(); -} -// Update the time -void Pause() -{ - ReRecTimer.Update(); -} - -// Start the timer when a game is booted -void RerecordingStart() -{ - g_FrameCounter = 0; - ReRecTimer.Start(); - - // Logging - //DEBUG_LOG(CONSOLE, "RerecordingStart: %i\n", g_FrameCounter); -} - -// Reset the frame counter -void RerecordingStop() -{ - // Write the final time and Stop the timer - ReRecTimer.Stop(); - - // Update status bar - WriteStatus(); -} - -/* Wind back the frame counter when a save state is loaded. Currently we don't know what that means in - time so we just guess that the time is proportional the the number of frames - - Todo: There are many assumptions here: We probably want to replace the time here by the actual time - that we save together with the save state or the input recording for example. And have it adjusted - for full speed playback (whether it's 30 fps or 60 fps or some other speed that the game is natively - capped at). Also the input interrupts do not occur as often as the frame renderings, they occur more - often. So we may want to move the input recording to fram updates, or perhaps sync the input interrupts - to frame updates. - */ -void WindBack(int Counter) -{ - /* Counter should be smaller than g_FrameCounter, however it currently updates faster than the - frames so currently it may not be the same. Therefore I use the abs() function. */ - int AbsoluteFrameDifference = abs(g_FrameCounter - Counter); - float FractionalFrameDifference = (float) AbsoluteFrameDifference / (float) g_FrameCounter; - - // Update the frame counter - g_FrameCounter = Counter; - - // Approximate a time to wind back the clock to - // Get the current time - u64 CurrentTimeMs = ReRecTimer.GetTimeElapsed(); - // Save the current time in seconds in a new double - double CurrentTimeSeconds = (double) (CurrentTimeMs / 1000); - // Reduce it by the same proportion as the counter was wound back - CurrentTimeSeconds = CurrentTimeSeconds * FractionalFrameDifference; - // Update the clock - ReRecTimer.WindBackStartingTime((u64)CurrentTimeSeconds * 1000); - - // Logging - DEBUG_LOG(CONSOLE, "WindBack: %i %u\n", Counter, (u64)CurrentTimeSeconds); -} - - - - -// Frame advance -// --------------- -void FrameAdvance() -{ - // Update status bar - WriteStatus(); - - // If a game is not started, return - if (Core::GetState() == Core::CORE_UNINITIALIZED) return; - - // Play to the next frame - if (g_FrameStep) - { - Run(); - Core::SetState(Core::CORE_RUN); - } -} - -// Turn on frame stepping -void FrameStepOnOff() -{ - /* Turn frame step on or off. If a game is running and we turn this on it means that the game - will pause after the next frame update */ - g_FrameStep = !g_FrameStep; - - // Update status bar - WriteStatus(); - - // If a game is not started, return - if(Core::GetState() == Core::CORE_UNINITIALIZED) return; - - // Run the emulation if we turned off framestepping - if (!g_FrameStep) - { - Run(); - Core::SetState(Core::CORE_RUN); - } -} - - - - -// General functions -// --------------- - -// Write to the status bar -void WriteStatus() -{ - std::string TmpStr = "Time: " + ReRecTimer.GetTimeElapsedFormatted(); - TmpStr += StringFromFormat(" Frame: %s", ThousandSeparate(g_FrameCounter).c_str()); - // The FPS is the total average since the game was booted - TmpStr += StringFromFormat(" FPS: %i", (g_FrameCounter * 1000) / ReRecTimer.GetTimeElapsed()); - TmpStr += StringFromFormat(" FrameStep: %s", g_FrameStep ? "On" : "Off"); - Host_UpdateStatusBar(TmpStr.c_str(), 1); -} - - -// When a new frame is drawn -void FrameUpdate() -{ - // Write to the status bar - WriteStatus(); - /* I don't think the frequent update has any material speed inpact at all, but should it - have you can controls the update speed by changing the "% 10" in this line */ - //if (g_FrameCounter % 10 == 0) WriteStatus(); - - // Pause if frame stepping is on - if(g_FrameStep) - { - Pause(); - Core::SetState(Core::CORE_PAUSE); - } - - // Count one frame - g_FrameCounter++; -} - - - -} // Core - - -#endif // RERECORDING diff --git a/Source/Core/Core/Src/CoreTiming.cpp b/Source/Core/Core/Src/CoreTiming.cpp index bccadf30cc..525f7165f2 100644 --- a/Source/Core/Core/Src/CoreTiming.cpp +++ b/Source/Core/Core/Src/CoreTiming.cpp @@ -119,7 +119,7 @@ int RegisterEvent(const char *name, TimedCallback callback) // check for existing type with same name. // we want event type names to remain unique so that we can use them for serialization. - for (int i = 0; i < event_types.size(); ++i) + for (unsigned int i = 0; i < event_types.size(); ++i) { if (!strcmp(name, event_types[i].name)) { @@ -188,7 +188,7 @@ void EventDoState(PointerWrap &p, BaseEvent* ev) if (p.GetMode() == PointerWrap::MODE_READ) { bool foundMatch = false; - for (int i = 0; i < event_types.size(); ++i) + for (unsigned int i = 0; i < event_types.size(); ++i) { if (!strcmp(name.c_str(), event_types[i].name)) { diff --git a/Source/Core/Core/Src/DSP/DSPAccelerator.cpp b/Source/Core/Core/Src/DSP/DSPAccelerator.cpp index b1452c249c..dcb79b7ac5 100644 --- a/Source/Core/Core/Src/DSP/DSPAccelerator.cpp +++ b/Source/Core/Core/Src/DSP/DSPAccelerator.cpp @@ -168,7 +168,8 @@ u16 dsp_read_accelerator() if (Address >= EndAddress) { // Set address back to start address. - Address = (g_dsp.ifx_regs[DSP_ACSAH] << 16) | g_dsp.ifx_regs[DSP_ACSAL]; + if ((Address & ~0x1f) == (EndAddress & ~0x1f)) + Address = (g_dsp.ifx_regs[DSP_ACSAH] << 16) | g_dsp.ifx_regs[DSP_ACSAL]; DSPCore_SetException(EXP_ACCOV); } diff --git a/Source/Core/Core/Src/DSP/Jit/DSPJitRegCache.cpp b/Source/Core/Core/Src/DSP/Jit/DSPJitRegCache.cpp index 6bcbeca35e..ee5908889a 100644 --- a/Source/Core/Core/Src/DSP/Jit/DSPJitRegCache.cpp +++ b/Source/Core/Core/Src/DSP/Jit/DSPJitRegCache.cpp @@ -220,8 +220,8 @@ void DSPJitRegCache::flushRegs(DSPJitRegCache &cache, bool emit) for(i = 0; i <= DSP_REG_MAX_MEM_BACKED; i++) { if (cache.regs[i].loc.GetSimpleReg() != regs[i].loc.GetSimpleReg() && - xregs[cache.regs[i].loc.GetSimpleReg()].guest_reg == - DSP_REG_NONE) { + xregs[cache.regs[i].loc.GetSimpleReg()].guest_reg == DSP_REG_NONE) + { movToHostReg(i, cache.regs[i].loc.GetSimpleReg(), true); diff --git a/Source/Core/Core/Src/Debugger/PPCDebugInterface.h b/Source/Core/Core/Src/Debugger/PPCDebugInterface.h index c305235049..5f9e41bb39 100644 --- a/Source/Core/Core/Src/Debugger/PPCDebugInterface.h +++ b/Source/Core/Core/Src/Debugger/PPCDebugInterface.h @@ -34,7 +34,7 @@ public: virtual void step() {} virtual void breakNow(); virtual void runToBreakpoint(); - virtual void insertBLR(unsigned int address, unsigned int); + virtual void insertBLR(unsigned int address, unsigned int value); virtual int getColor(unsigned int address); virtual std::string getDescription(unsigned int address); virtual void showJitResults(u32 address); diff --git a/Source/Core/Core/Src/GeckoCode.cpp b/Source/Core/Core/Src/GeckoCode.cpp index 35b2f53392..2d5f694ded 100644 --- a/Source/Core/Core/Src/GeckoCode.cpp +++ b/Source/Core/Core/Src/GeckoCode.cpp @@ -171,7 +171,7 @@ bool InstallCodeHandler() Memory::Write_U8(1, 0x80001807); // Invalidate the icache - for (int i = 0; i < data.length(); i += 32) + for (unsigned int i = 0; i < data.length(); i += 32) { PowerPC::ppcState.iCache.Invalidate(0x80001800 + i); } diff --git a/Source/Core/Core/Src/GeckoCodeConfig.cpp b/Source/Core/Core/Src/GeckoCodeConfig.cpp index a23d531f7e..10c2068e3e 100644 --- a/Source/Core/Core/Src/GeckoCodeConfig.cpp +++ b/Source/Core/Core/Src/GeckoCodeConfig.cpp @@ -42,8 +42,6 @@ void LoadCodes(const IniFile& inifile, std::vector<GeckoCode>& gcodes) std::istringstream ss(*lines_iter); - int read_state = 0; - switch ((*lines_iter)[0]) { @@ -61,7 +59,6 @@ void LoadCodes(const IniFile& inifile, std::vector<GeckoCode>& gcodes) gcode.name = StripSpaces(gcode.name); // read the code creator name std::getline(ss, gcode.creator, ']'); - read_state = 0; break; // notes diff --git a/Source/Core/Core/Src/HW/AudioInterface.cpp b/Source/Core/Core/Src/HW/AudioInterface.cpp index f4141818ae..0a33e7c773 100644 --- a/Source/Core/Core/Src/HW/AudioInterface.cpp +++ b/Source/Core/Core/Src/HW/AudioInterface.cpp @@ -354,9 +354,6 @@ unsigned int Callback_GetStreaming(short* _pDestBuffer, unsigned int _numSamples static s16 l1 = 0; static s16 l2 = 0; - static s16 r1 = 0; - static s16 r2 = 0; - if ( frac >= 0x10000 || frac == 0) { @@ -364,9 +361,6 @@ unsigned int Callback_GetStreaming(short* _pDestBuffer, unsigned int _numSamples l1 = l2; //current l2 = pcm[pos * 2]; //next - - r1 = r2; //current - r2 = pcm[pos * 2 + 1]; //next } pcm_l = ((l1 << 16) + (l2 - l1) * (u16)frac) >> 16; diff --git a/Source/Core/Core/Src/HW/CPU.cpp b/Source/Core/Core/Src/HW/CPU.cpp index f760abcec6..a7a272e263 100644 --- a/Source/Core/Core/Src/HW/CPU.cpp +++ b/Source/Core/Core/Src/HW/CPU.cpp @@ -24,6 +24,7 @@ #include "../Core.h" #include "CPU.h" #include "DSP.h" +#include "Movie.h" #include "VideoBackendBase.h" @@ -36,6 +37,10 @@ namespace void CCPU::Init(int cpu_core) { + if (Movie::IsPlayingInput() && Movie::IsConfigSaved()) + { + cpu_core = Movie::GetCPUMode(); + } PowerPC::Init(cpu_core); m_SyncEvent = 0; } diff --git a/Source/Core/Core/Src/HW/DSP.cpp b/Source/Core/Core/Src/HW/DSP.cpp index f2509555ed..5945cb7141 100644 --- a/Source/Core/Core/Src/HW/DSP.cpp +++ b/Source/Core/Core/Src/HW/DSP.cpp @@ -697,14 +697,12 @@ void UpdateAudioDMA() void Do_ARAM_DMA() { - // Fake the DMA taking time to complete. The delay is not accurate, but - // seems like a good estimate - CoreTiming::ScheduleEvent_Threadsafe(g_arDMA.Cnt.count >> 1, et_GenerateDSPInterrupt, INT_ARAM | (1<<16)); - // Emulating the DMA wait time fixes Knockout Kings 2003 in DSP HLE mode if (!GetDSPEmulator()->IsLLE()) g_dspState.DSPControl.DMAState = 1; + GenerateDSPInterrupt(INT_ARAM, true); + // Real hardware DMAs in 32byte chunks, but we can get by with 8byte chunks if (g_arDMA.Cnt.dir) { @@ -720,6 +718,8 @@ void Do_ARAM_DMA() { while (g_arDMA.Cnt.count) { + // These are logically seperated in code to show that a memory map has been set up + // See below in the write section for more information if ((g_ARAM_Info.Hex & 0xf) == 3) { Memory::Write_U64_Swap(*(u64*)&g_ARAM.ptr[g_arDMA.ARAddr & g_ARAM.mask], g_arDMA.MMAddr); diff --git a/Source/Core/Core/Src/HW/DSPHLE/DSPHLE.cpp b/Source/Core/Core/Src/HW/DSPHLE/DSPHLE.cpp index 66ee4bef84..817610ea0f 100644 --- a/Source/Core/Core/Src/HW/DSPHLE/DSPHLE.cpp +++ b/Source/Core/Core/Src/HW/DSPHLE/DSPHLE.cpp @@ -20,7 +20,6 @@ #include "ChunkFile.h" #include "IniFile.h" #include "HLEMixer.h" -#include "Setup.h" #include "StringUtil.h" #include "LogManager.h" #include "IniFile.h" diff --git a/Source/Core/Core/Src/HW/DSPHLE/UCodes/UCode_AX.cpp b/Source/Core/Core/Src/HW/DSPHLE/UCodes/UCode_AX.cpp index da4b10f34e..81ef7c6482 100644 --- a/Source/Core/Core/Src/HW/DSPHLE/UCodes/UCode_AX.cpp +++ b/Source/Core/Core/Src/HW/DSPHLE/UCodes/UCode_AX.cpp @@ -12,459 +12,683 @@ // 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 +// Official Git repository and contact information can be found at // http://code.google.com/p/dolphin-emu/ -#include "FileUtil.h" // For IsDirectory() -#include "StringUtil.h" // For StringFromFormat() -#include <sstream> - -#include "Mixer.h" -#include "../MailHandler.h" -#include "../../DSP.h" -#include "UCodes.h" -#include "UCode_AXStructs.h" #include "UCode_AX.h" +#include "../../DSP.h" + +#define AX_GC #include "UCode_AX_Voice.h" -CUCode_AX::CUCode_AX(DSPHLE *dsp_hle, u32 l_CRC) - : IUCode(dsp_hle, l_CRC) - , m_addressPBs(0xFFFFFFFF) +CUCode_AX::CUCode_AX(DSPHLE* dsp_hle, u32 crc) + : IUCode(dsp_hle, crc) + , m_cmdlist_size(0) + , m_axthread(&SpawnAXThread, this) { - // we got loaded + WARN_LOG(DSPHLE, "Instantiating CUCode_AX: crc=%08x", crc); m_rMailHandler.PushMail(DSP_INIT); - - templbuffer = new int[1024 * 1024]; - temprbuffer = new int[1024 * 1024]; + DSP::GenerateDSPInterruptFromDSPEmu(DSP::INT_DSP); } CUCode_AX::~CUCode_AX() { + m_cmdlist_size = (u16)-1; // Special value to signal end + NotifyAXThread(); + m_axthread.join(); + m_rMailHandler.Clear(); - delete [] templbuffer; - delete [] temprbuffer; } -// Needs A LOT of love! -static void ProcessUpdates(AXPB &PB) +void CUCode_AX::SpawnAXThread(CUCode_AX* self) { - // Make the updates we are told to do. When there are multiple updates for a block they - // are placed in memory directly following updaddr. They are mostly for initial time - // delays, sometimes for the FIR filter or channel volumes. We do all of them at once here. - // If we get both an on and an off update we chose on. Perhaps that makes the RE1 music - // work better. - int numupd = PB.updates.num_updates[0] - + PB.updates.num_updates[1] - + PB.updates.num_updates[2] - + PB.updates.num_updates[3] - + PB.updates.num_updates[4]; - if (numupd > 64) numupd = 64; // prevent crazy values TODO: LOL WHAT - const u32 updaddr = (u32)(PB.updates.data_hi << 16) | PB.updates.data_lo; - int on = 0, off = 0; - for (int j = 0; j < numupd; j++) + self->AXThread(); +} + +void CUCode_AX::AXThread() +{ + while (true) { - const u16 updpar = HLEMemory_Read_U16(updaddr + j*4); - const u16 upddata = HLEMemory_Read_U16(updaddr + j*4 + 2); - // some safety checks, I hope it's enough - if (updaddr > 0x80000000 && updaddr < 0x817fffff - && updpar < 63 && updpar > 3 // updpar > 3 because we don't want to change - // 0-3, those are important - //&& (upd0 || upd1 || upd2 || upd3 || upd4) // We should use these in some way to I think - // but I don't know how or when - ) { - ((u16*)&PB)[updpar] = upddata; // WTF ABOUNDS! + std::unique_lock<std::mutex> lk(m_cmdlist_mutex); + while (m_cmdlist_size == 0) + m_cmdlist_cv.wait(lk); } - if (updpar == 7 && upddata != 0) on++; - if (updpar == 7 && upddata == 0) off++; + + if (m_cmdlist_size == (u16)-1) // End of thread signal + break; + + m_processing.lock(); + HandleCommandList(); + m_cmdlist_size = 0; + + // Signal end of processing + m_rMailHandler.PushMail(DSP_YIELD); + DSP::GenerateDSPInterruptFromDSPEmu(DSP::INT_DSP); + m_processing.unlock(); } - // hack: if we get both an on and an off select on rather than off - if (on > 0 && off > 0) PB.running = 1; } -static void VoiceHacks(AXPB &pb) +void CUCode_AX::NotifyAXThread() +{ + std::unique_lock<std::mutex> lk(m_cmdlist_mutex); + m_cmdlist_cv.notify_one(); +} + +void CUCode_AX::HandleCommandList() { - // get necessary values - const u32 sampleEnd = (pb.audio_addr.end_addr_hi << 16) | pb.audio_addr.end_addr_lo; - const u32 loopPos = (pb.audio_addr.loop_addr_hi << 16) | pb.audio_addr.loop_addr_lo; - // const u32 updaddr = (u32)(pb.updates.data_hi << 16) | pb.updates.data_lo; - // const u16 updpar = HLEMemory_Read_U16(updaddr); - // const u16 upddata = HLEMemory_Read_U16(updaddr + 2); - - // ======================================================================================= - /* Fix problems introduced with the SSBM fix. Sometimes when a music stream ended sampleEnd - would end up outside of bounds while the block was still playing resulting in noise - a strange noise. This should take care of that. - */ - if ((sampleEnd > (0x017fffff * 2) || loopPos > (0x017fffff * 2))) // ARAM bounds in nibbles + // Temp variables for addresses computation + u16 addr_hi, addr_lo; + u16 addr2_hi, addr2_lo; + u16 size; + + u32 pb_addr = 0; + +#if 0 + WARN_LOG(DSPHLE, "Command list:"); + for (u32 i = 0; m_cmdlist[i] != CMD_END; ++i) + WARN_LOG(DSPHLE, "%04x", m_cmdlist[i]); + WARN_LOG(DSPHLE, "-------------"); +#endif + + u32 curr_idx = 0; + bool end = false; + while (!end) { - pb.running = 0; + u16 cmd = m_cmdlist[curr_idx++]; - // also reset all values if it makes any difference - pb.audio_addr.cur_addr_hi = 0; pb.audio_addr.cur_addr_lo = 0; - pb.audio_addr.end_addr_hi = 0; pb.audio_addr.end_addr_lo = 0; - pb.audio_addr.loop_addr_hi = 0; pb.audio_addr.loop_addr_lo = 0; + switch (cmd) + { + // Some of these commands are unknown, or unused in this AX HLE. + // We still need to skip their arguments using "curr_idx += N". - pb.src.cur_addr_frac = 0; pb.src.ratio_hi = 0; pb.src.ratio_lo = 0; - pb.adpcm.pred_scale = 0; pb.adpcm.yn1 = 0; pb.adpcm.yn2 = 0; + case CMD_SETUP: + addr_hi = m_cmdlist[curr_idx++]; + addr_lo = m_cmdlist[curr_idx++]; + SetupProcessing(HILO_TO_32(addr)); + break; - pb.audio_addr.looping = 0; - pb.adpcm_loop_info.pred_scale = 0; - pb.adpcm_loop_info.yn1 = 0; pb.adpcm_loop_info.yn2 = 0; - } + case CMD_DL_AND_VOL_MIX: + { + addr_hi = m_cmdlist[curr_idx++]; + addr_lo = m_cmdlist[curr_idx++]; + u16 vol_main = m_cmdlist[curr_idx++]; + u16 vol_auxa = m_cmdlist[curr_idx++]; + u16 vol_auxb = m_cmdlist[curr_idx++]; + DownloadAndMixWithVolume(HILO_TO_32(addr), vol_main, vol_auxa, vol_auxb); + break; + } - /* - // the fact that no settings are reset (except running) after a SSBM type music stream or another - looping block (for example in Battle Stadium DON) has ended could cause loud garbled sound to be - played from one or more blocks. Perhaps it was in conjunction with the old sequenced music fix below, - I'm not sure. This was an attempt to prevent that anyway by resetting all. But I'm not sure if this - is needed anymore. Please try to play SSBM without it and see if it works anyway. - */ - if ( - // detect blocks that have recently been running that we should reset - pb.running == 0 && pb.audio_addr.looping == 1 - //pb.running == 0 && pb.adpcm_loop_info.pred_scale - - // this prevents us from ruining sequenced music blocks, may not be needed - /* - && !(pb.updates.num_updates[0] || pb.updates.num_updates[1] || pb.updates.num_updates[2] - || pb.updates.num_updates[3] || pb.updates.num_updates[4]) - */ - //&& !(updpar || upddata) - - && pb.mixer_control == 0 // only use this in SSBM - ) - { - // reset the detection values - pb.audio_addr.looping = 0; - pb.adpcm_loop_info.pred_scale = 0; - pb.adpcm_loop_info.yn1 = 0; pb.adpcm_loop_info.yn2 = 0; + case CMD_PB_ADDR: + addr_hi = m_cmdlist[curr_idx++]; + addr_lo = m_cmdlist[curr_idx++]; + pb_addr = HILO_TO_32(addr); + break; - //pb.audio_addr.cur_addr_hi = 0; pb.audio_addr.cur_addr_lo = 0; - //pb.audio_addr.end_addr_hi = 0; pb.audio_addr.end_addr_lo = 0; - //pb.audio_addr.loop_addr_hi = 0; pb.audio_addr.loop_addr_lo = 0; + case CMD_PROCESS: + ProcessPBList(pb_addr); + break; - //pb.src.cur_addr_frac = 0; PBs[i].src.ratio_hi = 0; PBs[i].src.ratio_lo = 0; - //pb.adpcm.pred_scale = 0; pb.adpcm.yn1 = 0; pb.adpcm.yn2 = 0; - } -} + case CMD_MIX_AUXA: + case CMD_MIX_AUXB: + // These two commands are handled almost the same internally. + addr_hi = m_cmdlist[curr_idx++]; + addr_lo = m_cmdlist[curr_idx++]; + addr2_hi = m_cmdlist[curr_idx++]; + addr2_lo = m_cmdlist[curr_idx++]; + MixAUXSamples(cmd - CMD_MIX_AUXA, HILO_TO_32(addr), HILO_TO_32(addr2)); + break; -void CUCode_AX::MixAdd(short* _pBuffer, int _iSize) -{ - if (_iSize > 1024 * 1024) - _iSize = 1024 * 1024; + case CMD_UPLOAD_LRS: + addr_hi = m_cmdlist[curr_idx++]; + addr_lo = m_cmdlist[curr_idx++]; + UploadLRS(HILO_TO_32(addr)); + break; - memset(templbuffer, 0, _iSize * sizeof(int)); - memset(temprbuffer, 0, _iSize * sizeof(int)); + case CMD_SET_LR: + addr_hi = m_cmdlist[curr_idx++]; + addr_lo = m_cmdlist[curr_idx++]; + SetMainLR(HILO_TO_32(addr)); + break; - AXPB PB; + case CMD_UNK_08: curr_idx += 10; break; // TODO: check - for (int x = 0; x < numPBaddr; x++) - { - //u32 blockAddr = m_addressPBs; - u32 blockAddr = PBaddr[x]; + case CMD_MIX_AUXB_NOWRITE: + addr_hi = m_cmdlist[curr_idx++]; + addr_lo = m_cmdlist[curr_idx++]; + MixAUXSamples(false, 0, HILO_TO_32(addr)); + break; - if (!blockAddr) - return; + case CMD_COMPRESSOR_TABLE_ADDR: curr_idx += 2; break; + case CMD_UNK_0B: break; // TODO: check other versions + case CMD_UNK_0C: break; // TODO: check other versions + + case CMD_MORE: + addr_hi = m_cmdlist[curr_idx++]; + addr_lo = m_cmdlist[curr_idx++]; + size = m_cmdlist[curr_idx++]; + + CopyCmdList(HILO_TO_32(addr), size); + curr_idx = 0; + break; + + case CMD_OUTPUT: + addr_hi = m_cmdlist[curr_idx++]; + addr_lo = m_cmdlist[curr_idx++]; + addr2_hi = m_cmdlist[curr_idx++]; + addr2_lo = m_cmdlist[curr_idx++]; + OutputSamples(HILO_TO_32(addr2), HILO_TO_32(addr)); + break; + + case CMD_END: + end = true; + break; + + case CMD_MIX_AUXB_LR: + addr_hi = m_cmdlist[curr_idx++]; + addr_lo = m_cmdlist[curr_idx++]; + addr2_hi = m_cmdlist[curr_idx++]; + addr2_lo = m_cmdlist[curr_idx++]; + MixAUXBLR(HILO_TO_32(addr), HILO_TO_32(addr2)); + break; + + case CMD_UNK_11: curr_idx += 2; break; + + case CMD_UNK_12: + { + u16 samp_val = m_cmdlist[curr_idx++]; + u16 idx = m_cmdlist[curr_idx++]; + addr_hi = m_cmdlist[curr_idx++]; + addr_lo = m_cmdlist[curr_idx++]; + + // TODO + (void)samp_val; + (void)idx; - for (int i = 0; i < NUMBER_OF_PBS; i++) - { - if (!ReadPB(blockAddr, PB)) break; + } + + // Send the contents of MAIN LRS, AUXA LRS and AUXB S to RAM, and + // mix data to MAIN LR and AUXB LR. + case CMD_SEND_AUX_AND_MIX: + { + // Address for Main + AUXA LRS upload + u16 main_auxa_up_hi = m_cmdlist[curr_idx++]; + u16 main_auxa_up_lo = m_cmdlist[curr_idx++]; - ProcessUpdates(PB); + // Address for AUXB S upload + u16 auxb_s_up_hi = m_cmdlist[curr_idx++]; + u16 auxb_s_up_lo = m_cmdlist[curr_idx++]; - if (m_CRC != 0x3389a79e) - VoiceHacks(PB); + // Address to read data for Main L + u16 main_l_dl_hi = m_cmdlist[curr_idx++]; + u16 main_l_dl_lo = m_cmdlist[curr_idx++]; - MixAddVoice(PB, templbuffer, temprbuffer, _iSize); + // Address to read data for Main R + u16 main_r_dl_hi = m_cmdlist[curr_idx++]; + u16 main_r_dl_lo = m_cmdlist[curr_idx++]; - if (!WritePB(blockAddr, PB)) + // Address to read data for AUXB L + u16 auxb_l_dl_hi = m_cmdlist[curr_idx++]; + u16 auxb_l_dl_lo = m_cmdlist[curr_idx++]; + + // Address to read data for AUXB R + u16 auxb_r_dl_hi = m_cmdlist[curr_idx++]; + u16 auxb_r_dl_lo = m_cmdlist[curr_idx++]; + + SendAUXAndMix(HILO_TO_32(main_auxa_up), HILO_TO_32(auxb_s_up), + HILO_TO_32(main_l_dl), HILO_TO_32(main_r_dl), + HILO_TO_32(auxb_l_dl), HILO_TO_32(auxb_r_dl)); break; + } - // next PB, or done - blockAddr = (PB.next_pb_hi << 16) | PB.next_pb_lo; - if (!blockAddr) + default: + ERROR_LOG(DSPHLE, "Unknown command in AX cmdlist: %04x", cmd); + end = true; break; } } +} + +static void ApplyUpdatesForMs(AXPB& pb, int curr_ms) +{ + u32 start_idx = 0; + for (int i = 0; i < curr_ms; ++i) + start_idx += pb.updates.num_updates[i]; - if (_pBuffer) + u32 update_addr = HILO_TO_32(pb.updates.data); + for (u32 i = start_idx; i < start_idx + pb.updates.num_updates[curr_ms]; ++i) { - for (int i = 0; i < _iSize; i++) - { - // Clamp into 16-bit. Maybe we should add a volume compressor here. - int left = templbuffer[i] + _pBuffer[0]; - int right = temprbuffer[i] + _pBuffer[1]; - if (left < -32767) left = -32767; - if (left > 32767) left = 32767; - if (right < -32767) right = -32767; - if (right > 32767) right = 32767; - *_pBuffer++ = left; - *_pBuffer++ = right; - } + u16 update_off = HLEMemory_Read_U16(update_addr + 4 * i); + u16 update_val = HLEMemory_Read_U16(update_addr + 4 * i + 2); + + ((u16*)&pb)[update_off] = update_val; } } - -// ------------------------------------------------------------------------------ -// Handle incoming mail -void CUCode_AX::HandleMail(u32 _uMail) +AXMixControl CUCode_AX::ConvertMixerControl(u32 mixer_control) { - if (m_UploadSetupInProgress) + u32 ret = 0; + + // TODO: find other UCode versions with different mixer_control values + if (m_CRC == 0x4e8a8b21) { - PrepareBootUCode(_uMail); - return; - } - else { - if ((_uMail & 0xFFFF0000) == MAIL_AX_ALIST) - { - // We are expected to get a new CmdBlock - DEBUG_LOG(DSPHLE, "GetNextCmdBlock (%ibytes)", (u16)_uMail); - } - else if (_uMail == 0xCDD10000) // Action 0 - AX_ResumeTask(); + ret |= MIX_L | MIX_R; + if (mixer_control & 0x0001) ret |= MIX_AUXA_L | MIX_AUXA_R; + if (mixer_control & 0x0002) ret |= MIX_AUXB_L | MIX_AUXB_R; + if (mixer_control & 0x0004) { - m_rMailHandler.PushMail(DSP_RESUME); + ret |= MIX_S; + if (ret & MIX_AUXA_L) ret |= MIX_AUXA_S; + if (ret & MIX_AUXB_L) ret |= MIX_AUXB_S; } - else if (_uMail == 0xCDD10001) // Action 1 - new ucode upload ( GC: BayBlade S.T.B,...) + if (mixer_control & 0x0008) { - DEBUG_LOG(DSPHLE,"DSP IROM - New Ucode!"); - // TODO find a better way to protect from HLEMixer? - soundStream->GetMixer()->SetHLEReady(false); - m_UploadSetupInProgress = true; + ret |= MIX_L_RAMP | MIX_R_RAMP; + if (ret & MIX_AUXA_L) ret |= MIX_AUXA_L_RAMP | MIX_AUXA_R_RAMP; + if (ret & MIX_AUXB_L) ret |= MIX_AUXB_L_RAMP | MIX_AUXB_R_RAMP; + if (ret & MIX_AUXA_S) ret |= MIX_AUXA_S_RAMP; + if (ret & MIX_AUXB_S) ret |= MIX_AUXB_S_RAMP; } - else if (_uMail == 0xCDD10002) // Action 2 - IROM_Reset(); ( GC: NFS Carbon, FF Crystal Chronicles,...) + } + else + { + if (mixer_control & 0x0001) ret |= MIX_L; + if (mixer_control & 0x0002) ret |= MIX_R; + if (mixer_control & 0x0004) ret |= MIX_S; + if (mixer_control & 0x0008) ret |= MIX_L_RAMP | MIX_R_RAMP | MIX_S_RAMP; + if (mixer_control & 0x0010) ret |= MIX_AUXA_L; + if (mixer_control & 0x0020) ret |= MIX_AUXA_R; + if (mixer_control & 0x0040) ret |= MIX_AUXA_L_RAMP | MIX_AUXA_R_RAMP; + if (mixer_control & 0x0080) ret |= MIX_AUXA_S; + if (mixer_control & 0x0100) ret |= MIX_AUXA_S_RAMP; + if (mixer_control & 0x0200) ret |= MIX_AUXB_L; + if (mixer_control & 0x0400) ret |= MIX_AUXB_R; + if (mixer_control & 0x0800) ret |= MIX_AUXB_L_RAMP | MIX_AUXB_R_RAMP; + if (mixer_control & 0x1000) ret |= MIX_AUXB_S; + if (mixer_control & 0x2000) ret |= MIX_AUXB_S_RAMP; + + // TODO: 0x4000 is used for Dolby Pro 2 sound mixing + } + + return (AXMixControl)ret; +} + +void CUCode_AX::SetupProcessing(u32 init_addr) +{ + u16 init_data[0x20]; + + for (u32 i = 0; i < 0x20; ++i) + init_data[i] = HLEMemory_Read_U16(init_addr + 2 * i); + + // List of all buffers we have to initialize + int* buffers[] = { + m_samples_left, + m_samples_right, + m_samples_surround, + m_samples_auxA_left, + m_samples_auxA_right, + m_samples_auxA_surround, + m_samples_auxB_left, + m_samples_auxB_right, + m_samples_auxB_surround + }; + + u32 init_idx = 0; + for (u32 i = 0; i < sizeof (buffers) / sizeof (buffers[0]); ++i) + { + s32 init_val = (s32)((init_data[init_idx] << 16) | init_data[init_idx + 1]); + s16 delta = (s16)init_data[init_idx + 2]; + + init_idx += 3; + + if (!init_val) + memset(buffers[i], 0, 5 * 32 * sizeof (int)); + else { - DEBUG_LOG(DSPHLE,"DSP IROM - Reset!"); - m_DSPHLE->SetUCode(UCODE_ROM); - return; + for (u32 j = 0; j < 32 * 5; ++j) + { + buffers[i][j] = init_val; + init_val += delta; + } } - else if (_uMail == 0xCDD10003) // Action 3 - AX_GetNextCmdBlock(); + } +} + +void CUCode_AX::DownloadAndMixWithVolume(u32 addr, u16 vol_main, u16 vol_auxa, u16 vol_auxb) +{ + int* buffers_main[3] = { m_samples_left, m_samples_right, m_samples_surround }; + int* buffers_auxa[3] = { m_samples_auxA_left, m_samples_auxA_right, m_samples_auxA_surround }; + int* buffers_auxb[3] = { m_samples_auxB_left, m_samples_auxB_right, m_samples_auxB_surround }; + int** buffers[3] = { buffers_main, buffers_auxa, buffers_auxb }; + u16 volumes[3] = { vol_main, vol_auxa, vol_auxb }; + + for (u32 i = 0; i < 3; ++i) + { + int* ptr = (int*)HLEMemory_Get_Pointer(addr); + u16 volume = volumes[i]; + for (u32 j = 0; j < 3; ++j) { + int* buffer = buffers[i][j]; + for (u32 k = 0; k < 5 * 32; ++k) + { + s64 sample = (s64)(s32)Common::swap32(*ptr++); + sample *= volume; + buffer[k] += (s32)(sample >> 15); + } } - else + } +} + +void CUCode_AX::ProcessPBList(u32 pb_addr) +{ + // Samples per millisecond. In theory DSP sampling rate can be changed from + // 32KHz to 48KHz, but AX always process at 32KHz. + const u32 spms = 32; + + AXPB pb; + + while (pb_addr) + { + AXBuffers buffers = {{ + m_samples_left, + m_samples_right, + m_samples_surround, + m_samples_auxA_left, + m_samples_auxA_right, + m_samples_auxA_surround, + m_samples_auxB_left, + m_samples_auxB_right, + m_samples_auxB_surround + }}; + + if (!ReadPB(pb_addr, pb)) + break; + + for (int curr_ms = 0; curr_ms < 5; ++curr_ms) { - DEBUG_LOG(DSPHLE, " >>>> u32 MAIL : AXTask Mail (%08x)", _uMail); - AXTask(_uMail); + ApplyUpdatesForMs(pb, curr_ms); + + Process1ms(pb, buffers, ConvertMixerControl(pb.mixer_control)); + + // Forward the buffers + for (u32 i = 0; i < sizeof (buffers.ptrs) / sizeof (buffers.ptrs[0]); ++i) + buffers.ptrs[i] += spms; } + + WritePB(pb_addr, pb); + pb_addr = HILO_TO_32(pb.next_pb); } } - -// ------------------------------------------------------------------------------ -// Update with DSP Interrupt -void CUCode_AX::Update(int cycles) +void CUCode_AX::MixAUXSamples(int aux_id, u32 write_addr, u32 read_addr) { - if (NeedsResumeMail()) + int* buffers[3] = { 0 }; + + switch (aux_id) { - m_rMailHandler.PushMail(DSP_RESUME); - DSP::GenerateDSPInterruptFromDSPEmu(DSP::INT_DSP); + case 0: + buffers[0] = m_samples_auxA_left; + buffers[1] = m_samples_auxA_right; + buffers[2] = m_samples_auxA_surround; + break; + + case 1: + buffers[0] = m_samples_auxB_left; + buffers[1] = m_samples_auxB_right; + buffers[2] = m_samples_auxB_surround; + break; } - // check if we have to send something - else if (!m_rMailHandler.IsEmpty()) + + // First, we need to send the contents of our AUX buffers to the CPU. + if (write_addr) { - DSP::GenerateDSPInterruptFromDSPEmu(DSP::INT_DSP); + int* ptr = (int*)HLEMemory_Get_Pointer(write_addr); + for (u32 i = 0; i < 3; ++i) + for (u32 j = 0; j < 5 * 32; ++j) + *ptr++ = Common::swap32(buffers[i][j]); } + + // Then, we read the new temp from the CPU and add to our current + // temp. + int* ptr = (int*)HLEMemory_Get_Pointer(read_addr); + for (u32 i = 0; i < 5 * 32; ++i) + m_samples_left[i] += (int)Common::swap32(*ptr++); + for (u32 i = 0; i < 5 * 32; ++i) + m_samples_right[i] += (int)Common::swap32(*ptr++); + for (u32 i = 0; i < 5 * 32; ++i) + m_samples_surround[i] += (int)Common::swap32(*ptr++); } -// ============================================ -// AX seems to bootup one task only and waits for resume-callbacks -// everytime the DSP has "spare time" it sends a resume-mail to the CPU -// and the __DSPHandler calls a AX-Callback which generates a new AXFrame -bool CUCode_AX::AXTask(u32& _uMail) +void CUCode_AX::UploadLRS(u32 dst_addr) { - u32 uAddress = _uMail; - DEBUG_LOG(DSPHLE, "Begin"); - DEBUG_LOG(DSPHLE, "====================================================================="); - DEBUG_LOG(DSPHLE, "%08x : AXTask - AXCommandList-Addr:", uAddress); - - u32 Addr__AXStudio; - u32 Addr__AXOutSBuffer; - u32 Addr__AXOutSBuffer_1; - u32 Addr__AXOutSBuffer_2; - u32 Addr__A; - u32 Addr__12; - u32 Addr__4_1; - u32 Addr__4_2; - //u32 Addr__4_3; - //u32 Addr__4_4; - u32 Addr__5_1; - u32 Addr__5_2; - u32 Addr__6; - u32 Addr__9; - - bool bExecuteList = true; - - numPBaddr = 0; - - while (bExecuteList) + int buffers[3][5 * 32]; + + for (u32 i = 0; i < 5 * 32; ++i) { - static int last_valid_command = 0; - u16 iCommand = HLEMemory_Read_U16(uAddress); - uAddress += 2; + buffers[0][i] = Common::swap32(m_samples_left[i]); + buffers[1][i] = Common::swap32(m_samples_right[i]); + buffers[2][i] = Common::swap32(m_samples_surround[i]); + } + memcpy(HLEMemory_Get_Pointer(dst_addr), buffers, sizeof (buffers)); +} - switch (iCommand) - { - case AXLIST_STUDIOADDR: //00 - Addr__AXStudio = HLEMemory_Read_U32(uAddress); - uAddress += 4; - DEBUG_LOG(DSPHLE, "%08x : AXLIST studio address: %08x", uAddress, Addr__AXStudio); - break; +void CUCode_AX::SetMainLR(u32 src_addr) +{ + int* ptr = (int*)HLEMemory_Get_Pointer(src_addr); + for (u32 i = 0; i < 5 * 32; ++i) + { + int samp = (int)Common::swap32(*ptr++); + m_samples_left[i] = samp; + m_samples_right[i] = samp; + m_samples_surround[i] = 0; + } +} - case 0x001: // 2byte x 10 - { - u32 address = HLEMemory_Read_U32(uAddress); - uAddress += 4; - u16 param1 = HLEMemory_Read_U16(uAddress); - uAddress += 2; - u16 param2 = HLEMemory_Read_U16(uAddress); - uAddress += 2; - u16 param3 = HLEMemory_Read_U16(uAddress); - uAddress += 2; - DEBUG_LOG(DSPHLE, "%08x : AXLIST 1: %08x, %04x, %04x, %04x", uAddress, address, param1, param2, param3); - } - break; +void CUCode_AX::OutputSamples(u32 lr_addr, u32 surround_addr) +{ + int surround_buffer[5 * 32]; - // - // Somewhere we should be getting a bitmask of AX_SYNC values - // that tells us what has been updated - // Dunno if important - // - case AXLIST_PBADDR: //02 - { - PBaddr[numPBaddr] = HLEMemory_Read_U32(uAddress); - numPBaddr++; + for (u32 i = 0; i < 5 * 32; ++i) + surround_buffer[i] = Common::swap32(m_samples_surround[i]); + memcpy(HLEMemory_Get_Pointer(surround_addr), surround_buffer, sizeof (surround_buffer)); - m_addressPBs = HLEMemory_Read_U32(uAddress); // left in for now - uAddress += 4; - soundStream->GetMixer()->SetHLEReady(true); - DEBUG_LOG(DSPHLE, "%08x : AXLIST PB address: %08x", uAddress, m_addressPBs); - } - break; + // 32 samples per ms, 5 ms, 2 channels + short buffer[5 * 32 * 2]; - case 0x0003: - DEBUG_LOG(DSPHLE, "%08x : AXLIST command 0x0003 ????", uAddress); - break; + // Output samples clamped to 16 bits and interlaced RLRLRLRLRL... + for (u32 i = 0; i < 5 * 32; ++i) + { + int left = m_samples_left[i]; + int right = m_samples_right[i]; - case 0x0004: // AUX? - Addr__4_1 = HLEMemory_Read_U32(uAddress); - uAddress += 4; - Addr__4_2 = HLEMemory_Read_U32(uAddress); - uAddress += 4; - DEBUG_LOG(DSPHLE, "%08x : AXLIST 4_1 4_2 addresses: %08x %08x", uAddress, Addr__4_1, Addr__4_2); - break; + if (left < -32767) left = -32767; + if (left > 32767) left = 32767; + if (right < -32767) right = -32767; + if (right > 32767) right = 32767; - case 0x0005: - Addr__5_1 = HLEMemory_Read_U32(uAddress); - uAddress += 4; - Addr__5_2 = HLEMemory_Read_U32(uAddress); - uAddress += 4; - DEBUG_LOG(DSPHLE, "%08x : AXLIST 5_1 5_2 addresses: %08x %08x", uAddress, Addr__5_1, Addr__5_2); - break; + buffer[2 * i] = Common::swap16(right); + buffer[2 * i + 1] = Common::swap16(left); + } - case 0x0006: - Addr__6 = HLEMemory_Read_U32(uAddress); - uAddress += 4; - DEBUG_LOG(DSPHLE, "%08x : AXLIST 6 address: %08x", uAddress, Addr__6); - break; + memcpy(HLEMemory_Get_Pointer(lr_addr), buffer, sizeof (buffer)); +} - case AXLIST_SBUFFER: - Addr__AXOutSBuffer = HLEMemory_Read_U32(uAddress); - uAddress += 4; - DEBUG_LOG(DSPHLE, "%08x : AXLIST OutSBuffer address: %08x", uAddress, Addr__AXOutSBuffer); - break; +void CUCode_AX::MixAUXBLR(u32 ul_addr, u32 dl_addr) +{ + // Upload AUXB L/R + int* ptr = (int*)HLEMemory_Get_Pointer(ul_addr); + for (u32 i = 0; i < 5 * 32; ++i) + *ptr++ = Common::swap32(m_samples_auxB_left[i]); + for (u32 i = 0; i < 5 * 32; ++i) + *ptr++ = Common::swap32(m_samples_auxB_right[i]); + + // Mix AUXB L/R to MAIN L/R, and replace AUXB L/R + ptr = (int*)HLEMemory_Get_Pointer(dl_addr); + for (u32 i = 0; i < 5 * 32; ++i) + { + int samp = Common::swap32(*ptr++); + m_samples_auxB_left[i] = samp; + m_samples_left[i] += samp; + } + for (u32 i = 0; i < 5 * 32; ++i) + { + int samp = Common::swap32(*ptr++); + m_samples_auxB_right[i] = samp; + m_samples_right[i] += samp; + } +} - case 0x0009: - Addr__9 = HLEMemory_Read_U32(uAddress); - uAddress += 4; - DEBUG_LOG(DSPHLE, "%08x : AXLIST 6 address: %08x", uAddress, Addr__9); - break; +void CUCode_AX::SendAUXAndMix(u32 main_auxa_up, u32 auxb_s_up, u32 main_l_dl, + u32 main_r_dl, u32 auxb_l_dl, u32 auxb_r_dl) +{ + // Buffers to upload first + int* up_buffers[] = { + m_samples_auxA_left, + m_samples_auxA_right, + m_samples_auxA_surround + }; + + // Upload AUXA LRS + int* ptr = (int*)HLEMemory_Get_Pointer(main_auxa_up); + for (u32 i = 0; i < sizeof (up_buffers) / sizeof (up_buffers[0]); ++i) + for (u32 j = 0; j < 32 * 5; ++j) + *ptr++ = Common::swap32(up_buffers[i][j]); + + // Upload AUXB S + ptr = (int*)HLEMemory_Get_Pointer(auxb_s_up); + for (u32 i = 0; i < 32 * 5; ++i) + *ptr++ = Common::swap32(m_samples_auxB_surround[i]); + + // Download buffers and addresses + int* dl_buffers[] = { + m_samples_left, + m_samples_right, + m_samples_auxB_left, + m_samples_auxB_right + }; + u32 dl_addrs[] = { + main_l_dl, + main_r_dl, + auxb_l_dl, + auxb_r_dl + }; + + // Download and mix + for (u32 i = 0; i < sizeof (dl_buffers) / sizeof (dl_buffers[0]); ++i) + { + int* dl_src = (int*)HLEMemory_Get_Pointer(dl_addrs[i]); + for (u32 j = 0; j < 32 * 5; ++j) + dl_buffers[i][j] += (int)Common::swap32(*dl_src++); + } +} - case AXLIST_COMPRESSORTABLE: // 0xa - Addr__A = HLEMemory_Read_U32(uAddress); - uAddress += 4; - DEBUG_LOG(DSPHLE, "%08x : AXLIST CompressorTable address: %08x", uAddress, Addr__A); - break; +void CUCode_AX::HandleMail(u32 mail) +{ + // Indicates if the next message is a command list address. + static bool next_is_cmdlist = false; + static u16 cmdlist_size = 0; - case 0x000e: - Addr__AXOutSBuffer_1 = HLEMemory_Read_U32(uAddress); - uAddress += 4; + bool set_next_is_cmdlist = false; - // Addr__AXOutSBuffer_2 is the address in RAM that we are supposed to mix to. - // Although we don't, currently. - Addr__AXOutSBuffer_2 = HLEMemory_Read_U32(uAddress); - uAddress += 4; - DEBUG_LOG(DSPHLE, "%08x : AXLIST sbuf2 addresses: %08x %08x", uAddress, Addr__AXOutSBuffer_1, Addr__AXOutSBuffer_2); - break; + // Wait for DSP processing to be done before answering any mail. This is + // safe to do because it matches what the DSP does on real hardware: there + // is no interrupt when a mail from CPU is received. + m_processing.lock(); - case AXLIST_END: - bExecuteList = false; - DEBUG_LOG(DSPHLE, "%08x : AXLIST end", uAddress); - break; + if (next_is_cmdlist) + { + CopyCmdList(mail, cmdlist_size); + NotifyAXThread(); + } + else if (m_UploadSetupInProgress) + { + PrepareBootUCode(mail); + } + else if (mail == MAIL_RESUME) + { + // Acknowledge the resume request + m_rMailHandler.PushMail(DSP_RESUME); + DSP::GenerateDSPInterruptFromDSPEmu(DSP::INT_DSP); + } + else if (mail == MAIL_NEW_UCODE) + { + soundStream->GetMixer()->SetHLEReady(false); + m_UploadSetupInProgress = true; + } + else if (mail == MAIL_RESET) + { + m_DSPHLE->SetUCode(UCODE_ROM); + } + else if (mail == MAIL_CONTINUE) + { + // We don't have to do anything here - the CPU does not wait for a ACK + // and sends a cmdlist mail just after. + } + else if ((mail & MAIL_CMDLIST_MASK) == MAIL_CMDLIST) + { + // A command list address is going to be sent next. + set_next_is_cmdlist = true; + cmdlist_size = (u16)(mail & ~MAIL_CMDLIST_MASK); + } + else + { + ERROR_LOG(DSPHLE, "Unknown mail sent to AX::HandleMail: %08x", mail); + } - case 0x0010: //Super Monkey Ball 2 - DEBUG_LOG(DSPHLE, "%08x : AXLIST 0x0010", uAddress); - //should probably read/skip stuff here - uAddress += 8; - break; + m_processing.unlock(); + next_is_cmdlist = set_next_is_cmdlist; +} - case 0x0011: - uAddress += 4; - break; +void CUCode_AX::CopyCmdList(u32 addr, u16 size) +{ + if (size >= (sizeof (m_cmdlist) / sizeof (u16))) + { + ERROR_LOG(DSPHLE, "Command list at %08x is too large: size=%d", addr, size); + return; + } - case 0x0012: - Addr__12 = HLEMemory_Read_U16(uAddress); - uAddress += 2; - break; + for (u32 i = 0; i < size; ++i, addr += 2) + m_cmdlist[i] = HLEMemory_Read_U16(addr); + m_cmdlist_size = size; +} - case 0x0013: - uAddress += 6 * 4; // 6 Addresses. - break; +void CUCode_AX::MixAdd(short* out_buffer, int nsamples) +{ + // Should never be called: we do not set HLE as ready. + // We accurately send samples to RAM instead of directly to the mixer. +} - default: - { - static bool bFirst = true; - if (bFirst) - { - char szTemp[2048]; - sprintf(szTemp, "Unknown AX-Command 0x%x (address: 0x%08x). Last valid: %02x\n", - iCommand, uAddress - 2, last_valid_command); - int num = -32; - while (num < 64+32) - { - char szTemp2[128] = ""; - sprintf(szTemp2, "%s0x%04x\n", num == 0 ? ">>" : " ", HLEMemory_Read_U16(uAddress + num)); - strcat(szTemp, szTemp2); - num += 2; - } - - PanicAlert("%s", szTemp); - // bFirst = false; - } - - // unknown command so stop the execution of this TaskList - bExecuteList = false; - } - break; - } - if (bExecuteList) - last_valid_command = iCommand; +void CUCode_AX::Update(int cycles) +{ + // Used for UCode switching. + if (NeedsResumeMail()) + { + m_rMailHandler.PushMail(DSP_RESUME); + DSP::GenerateDSPInterruptFromDSPEmu(DSP::INT_DSP); } - DEBUG_LOG(DSPHLE, "AXTask - done, send resume"); - DEBUG_LOG(DSPHLE, "====================================================================="); - DEBUG_LOG(DSPHLE, "End"); - - m_rMailHandler.PushMail(DSP_YIELD); - return true; } -void CUCode_AX::DoState(PointerWrap &p) +void CUCode_AX::DoAXState(PointerWrap& p) { - std::lock_guard<std::mutex> lk(m_csMix); + p.Do(m_cmdlist); + p.Do(m_cmdlist_size); + + p.Do(m_samples_left); + p.Do(m_samples_right); + p.Do(m_samples_surround); + p.Do(m_samples_auxA_left); + p.Do(m_samples_auxA_right); + p.Do(m_samples_auxA_surround); + p.Do(m_samples_auxB_left); + p.Do(m_samples_auxB_right); + p.Do(m_samples_auxB_surround); +} - p.Do(numPBaddr); - p.Do(m_addressPBs); - p.Do(PBaddr); +void CUCode_AX::DoState(PointerWrap& p) +{ + std::lock_guard<std::mutex> lk(m_processing); DoStateShared(p); + DoAXState(p); } diff --git a/Source/Core/Core/Src/HW/DSPHLE/UCodes/UCode_AX.h b/Source/Core/Core/Src/HW/DSPHLE/UCodes/UCode_AX.h index edb52a2801..8fd2a2af5f 100644 --- a/Source/Core/Core/Src/HW/DSPHLE/UCodes/UCode_AX.h +++ b/Source/Core/Core/Src/HW/DSPHLE/UCodes/UCode_AX.h @@ -12,52 +12,162 @@ // 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 +// Official Git repository and contact information can be found at // http://code.google.com/p/dolphin-emu/ -#ifndef _UCODE_AX -#define _UCODE_AX +// High-level emulation for the AX Gamecube UCode. +// +// TODO: +// * Depop support +// * ITD support +// * Polyphase sample interpolation support (not very useful) +// * Dolby Pro 2 mixing with recent AX versions -#include <iostream> -#include "UCode_AXStructs.h" +#ifndef _UCODE_AX_H +#define _UCODE_AX_H -enum +#include "UCodes.h" +#include "UCode_AX_Structs.h" + +// We can't directly use the mixer_control field from the PB because it does +// not mean the same in all AX versions. The AX UCode converts the +// mixer_control value to an AXMixControl bitfield. +enum AXMixControl { - NUMBER_OF_PBS = 128 + MIX_L = 0x000001, + MIX_L_RAMP = 0x000002, + MIX_R = 0x000004, + MIX_R_RAMP = 0x000008, + MIX_S = 0x000010, + MIX_S_RAMP = 0x000020, + + MIX_AUXA_L = 0x000040, + MIX_AUXA_L_RAMP = 0x000080, + MIX_AUXA_R = 0x000100, + MIX_AUXA_R_RAMP = 0x000200, + MIX_AUXA_S = 0x000400, + MIX_AUXA_S_RAMP = 0x000800, + + MIX_AUXB_L = 0x001000, + MIX_AUXB_L_RAMP = 0x002000, + MIX_AUXB_R = 0x004000, + MIX_AUXB_R_RAMP = 0x008000, + MIX_AUXB_S = 0x010000, + MIX_AUXB_S_RAMP = 0x020000, + + MIX_AUXC_L = 0x040000, + MIX_AUXC_L_RAMP = 0x080000, + MIX_AUXC_R = 0x100000, + MIX_AUXC_R_RAMP = 0x200000, + MIX_AUXC_S = 0x400000, + MIX_AUXC_S_RAMP = 0x800000 }; -class CUCode_AX : public IUCode +class CUCode_AX : public IUCode { public: - CUCode_AX(DSPHLE *dsp_hle, u32 _CRC); + CUCode_AX(DSPHLE* dsp_hle, u32 crc); virtual ~CUCode_AX(); - void HandleMail(u32 _uMail); - void MixAdd(short* _pBuffer, int _iSize); - void Update(int cycles); - void DoState(PointerWrap &p); + virtual void HandleMail(u32 mail); + virtual void MixAdd(short* out_buffer, int nsamples); + virtual void Update(int cycles); + virtual void DoState(PointerWrap& p); - // PBs - u8 numPBaddr; - u32 PBaddr[8]; //2 needed for MP2 - u32 m_addressPBs; + // Needed because StdThread.h std::thread implem does not support member + // pointers. + static void SpawnAXThread(CUCode_AX* self); -private: - enum +protected: + enum MailType { - MAIL_AX_ALIST = 0xBABE0000, - AXLIST_STUDIOADDR = 0x0000, - AXLIST_PBADDR = 0x0002, - AXLIST_SBUFFER = 0x0007, - AXLIST_COMPRESSORTABLE = 0x000A, - AXLIST_END = 0x000F + MAIL_RESUME = 0xCDD10000, + MAIL_NEW_UCODE = 0xCDD10001, + MAIL_RESET = 0xCDD10002, + MAIL_CONTINUE = 0xCDD10003, + + // CPU sends 0xBABE0000 | cmdlist_size to the DSP + MAIL_CMDLIST = 0xBABE0000, + MAIL_CMDLIST_MASK = 0xFFFF0000 }; - int *templbuffer; - int *temprbuffer; + // 32 * 5 because 32 samples per millisecond, for max 5 milliseconds. + int m_samples_left[32 * 5]; + int m_samples_right[32 * 5]; + int m_samples_surround[32 * 5]; + int m_samples_auxA_left[32 * 5]; + int m_samples_auxA_right[32 * 5]; + int m_samples_auxA_surround[32 * 5]; + int m_samples_auxB_left[32 * 5]; + int m_samples_auxB_right[32 * 5]; + int m_samples_auxB_surround[32 * 5]; + + // Volatile because it's set by HandleMail and accessed in + // HandleCommandList, which are running in two different threads. + volatile u16 m_cmdlist[512]; + volatile u32 m_cmdlist_size; + + std::thread m_axthread; + + // Sync objects + std::mutex m_processing; + std::condition_variable m_cmdlist_cv; + std::mutex m_cmdlist_mutex; + + // Copy a command list from memory to our temp buffer + void CopyCmdList(u32 addr, u16 size); - // ax task message handler - bool AXTask(u32& _uMail); + // Convert a mixer_control bitfield to our internal representation for that + // value. Required because that bitfield has a different meaning in some + // versions of AX. + AXMixControl ConvertMixerControl(u32 mixer_control); + + // Send a notification to the AX thread to tell him a new cmdlist addr is + // available for processing. + void NotifyAXThread(); + + void AXThread(); + + virtual void HandleCommandList(); + + void SetupProcessing(u32 init_addr); + void DownloadAndMixWithVolume(u32 addr, u16 vol_main, u16 vol_auxa, u16 vol_auxb); + void ProcessPBList(u32 pb_addr); + void MixAUXSamples(int aux_id, u32 write_addr, u32 read_addr); + void UploadLRS(u32 dst_addr); + void SetMainLR(u32 src_addr); + void OutputSamples(u32 out_addr, u32 surround_addr); + void MixAUXBLR(u32 ul_addr, u32 dl_addr); + void SendAUXAndMix(u32 main_auxa_up, u32 auxb_s_up, u32 main_l_dl, + u32 main_r_dl, u32 auxb_l_dl, u32 auxb_r_dl); + + // Handle save states for main AX. + void DoAXState(PointerWrap& p); + +private: + enum CmdType + { + CMD_SETUP = 0x00, + CMD_DL_AND_VOL_MIX = 0x01, + CMD_PB_ADDR = 0x02, + CMD_PROCESS = 0x03, + CMD_MIX_AUXA = 0x04, + CMD_MIX_AUXB = 0x05, + CMD_UPLOAD_LRS = 0x06, + CMD_SET_LR = 0x07, + CMD_UNK_08 = 0x08, + CMD_MIX_AUXB_NOWRITE = 0x09, + CMD_COMPRESSOR_TABLE_ADDR = 0x0A, + CMD_UNK_0B = 0x0B, + CMD_UNK_0C = 0x0C, + CMD_MORE = 0x0D, + CMD_OUTPUT = 0x0E, + CMD_END = 0x0F, + CMD_MIX_AUXB_LR = 0x10, + CMD_UNK_11 = 0x11, + CMD_UNK_12 = 0x12, + CMD_SEND_AUX_AND_MIX = 0x13, + }; }; -#endif // _UCODE_AX +#endif // !_UCODE_AX_H diff --git a/Source/Core/Core/Src/HW/DSPHLE/UCodes/UCode_AXWii.cpp b/Source/Core/Core/Src/HW/DSPHLE/UCodes/UCode_AXWii.cpp index 03b1d3b75b..f4effbba6d 100644 --- a/Source/Core/Core/Src/HW/DSPHLE/UCodes/UCode_AXWii.cpp +++ b/Source/Core/Core/Src/HW/DSPHLE/UCodes/UCode_AXWii.cpp @@ -21,10 +21,10 @@ #include "Mixer.h" #include "UCodes.h" -#include "UCode_AXStructs.h" +#include "UCode_AXWii_Structs.h" #include "UCode_AX.h" // for some functions in CUCode_AX #include "UCode_AXWii.h" -#include "UCode_AX_Voice.h" +#include "UCode_AXWii_Voice.h" CUCode_AXWii::CUCode_AXWii(DSPHLE *dsp_hle, u32 l_CRC) @@ -159,8 +159,8 @@ void CUCode_AXWii::Update(int cycles) bool CUCode_AXWii::AXTask(u32& _uMail) { u32 uAddress = _uMail; - u32 Addr__AXStudio; - u32 Addr__AXOutSBuffer; + //u32 Addr__AXStudio; + //u32 Addr__AXOutSBuffer; bool bExecuteList = true; /* @@ -178,7 +178,7 @@ bool CUCode_AXWii::AXTask(u32& _uMail) switch (iCommand) { case 0x0000: - Addr__AXStudio = HLEMemory_Read_U32(uAddress); + //Addr__AXStudio = HLEMemory_Read_U32(uAddress); uAddress += 4; break; @@ -193,7 +193,8 @@ bool CUCode_AXWii::AXTask(u32& _uMail) case 0x0004: // PBs are here now m_addressPBs = HLEMemory_Read_U32(uAddress); - soundStream->GetMixer()->SetHLEReady(true); + if (soundStream) + soundStream->GetMixer()->SetHLEReady(true); // soundStream->Update(); uAddress += 4; break; @@ -208,7 +209,7 @@ bool CUCode_AXWii::AXTask(u32& _uMail) break; case 0x0007: // AXLIST_SBUFFER - Addr__AXOutSBuffer = HLEMemory_Read_U32(uAddress); + //Addr__AXOutSBuffer = HLEMemory_Read_U32(uAddress); uAddress += 10; break; diff --git a/Source/Core/Core/Src/HW/DSPHLE/UCodes/UCode_AXWii.h b/Source/Core/Core/Src/HW/DSPHLE/UCodes/UCode_AXWii.h index 1e6cffcba0..dc07e71a63 100644 --- a/Source/Core/Core/Src/HW/DSPHLE/UCodes/UCode_AXWii.h +++ b/Source/Core/Core/Src/HW/DSPHLE/UCodes/UCode_AXWii.h @@ -18,7 +18,7 @@ #ifndef _UCODE_AXWII #define _UCODE_AXWII -#include "UCode_AXStructs.h" +#include "UCode_AXWii_Structs.h" #define NUMBER_OF_PBS 128 diff --git a/Source/Core/Core/Src/HW/DSPHLE/UCodes/UCode_AX_ADPCM.h b/Source/Core/Core/Src/HW/DSPHLE/UCodes/UCode_AXWii_ADPCM.h index 9130bb9da4..9130bb9da4 100644 --- a/Source/Core/Core/Src/HW/DSPHLE/UCodes/UCode_AX_ADPCM.h +++ b/Source/Core/Core/Src/HW/DSPHLE/UCodes/UCode_AXWii_ADPCM.h diff --git a/Source/Core/Core/Src/HW/DSPHLE/UCodes/UCode_AXStructs.h b/Source/Core/Core/Src/HW/DSPHLE/UCodes/UCode_AXWii_Structs.h index 7f082740de..7f082740de 100644 --- a/Source/Core/Core/Src/HW/DSPHLE/UCodes/UCode_AXStructs.h +++ b/Source/Core/Core/Src/HW/DSPHLE/UCodes/UCode_AXWii_Structs.h diff --git a/Source/Core/Core/Src/HW/DSPHLE/UCodes/UCode_AXWii_Voice.h b/Source/Core/Core/Src/HW/DSPHLE/UCodes/UCode_AXWii_Voice.h new file mode 100644 index 0000000000..55f7face27 --- /dev/null +++ b/Source/Core/Core/Src/HW/DSPHLE/UCodes/UCode_AXWii_Voice.h @@ -0,0 +1,271 @@ +// 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/ + +#ifndef _UCODE_AXWII_VOICE_H +#define _UCODE_AXWII_VOICE_H + +#include "UCodes.h" +#include "UCode_AXWii_ADPCM.h" +#include "UCode_AX.h" +#include "Mixer.h" +#include "../../AudioInterface.h" + +// MRAM -> ARAM for GC +inline bool ReadPB(u32 addr, AXPB &PB) +{ + const u16* PB_in_mram = (const u16*)Memory::GetPointer(addr); + if (PB_in_mram == NULL) + return false; + u16* PB_in_aram = (u16*)&PB; + + for (size_t p = 0; p < (sizeof(AXPB) >> 1); p++) + { + PB_in_aram[p] = Common::swap16(PB_in_mram[p]); + } + + return true; +} + +// MRAM -> ARAM for Wii +inline bool ReadPB(u32 addr, AXPBWii &PB) +{ + const u16* PB_in_mram = (const u16*)Memory::GetPointer(addr); + if (PB_in_mram == NULL) + return false; + u16* PB_in_aram = (u16*)&PB; + + // preswap the mixer_control + PB.mixer_control = ((u32)PB_in_mram[7] << 16) | ((u32)PB_in_mram[6] >> 16); + + for (size_t p = 0; p < (sizeof(AXPBWii) >> 1); p++) + { + PB_in_aram[p] = Common::swap16(PB_in_mram[p]); + } + + return true; +} + +// ARAM -> MRAM for GC +inline bool WritePB(u32 addr, AXPB &PB) +{ + const u16* PB_in_aram = (const u16*)&PB; + u16* PB_in_mram = (u16*)Memory::GetPointer(addr); + if (PB_in_mram == NULL) + return false; + + for (size_t p = 0; p < (sizeof(AXPB) >> 1); p++) + { + PB_in_mram[p] = Common::swap16(PB_in_aram[p]); + } + + return true; +} + +// ARAM -> MRAM for Wii +inline bool WritePB(u32 addr, AXPBWii &PB) +{ + const u16* PB_in_aram = (const u16*)&PB; + u16* PB_in_mram = (u16*)Memory::GetPointer(addr); + if (PB_in_mram == NULL) + return false; + + // preswap the mixer_control + *(u32*)&PB_in_mram[6] = (PB.mixer_control << 16) | (PB.mixer_control >> 16); + + for (size_t p = 0; p < (sizeof(AXPBWii) >> 1); p++) + { + PB_in_mram[p] = Common::swap16(PB_in_aram[p]); + } + + return true; +} + +////////////////////////////////////////////////////////////////////////// +// TODO: fix handling of gc/wii PB differences +// TODO: generally fix up the mess - looks crazy and kinda wrong +template<class ParamBlockType> +inline void MixAddVoice(ParamBlockType &pb, + int *templbuffer, int *temprbuffer, + int _iSize) +{ + if (pb.running) + { + const u32 ratio = (u32)(((pb.src.ratio_hi << 16) + pb.src.ratio_lo) + * /*ratioFactor:*/((float)AudioInterface::GetAIDSampleRate() / (float)soundStream->GetMixer()->GetSampleRate())); + u32 sampleEnd = (pb.audio_addr.end_addr_hi << 16) | pb.audio_addr.end_addr_lo; + u32 loopPos = (pb.audio_addr.loop_addr_hi << 16) | pb.audio_addr.loop_addr_lo; + + u32 samplePos = (pb.audio_addr.cur_addr_hi << 16) | pb.audio_addr.cur_addr_lo; + u32 frac = pb.src.cur_addr_frac; + + // ======================================================================================= + // Handle No-SRC streams - No src streams have pb.src_type == 2 and have pb.src.ratio_hi = 0 + // and pb.src.ratio_lo = 0. We handle that by setting the sampling ratio integer to 1. This + // makes samplePos update in the correct way. I'm unsure how we are actually supposed to + // detect that this setting. Updates did not fix this automatically. + // --------------------------------------------------------------------------------------- + // Stream settings + // src_type = 2 (most other games have src_type = 0) + // Affected games: + // Baten Kaitos - Eternal Wings (2003) + // Baten Kaitos - Origins (2006)? + // Soul Calibur 2: The movie music use src_type 2 but it needs no adjustment, perhaps + // the sound format plays in to, Baten use ADPCM, SC2 use PCM16 + //if (pb.src_type == 2 && (pb.src.ratio_hi == 0 && pb.src.ratio_lo == 0)) + if (pb.running && (pb.src.ratio_hi == 0 && pb.src.ratio_lo == 0)) + { + pb.src.ratio_hi = 1; + } + + // ======================================================================================= + // Games that use looping to play non-looping music streams - SSBM has info in all + // pb.adpcm_loop_info parameters but has pb.audio_addr.looping = 0. If we treat these streams + // like any other looping streams the music works. I'm unsure how we are actually supposed to + // detect that these kinds of blocks should be looping. It seems like pb.mixer_control == 0 may + // identify these types of blocks. Updates did not write any looping values. + if ( + (pb.adpcm_loop_info.pred_scale || pb.adpcm_loop_info.yn1 || pb.adpcm_loop_info.yn2) + && pb.mixer_control == 0 && pb.adpcm_loop_info.pred_scale <= 0x7F + ) + { + pb.audio_addr.looping = 1; + } + + + + // Top Spin 3 Wii + if (pb.audio_addr.sample_format > 25) + pb.audio_addr.sample_format = 0; + + // ======================================================================================= + // Walk through _iSize. _iSize = numSamples. If the game goes slow _iSize will be higher to + // compensate for that. _iSize can be as low as 100 or as high as 2000 some cases. + for (int s = 0; s < _iSize; s++) + { + int sample = 0; + u32 oldFrac = frac; + frac += ratio; + u32 newSamplePos = samplePos + (frac >> 16); //whole number of frac + + // ======================================================================================= + // Process sample format + switch (pb.audio_addr.sample_format) + { + case AUDIOFORMAT_PCM8: + pb.adpcm.yn2 = ((s8)DSP::ReadARAM(samplePos)) << 8; //current sample + pb.adpcm.yn1 = ((s8)DSP::ReadARAM(samplePos + 1)) << 8; //next sample + + if (pb.src_type == SRCTYPE_NEAREST) + sample = pb.adpcm.yn2; + else // linear interpolation + sample = (pb.adpcm.yn1 * (u16)oldFrac + pb.adpcm.yn2 * (u16)(0xFFFF - oldFrac) + pb.adpcm.yn2) >> 16; + + samplePos = newSamplePos; + break; + + case AUDIOFORMAT_PCM16: + pb.adpcm.yn2 = (s16)(u16)((DSP::ReadARAM(samplePos * 2) << 8) | (DSP::ReadARAM((samplePos * 2 + 1)))); //current sample + pb.adpcm.yn1 = (s16)(u16)((DSP::ReadARAM((samplePos + 1) * 2) << 8) | (DSP::ReadARAM(((samplePos + 1) * 2 + 1)))); //next sample + + if (pb.src_type == SRCTYPE_NEAREST) + sample = pb.adpcm.yn2; + else // linear interpolation + sample = (pb.adpcm.yn1 * (u16)oldFrac + pb.adpcm.yn2 * (u16)(0xFFFF - oldFrac) + pb.adpcm.yn2) >> 16; + + samplePos = newSamplePos; + break; + + case AUDIOFORMAT_ADPCM: + ADPCM_Step(pb.adpcm, samplePos, newSamplePos, frac); + + if (pb.src_type == SRCTYPE_NEAREST) + sample = pb.adpcm.yn2; + else // linear interpolation + sample = (pb.adpcm.yn1 * (u16)frac + pb.adpcm.yn2 * (u16)(0xFFFF - frac) + pb.adpcm.yn2) >> 16; //adpcm moves on frac + + break; + + default: + break; + } + + // =================================================================== + // Overall volume control. In addition to this there is also separate volume settings to + // different channels (left, right etc). + frac &= 0xffff; + + int vol = pb.vol_env.cur_volume >> 9; + sample = sample * vol >> 8; + + if (pb.mixer_control & MIXCONTROL_RAMPING) + { + int x = pb.vol_env.cur_volume; + x += pb.vol_env.cur_volume_delta; // I'm not sure about this, can anybody find a game + // that use this? Or how does it work? + if (x < 0) + x = 0; + if (x >= 0x7fff) + x = 0x7fff; + pb.vol_env.cur_volume = x; // maybe not per sample?? :P + } + + int leftmix = pb.mixer.left >> 5; + int rightmix = pb.mixer.right >> 5; + int left = sample * leftmix >> 8; + int right = sample * rightmix >> 8; + // adpcm has to walk from oldSamplePos to samplePos here + templbuffer[s] += left; + temprbuffer[s] += right; + + // Control the behavior when we reach the end of the sample + if (samplePos >= sampleEnd) + { + if (pb.audio_addr.looping == 1) + { + if ((samplePos & ~0x1f) == (sampleEnd & ~0x1f) || (pb.audio_addr.sample_format != AUDIOFORMAT_ADPCM)) + samplePos = loopPos; + if ((!pb.is_stream) && (pb.audio_addr.sample_format == AUDIOFORMAT_ADPCM)) + { + pb.adpcm.yn1 = pb.adpcm_loop_info.yn1; + pb.adpcm.yn2 = pb.adpcm_loop_info.yn2; + pb.adpcm.pred_scale = pb.adpcm_loop_info.pred_scale; + } + } + else + { + pb.running = 0; + samplePos = loopPos; + //samplePos = samplePos - sampleEnd + loopPos; + memset(&pb.dpop, 0, sizeof(pb.dpop)); + memset(pb.src.last_samples, 0, 8); + break; + } + } + } // end of the _iSize loop + + // Update volume + pb.mixer.left = ADPCM_Vol(pb.mixer.left, pb.mixer.left_delta); + pb.mixer.right = ADPCM_Vol(pb.mixer.right, pb.mixer.right_delta); + + pb.src.cur_addr_frac = (u16)frac; + pb.audio_addr.cur_addr_hi = samplePos >> 16; + pb.audio_addr.cur_addr_lo = (u16)samplePos; + + } // if (pb.running) +} + +#endif diff --git a/Source/Core/Core/Src/HW/DSPHLE/UCodes/UCode_AX_Structs.h b/Source/Core/Core/Src/HW/DSPHLE/UCodes/UCode_AX_Structs.h new file mode 100644 index 0000000000..c92196dd49 --- /dev/null +++ b/Source/Core/Core/Src/HW/DSPHLE/UCodes/UCode_AX_Structs.h @@ -0,0 +1,392 @@ +// 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/ + +#ifndef _UCODE_AX_STRUCTS_H +#define _UCODE_AX_STRUCTS_H + +struct PBMixer +{ + u16 left; + u16 left_delta; + u16 right; + u16 right_delta; + + u16 auxA_left; + u16 auxA_left_delta; + u16 auxA_right; + u16 auxA_right_delta; + + u16 auxB_left; + u16 auxB_left_delta; + u16 auxB_right; + u16 auxB_right_delta; + + u16 auxB_surround; + u16 auxB_surround_delta; + u16 surround; + u16 surround_delta; + u16 auxA_surround; + u16 auxA_surround_delta; +}; + +struct PBMixerWii +{ + // volume mixing values in .15, 0x8000 = ca. 1.0 + u16 left; + u16 left_delta; + u16 right; + u16 right_delta; + + u16 auxA_left; + u16 auxA_left_delta; + u16 auxA_right; + u16 auxA_right_delta; + + u16 auxB_left; + u16 auxB_left_delta; + u16 auxB_right; + u16 auxB_right_delta; + + // Note: the following elements usage changes a little in DPL2 mode + // TODO: implement and comment it in the mixer + u16 auxC_left; + u16 auxC_left_delta; + u16 auxC_right; + u16 auxC_right_delta; + + u16 surround; + u16 surround_delta; + u16 auxA_surround; + u16 auxA_surround_delta; + u16 auxB_surround; + u16 auxB_surround_delta; + u16 auxC_surround; + u16 auxC_surround_delta; +}; + +struct PBMixerWM +{ + u16 main0; + u16 main0_delta; + u16 aux0; + u16 aux0_delta; + + u16 main1; + u16 main1_delta; + u16 aux1; + u16 aux1_delta; + + u16 main2; + u16 main2_delta; + u16 aux2; + u16 aux2_delta; + + u16 main3; + u16 main3_delta; + u16 aux3; + u16 aux3_delta; +}; + +struct PBInitialTimeDelay +{ + u16 on; + u16 addrMemHigh; + u16 addrMemLow; + u16 offsetLeft; + u16 offsetRight; + u16 targetLeft; + u16 targetRight; +}; + +// Update data - read these each 1ms subframe and use them! +// It seems that to provide higher time precisions for MIDI events, some games +// use this thing to update the parameter blocks per 1ms sub-block (a block is 5ms). +// Using this data should fix games that are missing MIDI notes. +struct PBUpdates +{ + u16 num_updates[5]; + u16 data_hi; // These point to main RAM. Not sure about the structure of the data. + u16 data_lo; +}; + +// The DSP stores the final sample values for each voice after every frame of processing. +// The values are then accumulated for all dropped voices, added to the next frame of audio, +// and ramped down on a per-sample basis to provide a gentle "roll off." +struct PBDpop +{ + s16 left; + s16 auxA_left; + s16 auxB_left; + + s16 right; + s16 auxA_right; + s16 auxB_right; + + s16 surround; + s16 auxA_surround; + s16 auxB_surround; +}; + +struct PBDpopWii +{ + s16 left; + s16 auxA_left; + s16 auxB_left; + s16 auxC_left; + + s16 right; + s16 auxA_right; + s16 auxB_right; + s16 auxC_right; + + s16 surround; + s16 auxA_surround; + s16 auxB_surround; + s16 auxC_surround; +}; + +struct PBDpopWM +{ + s16 aMain0; + s16 aMain1; + s16 aMain2; + s16 aMain3; + + s16 aAux0; + s16 aAux1; + s16 aAux2; + s16 aAux3; +}; + +struct PBVolumeEnvelope +{ + u16 cur_volume; // volume at start of frame + s16 cur_volume_delta; // signed per sample delta (96 samples per frame) +}; + +struct PBUnknown2 +{ + u16 unknown_reserved[3]; +}; + +struct PBAudioAddr +{ + u16 looping; + u16 sample_format; + u16 loop_addr_hi; // Start of loop (this will point to a shared "zero" buffer if one-shot mode is active) + u16 loop_addr_lo; + u16 end_addr_hi; // End of sample (and loop), inclusive + u16 end_addr_lo; + u16 cur_addr_hi; + u16 cur_addr_lo; +}; + +struct PBADPCMInfo +{ + s16 coefs[16]; + u16 gain; + u16 pred_scale; + s16 yn1; + s16 yn2; +}; + +struct PBSampleRateConverter +{ + // ratio = (f32)ratio * 0x10000; + // valid range is 1/512 to 4.0000 + u16 ratio_hi; // integer part of sampling ratio + u16 ratio_lo; // fraction part of sampling ratio + u16 cur_addr_frac; + u16 last_samples[4]; +}; + +struct PBSampleRateConverterWM +{ + u16 currentAddressFrac; + u16 last_samples[4]; +}; + +struct PBADPCMLoopInfo +{ + u16 pred_scale; + u16 yn1; + u16 yn2; +}; + +struct PBLowPassFilter +{ + u16 enabled; + u16 yn1; + u16 a0; + u16 b0; +}; + +struct AXPB +{ + u16 next_pb_hi; + u16 next_pb_lo; + u16 this_pb_hi; + u16 this_pb_lo; + + u16 src_type; // Type of sample rate converter (none, ?, linear) + u16 coef_select; + u16 mixer_control; + + u16 running; // 1=RUN 0=STOP + u16 is_stream; // 1 = stream, 0 = one shot + + PBMixer mixer; + PBInitialTimeDelay initial_time_delay; + PBUpdates updates; + PBDpop dpop; + PBVolumeEnvelope vol_env; + PBUnknown2 unknown3; + PBAudioAddr audio_addr; + PBADPCMInfo adpcm; + PBSampleRateConverter src; + PBADPCMLoopInfo adpcm_loop_info; + PBLowPassFilter lpf; + + u16 padding[25]; +}; + +struct PBBiquadFilter +{ + + u16 on; // on = 2, off = 0 + u16 xn1; // History data + u16 xn2; + u16 yn1; + u16 yn2; + u16 b0; // Filter coefficients + u16 b1; + u16 b2; + u16 a1; + u16 a2; + +}; + +union PBInfImpulseResponseWM +{ + PBLowPassFilter lpf; + PBBiquadFilter biquad; +}; + +struct AXPBWii +{ + u16 next_pb_hi; + u16 next_pb_lo; + u16 this_pb_hi; + u16 this_pb_lo; + + u16 src_type; // Type of sample rate converter (none, 4-tap, linear) + u16 coef_select; // coef for the 4-tap src + u16 mixer_control_hi; + u16 mixer_control_lo; + + u16 running; // 1=RUN 0=STOP + u16 is_stream; // 1 = stream, 0 = one shot + + PBMixerWii mixer; + PBInitialTimeDelay initial_time_delay; + PBDpopWii dpop; + PBVolumeEnvelope vol_env; + PBAudioAddr audio_addr; + PBADPCMInfo adpcm; + PBSampleRateConverter src; + PBADPCMLoopInfo adpcm_loop_info; + PBLowPassFilter lpf; + PBBiquadFilter biquad; + + // WIIMOTE :D + u16 remote; + u16 remote_mixer_control; + + PBMixerWM remote_mixer; + PBDpopWM remote_dpop; + PBSampleRateConverterWM remote_src; + PBInfImpulseResponseWM remote_iir; + + u16 pad[12]; // align us, captain! (32B) +}; + +// Seems like nintendo used an early version of AXWii and forgot to remove the update functionality ;p +struct PBUpdatesWiiSports +{ + u16 num_updates[3]; + u16 data_hi; + u16 data_lo; +}; + +struct AXPBWiiSports +{ + u16 next_pb_hi; + u16 next_pb_lo; + u16 this_pb_hi; + u16 this_pb_lo; + + u16 src_type; // Type of sample rate converter (none, 4-tap, linear) + u16 coef_select; // coef for the 4-tap src + u32 mixer_control; + + u16 running; // 1=RUN 0=STOP + u16 is_stream; // 1 = stream, 0 = one shot + + PBMixerWii mixer; + PBInitialTimeDelay initial_time_delay; + PBUpdatesWiiSports updates; + PBDpopWii dpop; + PBVolumeEnvelope vol_env; + PBAudioAddr audio_addr; + PBADPCMInfo adpcm; + PBSampleRateConverter src; + PBADPCMLoopInfo adpcm_loop_info; + PBLowPassFilter lpf; + PBBiquadFilter biquad; + + // WIIMOTE :D + u16 remote; + u16 remote_mixer_control; + + PBMixerWM remote_mixer; + PBDpopWM remote_dpop; + PBSampleRateConverterWM remote_src; + PBInfImpulseResponseWM remote_iir; + + u16 pad[7]; // align us, captain! (32B) +}; + +// TODO: All these enums have changed a lot for wii +enum { + AUDIOFORMAT_ADPCM = 0, + AUDIOFORMAT_PCM8 = 0x19, + AUDIOFORMAT_PCM16 = 0xA, +}; + +enum { + SRCTYPE_POLYPHASE = 0, + SRCTYPE_LINEAR = 1, + SRCTYPE_NEAREST = 2, +}; + +// Both may be used at once +enum { + FILTER_LOWPASS = 1, + FILTER_BIQUAD = 2, +}; + +#endif // _UCODE_AX_STRUCTS_H diff --git a/Source/Core/Core/Src/HW/DSPHLE/UCodes/UCode_AX_Voice.h b/Source/Core/Core/Src/HW/DSPHLE/UCodes/UCode_AX_Voice.h index e6ee063ae3..349dc7e03b 100644 --- a/Source/Core/Core/Src/HW/DSPHLE/UCodes/UCode_AX_Voice.h +++ b/Source/Core/Core/Src/HW/DSPHLE/UCodes/UCode_AX_Voice.h @@ -12,259 +12,389 @@ // 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 +// Official Git repository and contact information can be found at // http://code.google.com/p/dolphin-emu/ +// This file is UGLY (full of #ifdef) so that it can be used with both GC and +// Wii version of AX. Maybe it would be better to abstract away the parts that +// can be made common. + #ifndef _UCODE_AX_VOICE_H #define _UCODE_AX_VOICE_H -#include "UCodes.h" -#include "UCode_AX_ADPCM.h" -#include "UCode_AX.h" -#include "Mixer.h" -#include "../../AudioInterface.h" +#if !defined(AX_GC) && !defined(AX_WII) +#error UCode_AX_Voice.h included without specifying version +#endif -// MRAM -> ARAM for GC -inline bool ReadPB(u32 addr, AXPB &PB) -{ - const u16* PB_in_mram = (const u16*)Memory::GetPointer(addr); - if (PB_in_mram == NULL) - return false; - u16* PB_in_aram = (u16*)&PB; +#include "Common.h" +#include "UCode_AX_Structs.h" +#include "../../DSP.h" + +#ifdef AX_GC +# define PB_TYPE AXPB +#else +# define PB_TYPE AXPBWii +#endif + +// Put all of that in an anonymous namespace to avoid stupid compilers merging +// functions from AX GC and AX Wii. +namespace { + +// Useful macro to convert xxx_hi + xxx_lo to xxx for 32 bits. +#define HILO_TO_32(name) \ + ((name##_hi << 16) | name##_lo) - for (size_t p = 0; p < (sizeof(AXPB) >> 1); p++) +// Used to pass a large amount of buffers to the mixing function. +union AXBuffers +{ + struct { - PB_in_aram[p] = Common::swap16(PB_in_mram[p]); - } + int* left; + int* right; + int* surround; + + int* auxA_left; + int* auxA_right; + int* auxA_surround; + + int* auxB_left; + int* auxB_right; + int* auxB_surround; + +#ifdef AX_WII + int* auxC_left; + int* auxC_right; + int* auxC_surround; +#endif + }; - return true; -} +#ifdef AX_GC + int* ptrs[9]; +#else + int* ptrs[12]; +#endif +}; -// MRAM -> ARAM for Wii -inline bool ReadPB(u32 addr, AXPBWii &PB) +// Read a PB from MRAM/ARAM +bool ReadPB(u32 addr, PB_TYPE& pb) { - const u16* PB_in_mram = (const u16*)Memory::GetPointer(addr); - if (PB_in_mram == NULL) + u16* dst = (u16*)&pb; + const u16* src = (const u16*)Memory::GetPointer(addr); + if (!src) return false; - u16* PB_in_aram = (u16*)&PB; - - // preswap the mixer_control - PB.mixer_control = ((u32)PB_in_mram[7] << 16) | ((u32)PB_in_mram[6] >> 16); - for (size_t p = 0; p < (sizeof(AXPBWii) >> 1); p++) - { - PB_in_aram[p] = Common::swap16(PB_in_mram[p]); - } + for (u32 i = 0; i < sizeof (pb) / sizeof (u16); ++i) + dst[i] = Common::swap16(src[i]); return true; } -// ARAM -> MRAM for GC -inline bool WritePB(u32 addr, AXPB &PB) +// Write a PB back to MRAM/ARAM +bool WritePB(u32 addr, const PB_TYPE& pb) { - const u16* PB_in_aram = (const u16*)&PB; - u16* PB_in_mram = (u16*)Memory::GetPointer(addr); - if (PB_in_mram == NULL) + const u16* src = (const u16*)&pb; + u16* dst = (u16*)Memory::GetPointer(addr); + if (!dst) return false; - for (size_t p = 0; p < (sizeof(AXPB) >> 1); p++) - { - PB_in_mram[p] = Common::swap16(PB_in_aram[p]); - } + for (u32 i = 0; i < sizeof (pb) / sizeof (u16); ++i) + dst[i] = Common::swap16(src[i]); return true; } -// ARAM -> MRAM for Wii -inline bool WritePB(u32 addr, AXPBWii &PB) +// Dump the value of a PB for debugging +#define DUMP_U16(field) WARN_LOG(DSPHLE, " %04x (%s)", pb.field, #field) +#define DUMP_U32(field) WARN_LOG(DSPHLE, " %08x (%s)", HILO_TO_32(pb.field), #field) +void DumpPB(const PB_TYPE& pb) { - const u16* PB_in_aram = (const u16*)&PB; - u16* PB_in_mram = (u16*)Memory::GetPointer(addr); - if (PB_in_mram == NULL) - return false; + DUMP_U32(next_pb); + DUMP_U32(this_pb); + DUMP_U16(src_type); + DUMP_U16(coef_select); +#ifdef AX_GC + DUMP_U16(mixer_control); +#else + DUMP_U32(mixer_control); +#endif + DUMP_U16(running); + DUMP_U16(is_stream); - // preswap the mixer_control - *(u32*)&PB_in_mram[6] = (PB.mixer_control << 16) | (PB.mixer_control >> 16); + // TODO: complete as needed +} - for (size_t p = 0; p < (sizeof(AXPBWii) >> 1); p++) - { - PB_in_mram[p] = Common::swap16(PB_in_aram[p]); - } +// Simulated accelerator state. +static u32 acc_loop_addr, acc_end_addr; +static u32* acc_cur_addr; +static PB_TYPE* acc_pb; - return true; +// Sets up the simulated accelerator. +void AcceleratorSetup(PB_TYPE* pb, u32* cur_addr) +{ + acc_pb = pb; + acc_loop_addr = HILO_TO_32(pb->audio_addr.loop_addr); + acc_end_addr = HILO_TO_32(pb->audio_addr.end_addr); + acc_cur_addr = cur_addr; } -////////////////////////////////////////////////////////////////////////// -// TODO: fix handling of gc/wii PB differences -// TODO: generally fix up the mess - looks crazy and kinda wrong -template<class ParamBlockType> -inline void MixAddVoice(ParamBlockType &pb, - int *templbuffer, int *temprbuffer, - int _iSize) +// Reads a sample from the simulated accelerator. Also handles looping and +// disabling streams that reached the end (this is done by an exception raised +// by the accelerator on real hardware). +u16 AcceleratorGetSample() { - if (pb.running) + u16 ret; + + switch (acc_pb->audio_addr.sample_format) { - const u32 ratio = (u32)(((pb.src.ratio_hi << 16) + pb.src.ratio_lo) - * /*ratioFactor:*/((float)AudioInterface::GetAIDSampleRate() / (float)soundStream->GetMixer()->GetSampleRate())); - u32 sampleEnd = (pb.audio_addr.end_addr_hi << 16) | pb.audio_addr.end_addr_lo; - u32 loopPos = (pb.audio_addr.loop_addr_hi << 16) | pb.audio_addr.loop_addr_lo; - - u32 samplePos = (pb.audio_addr.cur_addr_hi << 16) | pb.audio_addr.cur_addr_lo; - u32 frac = pb.src.cur_addr_frac; - - // ======================================================================================= - // Handle No-SRC streams - No src streams have pb.src_type == 2 and have pb.src.ratio_hi = 0 - // and pb.src.ratio_lo = 0. We handle that by setting the sampling ratio integer to 1. This - // makes samplePos update in the correct way. I'm unsure how we are actually supposed to - // detect that this setting. Updates did not fix this automatically. - // --------------------------------------------------------------------------------------- - // Stream settings - // src_type = 2 (most other games have src_type = 0) - // Affected games: - // Baten Kaitos - Eternal Wings (2003) - // Baten Kaitos - Origins (2006)? - // Soul Calibur 2: The movie music use src_type 2 but it needs no adjustment, perhaps - // the sound format plays in to, Baten use ADPCM, SC2 use PCM16 - //if (pb.src_type == 2 && (pb.src.ratio_hi == 0 && pb.src.ratio_lo == 0)) - if (pb.running && (pb.src.ratio_hi == 0 && pb.src.ratio_lo == 0)) + case 0x00: // ADPCM { - pb.src.ratio_hi = 1; - } + // ADPCM decoding, not much to explain here. + if ((*acc_cur_addr & 15) == 0) + { + acc_pb->adpcm.pred_scale = DSP::ReadARAM((*acc_cur_addr & ~15) >> 1); + *acc_cur_addr += 2; + } - // ======================================================================================= - // Games that use looping to play non-looping music streams - SSBM has info in all - // pb.adpcm_loop_info parameters but has pb.audio_addr.looping = 0. If we treat these streams - // like any other looping streams the music works. I'm unsure how we are actually supposed to - // detect that these kinds of blocks should be looping. It seems like pb.mixer_control == 0 may - // identify these types of blocks. Updates did not write any looping values. - if ( - (pb.adpcm_loop_info.pred_scale || pb.adpcm_loop_info.yn1 || pb.adpcm_loop_info.yn2) - && pb.mixer_control == 0 && pb.adpcm_loop_info.pred_scale <= 0x7F - ) - { - pb.audio_addr.looping = 1; - } + int scale = 1 << (acc_pb->adpcm.pred_scale & 0xF); + int coef_idx = (acc_pb->adpcm.pred_scale >> 4) & 0x7; + + s32 coef1 = acc_pb->adpcm.coefs[coef_idx * 2 + 0]; + s32 coef2 = acc_pb->adpcm.coefs[coef_idx * 2 + 1]; + + int temp = (*acc_cur_addr & 1) ? + (DSP::ReadARAM(*acc_cur_addr >> 1) & 0xF) : + (DSP::ReadARAM(*acc_cur_addr >> 1) >> 4); + + if (temp >= 8) + temp -= 16; + int val = (scale * temp) + ((0x400 + coef1 * acc_pb->adpcm.yn1 + coef2 * acc_pb->adpcm.yn2) >> 11); + if (val > 0x7FFF) val = 0x7FFF; + else if (val < -0x7FFF) val = -0x7FFF; - // Top Spin 3 Wii - if (pb.audio_addr.sample_format > 25) - pb.audio_addr.sample_format = 0; + acc_pb->adpcm.yn2 = acc_pb->adpcm.yn1; + acc_pb->adpcm.yn1 = val; + *acc_cur_addr += 1; + ret = val; + break; + } + + case 0x0A: // 16-bit PCM audio + ret = (DSP::ReadARAM(*acc_cur_addr * 2) << 8) | DSP::ReadARAM(*acc_cur_addr * 2 + 1); + acc_pb->adpcm.yn2 = acc_pb->adpcm.yn1; + acc_pb->adpcm.yn1 = ret; + *acc_cur_addr += 1; + break; + + case 0x19: // 8-bit PCM audio + ret = DSP::ReadARAM(*acc_cur_addr) << 8; + acc_pb->adpcm.yn2 = acc_pb->adpcm.yn1; + acc_pb->adpcm.yn1 = ret; + *acc_cur_addr += 1; + break; + + default: + ERROR_LOG(DSPHLE, "Unknown sample format: %d", acc_pb->audio_addr.sample_format); + return 0; + } + + // Have we reached the end address? + // + // On real hardware, this would raise an interrupt that is handled by the + // UCode. We simulate what this interrupt does here. + if (*acc_cur_addr >= acc_end_addr) + { + // If we are really at the end (and we don't simply have cur_addr > + // end_addr all the time), loop back to loop_addr. + if ((*acc_cur_addr & ~0x1F) == (acc_end_addr & ~0x1F)) + *acc_cur_addr = acc_loop_addr; - // ======================================================================================= - // Walk through _iSize. _iSize = numSamples. If the game goes slow _iSize will be higher to - // compensate for that. _iSize can be as low as 100 or as high as 2000 some cases. - for (int s = 0; s < _iSize; s++) + if (acc_pb->audio_addr.looping) { - int sample = 0; - u32 oldFrac = frac; - frac += ratio; - u32 newSamplePos = samplePos + (frac >> 16); //whole number of frac - - // ======================================================================================= - // Process sample format - switch (pb.audio_addr.sample_format) + // Set the ADPCM infos to continue processing at loop_addr. + // + // For some reason, yn1 and yn2 aren't set if the voice is not of + // stream type. This is what the AX UCode does and I don't really + // know why. + acc_pb->adpcm.pred_scale = acc_pb->adpcm_loop_info.pred_scale; + if (!acc_pb->is_stream) { - case AUDIOFORMAT_PCM8: - pb.adpcm.yn2 = ((s8)DSP::ReadARAM(samplePos)) << 8; //current sample - pb.adpcm.yn1 = ((s8)DSP::ReadARAM(samplePos + 1)) << 8; //next sample - - if (pb.src_type == SRCTYPE_NEAREST) - sample = pb.adpcm.yn2; - else // linear interpolation - sample = (pb.adpcm.yn1 * (u16)oldFrac + pb.adpcm.yn2 * (u16)(0xFFFF - oldFrac) + pb.adpcm.yn2) >> 16; - - samplePos = newSamplePos; - break; - - case AUDIOFORMAT_PCM16: - pb.adpcm.yn2 = (s16)(u16)((DSP::ReadARAM(samplePos * 2) << 8) | (DSP::ReadARAM((samplePos * 2 + 1)))); //current sample - pb.adpcm.yn1 = (s16)(u16)((DSP::ReadARAM((samplePos + 1) * 2) << 8) | (DSP::ReadARAM(((samplePos + 1) * 2 + 1)))); //next sample - - if (pb.src_type == SRCTYPE_NEAREST) - sample = pb.adpcm.yn2; - else // linear interpolation - sample = (pb.adpcm.yn1 * (u16)oldFrac + pb.adpcm.yn2 * (u16)(0xFFFF - oldFrac) + pb.adpcm.yn2) >> 16; - - samplePos = newSamplePos; - break; - - case AUDIOFORMAT_ADPCM: - ADPCM_Step(pb.adpcm, samplePos, newSamplePos, frac); - - if (pb.src_type == SRCTYPE_NEAREST) - sample = pb.adpcm.yn2; - else // linear interpolation - sample = (pb.adpcm.yn1 * (u16)frac + pb.adpcm.yn2 * (u16)(0xFFFF - frac) + pb.adpcm.yn2) >> 16; //adpcm moves on frac - - break; - - default: - break; + acc_pb->adpcm.yn1 = acc_pb->adpcm_loop_info.yn1; + acc_pb->adpcm.yn2 = acc_pb->adpcm_loop_info.yn2; } + } + else + { + // Non looping voice reached the end -> running = 0. + acc_pb->running = 0; + } + } - // =================================================================== - // Overall volume control. In addition to this there is also separate volume settings to - // different channels (left, right etc). - frac &= 0xffff; + return ret; +} - int vol = pb.vol_env.cur_volume >> 9; - sample = sample * vol >> 8; +// Read 32 input samples from ARAM, decoding and converting rate if required. +void GetInputSamples(PB_TYPE& pb, s16* samples) +{ + u32 cur_addr = HILO_TO_32(pb.audio_addr.cur_addr); + AcceleratorSetup(&pb, &cur_addr); - if (pb.mixer_control & MIXCONTROL_RAMPING) - { - int x = pb.vol_env.cur_volume; - x += pb.vol_env.cur_volume_delta; // I'm not sure about this, can anybody find a game - // that use this? Or how does it work? - if (x < 0) - x = 0; - if (x >= 0x7fff) - x = 0x7fff; - pb.vol_env.cur_volume = x; // maybe not per sample?? :P - } + // TODO: support polyphase interpolation if coefficients are available. + if (pb.src_type == SRCTYPE_POLYPHASE || pb.src_type == SRCTYPE_LINEAR) + { + // Convert the input to a higher or lower sample rate using a linear + // interpolation algorithm. The input to output ratio is set in + // pb.src.ratio, which is a floating point num stored as a 32b integer: + // * Upper 16 bits of the ratio are the integer part + // * Lower 16 bits are the decimal part + u32 ratio = HILO_TO_32(pb.src.ratio); + + // We start getting samples not from sample 0, but 0.<cur_addr_frac>. + // This avoids discontinuties in the audio stream, especially with very + // low ratios which interpolate a lot of values between two "real" + // samples. + u32 curr_pos = pb.src.cur_addr_frac; + + // These are the two samples between which we interpolate. The initial + // values are stored in the PB, and we update them when resampling the + // input data. + s16 curr0 = pb.src.last_samples[2]; + s16 curr1 = pb.src.last_samples[3]; + + for (u32 i = 0; i < 32; ++i) + { + // Get our current fractional position, used to know how much of + // curr0 and how much of curr1 the output sample should be. + s32 curr_frac_pos = curr_pos & 0xFFFF; - int leftmix = pb.mixer.left >> 5; - int rightmix = pb.mixer.right >> 5; - int left = sample * leftmix >> 8; - int right = sample * rightmix >> 8; - // adpcm has to walk from oldSamplePos to samplePos here - templbuffer[s] += left; - temprbuffer[s] += right; + // Linear interpolation: s1 + (s2 - s1) * pos + s16 sample = curr0 + (s16)(((curr1 - curr0) * (s32)curr_frac_pos) >> 16); + samples[i] = sample; - // Control the behavior when we reach the end of the sample - if (samplePos >= sampleEnd) + curr_pos += ratio; + + // While our current position is >= 1.0, shift to the next 2 + // samples for interpolation. + while ((curr_pos >> 16) != 0) { - if (pb.audio_addr.looping == 1) - { - samplePos = loopPos; - if ((!pb.is_stream) && (pb.audio_addr.sample_format == AUDIOFORMAT_ADPCM)) - { - pb.adpcm.yn1 = pb.adpcm_loop_info.yn1; - pb.adpcm.yn2 = pb.adpcm_loop_info.yn2; - pb.adpcm.pred_scale = pb.adpcm_loop_info.pred_scale; - } - } - else - { - pb.running = 0; - samplePos = loopPos; - //samplePos = samplePos - sampleEnd + loopPos; - memset(&pb.dpop, 0, sizeof(pb.dpop)); - memset(pb.src.last_samples, 0, 8); - break; - } + curr0 = curr1; + curr1 = AcceleratorGetSample(); + curr_pos -= 0x10000; } - } // end of the _iSize loop + } + + // Update the two last_samples values in the PB as well as the current + // position. + pb.src.last_samples[2] = curr0; + pb.src.last_samples[3] = curr1; + pb.src.cur_addr_frac = curr_pos & 0xFFFF; + } + else // SRCTYPE_NEAREST + { + // No sample rate conversion here: simply read 32 samples from the + // accelerator to the output buffer. + for (u32 i = 0; i < 32; ++i) + samples[i] = AcceleratorGetSample(); + + memcpy(pb.src.last_samples, samples + 28, 4 * sizeof (u16)); + } + + // Update current position in the PB. + pb.audio_addr.cur_addr_hi = (u16)(cur_addr >> 16); + pb.audio_addr.cur_addr_lo = (u16)(cur_addr & 0xFFFF); +} + +// Add samples to an output buffer, with optional volume ramping. +void MixAdd(int* out, const s16* input, u16* pvol, s16* dpop, bool ramp) +{ + u16& volume = pvol[0]; + u16 volume_delta = pvol[1]; + + // If volume ramping is disabled, set volume_delta to 0. That way, the + // mixing loop can avoid testing if volume ramping is enabled at each step, + // and just add volume_delta. + if (!ramp) + volume_delta = 0; - // Update volume - pb.mixer.left = ADPCM_Vol(pb.mixer.left, pb.mixer.left_delta); - pb.mixer.right = ADPCM_Vol(pb.mixer.right, pb.mixer.right_delta); + for (u32 i = 0; i < 32; ++i) + { + s64 sample = input[i]; + sample *= volume; + sample >>= 15; - pb.src.cur_addr_frac = (u16)frac; - pb.audio_addr.cur_addr_hi = samplePos >> 16; - pb.audio_addr.cur_addr_lo = (u16)samplePos; - - } // if (pb.running) + out[i] += (s16)sample; + volume += volume_delta; + + *dpop = (s16)sample; + } } +// Process 1ms of audio (32 samples) from a PB and mix it to the buffers. +void Process1ms(PB_TYPE& pb, const AXBuffers& buffers, AXMixControl mctrl) +{ + // If the voice is not running, nothing to do. + if (!pb.running) + return; + + // Read input samples, performing sample rate conversion if needed. + s16 samples[32]; + GetInputSamples(pb, samples); + + // Apply a global volume ramp using the volume envelope parameters. + for (u32 i = 0; i < 32; ++i) + { + s64 sample = 2 * (s16)samples[i] * (s16)pb.vol_env.cur_volume; + samples[i] = (s16)(sample >> 16); + pb.vol_env.cur_volume += pb.vol_env.cur_volume_delta; + } + + // Optionally, execute a low pass filter + if (pb.lpf.enabled) + { + // TODO + } + + // Mix LRS, AUXA and AUXB depending on mixer_control + // TODO: Handle DPL2 on AUXB. + + if (mctrl & MIX_L) + MixAdd(buffers.left, samples, &pb.mixer.left, &pb.dpop.left, mctrl & MIX_L_RAMP); + if (mctrl & MIX_R) + MixAdd(buffers.right, samples, &pb.mixer.right, &pb.dpop.right, mctrl & MIX_R_RAMP); + if (mctrl & MIX_S) + MixAdd(buffers.surround, samples, &pb.mixer.surround, &pb.dpop.surround, mctrl & MIX_S_RAMP); + + if (mctrl & MIX_AUXA_L) + MixAdd(buffers.auxA_left, samples, &pb.mixer.auxA_left, &pb.dpop.auxA_left, mctrl & MIX_AUXA_L_RAMP); + if (mctrl & MIX_AUXA_R) + MixAdd(buffers.auxA_right, samples, &pb.mixer.auxA_right, &pb.dpop.auxA_right, mctrl & MIX_AUXA_R_RAMP); + if (mctrl & MIX_AUXA_S) + MixAdd(buffers.auxA_surround, samples, &pb.mixer.auxA_surround, &pb.dpop.auxA_surround, mctrl & MIX_AUXA_S_RAMP); + + if (mctrl & MIX_AUXB_L) + MixAdd(buffers.auxB_left, samples, &pb.mixer.auxB_left, &pb.dpop.auxB_left, mctrl & MIX_AUXB_L_RAMP); + if (mctrl & MIX_AUXB_R) + MixAdd(buffers.auxB_right, samples, &pb.mixer.auxB_right, &pb.dpop.auxB_right, mctrl & MIX_AUXB_R_RAMP); + if (mctrl & MIX_AUXB_S) + MixAdd(buffers.auxB_surround, samples, &pb.mixer.auxB_surround, &pb.dpop.auxB_surround, mctrl & MIX_AUXB_S_RAMP); + +#ifdef AX_WII + if (mctrl & MIX_AUXC_L) + MixAdd(buffers.auxC_left, samples, &pb.mixer.auxC_left, &pb.dpop.auxC_left, mctrl & MIX_AUXC_L_RAMP); + if (mctrl & MIX_AUXC_R) + MixAdd(buffers.auxC_right, samples, &pb.mixer.auxC_right, &pb.dpop.auxC_right, mctrl & MIX_AUXC_R_RAMP); + if (mctrl & MIX_AUXC_S) + MixAdd(buffers.auxC_surround, samples, &pb.mixer.auxC_surround, &pb.dpop.auxC_surround, mctrl & MIX_AUXC_S_RAMP); #endif + + // Optionally, phase shift left or right channel to simulate 3D sound. + if (pb.initial_time_delay.on) + { + // TODO + } +} + +} // namespace + +#endif // !_UCODE_AX_VOICE_H diff --git a/Source/Core/Core/Src/HW/DSPHLE/UCodes/UCode_NewAXWii.cpp b/Source/Core/Core/Src/HW/DSPHLE/UCodes/UCode_NewAXWii.cpp new file mode 100644 index 0000000000..40ad6e1947 --- /dev/null +++ b/Source/Core/Core/Src/HW/DSPHLE/UCodes/UCode_NewAXWii.cpp @@ -0,0 +1,383 @@ +// 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 "StringUtil.h" + +#include "../MailHandler.h" +#include "Mixer.h" + +#include "UCodes.h" +#include "UCode_AX_Structs.h" +#include "UCode_NewAXWii.h" + +#define AX_WII +#include "UCode_AX_Voice.h" + + +CUCode_NewAXWii::CUCode_NewAXWii(DSPHLE *dsp_hle, u32 l_CRC) + : CUCode_AX(dsp_hle, l_CRC) +{ + WARN_LOG(DSPHLE, "Instantiating CUCode_NewAXWii"); +} + +CUCode_NewAXWii::~CUCode_NewAXWii() +{ +} + +void CUCode_NewAXWii::HandleCommandList() +{ + // Temp variables for addresses computation + u16 addr_hi, addr_lo; + u16 addr2_hi, addr2_lo; + u16 volume; + +// WARN_LOG(DSPHLE, "Command list:"); +// for (u32 i = 0; m_cmdlist[i] != CMD_END; ++i) +// WARN_LOG(DSPHLE, "%04x", m_cmdlist[i]); +// WARN_LOG(DSPHLE, "-------------"); + + u32 curr_idx = 0; + bool end = false; + while (!end) + { + u16 cmd = m_cmdlist[curr_idx++]; + + switch (cmd) + { + // Some of these commands are unknown, or unused in this AX HLE. + // We still need to skip their arguments using "curr_idx += N". + + case CMD_SETUP: + addr_hi = m_cmdlist[curr_idx++]; + addr_lo = m_cmdlist[curr_idx++]; + SetupProcessing(HILO_TO_32(addr)); + break; + + case CMD_UNK_01: curr_idx += 2; break; + case CMD_UNK_02: curr_idx += 2; break; + case CMD_UNK_03: curr_idx += 2; break; + + case CMD_PROCESS: + addr_hi = m_cmdlist[curr_idx++]; + addr_lo = m_cmdlist[curr_idx++]; + ProcessPBList(HILO_TO_32(addr)); + break; + + case CMD_MIX_AUXA: + case CMD_MIX_AUXB: + case CMD_MIX_AUXC: + volume = m_cmdlist[curr_idx++]; + addr_hi = m_cmdlist[curr_idx++]; + addr_lo = m_cmdlist[curr_idx++]; + addr2_hi = m_cmdlist[curr_idx++]; + addr2_lo = m_cmdlist[curr_idx++]; + MixAUXSamples(cmd - CMD_MIX_AUXA, HILO_TO_32(addr), HILO_TO_32(addr2), volume); + break; + + // These two go together and manipulate some AUX buffers. + case CMD_UNK_08: curr_idx += 13; break; + case CMD_UNK_09: curr_idx += 13; break; + + case CMD_UNK_0A: curr_idx += 4; break; + + case CMD_OUTPUT: + volume = m_cmdlist[curr_idx++]; + addr_hi = m_cmdlist[curr_idx++]; + addr_lo = m_cmdlist[curr_idx++]; + addr2_hi = m_cmdlist[curr_idx++]; + addr2_lo = m_cmdlist[curr_idx++]; + OutputSamples(HILO_TO_32(addr2), HILO_TO_32(addr), volume); + break; + + case CMD_UNK_0C: curr_idx += 5; break; + + case CMD_WM_OUTPUT: + { + u32 addresses[4] = { + (u32)(m_cmdlist[curr_idx + 0] << 16) | m_cmdlist[curr_idx + 1], + (u32)(m_cmdlist[curr_idx + 2] << 16) | m_cmdlist[curr_idx + 3], + (u32)(m_cmdlist[curr_idx + 4] << 16) | m_cmdlist[curr_idx + 5], + (u32)(m_cmdlist[curr_idx + 6] << 16) | m_cmdlist[curr_idx + 7], + }; + curr_idx += 8; + OutputWMSamples(addresses); + break; + } + + case CMD_END: + end = true; + break; + } + } +} + +void CUCode_NewAXWii::SetupProcessing(u32 init_addr) +{ + // TODO: should be easily factorizable with AX + s16 init_data[60]; + + for (u32 i = 0; i < 60; ++i) + init_data[i] = HLEMemory_Read_U16(init_addr + 2 * i); + + // List of all buffers we have to initialize + struct { + int* ptr; + u32 samples; + } buffers[] = { + { m_samples_left, 32 }, + { m_samples_right, 32 }, + { m_samples_surround, 32 }, + { m_samples_auxA_left, 32 }, + { m_samples_auxA_right, 32 }, + { m_samples_auxA_surround, 32 }, + { m_samples_auxB_left, 32 }, + { m_samples_auxB_right, 32 }, + { m_samples_auxB_surround, 32 }, + { m_samples_auxC_left, 32 }, + { m_samples_auxC_right, 32 }, + { m_samples_auxC_surround, 32 }, + + { m_samples_wm0, 6 }, + { m_samples_aux0, 6 }, + { m_samples_wm1, 6 }, + { m_samples_aux1, 6 }, + { m_samples_wm2, 6 }, + { m_samples_aux2, 6 }, + { m_samples_wm3, 6 }, + { m_samples_aux3, 6 } + }; + + u32 init_idx = 0; + for (u32 i = 0; i < sizeof (buffers) / sizeof (buffers[0]); ++i) + { + s32 init_val = (s32)((init_data[init_idx] << 16) | init_data[init_idx + 1]); + s16 delta = (s16)init_data[init_idx + 2]; + + init_idx += 3; + + if (!init_val) + memset(buffers[i].ptr, 0, 3 * buffers[i].samples * sizeof (int)); + else + { + for (u32 j = 0; j < 3 * buffers[i].samples; ++j) + { + buffers[i].ptr[j] = init_val; + init_val += delta; + } + } + } +} + +AXMixControl CUCode_NewAXWii::ConvertMixerControl(u32 mixer_control) +{ + u32 ret = 0; + + if (mixer_control & 0x00000001) ret |= MIX_L; + if (mixer_control & 0x00000002) ret |= MIX_R; + if (mixer_control & 0x00000004) ret |= MIX_L_RAMP | MIX_R_RAMP; + if (mixer_control & 0x00000008) ret |= MIX_S; + if (mixer_control & 0x00000010) ret |= MIX_S_RAMP; + if (mixer_control & 0x00010000) ret |= MIX_AUXA_L; + if (mixer_control & 0x00020000) ret |= MIX_AUXA_R; + if (mixer_control & 0x00040000) ret |= MIX_AUXA_L_RAMP | MIX_AUXA_R_RAMP; + if (mixer_control & 0x00080000) ret |= MIX_AUXA_S; + if (mixer_control & 0x00100000) ret |= MIX_AUXA_S_RAMP; + if (mixer_control & 0x00200000) ret |= MIX_AUXB_L; + if (mixer_control & 0x00400000) ret |= MIX_AUXB_R; + if (mixer_control & 0x00800000) ret |= MIX_AUXB_L_RAMP | MIX_AUXB_R_RAMP; + if (mixer_control & 0x01000000) ret |= MIX_AUXB_S; + if (mixer_control & 0x02000000) ret |= MIX_AUXB_S_RAMP; + if (mixer_control & 0x04000000) ret |= MIX_AUXC_L; + if (mixer_control & 0x08000000) ret |= MIX_AUXC_R; + if (mixer_control & 0x10000000) ret |= MIX_AUXC_L_RAMP | MIX_AUXC_R_RAMP; + if (mixer_control & 0x20000000) ret |= MIX_AUXC_S; + if (mixer_control & 0x40000000) ret |= MIX_AUXC_S_RAMP; + + return (AXMixControl)ret; +} + +void CUCode_NewAXWii::ProcessPBList(u32 pb_addr) +{ + const u32 spms = 32; + + AXPBWii pb; + + while (pb_addr) + { + AXBuffers buffers = {{ + m_samples_left, + m_samples_right, + m_samples_surround, + m_samples_auxA_left, + m_samples_auxA_right, + m_samples_auxA_surround, + m_samples_auxB_left, + m_samples_auxB_right, + m_samples_auxB_surround, + m_samples_auxC_left, + m_samples_auxC_right, + m_samples_auxC_surround + }}; + + if (!ReadPB(pb_addr, pb)) + break; + + for (int curr_ms = 0; curr_ms < 3; ++curr_ms) + { + Process1ms(pb, buffers, ConvertMixerControl(HILO_TO_32(pb.mixer_control))); + + // Forward the buffers + for (u32 i = 0; i < sizeof (buffers.ptrs) / sizeof (buffers.ptrs[0]); ++i) + buffers.ptrs[i] += spms; + } + + WritePB(pb_addr, pb); + pb_addr = HILO_TO_32(pb.next_pb); + } +} + +void CUCode_NewAXWii::MixAUXSamples(int aux_id, u32 write_addr, u32 read_addr, u16 volume) +{ + int* buffers[3] = { 0 }; + int* main_buffers[3] = { + m_samples_left, + m_samples_right, + m_samples_surround + }; + + switch (aux_id) + { + case 0: + buffers[0] = m_samples_auxA_left; + buffers[1] = m_samples_auxA_right; + buffers[2] = m_samples_auxA_surround; + break; + + case 1: + buffers[0] = m_samples_auxB_left; + buffers[1] = m_samples_auxB_right; + buffers[2] = m_samples_auxB_surround; + break; + + case 2: + buffers[0] = m_samples_auxC_left; + buffers[1] = m_samples_auxC_right; + buffers[2] = m_samples_auxC_surround; + break; + } + + // Send the content of AUX buffers to the CPU + if (write_addr) + { + int* ptr = (int*)HLEMemory_Get_Pointer(write_addr); + for (u32 i = 0; i < 3; ++i) + for (u32 j = 0; j < 3 * 32; ++j) + *ptr++ = Common::swap32(buffers[i][j]); + } + + // Then read the buffers from the CPU and add to our main buffers. + int* ptr = (int*)HLEMemory_Get_Pointer(read_addr); + for (u32 i = 0; i < 3; ++i) + for (u32 j = 0; j < 3 * 32; ++j) + { + s64 new_val = main_buffers[i][j] + Common::swap32(*ptr++); + main_buffers[i][j] = (new_val * volume) >> 15; + } +} + +void CUCode_NewAXWii::OutputSamples(u32 lr_addr, u32 surround_addr, u16 volume) +{ + int surround_buffer[3 * 32] = { 0 }; + + for (u32 i = 0; i < 3 * 32; ++i) + surround_buffer[i] = Common::swap32(m_samples_surround[i]); + memcpy(HLEMemory_Get_Pointer(surround_addr), surround_buffer, sizeof (surround_buffer)); + + short buffer[3 * 32 * 2]; + + // Clamp internal buffers to 16 bits. + for (u32 i = 0; i < 3 * 32; ++i) + { + int left = m_samples_left[i]; + int right = m_samples_right[i]; + + // Apply global volume. Cast to s64 to avoid overflow. + left = ((s64)left * volume) >> 15; + right = ((s64)right * volume) >> 15; + + if (left < -32767) left = -32767; + if (left > 32767) left = 32767; + if (right < -32767) right = -32767; + if (right > 32767) right = 32767; + + m_samples_left[i] = left; + m_samples_right[i] = right; + } + + for (u32 i = 0; i < 3 * 32; ++i) + { + buffer[2 * i] = Common::swap16(m_samples_left[i]); + buffer[2 * i + 1] = Common::swap16(m_samples_right[i]); + } + + memcpy(HLEMemory_Get_Pointer(lr_addr), buffer, sizeof (buffer)); +} + +void CUCode_NewAXWii::OutputWMSamples(u32* addresses) +{ + int* buffers[] = { + m_samples_wm0, + m_samples_wm1, + m_samples_wm2, + m_samples_wm3 + }; + + for (u32 i = 0; i < 4; ++i) + { + int* in = buffers[i]; + u16* out = (u16*)HLEMemory_Get_Pointer(addresses[i]); + for (u32 j = 0; j < 3 * 6; ++j) + { + int sample = in[j]; + if (sample < -32767) sample = -32767; + if (sample > 32767) sample = 32767; + out[j] = Common::swap16((u16)sample); + } + } +} + +void CUCode_NewAXWii::DoState(PointerWrap &p) +{ + std::lock_guard<std::mutex> lk(m_processing); + + DoStateShared(p); + DoAXState(p); + + p.Do(m_samples_auxC_left); + p.Do(m_samples_auxC_right); + p.Do(m_samples_auxC_surround); + + p.Do(m_samples_wm0); + p.Do(m_samples_wm1); + p.Do(m_samples_wm2); + p.Do(m_samples_wm3); + + p.Do(m_samples_aux0); + p.Do(m_samples_aux1); + p.Do(m_samples_aux2); + p.Do(m_samples_aux3); +} diff --git a/Source/Core/Core/Src/HW/DSPHLE/UCodes/UCode_NewAXWii.h b/Source/Core/Core/Src/HW/DSPHLE/UCodes/UCode_NewAXWii.h new file mode 100644 index 0000000000..4c9bc5757c --- /dev/null +++ b/Source/Core/Core/Src/HW/DSPHLE/UCodes/UCode_NewAXWii.h @@ -0,0 +1,80 @@ +// 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 Git repository and contact information can be found at +// http://code.google.com/p/dolphin-emu/ + +#ifndef _UCODE_NEWAXWII_H +#define _UCODE_NEWAXWII_H + +#include "UCode_AX.h" + +class CUCode_NewAXWii : public CUCode_AX +{ +public: + CUCode_NewAXWii(DSPHLE *dsp_hle, u32 _CRC); + virtual ~CUCode_NewAXWii(); + + virtual void DoState(PointerWrap &p); + +protected: + int m_samples_auxC_left[32 * 3]; + int m_samples_auxC_right[32 * 3]; + int m_samples_auxC_surround[32 * 3]; + + // Wiimote buffers + int m_samples_wm0[6 * 3]; + int m_samples_aux0[6 * 3]; + int m_samples_wm1[6 * 3]; + int m_samples_aux1[6 * 3]; + int m_samples_wm2[6 * 3]; + int m_samples_aux2[6 * 3]; + int m_samples_wm3[6 * 3]; + int m_samples_aux3[6 * 3]; + + // Convert a mixer_control bitfield to our internal representation for that + // value. Required because that bitfield has a different meaning in some + // versions of AX. + AXMixControl ConvertMixerControl(u32 mixer_control); + + virtual void HandleCommandList(); + + void SetupProcessing(u32 init_addr); + void ProcessPBList(u32 pb_addr); + void MixAUXSamples(int aux_id, u32 write_addr, u32 read_addr, u16 volume); + void OutputSamples(u32 lr_addr, u32 surround_addr, u16 volume); + void OutputWMSamples(u32* addresses); // 4 addresses + +private: + enum CmdType + { + CMD_SETUP = 0x00, + CMD_UNK_01 = 0x01, + CMD_UNK_02 = 0x02, + CMD_UNK_03 = 0x03, + CMD_PROCESS = 0x04, + CMD_MIX_AUXA = 0x05, + CMD_MIX_AUXB = 0x06, + CMD_MIX_AUXC = 0x07, + CMD_UNK_08 = 0x08, + CMD_UNK_09 = 0x09, + CMD_UNK_0A = 0x0A, + CMD_OUTPUT = 0x0B, + CMD_UNK_0C = 0x0C, + CMD_WM_OUTPUT = 0x0D, + CMD_END = 0x0E + }; +}; + +#endif // _UCODE_AXWII diff --git a/Source/Core/Core/Src/HW/DSPHLE/UCodes/UCodes.cpp b/Source/Core/Core/Src/HW/DSPHLE/UCodes/UCodes.cpp index c04bf41403..86773ad020 100644 --- a/Source/Core/Core/Src/HW/DSPHLE/UCodes/UCodes.cpp +++ b/Source/Core/Core/Src/HW/DSPHLE/UCodes/UCodes.cpp @@ -19,6 +19,7 @@ #include "UCode_AX.h" #include "UCode_AXWii.h" +#include "UCode_NewAXWii.h" #include "UCode_Zelda.h" #include "UCode_ROM.h" #include "UCode_CARD.h" @@ -26,6 +27,12 @@ #include "UCode_GBA.h" #include "Hash.h" +#if 0 +# define AXWII CUCode_NewAXWii +#else +# define AXWII CUCode_AXWii +#endif + IUCode* UCodeFactory(u32 _CRC, DSPHLE *dsp_hle, bool bWii) { switch (_CRC) @@ -90,13 +97,13 @@ IUCode* UCodeFactory(u32 _CRC, DSPHLE *dsp_hle, bool bWii) case 0x4cc52064: // Bleach: Versus Crusade case 0xd9c4bf34: // WiiMenu INFO_LOG(DSPHLE, "CRC %08x: Wii - AXWii chosen", _CRC); - return new CUCode_AXWii(dsp_hle, _CRC); + return new AXWII(dsp_hle, _CRC); default: if (bWii) { PanicAlert("DSPHLE: Unknown ucode (CRC = %08x) - forcing AXWii.\n\nTry LLE emulator if this is homebrew.", _CRC); - return new CUCode_AXWii(dsp_hle, _CRC); + return new AXWII(dsp_hle, _CRC); } else { diff --git a/Source/Core/Core/Src/HW/DSPLLE/DSPDebugInterface.cpp b/Source/Core/Core/Src/HW/DSPLLE/DSPDebugInterface.cpp index 2e2816ae77..58534f137a 100644 --- a/Source/Core/Core/Src/HW/DSPLLE/DSPDebugInterface.cpp +++ b/Source/Core/Core/Src/HW/DSPLLE/DSPDebugInterface.cpp @@ -134,7 +134,7 @@ void DSPDebugInterface::toggleMemCheck(unsigned int address) PanicAlert("MemCheck functionality not supported in DSP module."); } -void DSPDebugInterface::insertBLR(unsigned int address) +void DSPDebugInterface::insertBLR(unsigned int address, unsigned int value) { PanicAlert("insertBLR functionality not supported in DSP module."); } diff --git a/Source/Core/Core/Src/HW/DSPLLE/DSPDebugInterface.h b/Source/Core/Core/Src/HW/DSPLLE/DSPDebugInterface.h index 5ace467ae6..dafe91f28b 100644 --- a/Source/Core/Core/Src/HW/DSPLLE/DSPDebugInterface.h +++ b/Source/Core/Core/Src/HW/DSPLLE/DSPDebugInterface.h @@ -27,7 +27,7 @@ public: virtual void setPC(unsigned int address); virtual void step() {} virtual void runToBreakpoint(); - virtual void insertBLR(unsigned int address); + virtual void insertBLR(unsigned int address, unsigned int value); virtual int getColor(unsigned int address); virtual std::string getDescription(unsigned int address); }; diff --git a/Source/Core/Core/Src/HW/DVDInterface.cpp b/Source/Core/Core/Src/HW/DVDInterface.cpp index f2b387fbd6..214fb5dc02 100644 --- a/Source/Core/Core/Src/HW/DVDInterface.cpp +++ b/Source/Core/Core/Src/HW/DVDInterface.cpp @@ -29,6 +29,7 @@ #include "Memmap.h" #include "../VolumeHandler.h" #include "AudioInterface.h" +#include "../Movie.h" // Disc transfer rate measured in bytes per second static const u32 DISC_TRANSFER_RATE_GC = 3125 * 1024; @@ -334,6 +335,17 @@ void ChangeDisc(const char* _newFileName) std::string* _FileName = new std::string(_newFileName); CoreTiming::ScheduleEvent_Threadsafe(0, ejectDisc); CoreTiming::ScheduleEvent_Threadsafe(500000000, insertDisc, (u64)_FileName); + if (Movie::IsRecordingInput()) + { + Movie::g_bDiscChange = true; + std::string fileName = _newFileName; + int sizeofpath = fileName.find_last_of("/\\") + 1; + if (fileName.substr(sizeofpath).length() > 40) + { + PanicAlert("Saving iso filename to .dtm failed; max file name length is 40 characters."); + } + Movie::g_discChange = fileName.substr(sizeofpath); + } } void SetLidOpen(bool _bOpen) diff --git a/Source/Core/Core/Src/HW/EXI_DeviceMemoryCard.cpp b/Source/Core/Core/Src/HW/EXI_DeviceMemoryCard.cpp index 6f4bc502b6..c157e55d1b 100644 --- a/Source/Core/Core/Src/HW/EXI_DeviceMemoryCard.cpp +++ b/Source/Core/Core/Src/HW/EXI_DeviceMemoryCard.cpp @@ -52,6 +52,9 @@ CEXIMemoryCard::CEXIMemoryCard(const int index) , m_bDirty(false) { m_strFilename = (card_index == 0) ? SConfig::GetInstance().m_strMemoryCardA : SConfig::GetInstance().m_strMemoryCardB; + if (Movie::IsPlayingInput() && Movie::IsConfigSaved() && Movie::IsUsingMemcard() && Movie::IsStartingFromClearSave()) + m_strFilename = "Movie.raw"; + // we're potentially leaking events here, since there's no UnregisterEvent until emu shutdown, but I guess it's inconsequential et_this_card = CoreTiming::RegisterEvent((card_index == 0) ? "memcardA" : "memcardB", FlushCallback); diff --git a/Source/Core/Core/Src/HW/GCMemcard.cpp b/Source/Core/Core/Src/HW/GCMemcard.cpp index 381f942925..dd15a32914 100644 --- a/Source/Core/Core/Src/HW/GCMemcard.cpp +++ b/Source/Core/Core/Src/HW/GCMemcard.cpp @@ -265,7 +265,7 @@ bool GCMemcard::Save() mcdFile.WriteBytes(&dir_backup, BLOCK_SIZE); mcdFile.WriteBytes(&bat, BLOCK_SIZE); mcdFile.WriteBytes(&bat_backup, BLOCK_SIZE); - for (int i = 0; i < maxBlock - MC_FST_BLOCKS; ++i) + for (unsigned int i = 0; i < maxBlock - MC_FST_BLOCKS; ++i) { mcdFile.WriteBytes(mc_data_blocks[i].block, BLOCK_SIZE); } @@ -473,11 +473,20 @@ std::string GCMemcard::DEntry_IconFmt(u8 index) const return format; } -u16 GCMemcard::DEntry_AnimSpeed(u8 index) const +std::string GCMemcard::DEntry_AnimSpeed(u8 index) const { if (!m_valid || index > DIRLEN) - return 0xFF; - return BE16(CurrentDir->Dir[index].AnimSpeed); + return ""; + int x = CurrentDir->Dir[index].AnimSpeed[0]; + std::string speed; + for(int i = 0; i < 16; i++) + { + if (i == 8) x = CurrentDir->Dir[index].AnimSpeed[1]; + speed.push_back((x & 0x80) ? '1' : '0'); + x = x << 1; + } + speed.push_back(0); + return speed; } std::string GCMemcard::DEntry_Permissions(u8 index) const @@ -578,7 +587,7 @@ u16 GCMemcard::BlockAlloc::NextFreeBlock(u16 StartingBlock) const for (u16 i = StartingBlock; i < BAT_SIZE; ++i) if (Map[i-MC_FST_BLOCKS] == 0) return i; - for (u16 i = 0; i < StartingBlock; ++i) + for (u16 i = MC_FST_BLOCKS; i < StartingBlock; ++i) if (Map[i-MC_FST_BLOCKS] == 0) return i; } @@ -600,7 +609,7 @@ bool GCMemcard::BlockAlloc::ClearBlocks(u16 FirstBlock, u16 BlockCount) { return false; } - for (int i = 0; i < length; ++i) + for (unsigned int i = 0; i < length; ++i) Map[blocks.at(i)-MC_FST_BLOCKS] = 0; FreeBlocks = BE16(BE16(FreeBlocks) + BlockCount); @@ -616,7 +625,7 @@ u32 GCMemcard::GetSaveData(u8 index, std::vector<GCMBlock> & Blocks) const u16 block = DEntry_FirstBlock(index); u16 BlockCount = DEntry_BlockCount(index); - u16 memcardSize = BE16(hdr.SizeMb) * MBIT_TO_BLOCKS; + //u16 memcardSize = BE16(hdr.SizeMb) * MBIT_TO_BLOCKS; if ((block == 0xFFFF) || (BlockCount == 0xFFFF)) { @@ -660,12 +669,10 @@ u32 GCMemcard::ImportFile(DEntry& direntry, std::vector<GCMBlock> &saveBlocks) Directory UpdatedDir = *CurrentDir; // find first free dir entry - int index = -1; for (int i=0; i < DIRLEN; i++) { if (BE32(UpdatedDir.Dir[i].Gamecode) == 0xFFFFFFFF) { - index = i; UpdatedDir.Dir[i] = direntry; *(u16*)&UpdatedDir.Dir[i].FirstBlock = BE16(firstBlock); UpdatedDir.Dir[i].CopyCounter = UpdatedDir.Dir[i].CopyCounter+1; @@ -878,7 +885,7 @@ u32 GCMemcard::ImportGciInternal(FILE* gcih, const char *inputFile, const std::s std::vector<GCMBlock> saveData; saveData.reserve(size); - for (int i = 0; i < size; ++i) + for (unsigned int i = 0; i < size; ++i) { GCMBlock b; gci.ReadBytes(b.block, BLOCK_SIZE); @@ -991,7 +998,7 @@ u32 GCMemcard::ExportGci(u8 index, const char *fileName, const std::string &dire return NOMEMCARD; } gci.Seek(DENTRY_SIZE + offset, SEEK_SET); - for (int i = 0; i < size; ++i) + for (unsigned int i = 0; i < size; ++i) { gci.WriteBytes(saveData[i].block, BLOCK_SIZE); } @@ -1086,15 +1093,18 @@ u32 GCMemcard::ReadAnimRGBA8(u8 index, u32* buffer, u8 *delays) const // To ensure only one type of icon is used // Sonic Heroes it the only game I have seen that tries to use a CI8 and RGB5A3 icon - int fmtCheck = 0; + //int fmtCheck = 0; int formats = BE16(CurrentDir->Dir[index].IconFmt); int fdelays = BE16(CurrentDir->Dir[index].AnimSpeed); int flags = CurrentDir->Dir[index].BIFlags; - // Timesplitters 2 is the only game that I see this in + // Timesplitters 2 and 3 is the only game that I see this in // May be a hack - if (flags == 0xFB) flags = ~flags; + //if (flags == 0xFB) flags = ~flags; + // Batten Kaitos has 0x65 as flag too. Everything but the first 3 bytes seems irrelevant. + // Something similar happens with Wario Ware Inc. AnimSpeed + int bnrFormat = (flags&3); u32 DataOffset = BE32(CurrentDir->Dir[index].ImageOffset); @@ -1110,7 +1120,6 @@ u32 GCMemcard::ReadAnimRGBA8(u8 index, u32* buffer, u8 *delays) const switch (bnrFormat) { case 1: - case 3: animData += 96*32 + 2*256; // image+palette break; case 2: @@ -1122,40 +1131,48 @@ u32 GCMemcard::ReadAnimRGBA8(u8 index, u32* buffer, u8 *delays) const u8* data[8]; int frames = 0; - for (int i = 0; i < 8; i++) { fmts[i] = (formats >> (2*i))&3; - delays[i] = ((fdelays >> (2*i))&3) << 2; + delays[i] = ((fdelays >> (2*i))&3); data[i] = animData; - if (!fmtCheck) fmtCheck = fmts[i]; - if (fmtCheck == fmts[i]) + if (!delays[i]) + { + //First icon_speed = 0 indicates there aren't any more icons + break; + } + //If speed is set there is an icon (it can be a "blank frame") + frames++; + if (fmts[i] != 0) { switch (fmts[i]) { case CI8SHARED: // CI8 with shared palette animData += 32*32; - frames++; break; case RGB5A3: // RGB5A3 animData += 32*32*2; - frames++; break; case CI8: // CI8 with own palette animData += 32*32 + 2*256; - frames++; break; } } } u16* sharedPal = (u16*)(animData); + int j = 0; for (int i = 0; i < 8; i++) { - if (fmtCheck == fmts[i]) + if (!delays[i]) + { + //First icon_speed = 0 indicates there aren't any more icons + break; + } + if (fmts[i] != 0) { switch (fmts[i]) { @@ -1165,6 +1182,7 @@ u32 GCMemcard::ReadAnimRGBA8(u8 index, u32* buffer, u8 *delays) const break; case RGB5A3: // RGB5A3 decode5A3image(buffer, (u16*)(data[i]), 32, 32); + buffer += 32*32; break; case CI8: // CI8 with own palette u16 *paldata = (u16*)(data[i] + 32*32); @@ -1173,6 +1191,33 @@ u32 GCMemcard::ReadAnimRGBA8(u8 index, u32* buffer, u8 *delays) const break; } } + else + { + //Speed is set but there's no actual icon + //This is used to reduce animation speed in Pikmin and Luigi's Mansion for example + //These "blank frames" show the next icon + for(j=i; j<8;++j) + { + if (fmts[j] != 0) + { + switch (fmts[j]) + { + case CI8SHARED: // CI8 with shared palette + decodeCI8image(buffer,data[j],sharedPal,32,32); + break; + case RGB5A3: // RGB5A3 + decode5A3image(buffer, (u16*)(data[j]), 32, 32); + buffer += 32*32; + break; + case CI8: // CI8 with own palette + u16 *paldata = (u16*)(data[j] + 32*32); + decodeCI8image(buffer, data[j], paldata, 32, 32); + buffer += 32*32; + break; + } + } + } + } } return frames; @@ -1269,7 +1314,6 @@ void GCMemcard::FormatInternal(GCMC_Header &GCP) calc_checksumsBE((u16*)p_bat_backup+2, 0xFFE, &p_bat_backup->Checksum, &p_bat_backup->Checksum_Inv); } - void GCMemcard::CARD_GetSerialNo(u32 *serial1,u32 *serial2) { u32 serial[8]; @@ -1349,7 +1393,7 @@ s32 GCMemcard::PSO_MakeSaveGameValid(DEntry& direntry, std::vector<GCMBlock> &Fi if (strcmp((char*)direntry.Filename,"PSO_SYSTEM")!=0) { // check for PSO3 system file - if (strcmp((char*)&FileBuffer[0].block[0x08],"PSO3_SYSTEM")==0) + if (strcmp((char*)direntry.Filename,"PSO3_SYSTEM")==0) { // PSO3 data block size adjustment pso3offset = 0x10; diff --git a/Source/Core/Core/Src/HW/GCMemcard.h b/Source/Core/Core/Src/HW/GCMemcard.h index d2de93effb..557187b384 100644 --- a/Source/Core/Core/Src/HW/GCMemcard.h +++ b/Source/Core/Core/Src/HW/GCMemcard.h @@ -116,8 +116,8 @@ private: // bits 0 and 1: image format // 00 no banner // 01 CI8 banner - // 01 RGB5A3 banner - // 11 ? maybe ==01? haven't seen it + // 10 RGB5A3 banner + // 11 ? maybe ==00? Time Splitters 2 and 3 have it and don't have banner // u8 Filename[DENTRY_STRLEN]; //0x08 0x20 filename u8 ModTime[4]; //0x28 0x04 Time of file's last modification in seconds since 12am, January 1st, 2000 @@ -213,7 +213,7 @@ public: u32 DEntry_ModTime(u8 index) const; u32 DEntry_ImageOffset(u8 index) const; std::string DEntry_IconFmt(u8 index) const; - u16 DEntry_AnimSpeed(u8 index) const; + std::string DEntry_AnimSpeed(u8 index) const; std::string DEntry_Permissions(u8 index) const; u8 DEntry_CopyCounter(u8 index) const; // get first block for file diff --git a/Source/Core/Core/Src/HW/Memmap.cpp b/Source/Core/Core/Src/HW/Memmap.cpp index 1156d456ad..2da999eeac 100644 --- a/Source/Core/Core/Src/HW/Memmap.cpp +++ b/Source/Core/Core/Src/HW/Memmap.cpp @@ -656,8 +656,10 @@ u8 *GetPointer(const u32 _Address) case 0x9: case 0xd: if (SConfig::GetInstance().m_LocalCoreStartupParameter.bWii) + { if ((_Address & 0xfffffff) < EXRAM_SIZE) return m_pPhysicalEXRAM + (_Address & EXRAM_MASK); + } else break; diff --git a/Source/Core/Core/Src/HW/SI.cpp b/Source/Core/Core/Src/HW/SI.cpp index 84a3744d6f..0f563806ce 100644 --- a/Source/Core/Core/Src/HW/SI.cpp +++ b/Source/Core/Core/Src/HW/SI.cpp @@ -273,7 +273,7 @@ void Init() g_Channel[i].m_InLo.Hex = 0; if (Movie::IsRecordingInput() || Movie::IsPlayingInput()) - AddDevice(Movie::IsUsingPad(i) ? SIDEVICE_GC_CONTROLLER : SIDEVICE_NONE, i); + AddDevice(Movie::IsUsingPad(i) ? (Movie::IsUsingBongo(i) ? SIDEVICE_GC_TARUKONGA : SIDEVICE_GC_CONTROLLER) : SIDEVICE_NONE, i); else AddDevice(SConfig::GetInstance().m_SIDevice[i], i); } diff --git a/Source/Core/Core/Src/HW/SI_DeviceAMBaseboard.cpp b/Source/Core/Core/Src/HW/SI_DeviceAMBaseboard.cpp index 897b6d1227..3537ed3747 100644 --- a/Source/Core/Core/Src/HW/SI_DeviceAMBaseboard.cpp +++ b/Source/Core/Core/Src/HW/SI_DeviceAMBaseboard.cpp @@ -262,7 +262,6 @@ int CSIDevice_AMBaseboard::RunBuffer(u8* _pBuffer, int _iLength) { int cmd = *jvs_io++; - int unknown = 0; DEBUG_LOG(AMBASEBOARDDEBUG, "JVS IO, node=%d, cmd=%02x", node, cmd); switch (cmd) @@ -362,10 +361,7 @@ int CSIDevice_AMBaseboard::RunBuffer(u8* _pBuffer, int _iLength) } case 0xf0: if (*jvs_io++ == 0xD9) - { ERROR_LOG(AMBASEBOARDDEBUG, "JVS RESET"); - } else - unknown = 1; msg.addData(1); d10_1 |= 1; diff --git a/Source/Core/Core/Src/HW/SI_DeviceGCController.cpp b/Source/Core/Core/Src/HW/SI_DeviceGCController.cpp index a9b708324d..74c020fd39 100644 --- a/Source/Core/Core/Src/HW/SI_DeviceGCController.cpp +++ b/Source/Core/Core/Src/HW/SI_DeviceGCController.cpp @@ -132,15 +132,17 @@ bool CSIDevice_GCController::GetData(u32& _Hi, u32& _Low) if(Movie::IsPlayingInput()) { Movie::PlayController(&PadStatus, ISIDevice::m_iDeviceNumber); - if(!Core::g_CoreStartupParameter.bWii) + if(!Movie::IsUsingWiimote(0)) Movie::InputUpdate(); } else if(Movie::IsRecordingInput()) { Movie::RecordInput(&PadStatus, ISIDevice::m_iDeviceNumber); - if(!Core::g_CoreStartupParameter.bWii) + if(!Movie::IsUsingWiimote(0)) Movie::InputUpdate(); } + else + Movie::CheckPadStatus(&PadStatus, ISIDevice::m_iDeviceNumber); // Thankfully changing mode does not change the high bits ;) _Hi = (u32)((u8)PadStatus.stickY); diff --git a/Source/Core/Core/Src/HW/Wiimote.cpp b/Source/Core/Core/Src/HW/Wiimote.cpp index 30ab7af141..0928deffb1 100644 --- a/Source/Core/Core/Src/HW/Wiimote.cpp +++ b/Source/Core/Core/Src/HW/Wiimote.cpp @@ -136,9 +136,9 @@ void DoState(unsigned char **ptr, int mode) { // TODO: - //PointerWrap p(ptr, mode); - //for (unsigned int i=0; i<4; ++i) - // ((WiimoteEmu::Wiimote*)g_plugin.controllers[i])->DoState(p); + PointerWrap p(ptr, mode); + for (unsigned int i=0; i<4; ++i) + ((WiimoteEmu::Wiimote*)g_plugin.controllers[i])->DoState(p); } // ___________________________________________________________________________ diff --git a/Source/Core/Core/Src/HW/WiimoteEmu/EmuSubroutines.cpp b/Source/Core/Core/Src/HW/WiimoteEmu/EmuSubroutines.cpp index e7036c8fcb..5c34fff9ac 100644 --- a/Source/Core/Core/Src/HW/WiimoteEmu/EmuSubroutines.cpp +++ b/Source/Core/Core/Src/HW/WiimoteEmu/EmuSubroutines.cpp @@ -594,13 +594,69 @@ void Wiimote::SendReadDataReply(ReadRequest& _request) void Wiimote::DoState(PointerWrap& p) { - // not working :( - //if (p.MODE_READ == p.GetMode()) - //{ - // // LOAD - // Reset(); // should cause a status report to be sent, then wii should re-setup wiimote - //} - //p.Do(m_reporting_channel); + p.Do(m_extension->active_extension); + p.Do(m_extension->switch_extension); + + p.Do(m_accel); + p.Do(m_index); + p.Do(ir_sin); + p.Do(ir_cos); + p.Do(m_rumble_on); + p.Do(m_speaker_mute); + p.Do(m_motion_plus_present); + p.Do(m_motion_plus_active); + p.Do(m_reporting_auto); + p.Do(m_reporting_mode); + p.Do(m_reporting_channel); + p.Do(m_shake_step); + p.Do(m_sensor_bar_on_top); + p.Do(m_status); + p.Do(m_adpcm_state); + p.Do(m_ext_key); + p.DoArray(m_eeprom, sizeof(m_eeprom)); + p.Do(m_reg_motion_plus); + p.Do(m_reg_ir); + p.Do(m_reg_ext); + p.Do(m_reg_speaker); + + //Do 'm_read_requests' queue + { + u32 size = 0; + if (p.mode == PointerWrap::MODE_READ) + { + //clear + while (m_read_requests.size()) + m_read_requests.pop(); + + p.Do(size); + while (size--) + { + ReadRequest tmp; + p.Do(tmp.address); + p.Do(tmp.position); + p.Do(tmp.size); + tmp.data = new u8[tmp.size]; + p.DoArray(tmp.data, tmp.size); + m_read_requests.push(tmp); + } + } + else + { + std::queue<ReadRequest> tmp_queue(m_read_requests); + size = m_read_requests.size(); + p.Do(size); + while (!tmp_queue.empty()) + { + ReadRequest tmp = tmp_queue.front(); + p.Do(tmp.address); + p.Do(tmp.position); + p.Do(tmp.size); + p.DoArray(tmp.data, tmp.size); + tmp_queue.pop(); + } + } + } + p.DoMarker("Wiimote"); } } diff --git a/Source/Core/Core/Src/HW/WiimoteEmu/WiimoteEmu.cpp b/Source/Core/Core/Src/HW/WiimoteEmu/WiimoteEmu.cpp index 6f7f80ece7..b7652e973a 100644 --- a/Source/Core/Core/Src/HW/WiimoteEmu/WiimoteEmu.cpp +++ b/Source/Core/Core/Src/HW/WiimoteEmu/WiimoteEmu.cpp @@ -762,9 +762,9 @@ void Wiimote::Update() } } } - if (Movie::IsRecordingInput()) + if (!Movie::IsPlayingInput()) { - Movie::RecordWiimote(m_index, data, rptf, m_reg_ir.mode); + Movie::CheckWiimoteStatus(m_index, data, rptf, m_reg_ir.mode); } // don't send a data report if auto reporting is off diff --git a/Source/Core/Core/Src/HW/WiimoteReal/IOdarwin.mm b/Source/Core/Core/Src/HW/WiimoteReal/IOdarwin.mm index 8e3586f7d9..9ee39e5b92 100644 --- a/Source/Core/Core/Src/HW/WiimoteReal/IOdarwin.mm +++ b/Source/Core/Core/Src/HW/WiimoteReal/IOdarwin.mm @@ -185,6 +185,11 @@ bool Wiimote::Connect() RealDisconnect(); return false; } + + // As of 10.8 these need explicit retaining or writing to the wiimote has a very high + // chance of crashing and burning. + [ichan retain]; + [cchan retain]; NOTICE_LOG(WIIMOTE, "Connected to wiimote %i at %s", index + 1, [[btd getAddressString] UTF8String]); @@ -215,7 +220,8 @@ void Wiimote::RealDisconnect() m_wiimote_thread.join(); [btd closeConnection]; - + [ichan release]; + [cchan release]; btd = NULL; cchan = NULL; ichan = NULL; diff --git a/Source/Core/Core/Src/HW/WiimoteReal/WiimoteReal.cpp b/Source/Core/Core/Src/HW/WiimoteReal/WiimoteReal.cpp index 5e03e36e68..28ce6106c7 100644 --- a/Source/Core/Core/Src/HW/WiimoteReal/WiimoteReal.cpp +++ b/Source/Core/Core/Src/HW/WiimoteReal/WiimoteReal.cpp @@ -512,14 +512,14 @@ void StateChange(EMUSTATE_CHANGE newState) // TODO: disable/enable auto reporting, maybe } -#define ARRAYSIZE(_arr) (sizeof(_arr)/(sizeof(_arr[0]))) - bool IsValidBluetoothName(const char* name) { static const char* kValidWiiRemoteBluetoothNames[] = { "Nintendo RVL-CNT-01", "Nintendo RVL-CNT-01-TR", "Nintendo RVL-WBC-01", }; + if (name == NULL) + return false; for (size_t i = 0; i < ARRAYSIZE(kValidWiiRemoteBluetoothNames); i++) if (strcmp(name, kValidWiiRemoteBluetoothNames[i]) == 0) return true; diff --git a/Source/Core/Core/Src/IPC_HLE/WII_IPC_HLE.cpp b/Source/Core/Core/Src/IPC_HLE/WII_IPC_HLE.cpp index afa2b2ceb0..db45802e6f 100644 --- a/Source/Core/Core/Src/IPC_HLE/WII_IPC_HLE.cpp +++ b/Source/Core/Core/Src/IPC_HLE/WII_IPC_HLE.cpp @@ -321,7 +321,7 @@ void ExecuteCommand(u32 _Address) bool CmdSuccess = false; ECommandType Command = static_cast<ECommandType>(Memory::Read_U32(_Address)); - volatile int DeviceID = Memory::Read_U32(_Address + 8); + volatile s32 DeviceID = Memory::Read_U32(_Address + 8); IWII_IPC_HLE_Device* pDevice = (DeviceID >= 0 && DeviceID < IPC_MAX_FDS) ? g_FdMap[DeviceID] : NULL; diff --git a/Source/Core/Core/Src/IPC_HLE/WII_IPC_HLE_Device.h b/Source/Core/Core/Src/IPC_HLE/WII_IPC_HLE_Device.h index c124bb4448..d2907d7ee9 100644 --- a/Source/Core/Core/Src/IPC_HLE/WII_IPC_HLE_Device.h +++ b/Source/Core/Core/Src/IPC_HLE/WII_IPC_HLE_Device.h @@ -21,8 +21,7 @@ #include <queue> #include "../HW/Memmap.h" -class PointerWrap; - +#include "ChunkFile.h" #define FS_SUCCESS (u32)0 // Success #define FS_EACCES (u32)-1 // Permission denied @@ -62,7 +61,11 @@ public: virtual ~IWII_IPC_HLE_Device() { } - virtual void DoState(PointerWrap& p) { DoStateShared(p); } + virtual void DoState(PointerWrap& p) + { + DoStateShared(p); + p.Do(m_Active); + } void DoStateShared(PointerWrap& p); diff --git a/Source/Core/Core/Src/IPC_HLE/WII_IPC_HLE_Device_FileIO.cpp b/Source/Core/Core/Src/IPC_HLE/WII_IPC_HLE_Device_FileIO.cpp index dfe63ee1ef..6b490a1922 100644 --- a/Source/Core/Core/Src/IPC_HLE/WII_IPC_HLE_Device_FileIO.cpp +++ b/Source/Core/Core/Src/IPC_HLE/WII_IPC_HLE_Device_FileIO.cpp @@ -183,8 +183,8 @@ void CWII_IPC_HLE_Device_FileIO::CloseFile() bool CWII_IPC_HLE_Device_FileIO::Seek(u32 _CommandAddress) { u32 ReturnValue = FS_RESULT_FATAL; - const s32 SeekPosition = Memory::Read_U32(_CommandAddress + 0xC); - const s32 Mode = Memory::Read_U32(_CommandAddress + 0x10); + const u32 SeekPosition = Memory::Read_U32(_CommandAddress + 0xC); + const u32 Mode = Memory::Read_U32(_CommandAddress + 0x10); if (OpenFile()) @@ -205,7 +205,7 @@ bool CWII_IPC_HLE_Device_FileIO::Seek(u32 _CommandAddress) } case 1: { - s32 wantedPos = SeekPosition+m_SeekPos; + u32 wantedPos = SeekPosition+m_SeekPos; if (wantedPos >=0 && wantedPos <= fileSize) { m_SeekPos = wantedPos; @@ -215,7 +215,7 @@ bool CWII_IPC_HLE_Device_FileIO::Seek(u32 _CommandAddress) } case 2: { - s32 wantedPos = fileSize+m_SeekPos; + u64 wantedPos = fileSize+m_SeekPos; if (wantedPos >=0 && wantedPos <= fileSize) { m_SeekPos = wantedPos; @@ -371,6 +371,8 @@ void CWII_IPC_HLE_Device_FileIO::DoState(PointerWrap &p) p.Do(have_file_handle); p.Do(m_Mode); p.Do(seek); + p.Do(m_SeekPos); + p.Do(m_Filename); if (p.GetMode() == PointerWrap::MODE_READ) { diff --git a/Source/Core/Core/Src/IPC_HLE/WII_IPC_HLE_Device_es.cpp b/Source/Core/Core/Src/IPC_HLE/WII_IPC_HLE_Device_es.cpp index ae389d7b69..f409c88c83 100644 --- a/Source/Core/Core/Src/IPC_HLE/WII_IPC_HLE_Device_es.cpp +++ b/Source/Core/Core/Src/IPC_HLE/WII_IPC_HLE_Device_es.cpp @@ -57,7 +57,11 @@ #include "NandPaths.h" #include "CommonPaths.h" #include "IPC_HLE/WII_IPC_HLE_Device_usb.h" +#include "../Movie.h" +#ifdef _WIN32 +#include <Windows.h> +#endif std::string CWII_IPC_HLE_Device_es::m_ContentFile; @@ -783,14 +787,17 @@ bool CWII_IPC_HLE_Device_es::IOCtlV(u32 _CommandAddress) } else { + static CWII_IPC_HLE_Device_usb_oh1_57e_305* s_Usb = GetUsbPointer(); + bool* wiiMoteConnected = new bool[s_Usb->m_WiiMotes.size()]; + for(unsigned int i = 0; i < s_Usb->m_WiiMotes.size(); + i++) wiiMoteConnected[i] = s_Usb->m_WiiMotes[i].IsConnected(); + std::string tContentFile(m_ContentFile.c_str()); WII_IPC_HLE_Interface::Reset(true); WII_IPC_HLE_Interface::Init(); - - static CWII_IPC_HLE_Device_usb_oh1_57e_305* s_Usb = GetUsbPointer(); for (unsigned int i = 0; i < s_Usb->m_WiiMotes.size(); i++) { - if (s_Usb->m_WiiMotes[i].IsConnected()) + if (wiiMoteConnected[i]) { s_Usb->m_WiiMotes[i].Activate(false); s_Usb->m_WiiMotes[i].Activate(true); @@ -801,6 +808,7 @@ bool CWII_IPC_HLE_Device_es::IOCtlV(u32 _CommandAddress) } } + delete[] wiiMoteConnected; WII_IPC_HLE_Interface::SetDefaultContentFile(tContentFile); } // Pass the "#002 check" @@ -891,6 +899,52 @@ u32 CWII_IPC_HLE_Device_es::ES_DIVerify(u8* _pTMD, u32 _sz) File::CreateFullPath(tmdPath); File::CreateFullPath(Common::GetTitleDataPath(tmdTitleID)); + + Movie::g_titleID = tmdTitleID; + std::string savePath = Common::GetTitleDataPath(tmdTitleID); + if (Movie::IsRecordingInput()) + { + // TODO: Check for the actual save data + if (File::Exists((savePath + "banner.bin").c_str())) + Movie::g_bClearSave = false; + else + Movie::g_bClearSave = true; + } + + // TODO: Force the game to save to another location, instead of moving the user's save. + if (Movie::IsPlayingInput() && Movie::IsConfigSaved() && Movie::IsStartingFromClearSave()) + { + if (File::Exists((savePath + "banner.bin").c_str())) + { + if (File::Exists((savePath + "../backup/").c_str())) + { + // The last run of this game must have been to play back a movie, so their save is already backed up. + File::DeleteDirRecursively(savePath.c_str()); + } + else + { + #ifdef _WIN32 + MoveFile(savePath.c_str(), (savePath + "../backup/").c_str()); + #else + File::CopyDir(savePath.c_str(),(savePath + "../backup/").c_str()); + File::DeleteDirRecursively(savePath.c_str()); + #endif + } + } + } + else if (File::Exists((savePath + "../backup/").c_str())) + { + // Delete the save made by a previous movie, and copy back the user's save. + if (File::Exists((savePath + "banner.bin").c_str())) + File::DeleteDirRecursively(savePath); + #ifdef _WIN32 + MoveFile((savePath + "../backup/").c_str(), savePath.c_str()); + #else + File::CopyDir((savePath + "../backup/").c_str(), savePath.c_str()); + File::DeleteDirRecursively((savePath + "../backup/").c_str()); + #endif + } + if(!File::Exists(tmdPath)) { File::IOFile _pTMDFile(tmdPath, "wb"); diff --git a/Source/Core/Core/Src/IPC_HLE/WII_IPC_HLE_Device_net.cpp b/Source/Core/Core/Src/IPC_HLE/WII_IPC_HLE_Device_net.cpp index 75db39b994..0ac752e867 100644 --- a/Source/Core/Core/Src/IPC_HLE/WII_IPC_HLE_Device_net.cpp +++ b/Source/Core/Core/Src/IPC_HLE/WII_IPC_HLE_Device_net.cpp @@ -46,6 +46,7 @@ it failed) #endif #include "WII_IPC_HLE_Device_net.h" +#include "../ConfigManager.h" #include "FileUtil.h" #include <stdio.h> #include <string> @@ -276,11 +277,36 @@ bool CWII_IPC_HLE_Device_net_ncd_manage::IOCtlV(u32 _CommandAddress) // No idea why the fifth and sixth bytes are left untouched. { // hardcoded address as a fallback - // TODO: Make this configurable? Different MAC addresses MIGHT be needed for requesting a user id or encrypting content with NWC24 const u8 default_address[] = { 0x00, 0x19, 0x1e, 0xfd, 0x71, 0x84 }; INFO_LOG(WII_IPC_NET, "NET_NCD_MANAGE: IOCTLV_NCD_GETWIRELESSMACADDRESS"); + if (!SConfig::GetInstance().m_WirelessMac.empty()) + { + int x = 0; + int tmpaddress[6]; + for (unsigned int i = 0; i < SConfig::GetInstance().m_WirelessMac.length() && x < 6; i++) + { + if (SConfig::GetInstance().m_WirelessMac[i] == ':' || SConfig::GetInstance().m_WirelessMac[i] == '-') + continue; + + std::stringstream ss; + ss << std::hex << SConfig::GetInstance().m_WirelessMac[i]; + if (SConfig::GetInstance().m_WirelessMac[i+1] != ':' && SConfig::GetInstance().m_WirelessMac[i+1] != '-') + { + ss << std::hex << SConfig::GetInstance().m_WirelessMac[i+1]; + i++; + } + ss >> tmpaddress[x]; + x++; + } + u8 address[6]; + for (int i = 0; i < 6;i++) + address[i] = tmpaddress[i]; + Memory::WriteBigEData(address, CommandBuffer.PayloadBuffer.at(1).m_Address, 4); + break; + } + #if defined(__linux__) const char *check_devices[3] = { "wlan0", "ath0", "eth0" }; int fd, ret; @@ -324,7 +350,6 @@ bool CWII_IPC_HLE_Device_net_ncd_manage::IOCtlV(u32 _CommandAddress) if (SUCCEEDED(ret)) Memory::WriteBigEData(adapter_info->Address, CommandBuffer.PayloadBuffer.at(1).m_Address, 4); else Memory::WriteBigEData(default_address, CommandBuffer.PayloadBuffer.at(1).m_Address, 4); - delete[] adapter_info; #else Memory::WriteBigEData(default_address, CommandBuffer.PayloadBuffer.at(1).m_Address, 4); 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 d53d1ebd2a..af10e98d60 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 @@ -104,14 +104,8 @@ CWII_IPC_HLE_Device_usb_oh1_57e_305::~CWII_IPC_HLE_Device_usb_oh1_57e_305() void CWII_IPC_HLE_Device_usb_oh1_57e_305::DoState(PointerWrap &p) { -/* - //things that do not get saved: (why not?) - - std::vector<CWII_IPC_HLE_WiiMote> m_WiiMotes; - - std::deque<SQueuedEvent> m_EventQueue; - */ - + p.Do(m_Active); + p.Do(m_ControllerBD); p.Do(m_CtrlSetup); p.Do(m_ACLSetup); p.Do(m_HCIEndpoint); @@ -119,75 +113,30 @@ void CWII_IPC_HLE_Device_usb_oh1_57e_305::DoState(PointerWrap &p) p.Do(m_last_ticks); p.DoArray(m_PacketCount,4); p.Do(m_ScanEnable); + p.Do(m_EventQueue); m_acl_pool.DoState(p); - bool storeFullData = (Movie::IsRecordingInput() || Movie::IsPlayingInput()); - p.Do(storeFullData); - p.DoMarker("storeFullData in CWII_IPC_HLE_Device_usb_oh1_57e_305"); - - if (!storeFullData) - { - if (p.GetMode() == PointerWrap::MODE_READ) - { - m_EventQueue.clear(); - - if (SConfig::GetInstance().m_WiimoteReconnectOnLoad) - { - // Reset the connection of all connected wiimotes - for (unsigned int i = 0; i < 4; i++) - { - if (!m_WiiMotes[i].IsInactive()) - { - m_WiiMotes[i].Activate(false); - m_WiiMotes[i].Activate(true); - } - else - { - m_WiiMotes[i].Activate(false); - } - } - } - } + for (unsigned int i = 0; i < 4; i++)
+ m_WiiMotes[i].DoState(p);
+
+ // Reset the connection of real and hybrid wiimotes
+ if (p.GetMode() == PointerWrap::MODE_READ && SConfig::GetInstance().m_WiimoteReconnectOnLoad)
+ {
+ for (unsigned int i = 0; i < 4; i++)
+ {
+ if (WIIMOTE_SRC_EMU == g_wiimote_sources[i] || WIIMOTE_SRC_NONE == g_wiimote_sources[i])
+ continue;
+ // TODO: Selectively clear real wiimote messages if possible. Or create a real wiimote channel and reporting mode pre-setup to vacate the need for m_WiimoteReconnectOnLoad.
+ m_EventQueue.clear();
+ if (!m_WiiMotes[i].IsInactive())
+ {
+ m_WiiMotes[i].Activate(false);
+ m_WiiMotes[i].Activate(true);
+ }
+ else
+ m_WiiMotes[i].Activate(false);
+ }
} - else - { - // I'm not sure why these things aren't normally saved, but I think they can affect the emulation state, - // so if sync matters (e.g. if a movie is active), we really should save them. - // also, it's definitely not safe to do the above auto-reconnect hack either. - // (unless we can do it without changing anything that affects emulation state, which is not currently the case) - - p.Do(m_EventQueue); - p.DoMarker("m_EventQueue"); - - // m_WiiMotes is kind of annoying to save. maybe this could be done in a more general way. - u32 vec_size = (u32)m_WiiMotes.size(); - p.Do(vec_size); - for (u32 i = 0; i < vec_size; ++i) - { - if (i < m_WiiMotes.size()) - { - CWII_IPC_HLE_WiiMote& wiimote = m_WiiMotes[i]; - wiimote.DoState(p); - } - else - { - bdaddr_t tmpBD = BDADDR_ANY; - CWII_IPC_HLE_WiiMote wiimote = CWII_IPC_HLE_WiiMote(this, i, tmpBD, false); - wiimote.DoState(p); - if (p.GetMode() == PointerWrap::MODE_READ) - { - m_WiiMotes.push_back(wiimote); - _dbg_assert_(WII_IPC_WIIMOTE, m_WiiMotes.size() == i); - } - } - } - if (p.GetMode() == PointerWrap::MODE_READ) - while ((u32)m_WiiMotes.size() > vec_size) - m_WiiMotes.pop_back(); - p.DoMarker("m_WiiMotes"); - } - - DoStateShared(p); } bool CWII_IPC_HLE_Device_usb_oh1_57e_305::RemoteDisconnect(u16 _connectionHandle) @@ -1518,9 +1467,9 @@ void CWII_IPC_HLE_Device_usb_oh1_57e_305::CommandWriteLinkPolicy(u8* _Input) DEBUG_LOG(WII_IPC_WIIMOTE, " ConnectionHandle: 0x%04x", pLinkPolicy->con_handle); DEBUG_LOG(WII_IPC_WIIMOTE, " Policy: 0x%04x", pLinkPolicy->settings); - hci_write_link_policy_settings_rp Reply; - Reply.status = 0x00; - Reply.con_handle = pLinkPolicy->con_handle; + //hci_write_link_policy_settings_rp Reply; + //Reply.status = 0x00; + //Reply.con_handle = pLinkPolicy->con_handle; SendEventCommandStatus(HCI_CMD_WRITE_LINK_POLICY_SETTINGS); @@ -1929,4 +1878,4 @@ void CWII_IPC_HLE_Device_usb_oh1_57e_305::LOG_LinkKey(const u8* _pLinkKey) , _pLinkKey[0], _pLinkKey[1], _pLinkKey[2], _pLinkKey[3], _pLinkKey[4], _pLinkKey[5], _pLinkKey[6], _pLinkKey[7] , _pLinkKey[8], _pLinkKey[9], _pLinkKey[10], _pLinkKey[11], _pLinkKey[12], _pLinkKey[13], _pLinkKey[14], _pLinkKey[15]); -}
\ No newline at end of file +} diff --git a/Source/Core/Core/Src/IPC_HLE/WII_IPC_HLE_WiiMote.cpp b/Source/Core/Core/Src/IPC_HLE/WII_IPC_HLE_WiiMote.cpp index 8445eeffdc..e59e1b3208 100644 --- a/Source/Core/Core/Src/IPC_HLE/WII_IPC_HLE_WiiMote.cpp +++ b/Source/Core/Core/Src/IPC_HLE/WII_IPC_HLE_WiiMote.cpp @@ -102,6 +102,7 @@ void CWII_IPC_HLE_WiiMote::DoState(PointerWrap &p) p.Do(uclass); p.Do(features); p.Do(lmp_version); + p.Do(lmp_subversion); p.Do(m_LinkKey); p.Do(m_Name); diff --git a/Source/Core/Core/Src/Movie.cpp b/Source/Core/Core/Src/Movie.cpp index ba489dfcf6..5eb1660d8e 100644 --- a/Source/Core/Core/Src/Movie.cpp +++ b/Source/Core/Core/Src/Movie.cpp @@ -27,12 +27,18 @@ #include "HW/WiimoteEmu/WiimoteEmu.h" #include "HW/WiimoteEmu/WiimoteHid.h" #include "IPC_HLE/WII_IPC_HLE_Device_usb.h" -#include "VideoBackendBase.h" #include "State.h" #include "Timer.h" +#include "VideoConfig.h" +#include "HW/EXI.h" +#include "HW/EXI_Device.h" +#include "HW/EXI_Channel.h" +#include "HW/DVDInterface.h" +#include "../../Common/Src/NandPaths.h" +#include "Crypto/md5.h" -// large enough for just over 24 hours of single-player recording -#define MAX_DTM_LENGTH (40 * 1024 * 1024) +// The chunk to allocate movie data in multiples of. +#define DTM_BASE_LENGTH (1024) std::mutex cs_frameSkip; @@ -50,11 +56,22 @@ u8 g_numPads = 0; ControllerState g_padState; DTMHeader tmpHeader; u8* tmpInput = NULL; +size_t tmpInputAllocated = 0; u64 g_currentByte = 0, g_totalBytes = 0; u64 g_currentFrame = 0, g_totalFrames = 0; // VI u64 g_currentLagCount = 0, g_totalLagCount = 0; // just stats u64 g_currentInputCount = 0, g_totalInputCount = 0; // just stats u64 g_recordingStartTime; // seconds since 1970 that recording started +bool bSaveConfig, bSkipIdle, bDualCore, bProgressive, bDSPHLE, bFastDiscSpeed = false; +bool bMemcard, g_bClearSave = false; +std::string videoBackend = "unknown"; +int iCPUCore = 1; +bool g_bDiscChange = false; +std::string g_discChange = ""; +std::string author = ""; +u64 g_titleID = 0; +unsigned char MD5[16]; +u8 bongos; bool g_bRecordingFromSaveState = false; bool g_bPolled = false; @@ -66,9 +83,39 @@ std::string g_InputDisplay[8]; ManipFunction mfunc = NULL; +void EnsureTmpInputSize(size_t bound) +{ + if (tmpInputAllocated >= bound) + return; + // The buffer expands in powers of two of DTM_BASE_LENGTH + // (standard exponential buffer growth). + size_t newAlloc = DTM_BASE_LENGTH; + while (newAlloc < bound) + newAlloc *= 2; + u8* newTmpInput = new u8[newAlloc]; + tmpInputAllocated = newAlloc; + if (tmpInput != NULL) + { + if (g_totalBytes > 0) + memcpy(newTmpInput, tmpInput, (size_t)g_totalBytes); + delete[] tmpInput; + } + tmpInput = newTmpInput; +} std::string GetInputDisplay() { + if (!IsPlayingInput() && !IsRecordingInput()) + { + g_numPads = 0; + for (int i = 0; i < 4; i++) + { + if (SConfig::GetInstance().m_SIDevice[i] == SIDEVICE_GC_CONTROLLER || SConfig::GetInstance().m_SIDevice[i] == SIDEVICE_GC_TARUKONGA) + g_numPads |= (1 << i); + if (g_wiimote_sources[i] != WIIMOTE_SRC_NONE) + g_numPads |= (1 << (i + 4)); + } + } std::string inputDisplay = ""; for (int i = 0; i < 8; ++i) if ((g_numPads & (1 << i)) != 0) @@ -87,6 +134,10 @@ void FrameUpdate() g_totalFrames = g_currentFrame; g_totalLagCount = g_currentLagCount; } + if (IsPlayingInput() && IsConfigSaved()) + { + SetGraphicsConfig(); + } if (g_bFrameStep) { @@ -112,8 +163,29 @@ void Init() g_bPolled = false; g_bFrameStep = false; g_bFrameStop = false; + bSaveConfig = false; + iCPUCore = SConfig::GetInstance().m_LocalCoreStartupParameter.iCPUCore; + if (IsPlayingInput()) + { + ReadHeader(); + std::thread md5thread(CheckMD5); + 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()); + EndPlayInput(false); + } + } + if (IsRecordingInput()) + { + GetSettings(); + std::thread md5thread(GetMD5); + } + g_frameSkipCounter = g_framesToSkip; memset(&g_padState, 0, sizeof(g_padState)); + if (!tmpHeader.bFromSaveState || !IsPlayingInput()) + Core::SetStateFileName(""); + for (int i = 0; i < 8; ++i) g_InputDisplay[i].clear(); @@ -121,15 +193,10 @@ void Init() { g_bRecordingFromSaveState = false; g_rerecords = 0; - g_numPads = 0; g_currentByte = 0; g_currentFrame = 0; g_currentLagCount = 0; g_currentInputCount = 0; - // we don't clear these things because otherwise we can't resume playback if we load a movie state later - //g_totalFrames = g_totalBytes = 0; - //delete tmpInput; - //tmpInput = NULL; } } @@ -138,6 +205,9 @@ void InputUpdate() g_currentInputCount++; if (IsRecordingInput()) g_totalInputCount = g_currentInputCount; + + if (IsPlayingInput() && g_currentInputCount == (g_totalInputCount -1) && SConfig::GetInstance().m_PauseMovie) + Core::SetState(Core::CORE_PAUSE); } void SetFrameSkipping(unsigned int framesToSkip) @@ -197,7 +267,7 @@ void FrameSkipping() g_frameSkipCounter++; if (g_frameSkipCounter > g_framesToSkip || Core::ShouldSkipFrame(g_frameSkipCounter) == false) g_frameSkipCounter = 0; - + g_video_backend->Video_SetRendering(!g_frameSkipCounter); } } @@ -217,6 +287,11 @@ bool IsJustStartingRecordingInputFromSaveState() return IsRecordingInputFromSaveState() && g_currentFrame == 0; } +bool IsJustStartingPlayingInputFromSaveState() +{ + return IsRecordingInputFromSaveState() && g_currentFrame == 1 && IsPlayingInput(); +} + bool IsPlayingInput() { return (g_playMode == MODE_PLAYING); @@ -237,11 +312,60 @@ bool IsUsingPad(int controller) return ((g_numPads & (1 << controller)) != 0); } +bool IsUsingBongo(int controller) +{ + return ((bongos & (1 << controller)) != 0); +} + bool IsUsingWiimote(int wiimote) { return ((g_numPads & (1 << (wiimote + 4))) != 0); } +bool IsConfigSaved() +{ + return bSaveConfig; +} +bool IsDualCore() +{ + return bDualCore; +} + +bool IsProgressive() +{ + return bProgressive; +} + +bool IsSkipIdle() +{ + return bSkipIdle; +} + +bool IsDSPHLE() +{ + return bDSPHLE; +} + +bool IsFastDiscSpeed() +{ + return bFastDiscSpeed; +} + +int GetCPUMode() +{ + return iCPUCore; +} + +bool IsStartingFromClearSave() +{ + return g_bClearSave; +} + +bool IsUsingMemcard() +{ + return bMemcard; +} + void ChangePads(bool instantly) { if (Core::GetState() == Core::CORE_UNINITIALIZED) @@ -250,7 +374,7 @@ void ChangePads(bool instantly) int controllers = 0; for (int i = 0; i < 4; i++) - if (SConfig::GetInstance().m_SIDevice[i] == SIDEVICE_GC_CONTROLLER) + if (SConfig::GetInstance().m_SIDevice[i] == SIDEVICE_GC_CONTROLLER || SConfig::GetInstance().m_SIDevice[i] == SIDEVICE_GC_TARUKONGA) controllers |= (1 << i); if (instantly && (g_numPads & 0x0F) == controllers) @@ -258,9 +382,9 @@ void ChangePads(bool instantly) for (int i = 0; i < 4; i++) if (instantly) // Changes from savestates need to be instantaneous - SerialInterface::AddDevice(IsUsingPad(i) ? SIDEVICE_GC_CONTROLLER : SIDEVICE_NONE, i); + SerialInterface::AddDevice(IsUsingPad(i) ? (IsUsingBongo(i) ? SIDEVICE_GC_TARUKONGA : SIDEVICE_GC_CONTROLLER) : SIDEVICE_NONE, i); else - SerialInterface::ChangeDevice(IsUsingPad(i) ? SIDEVICE_GC_CONTROLLER : SIDEVICE_NONE, i); + SerialInterface::ChangeDevice(IsUsingPad(i) ? (IsUsingBongo(i) ? SIDEVICE_GC_TARUKONGA : SIDEVICE_GC_CONTROLLER) : SIDEVICE_NONE, i); } void ChangeWiiPads(bool instantly) @@ -287,6 +411,17 @@ bool BeginRecordingInput(int controllers) if(g_playMode != MODE_NONE || controllers == 0) return false; + g_numPads = controllers; + g_currentFrame = g_totalFrames = 0; + g_currentLagCount = g_totalLagCount = 0; + g_currentInputCount = g_totalInputCount = 0; + g_recordingStartTime = Common::Timer::GetLocalTimeSinceJan1970(); + g_rerecords = 0; + + for (int i = 0; i < 4; i++) + if (SConfig::GetInstance().m_SIDevice[i] == SIDEVICE_GC_TARUKONGA) + bongos |= (1 << i); + if (Core::IsRunning()) { if(File::Exists(tmpStateFilename)) @@ -294,20 +429,25 @@ bool BeginRecordingInput(int controllers) State::SaveAs(tmpStateFilename.c_str()); g_bRecordingFromSaveState = true; + + // This is only done here if starting from save state because otherwise we won't have the titleid. Otherwise it's set in WII_IPC_HLE_Device_es.cpp. + // TODO: find a way to GetTitleDataPath() from Movie::Init() + if (Core::g_CoreStartupParameter.bWii) + { + if (File::Exists((Common::GetTitleDataPath(g_titleID) + "banner.bin").c_str())) + Movie::g_bClearSave = false; + else + Movie::g_bClearSave = true; + } + std::thread md5thread(GetMD5); } - - g_numPads = controllers; - g_currentFrame = g_totalFrames = 0; - g_currentLagCount = g_totalLagCount = 0; - g_currentInputCount = g_totalInputCount = 0; - g_recordingStartTime = Common::Timer::GetLocalTimeSinceJan1970(); - g_rerecords = 0; g_playMode = MODE_RECORDING; + GetSettings(); + author = SConfig::GetInstance().m_strMovieAuthor; + EnsureTmpInputSize(1); - delete [] tmpInput; - tmpInput = new u8[MAX_DTM_LENGTH]; g_currentByte = g_totalBytes = 0; - + Core::DisplayMessage("Starting movie recording", 2000); return true; } @@ -390,15 +530,6 @@ void SetInputDisplayString(ControllerState padState, int controllerID) if(g_padState.DPadRight) g_InputDisplay[controllerID].append(" RIGHT"); - //if(g_padState.L) - //{ - // g_InputDisplay[controllerID].append(" L"); - //} - //if(g_padState.R) - //{ - // g_InputDisplay[controllerID].append(" R"); - //} - Analog1DToString(g_padState.TriggerL, " L", inp); g_InputDisplay[controllerID].append(inp); @@ -465,60 +596,121 @@ void SetWiiInputDisplayString(int remoteID, u8* const coreData, u8* const accelD g_InputDisplay[controllerID].append("\n"); } - - -void RecordInput(SPADStatus *PadStatus, int controllerID) +void CheckPadStatus(SPADStatus *PadStatus, int controllerID) { - if(!IsRecordingInput() || !IsUsingPad(controllerID)) - return; - g_padState.A = ((PadStatus->button & PAD_BUTTON_A) != 0); g_padState.B = ((PadStatus->button & PAD_BUTTON_B) != 0); g_padState.X = ((PadStatus->button & PAD_BUTTON_X) != 0); g_padState.Y = ((PadStatus->button & PAD_BUTTON_Y) != 0); g_padState.Z = ((PadStatus->button & PAD_TRIGGER_Z) != 0); g_padState.Start = ((PadStatus->button & PAD_BUTTON_START) != 0); - + g_padState.DPadUp = ((PadStatus->button & PAD_BUTTON_UP) != 0); g_padState.DPadDown = ((PadStatus->button & PAD_BUTTON_DOWN) != 0); g_padState.DPadLeft = ((PadStatus->button & PAD_BUTTON_LEFT) != 0); g_padState.DPadRight = ((PadStatus->button & PAD_BUTTON_RIGHT) != 0); - + g_padState.L = ((PadStatus->button & PAD_TRIGGER_L) != 0); g_padState.R = ((PadStatus->button & PAD_TRIGGER_R) != 0); g_padState.TriggerL = PadStatus->triggerLeft; g_padState.TriggerR = PadStatus->triggerRight; - + g_padState.AnalogStickX = PadStatus->stickX; g_padState.AnalogStickY = PadStatus->stickY; - + g_padState.CStickX = PadStatus->substickX; g_padState.CStickY = PadStatus->substickY; + SetInputDisplayString(g_padState, controllerID); +} + +void RecordInput(SPADStatus *PadStatus, int controllerID) +{ + if (!IsRecordingInput() || !IsUsingPad(controllerID)) + return; + + CheckPadStatus(PadStatus, controllerID); + if (g_bDiscChange) + { + g_padState.disc = g_bDiscChange; + g_bDiscChange = false; + } + + EnsureTmpInputSize((size_t)(g_currentByte + 8)); memcpy(&(tmpInput[g_currentByte]), &g_padState, 8); g_currentByte += 8; g_totalBytes = g_currentByte; - - SetInputDisplayString(g_padState, controllerID); } -void RecordWiimote(int wiimote, u8 *data, const WiimoteEmu::ReportFeatures& rptf, int irMode) +void CheckWiimoteStatus(int wiimote, u8 *data, const WiimoteEmu::ReportFeatures& rptf, int irMode) { - if(!IsRecordingInput() || !IsUsingWiimote(wiimote)) - return; - u8* const coreData = rptf.core?(data+rptf.core):NULL; u8* const accelData = rptf.accel?(data+rptf.accel):NULL; u8* const irData = rptf.ir?(data+rptf.ir):NULL; u8 size = rptf.size; + SetWiiInputDisplayString(wiimote, coreData, accelData, irData); + + if (IsRecordingInput()) + RecordWiimote(wiimote, data, size); +} + +void RecordWiimote(int wiimote, u8 *data, u8 size) +{ + if(!IsRecordingInput() || !IsUsingWiimote(wiimote)) + return; InputUpdate(); + EnsureTmpInputSize((size_t)(g_currentByte + size + 1)); tmpInput[g_currentByte++] = size; memcpy(&(tmpInput[g_currentByte]), data, size); g_currentByte += size; g_totalBytes = g_currentByte; - SetWiiInputDisplayString(wiimote, coreData, accelData, irData); +} + +void ReadHeader() +{ + g_numPads = tmpHeader.numControllers; + g_recordingStartTime = tmpHeader.recordingStartTime; + if (g_rerecords < tmpHeader.numRerecords) + g_rerecords = tmpHeader.numRerecords; + + if (tmpHeader.bSaveConfig) + { + bSaveConfig = true; + bSkipIdle = tmpHeader.bSkipIdle; + bDualCore = tmpHeader.bDualCore; + bProgressive = tmpHeader.bProgressive; + bDSPHLE = tmpHeader.bDSPHLE; + bFastDiscSpeed = tmpHeader.bFastDiscSpeed; + iCPUCore = tmpHeader.CPUCore; + g_bClearSave = tmpHeader.bClearSave; + bMemcard = tmpHeader.bMemcard; + bongos = tmpHeader.bongos; + } + else + { + GetSettings(); + } + + videoBackend.resize(ARRAYSIZE(tmpHeader.videoBackend)); + for (unsigned int i = 0; i < ARRAYSIZE(tmpHeader.videoBackend);i++) + { + videoBackend[i] = tmpHeader.videoBackend[i]; + } + + g_discChange.resize(ARRAYSIZE(tmpHeader.discChange)); + for (unsigned int i = 0; i < ARRAYSIZE(tmpHeader.discChange);i++) + { + g_discChange[i] = tmpHeader.discChange[i]; + } + + author.resize(ARRAYSIZE(tmpHeader.author)); + for (unsigned int i = 0; i < ARRAYSIZE(tmpHeader.author);i++) + { + author[i] = tmpHeader.author[i]; + } + memcpy(MD5, tmpHeader.md5, 16); } bool PlayInput(const char *filename) @@ -528,19 +720,19 @@ bool PlayInput(const char *filename) if(!File::Exists(filename)) return false; - + File::IOFile g_recordfd; - + if (!g_recordfd.Open(filename, "rb")) return false; - + g_recordfd.ReadArray(&tmpHeader, 1); if(tmpHeader.filetype[0] != 'D' || tmpHeader.filetype[1] != 'T' || tmpHeader.filetype[2] != 'M' || tmpHeader.filetype[3] != 0x1A) { PanicAlertT("Invalid recording file"); goto cleanup; } - + // Load savestate (and skip to frame data) if(tmpHeader.bFromSaveState) { @@ -548,29 +740,13 @@ bool PlayInput(const char *filename) if(File::Exists(stateFilename)) Core::SetStateFileName(stateFilename); g_bRecordingFromSaveState = true; + Movie::LoadInput(filename); } - - /* TODO: Put this verification somewhere we have the gameID of the played game - // TODO: Replace with Unique ID - if(tmpHeader.uniqueID != 0) { - PanicAlert("Recording Unique ID Verification Failed"); - goto cleanup; - } - - 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)", header.gameID, Core::g_CoreStartupParameter.GetUniqueID().c_str()); - goto cleanup; - } - */ - - g_numPads = tmpHeader.numControllers; - g_rerecords = tmpHeader.numRerecords; + ReadHeader(); g_totalFrames = tmpHeader.frameCount; g_totalLagCount = tmpHeader.lagCount; g_totalInputCount = tmpHeader.inputCount; - g_recordingStartTime = tmpHeader.recordingStartTime; - g_currentFrame = 0; g_currentLagCount = 0; g_currentInputCount = 0; @@ -578,14 +754,13 @@ bool PlayInput(const char *filename) g_playMode = MODE_PLAYING; g_totalBytes = g_recordfd.GetSize() - 256; - delete tmpInput; - tmpInput = new u8[MAX_DTM_LENGTH]; + EnsureTmpInputSize((size_t)g_totalBytes); g_recordfd.ReadArray(tmpInput, (size_t)g_totalBytes); g_currentByte = 0; g_recordfd.Close(); - + return true; - + cleanup: g_recordfd.Close(); return false; @@ -609,28 +784,24 @@ void DoState(PointerWrap &p) void LoadInput(const char *filename) { File::IOFile t_record(filename, "r+b"); - + t_record.ReadArray(&tmpHeader, 1); - + if(tmpHeader.filetype[0] != 'D' || tmpHeader.filetype[1] != 'T' || tmpHeader.filetype[2] != 'M' || tmpHeader.filetype[3] != 0x1A) { PanicAlertT("Savestate movie %s is corrupted, movie recording stopping...", filename); EndPlayInput(false); return; } - + ReadHeader(); if (!g_bReadOnly) { - if (g_rerecords > tmpHeader.numRerecords) - { - tmpHeader.numRerecords = g_rerecords; - } - tmpHeader.numRerecords++; + g_rerecords++; + tmpHeader.numRerecords = g_rerecords; t_record.Seek(0, SEEK_SET); t_record.WriteArray(&tmpHeader, 1); } - - g_numPads = tmpHeader.numControllers; + ChangePads(true); if (Core::g_CoreStartupParameter.bWii) ChangeWiiPads(true); @@ -650,9 +821,8 @@ void LoadInput(const char *filename) g_totalLagCount = tmpHeader.lagCount; g_totalInputCount = tmpHeader.inputCount; + EnsureTmpInputSize((size_t)totalSavedBytes); g_totalBytes = totalSavedBytes; - delete [] tmpInput; - tmpInput = new u8[MAX_DTM_LENGTH]; t_record.ReadArray(tmpInput, (size_t)g_totalBytes); } else if (g_currentByte > 0) @@ -710,7 +880,7 @@ void LoadInput(const char *filename) } t_record.Close(); - g_rerecords = tmpHeader.numRerecords; + bSaveConfig = tmpHeader.bSaveConfig; if (!afterEnd) { @@ -752,6 +922,18 @@ void PlayController(SPADStatus *PadStatus, int controllerID) if (!IsPlayingInput() || !IsUsingPad(controllerID) || tmpInput == NULL) return; + if (g_currentFrame == 1) + { + if (tmpHeader.bMemcard) + { + ExpansionInterface::ChangeDevice(0, EXIDEVICE_MEMORYCARD, 0); + } + else if (!tmpHeader.bMemcard) + { + ExpansionInterface::ChangeDevice(0, EXIDEVICE_NONE, 0); + } + } + if (g_currentByte + 8 > g_totalBytes) { PanicAlertT("Premature movie end in PlayController. %u + 8 > %u", (u32)g_currentByte, (u32)g_totalBytes); @@ -759,8 +941,7 @@ void PlayController(SPADStatus *PadStatus, int controllerID) return; } - // dtm files don't save the mic button or error bit. not sure if they're actually - // used, but better safe than sorry + // dtm files don't save the mic button or error bit. not sure if they're actually used, but better safe than sorry signed char e = PadStatus->err; memset(PadStatus, 0, sizeof(SPADStatus)); PadStatus->err = e; @@ -812,9 +993,35 @@ void PlayController(SPADStatus *PadStatus, int controllerID) PadStatus->button |= PAD_TRIGGER_L; if(g_padState.R) PadStatus->button |= PAD_TRIGGER_R; + if (g_padState.disc) + { + // This implementation assumes the disc change will only happen once. Trying to change more than that will cause + // it to load the last disc every time. As far as i know though, there are no 3+ disc games, so this should be fine. + Core::SetState(Core::CORE_PAUSE); + int numPaths = (int)SConfig::GetInstance().m_ISOFolder.size(); + bool found = false; + std::string path; + for (int i = 0; i < numPaths; i++) + { + path = SConfig::GetInstance().m_ISOFolder[i]; + if (File::Exists((path + '/' + g_discChange.c_str()).c_str())) + { + found = true; + break; + } + } + if (found) + { + DVDInterface::ChangeDisc((path + '/' + g_discChange.c_str()).c_str()); + Core::SetState(Core::CORE_RUN); + } + else + { + PanicAlert("Change the disc to %s", g_discChange.c_str()); + } + } SetInputDisplayString(g_padState, controllerID); - CheckInputEnd(); } @@ -873,10 +1080,11 @@ void EndPlayInput(bool cont) } else if(g_playMode != MODE_NONE) { - g_numPads = g_rerecords = 0; + g_rerecords = 0; g_currentByte = 0; g_playMode = MODE_NONE; Core::DisplayMessage("Movie End.", 2000); + g_bRecordingFromSaveState = 0; // we don't clear these things because otherwise we can't resume playback if we load a movie state later //g_totalFrames = g_totalBytes = 0; //delete tmpInput; @@ -887,7 +1095,6 @@ void EndPlayInput(bool cont) void SaveRecording(const char *filename) { File::IOFile save_record(filename, "wb"); - // Create the real header now and write it DTMHeader header; memset(&header, 0, sizeof(DTMHeader)); @@ -903,13 +1110,33 @@ void SaveRecording(const char *filename) header.inputCount = g_totalInputCount; header.numRerecords = g_rerecords; header.recordingStartTime = g_recordingStartTime; - + + header.bSaveConfig = true; + header.bSkipIdle = bSkipIdle; + header.bDualCore = bDualCore; + header.bProgressive = bProgressive; + header.bDSPHLE = bDSPHLE; + header.bFastDiscSpeed = bFastDiscSpeed; + strncpy((char *)header.videoBackend, videoBackend.c_str(),ARRAYSIZE(header.videoBackend)); + header.CPUCore = iCPUCore; + header.bEFBAccessEnable = g_ActiveConfig.bEFBAccessEnable; + header.bEFBCopyEnable = g_ActiveConfig.bEFBCopyEnable; + header.bCopyEFBToTexture = g_ActiveConfig.bCopyEFBToTexture; + header.bEFBCopyCacheEnable = g_ActiveConfig.bEFBCopyCacheEnable; + header.bEFBEmulateFormatChanges = g_ActiveConfig.bEFBEmulateFormatChanges; + header.bUseXFB = g_ActiveConfig.bUseXFB; + header.bUseRealXFB = g_ActiveConfig.bUseRealXFB; + header.bMemcard = bMemcard; + header.bClearSave = g_bClearSave; + strncpy((char *)header.discChange, g_discChange.c_str(),ARRAYSIZE(header.discChange)); + strncpy((char *)header.author, author.c_str(),ARRAYSIZE(header.author)); + memcpy(header.md5,MD5,16); + header.bongos = bongos; + // TODO header.uniqueID = 0; - // header.author; - // header.videoBackend; // header.audioEmulator; - + save_record.WriteArray(&header, 1); bool success = save_record.WriteArray(tmpInput, (size_t)g_totalBytes); @@ -937,4 +1164,72 @@ void CallInputManip(SPADStatus *PadStatus, int controllerID) if (mfunc) (*mfunc)(PadStatus, controllerID); } + +void SetGraphicsConfig() +{ + g_Config.bEFBAccessEnable = tmpHeader.bEFBAccessEnable; + g_Config.bEFBCopyEnable = tmpHeader.bEFBCopyEnable; + g_Config.bCopyEFBToTexture = tmpHeader.bCopyEFBToTexture; + g_Config.bEFBCopyCacheEnable = tmpHeader.bEFBCopyCacheEnable; + g_Config.bEFBEmulateFormatChanges = tmpHeader.bEFBEmulateFormatChanges; + g_Config.bUseXFB = tmpHeader.bUseXFB; + g_Config.bUseRealXFB = tmpHeader.bUseRealXFB; +} + +void GetSettings() +{ + bSaveConfig = true; + bSkipIdle = SConfig::GetInstance().m_LocalCoreStartupParameter.bSkipIdle; + bDualCore = SConfig::GetInstance().m_LocalCoreStartupParameter.bCPUThread; + bProgressive = SConfig::GetInstance().m_LocalCoreStartupParameter.bProgressive; + bDSPHLE = SConfig::GetInstance().m_LocalCoreStartupParameter.bDSPHLE; + bFastDiscSpeed = SConfig::GetInstance().m_LocalCoreStartupParameter.bFastDiscSpeed; + videoBackend = SConfig::GetInstance().m_LocalCoreStartupParameter.m_strVideoBackend; + iCPUCore = SConfig::GetInstance().m_LocalCoreStartupParameter.iCPUCore; + if (!Core::g_CoreStartupParameter.bWii) + g_bClearSave = !File::Exists(SConfig::GetInstance().m_strMemoryCardA); + bMemcard = SConfig::GetInstance().m_EXIDevice[0] == EXIDEVICE_MEMORYCARD; +} + +void CheckMD5() +{ + for (int i=0, n=0; i<16; i++) + { + if (tmpHeader.md5[i] != 0) + continue; + n++; + if (n == 16) + return; + } + Core::DisplayMessage("Verifying checksum...", 2000); + + unsigned char gameMD5[16]; + char game[255]; + memcpy(game, SConfig::GetInstance().m_LocalCoreStartupParameter.m_strFilename.c_str(), SConfig::GetInstance().m_LocalCoreStartupParameter.m_strFilename.size()); + md5_file(game, gameMD5); + + if (memcmp(gameMD5,MD5,16) == 0) + Core::DisplayMessage("Checksum of current game matches the recorded game.", 2000); + else + PanicAlert("Checksum of current game does not match the recorded game!"); +} + +void GetMD5() +{ + Core::DisplayMessage("Calculating checksum of game file...", 2000); + for (int i = 0; i < 16; i++) + MD5[i] = 0; + char game[255]; + memcpy(game, SConfig::GetInstance().m_LocalCoreStartupParameter.m_strFilename.c_str(),SConfig::GetInstance().m_LocalCoreStartupParameter.m_strFilename.size()); + md5_file(game, MD5); + Core::DisplayMessage("Finished calculating checksum.", 2000); +} + +void Shutdown() +{ + g_currentInputCount = g_totalInputCount = g_totalFrames = g_totalBytes = 0; + delete [] tmpInput; + tmpInput = NULL; + tmpInputAllocated = 0; +} }; diff --git a/Source/Core/Core/Src/Movie.h b/Source/Core/Core/Src/Movie.h index 09a0f5d84a..2cb4c78e23 100644 --- a/Source/Core/Core/Src/Movie.h +++ b/Source/Core/Core/Src/Movie.h @@ -19,7 +19,6 @@ #define __MOVIE_H #include "Common.h" -#include "FileUtil.h" #include "../../InputCommon/Src/GCPadStatus.h" #include <string> @@ -48,19 +47,22 @@ struct ControllerState { bool Start:1, A:1, B:1, X:1, Y:1, Z:1; // Binary buttons, 6 bits bool DPadUp:1, DPadDown:1, // Binary D-Pad buttons, 4 bits DPadLeft:1, DPadRight:1; - bool L:1, R:1; // Binary triggers, 2 bits - bool reserved:4; // Reserved bits used for padding, 4 bits + bool L:1, R:1; // Binary triggers, 2 bits + bool disc:1; // Checks for disc being changed + bool reserved:3; // Reserved bits used for padding, 4 bits - u8 TriggerL, TriggerR; // Triggers, 16 bits + u8 TriggerL, TriggerR; // Triggers, 16 bits u8 AnalogStickX, AnalogStickY; // Main Stick, 16 bits u8 CStickX, CStickY; // Sub-Stick, 16 bits }; // Total: 60 + 4 = 64 bits per frame +static_assert(sizeof(ControllerState) == 8, "ControllerState should be 8 bytes"); #pragma pack(pop) // Global declarations -extern bool g_bFrameStep, g_bPolled, g_bReadOnly; +extern bool g_bFrameStep, g_bPolled, g_bReadOnly, g_bDiscChange, g_bClearSave; extern PlayMode g_playMode; +extern u64 g_titleID; extern u32 g_framesToSkip, g_frameSkipCounter; @@ -73,6 +75,7 @@ extern u64 g_currentByte, g_totalBytes; extern u64 g_currentFrame, g_totalFrames; extern u64 g_currentLagCount, g_totalLagCount; extern u64 g_currentInputCount, g_totalInputCount; +extern std::string g_discChange; extern u32 g_rerecords; @@ -92,15 +95,36 @@ struct DTMHeader { u64 uniqueID; // (not implemented) A Unique ID comprised of: md5(time + Game ID) u32 numRerecords; // Number of rerecords/'cuts' of this TAS u8 author[32]; // Author's name (encoded in UTF-8) - + u8 videoBackend[16]; // UTF-8 representation of the video backend u8 audioEmulator[16]; // UTF-8 representation of the audio emulator - u8 padBackend[16]; // UTF-8 representation of the input backend + unsigned char md5[16]; // MD5 of game iso u64 recordingStartTime; // seconds since 1970 that recording started (used for RTC) - u8 reserved[119]; // Make heading 256 bytes, just because we can + bool bSaveConfig; // Loads the settings below on startup if true + bool bSkipIdle; + bool bDualCore; + bool bProgressive; + bool bDSPHLE; + bool bFastDiscSpeed; + u8 CPUCore; // 0 = interpreter, 1 = JIT, 2 = JITIL + bool bEFBAccessEnable; + bool bEFBCopyEnable; + bool bCopyEFBToTexture; + bool bEFBCopyCacheEnable; + bool bEFBEmulateFormatChanges; + bool bUseXFB; + bool bUseRealXFB; + bool bMemcard; + bool bClearSave; // Create a new memory card when playing back a movie if true + u8 bongos; + u8 reserved[15]; // Padding for any new config options + u8 discChange[40]; // Name of iso file to switch to, for two disc games. + u8 reserved2[47]; // Make heading 256 bytes, just because we can }; +static_assert(sizeof(DTMHeader) == 256, "DTMHeader should be 256 bytes"); + #pragma pack(pop) void FrameUpdate(); @@ -109,16 +133,29 @@ void Init(); void SetPolledDevice(); -bool IsAutoFiring(); bool IsRecordingInput(); bool IsRecordingInputFromSaveState(); bool IsJustStartingRecordingInputFromSaveState(); +bool IsJustStartingPlayingInputFromSaveState(); bool IsPlayingInput(); bool IsReadOnly(); u64 GetRecordingStartTime(); +bool IsConfigSaved(); +bool IsDualCore(); +bool IsProgressive(); +bool IsSkipIdle(); +bool IsDSPHLE(); +bool IsFastDiscSpeed(); +int GetCPUMode(); +bool IsStartingFromClearSave(); +bool IsUsingMemcard(); +void SetGraphicsConfig(); +void GetSettings(); + bool IsUsingPad(int controller); bool IsUsingWiimote(int wiimote); +bool IsUsingBongo(int controller); void ChangePads(bool instantly = false); void ChangeWiiPads(bool instantly = false); @@ -131,15 +168,21 @@ void FrameSkipping(); bool BeginRecordingInput(int controllers); void RecordInput(SPADStatus *PadStatus, int controllerID); -void RecordWiimote(int wiimote, u8* data, const struct WiimoteEmu::ReportFeatures& rptf, int irMode); +void RecordWiimote(int wiimote, u8 *data, u8 size); bool PlayInput(const char *filename); void LoadInput(const char *filename); +void ReadHeader(); void PlayController(SPADStatus *PadStatus, int controllerID); bool PlayWiimote(int wiimote, u8* data, const struct WiimoteEmu::ReportFeatures& rptf, int irMode); void EndPlayInput(bool cont); void SaveRecording(const char *filename); void DoState(PointerWrap &p); +void CheckMD5(); +void GetMD5(); +void Shutdown(); +void CheckPadStatus(SPADStatus *PadStatus, int controllerID); +void CheckWiimoteStatus(int wiimote, u8* data, const struct WiimoteEmu::ReportFeatures& rptf, int irMode); std::string GetInputDisplay(); @@ -150,4 +193,4 @@ void SetInputManip(ManipFunction); void CallInputManip(SPADStatus *PadStatus, int controllerID); }; -#endif // __FRAME_H +#endif // __MOVIE_H diff --git a/Source/Core/Core/Src/PowerPC/Interpreter/Interpreter_Tables.cpp b/Source/Core/Core/Src/PowerPC/Interpreter/Interpreter_Tables.cpp index 33540bfb64..8ea35503bf 100644 --- a/Source/Core/Core/Src/PowerPC/Interpreter/Interpreter_Tables.cpp +++ b/Source/Core/Core/Src/PowerPC/Interpreter/Interpreter_Tables.cpp @@ -295,6 +295,7 @@ static GekkoOPTemplate table31_2[] = {266, Interpreter::addx, {"addx", OPTYPE_INTEGER, FL_OUT_D | FL_IN_AB | FL_RC_BIT, 0, 0, 0, 0}}, {778, Interpreter::addx, {"addox", OPTYPE_INTEGER, FL_OUT_D | FL_IN_AB | FL_RC_BIT, 0, 0, 0, 0}}, {10, Interpreter::addcx, {"addcx", OPTYPE_INTEGER, FL_OUT_D | FL_IN_AB | FL_SET_CA | FL_RC_BIT, 0, 0, 0, 0}}, + {522, Interpreter::addcx, {"addcox", OPTYPE_INTEGER, FL_OUT_D | FL_IN_AB | FL_SET_CA | FL_RC_BIT, 0, 0, 0, 0}}, {138, Interpreter::addex, {"addex", OPTYPE_INTEGER, FL_OUT_D | FL_IN_AB | FL_READ_CA | FL_SET_CA | FL_RC_BIT, 0, 0, 0, 0}}, {234, Interpreter::addmex, {"addmex", OPTYPE_INTEGER, FL_OUT_D | FL_IN_AB | FL_READ_CA | FL_SET_CA | FL_RC_BIT, 0, 0, 0, 0}}, {202, Interpreter::addzex, {"addzex", OPTYPE_INTEGER, FL_OUT_D | FL_IN_AB | FL_READ_CA | FL_SET_CA | FL_RC_BIT, 0, 0, 0, 0}}, @@ -310,6 +311,7 @@ static GekkoOPTemplate table31_2[] = {40, Interpreter::subfx, {"subfx", OPTYPE_INTEGER, FL_OUT_D | FL_IN_AB | FL_RC_BIT, 0, 0, 0, 0}}, {552, Interpreter::subfx, {"subox", OPTYPE_INTEGER, FL_OUT_D | FL_IN_AB | FL_RC_BIT, 0, 0, 0, 0}}, {8, Interpreter::subfcx, {"subfcx", OPTYPE_INTEGER, FL_OUT_D | FL_IN_AB | FL_SET_CA | FL_RC_BIT, 0, 0, 0, 0}}, + {520, Interpreter::subfcx, {"subfcox", OPTYPE_INTEGER, FL_OUT_D | FL_IN_AB | FL_SET_CA | FL_RC_BIT, 0, 0, 0, 0}}, {136, Interpreter::subfex, {"subfex", OPTYPE_INTEGER, FL_OUT_D | FL_IN_AB | FL_READ_CA | FL_SET_CA | FL_RC_BIT, 0, 0, 0, 0}}, {232, Interpreter::subfmex, {"subfmex", OPTYPE_INTEGER, FL_OUT_D | FL_IN_AB | FL_READ_CA | FL_SET_CA | FL_RC_BIT, 0, 0, 0, 0}}, {200, Interpreter::subfzex, {"subfzex", OPTYPE_INTEGER, FL_OUT_D | FL_IN_AB | FL_READ_CA | FL_SET_CA | FL_RC_BIT, 0, 0, 0, 0}}, diff --git a/Source/Core/Core/Src/PowerPC/Jit64/Jit64_Tables.cpp b/Source/Core/Core/Src/PowerPC/Jit64/Jit64_Tables.cpp index 8d593a6742..ddb59903d2 100644 --- a/Source/Core/Core/Src/PowerPC/Jit64/Jit64_Tables.cpp +++ b/Source/Core/Core/Src/PowerPC/Jit64/Jit64_Tables.cpp @@ -308,6 +308,7 @@ static GekkoOPTemplate table31_2[] = {266, &Jit64::addx}, //"addx", OPTYPE_INTEGER, FL_OUT_D | FL_IN_AB | FL_RC_BIT}}, {778, &Jit64::addx}, //"addx", OPTYPE_INTEGER, FL_OUT_D | FL_IN_AB | FL_RC_BIT}}, {10, &Jit64::addcx}, //"addcx", OPTYPE_INTEGER, FL_OUT_D | FL_IN_AB | FL_SET_CA | FL_RC_BIT}}, + {522, &Jit64::addcx}, //"addcox", OPTYPE_INTEGER, FL_OUT_D | FL_IN_AB | FL_SET_CA | FL_RC_BIT}}, {138, &Jit64::addex}, //"addex", OPTYPE_INTEGER, FL_OUT_D | FL_IN_AB | FL_READ_CA | FL_SET_CA | FL_RC_BIT}}, {234, &Jit64::addmex}, //"addmex", OPTYPE_INTEGER, FL_OUT_D | FL_IN_AB | FL_READ_CA | FL_SET_CA | FL_RC_BIT}}, {202, &Jit64::addzex}, //"addzex", OPTYPE_INTEGER, FL_OUT_D | FL_IN_AB | FL_READ_CA | FL_SET_CA | FL_RC_BIT}}, @@ -323,6 +324,7 @@ static GekkoOPTemplate table31_2[] = {40, &Jit64::subfx}, //"subfx", OPTYPE_INTEGER, FL_OUT_D | FL_IN_AB | FL_RC_BIT}}, {552, &Jit64::subfx}, //"subox", OPTYPE_INTEGER, FL_OUT_D | FL_IN_AB | FL_RC_BIT}}, {8, &Jit64::subfcx}, //"subfcx", OPTYPE_INTEGER, FL_OUT_D | FL_IN_AB | FL_SET_CA | FL_RC_BIT}}, + {520, &Jit64::subfcx}, //"subfcox", OPTYPE_INTEGER, FL_OUT_D | FL_IN_AB | FL_SET_CA | FL_RC_BIT}}, {136, &Jit64::subfex}, //"subfex", OPTYPE_INTEGER, FL_OUT_D | FL_IN_AB | FL_READ_CA | FL_SET_CA | FL_RC_BIT}}, {232, &Jit64::subfmex}, //"subfmex", OPTYPE_INTEGER, FL_OUT_D | FL_IN_AB | FL_READ_CA | FL_SET_CA | FL_RC_BIT}}, {200, &Jit64::subfzex}, //"subfzex", OPTYPE_INTEGER, FL_OUT_D | FL_IN_AB | FL_READ_CA | FL_SET_CA | FL_RC_BIT}}, diff --git a/Source/Core/Core/Src/PowerPC/Jit64/Jit_Integer.cpp b/Source/Core/Core/Src/PowerPC/Jit64/Jit_Integer.cpp index 5aaf4b99f1..3d88d687e0 100644 --- a/Source/Core/Core/Src/PowerPC/Jit64/Jit_Integer.cpp +++ b/Source/Core/Core/Src/PowerPC/Jit64/Jit_Integer.cpp @@ -1097,7 +1097,7 @@ void Jit64::mulli(UGeckoInstruction inst) gpr.BindToRegister(d, (d == a), true); if (imm == 0) XOR(32, gpr.R(d), gpr.R(d)); - else if(imm == -1) + else if(imm == (u32)-1) { if (d != a) MOV(32, gpr.R(d), gpr.R(a)); @@ -1147,7 +1147,7 @@ void Jit64::mullwx(UGeckoInstruction inst) int src = gpr.R(a).IsImm() ? b : a; if (imm == 0) XOR(32, gpr.R(d), gpr.R(d)); - else if(imm == -1) + else if(imm == (u32)-1) { if (d != src) MOV(32, gpr.R(d), gpr.R(src)); @@ -1263,7 +1263,7 @@ void Jit64::divwux(UGeckoInstruction inst) while(!(divisor & (1 << shift))) shift--; - if (divisor == (1 << shift)) + if (divisor == (u32)(1 << shift)) { gpr.Lock(a, b, d); gpr.BindToRegister(d, d == a, true); @@ -1387,7 +1387,7 @@ void Jit64::divwx(UGeckoInstruction inst) if (gpr.R(a).IsImm() && gpr.R(b).IsImm()) { s32 i = (s32)gpr.R(a).offset, j = (s32)gpr.R(b).offset; - if( j == 0 || i == 0x80000000 && j == -1) + if( j == 0 || (i == (s32)0x80000000 && j == -1)) { gpr.SetImmediate32(d, (i >> 31) ^ j); if (inst.OE) diff --git a/Source/Core/Core/Src/PowerPC/Jit64IL/IR_X86.cpp b/Source/Core/Core/Src/PowerPC/Jit64IL/IR_X86.cpp index e91291fa90..ce47e2c3ac 100644 --- a/Source/Core/Core/Src/PowerPC/Jit64IL/IR_X86.cpp +++ b/Source/Core/Core/Src/PowerPC/Jit64IL/IR_X86.cpp @@ -472,10 +472,10 @@ static OpArg regBuildMemAddress(RegInfo& RI, InstLoc I, InstLoc AI, #else // 64-bit if (Profiled) { - RI.Jit->LEA(32, EAX, M((void*)addr)); + RI.Jit->LEA(32, EAX, M((void*)(u64)addr)); return MComplex(RBX, EAX, SCALE_1, 0); } - return M((void*)addr); + return M((void*)(u64)addr); #endif } } diff --git a/Source/Core/Core/Src/PowerPC/Jit64IL/JitIL_Tables.cpp b/Source/Core/Core/Src/PowerPC/Jit64IL/JitIL_Tables.cpp index 9e8e36f9c3..9418030b9c 100644 --- a/Source/Core/Core/Src/PowerPC/Jit64IL/JitIL_Tables.cpp +++ b/Source/Core/Core/Src/PowerPC/Jit64IL/JitIL_Tables.cpp @@ -309,6 +309,7 @@ static GekkoOPTemplate table31_2[] = {266, &JitIL::addx}, //"addx", OPTYPE_INTEGER, FL_OUT_D | FL_IN_AB | FL_RC_BIT}}, {778, &JitIL::addx}, //"addx", OPTYPE_INTEGER, FL_OUT_D | FL_IN_AB | FL_RC_BIT}}, {10, &JitIL::Default}, //"addcx", OPTYPE_INTEGER, FL_OUT_D | FL_IN_AB | FL_SET_CA | FL_RC_BIT}}, + {522, &JitIL::Default}, //"addcox", OPTYPE_INTEGER, FL_OUT_D | FL_IN_AB | FL_SET_CA | FL_RC_BIT}}, {138, &JitIL::addex}, //"addex", OPTYPE_INTEGER, FL_OUT_D | FL_IN_AB | FL_READ_CA | FL_SET_CA | FL_RC_BIT}}, {234, &JitIL::Default}, //"addmex", OPTYPE_INTEGER, FL_OUT_D | FL_IN_AB | FL_READ_CA | FL_SET_CA | FL_RC_BIT}}, {202, &JitIL::addzex}, //"addzex", OPTYPE_INTEGER, FL_OUT_D | FL_IN_AB | FL_READ_CA | FL_SET_CA | FL_RC_BIT}}, @@ -324,6 +325,7 @@ static GekkoOPTemplate table31_2[] = {40, &JitIL::subfx}, //"subfx", OPTYPE_INTEGER, FL_OUT_D | FL_IN_AB | FL_RC_BIT}}, {552, &JitIL::subfx}, //"subox", OPTYPE_INTEGER, FL_OUT_D | FL_IN_AB | FL_RC_BIT}}, {8, &JitIL::subfcx}, //"subfcx", OPTYPE_INTEGER, FL_OUT_D | FL_IN_AB | FL_SET_CA | FL_RC_BIT}}, + {520, &JitIL::subfcx}, //"subfcox", OPTYPE_INTEGER, FL_OUT_D | FL_IN_AB | FL_SET_CA | FL_RC_BIT}}, {136, &JitIL::subfex}, //"subfex", OPTYPE_INTEGER, FL_OUT_D | FL_IN_AB | FL_READ_CA | FL_SET_CA | FL_RC_BIT}}, {232, &JitIL::Default}, //"subfmex", OPTYPE_INTEGER, FL_OUT_D | FL_IN_AB | FL_READ_CA | FL_SET_CA | FL_RC_BIT}}, {200, &JitIL::Default}, //"subfzex", OPTYPE_INTEGER, FL_OUT_D | FL_IN_AB | FL_READ_CA | FL_SET_CA | FL_RC_BIT}}, diff --git a/Source/Core/Core/Src/State.cpp b/Source/Core/Core/Src/State.cpp index 8ef47467e8..a532ace217 100644 --- a/Source/Core/Core/Src/State.cpp +++ b/Source/Core/Core/Src/State.cpp @@ -71,7 +71,7 @@ static Common::Event g_compressAndDumpStateSyncEvent; static std::thread g_save_thread; // Don't forget to increase this after doing changes on the savestate system -static const int STATE_VERSION = 8; +static const u32 STATE_VERSION = 10; struct StateHeader { @@ -196,10 +196,18 @@ void CompressAndDumpState(CompressAndDumpState_args save_args) { if (File::Exists(File::GetUserPath(D_STATESAVES_IDX) + "lastState.sav")) File::Delete((File::GetUserPath(D_STATESAVES_IDX) + "lastState.sav")); + if (File::Exists(File::GetUserPath(D_STATESAVES_IDX) + "lastState.sav.dtm")) + File::Delete((File::GetUserPath(D_STATESAVES_IDX) + "lastState.sav.dtm")); if (!File::Rename(filename, File::GetUserPath(D_STATESAVES_IDX) + "lastState.sav")) Core::DisplayMessage("Failed to move previous state to state undo backup", 1000); + else + File::Rename(filename + ".dtm", File::GetUserPath(D_STATESAVES_IDX) + "lastState.sav.dtm"); } + if ((Movie::IsRecordingInput() || Movie::IsPlayingInput()) && !Movie::IsJustStartingRecordingInputFromSaveState()) + Movie::SaveRecording((filename + ".dtm").c_str()); + else if (!Movie::IsRecordingInput() && !Movie::IsPlayingInput()) + File::Delete(filename + ".dtm"); File::IOFile f(filename, "wb"); if (!f) @@ -273,10 +281,6 @@ void SaveAs(const std::string& filename) if (p.GetMode() == PointerWrap::MODE_WRITE) { Core::DisplayMessage("Saving State...", 1000); - if ((Movie::IsRecordingInput() || Movie::IsPlayingInput()) && !Movie::IsJustStartingRecordingInputFromSaveState()) - Movie::SaveRecording((filename + ".dtm").c_str()); - else if (!Movie::IsRecordingInput() && !Movie::IsPlayingInput()) - File::Delete(filename + ".dtm"); CompressAndDumpState_args save_args; save_args.buffer_vector = &g_current_buffer; @@ -383,9 +387,14 @@ void LoadAs(const std::string& filename) g_loadDepth++; // Save temp buffer for undo load state + if (!Movie::IsJustStartingRecordingInputFromSaveState()) { std::lock_guard<std::mutex> lk(g_cs_undo_load_buffer); SaveToBuffer(g_undo_load_buffer); + if (Movie::IsRecordingInput() || Movie::IsPlayingInput()) + Movie::SaveRecording("undo.dtm"); + else if (File::Exists("undo.dtm")) + File::Delete("undo.dtm"); } bool loaded = false; @@ -413,7 +422,7 @@ void LoadAs(const std::string& filename) Core::DisplayMessage(StringFromFormat("Loaded state from %s", filename.c_str()).c_str(), 2000); if (File::Exists(filename + ".dtm")) Movie::LoadInput((filename + ".dtm").c_str()); - else if (!Movie::IsJustStartingRecordingInputFromSaveState()) + else if (!Movie::IsJustStartingRecordingInputFromSaveState() && !Movie::IsJustStartingPlayingInputFromSaveState()) Movie::EndPlayInput(false); } else @@ -534,7 +543,16 @@ void UndoLoadState() { std::lock_guard<std::mutex> lk(g_cs_undo_load_buffer); if (!g_undo_load_buffer.empty()) - LoadFromBuffer(g_undo_load_buffer); + { + if (File::Exists("undo.dtm") || (!Movie::IsRecordingInput() && !Movie::IsPlayingInput())) + { + LoadFromBuffer(g_undo_load_buffer); + if (Movie::IsRecordingInput() || Movie::IsPlayingInput()) + Movie::LoadInput("undo.dtm"); + } + else + PanicAlert("No undo.dtm found, aborting undo load state to prevent movie desyncs"); + } else PanicAlert("There is nothing to undo!"); } @@ -542,7 +560,7 @@ void UndoLoadState() // Load the state that the last save state overwritten on void UndoSaveState() { - LoadAs((File::GetUserPath(D_STATESAVES_IDX) + "lastState.sav").c_str()); + LoadAs((File::GetUserPath(D_STATESAVES_IDX) + "lastState.sav").c_str()); } } // namespace State diff --git a/Source/Core/DolphinWX/CMakeLists.txt b/Source/Core/DolphinWX/CMakeLists.txt index 77ac9eb439..858e05bbfd 100644 --- a/Source/Core/DolphinWX/CMakeLists.txt +++ b/Source/Core/DolphinWX/CMakeLists.txt @@ -8,7 +8,6 @@ set(LIBS core z sfml-network ${GTK2_LIBRARIES} - ${OPENGL_LIBRARIES} ${XRANDR_LIBRARIES} ${X11_LIBRARIES}) @@ -31,7 +30,8 @@ if(LIBAV_FOUND) endif() if(wxWidgets_FOUND) - set(SRCS Src/ARCodeAddEdit.cpp + set(SRCS + Src/ARCodeAddEdit.cpp Src/AboutDolphin.cpp Src/CheatsWindow.cpp Src/ConfigMain.cpp @@ -79,7 +79,27 @@ if(wxWidgets_FOUND) set(WXLIBS ${wxWidgets_LIBRARIES}) else() - set(SRCS Src/MainNoGUI.cpp) + set(SRCS + Src/MainNoGUI.cpp) +endif() + +if(USE_EGL) + set(SRCS ${SRCS} Src/GLInterface/EGL.cpp + Src/GLInterface/X11_Util.cpp) +else() + if(WIN32) + set(SRCS ${SRCS} Src/GLInterface/GLW.cpp) + elseif(${CMAKE_SYSTEM_NAME} MATCHES "Darwin") + if(USE_WX) + set(SRCS ${SRCS} Src/GLInterface/WX.cpp) + else() + set(SRCS ${SRCS} Src/GLInterface/AGL.cpp) + endif() + else() + set(SRCS ${SRCS} Src/GLInterface/GLX.cpp + Src/GLInterface/X11_Util.cpp) + + endif() endif() if(WIN32) @@ -153,6 +173,7 @@ if(${CMAKE_SYSTEM_NAME} MATCHES "Darwin") file(WRITE ${CMAKE_CURRENT_BINARY_DIR}/postprocess_bundle.cmake " include(BundleUtilities) message(\"Fixing up application bundle: ${BUNDLE_PATH}\") + set(BU_CHMOD_BUNDLE_ITEMS ON) fixup_bundle(\"${BUNDLE_PATH}\" \"\" \"\") ") add_custom_command(TARGET ${DOLPHIN_EXE} POST_BUILD @@ -195,3 +216,5 @@ if(${CMAKE_SYSTEM_NAME} MATCHES "Darwin") else() install(TARGETS ${DOLPHIN_EXE} RUNTIME DESTINATION ${bindir}) endif() + +set(CPACK_PACKAGE_EXECUTABLES ${CPACK_PACKAGE_EXECUTABLES} ${DOLPHIN_EXE}) diff --git a/Source/Core/DolphinWX/Dolphin.vcxproj b/Source/Core/DolphinWX/Dolphin.vcxproj index 72c40a3db4..0d80b1fa5b 100644 --- a/Source/Core/DolphinWX/Dolphin.vcxproj +++ b/Source/Core/DolphinWX/Dolphin.vcxproj @@ -130,7 +130,7 @@ </PropertyGroup> <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> <ClCompile> - <AdditionalIncludeDirectories>..\Common\Src;..\VideoCommon\Src;..\AudioCommon\Src;..\Core\Src;..\Core\Src\PowerPC\JitCommon;..\DebuggerWX\Src;..\..\..\Externals\Bochs_disasm;..\InputCommon\Src;..\DiscIO\Src;..\..\..\Externals\SFML\include;..\..\..\Externals\wxWidgets3;..\..\..\Externals\wxWidgets3\include;..\..\..\Externals\CLRun\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> + <AdditionalIncludeDirectories>..\..\..\Externals\GLew\include;..\Common\Src;..\VideoCommon\Src;..\AudioCommon\Src;..\Core\Src;..\Core\Src\PowerPC\JitCommon;..\DebuggerWX\Src;..\..\..\Externals\Bochs_disasm;..\InputCommon\Src;..\DiscIO\Src;..\..\..\Externals\SFML\include;..\..\..\Externals\wxWidgets3;..\..\..\Externals\wxWidgets3\include;..\..\..\Externals\CLRun\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> </ClCompile> <Link /> <PostBuildEvent> @@ -144,7 +144,7 @@ xcopy "$(SolutionDir)..\Externals\SDL\$(PlatformName)\*.dll" "$(TargetDir)" /e / </ItemDefinitionGroup> <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> <ClCompile> - <AdditionalIncludeDirectories>..\Common\Src;..\VideoCommon\Src;..\AudioCommon\Src;..\Core\Src;..\Core\Src\PowerPC\JitCommon;..\DebuggerWX\Src;..\..\..\Externals\Bochs_disasm;..\InputCommon\Src;..\DiscIO\Src;..\..\..\Externals\SFML\include;..\..\..\Externals\wxWidgets3;..\..\..\Externals\wxWidgets3\include;..\..\..\Externals\CLRun\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> + <AdditionalIncludeDirectories>..\..\..\Externals\GLew\include;..\Common\Src;..\VideoCommon\Src;..\AudioCommon\Src;..\Core\Src;..\Core\Src\PowerPC\JitCommon;..\DebuggerWX\Src;..\..\..\Externals\Bochs_disasm;..\InputCommon\Src;..\DiscIO\Src;..\..\..\Externals\SFML\include;..\..\..\Externals\wxWidgets3;..\..\..\Externals\wxWidgets3\include;..\..\..\Externals\CLRun\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> </ClCompile> <Link /> <PostBuildEvent> @@ -158,7 +158,7 @@ xcopy "$(SolutionDir)..\Externals\SDL\$(PlatformName)\*.dll" "$(TargetDir)" /e / </ItemDefinitionGroup> <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> <ClCompile> - <AdditionalIncludeDirectories>..\Common\Src;..\VideoCommon\Src;..\AudioCommon\Src;..\Core\Src;..\Core\Src\PowerPC\JitCommon;..\DebuggerWX\Src;..\..\..\Externals\Bochs_disasm;..\InputCommon\Src;..\DiscIO\Src;..\..\..\Externals\SFML\include;..\..\..\Externals\wxWidgets3;..\..\..\Externals\wxWidgets3\include;..\..\..\Externals\CLRun\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> + <AdditionalIncludeDirectories>..\..\..\Externals\GLew\include;..\Common\Src;..\VideoCommon\Src;..\AudioCommon\Src;..\Core\Src;..\Core\Src\PowerPC\JitCommon;..\DebuggerWX\Src;..\..\..\Externals\Bochs_disasm;..\InputCommon\Src;..\DiscIO\Src;..\..\..\Externals\SFML\include;..\..\..\Externals\wxWidgets3;..\..\..\Externals\wxWidgets3\include;..\..\..\Externals\CLRun\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> <OpenMPSupport> </OpenMPSupport> </ClCompile> @@ -174,7 +174,7 @@ xcopy "$(SolutionDir)..\Externals\SDL\$(PlatformName)\*.dll" "$(TargetDir)" /e / </ItemDefinitionGroup> <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='DebugFast|Win32'"> <ClCompile> - <AdditionalIncludeDirectories>..\Common\Src;..\VideoCommon\Src;..\AudioCommon\Src;..\Core\Src;..\Core\Src\PowerPC\JitCommon;..\DebuggerWX\Src;..\..\..\Externals\Bochs_disasm;..\InputCommon\Src;..\InputUICommon\Src;..\DiscIO\Src;..\..\..\Externals\SFML\include;..\..\..\Externals\wxWidgets3;..\..\..\Externals\wxWidgets3\include;..\..\..\Externals\CLRun\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> + <AdditionalIncludeDirectories>..\..\..\Externals\GLew\include;..\Common\Src;..\VideoCommon\Src;..\AudioCommon\Src;..\Core\Src;..\Core\Src\PowerPC\JitCommon;..\DebuggerWX\Src;..\..\..\Externals\Bochs_disasm;..\InputCommon\Src;..\InputUICommon\Src;..\DiscIO\Src;..\..\..\Externals\SFML\include;..\..\..\Externals\wxWidgets3;..\..\..\Externals\wxWidgets3\include;..\..\..\Externals\CLRun\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> </ClCompile> <Link /> <PostBuildEvent> @@ -188,7 +188,7 @@ xcopy "$(SolutionDir)..\Externals\SDL\$(PlatformName)\*.dll" "$(TargetDir)" /e / </ItemDefinitionGroup> <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> <ClCompile> - <AdditionalIncludeDirectories>..\Common\Src;..\VideoCommon\Src;..\AudioCommon\Src;..\Core\Src;..\Core\Src\PowerPC\JitCommon;..\DebuggerWX\Src;..\..\..\Externals\Bochs_disasm;..\InputCommon\Src;..\DiscIO\Src;..\..\..\Externals\SFML\include;..\..\..\Externals\wxWidgets3;..\..\..\Externals\wxWidgets3\include;..\..\..\Externals\CLRun\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> + <AdditionalIncludeDirectories>..\..\..\Externals\GLew\include;..\Common\Src;..\VideoCommon\Src;..\AudioCommon\Src;..\Core\Src;..\Core\Src\PowerPC\JitCommon;..\DebuggerWX\Src;..\..\..\Externals\Bochs_disasm;..\InputCommon\Src;..\DiscIO\Src;..\..\..\Externals\SFML\include;..\..\..\Externals\wxWidgets3;..\..\..\Externals\wxWidgets3\include;..\..\..\Externals\CLRun\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> <OpenMPSupport> </OpenMPSupport> </ClCompile> @@ -201,10 +201,12 @@ xcopy "$(SolutionDir)..\Externals\SDL\$(PlatformName)\*.dll" "$(TargetDir)" /e / </Command> <Message>Copying Data\* to $(TargetDir)</Message> </PostBuildEvent> + <ResourceCompile> + </ResourceCompile> </ItemDefinitionGroup> <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='DebugFast|x64'"> <ClCompile> - <AdditionalIncludeDirectories>..\Common\Src;..\VideoCommon\Src;..\AudioCommon\Src;..\Core\Src;..\Core\Src\PowerPC\JitCommon;..\DebuggerWX\Src;..\..\..\Externals\Bochs_disasm;..\InputCommon\Src;..\InputUICommon\Src;..\DiscIO\Src;..\..\..\Externals\SFML\include;..\..\..\Externals\wxWidgets3;..\..\..\Externals\wxWidgets3\include;..\..\..\Externals\CLRun\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> + <AdditionalIncludeDirectories>..\..\..\Externals\GLew\include;..\Common\Src;..\VideoCommon\Src;..\AudioCommon\Src;..\Core\Src;..\Core\Src\PowerPC\JitCommon;..\DebuggerWX\Src;..\..\..\Externals\Bochs_disasm;..\InputCommon\Src;..\InputUICommon\Src;..\DiscIO\Src;..\..\..\Externals\SFML\include;..\..\..\Externals\wxWidgets3;..\..\..\Externals\wxWidgets3\include;..\..\..\Externals\CLRun\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> </ClCompile> <Link /> <PostBuildEvent> @@ -265,6 +267,7 @@ xcopy "$(SolutionDir)..\Externals\SDL\$(PlatformName)\*.dll" "$(TargetDir)" /e / <ClCompile Include="Src\PHackSettings.cpp" /> <ClCompile Include="Src\Debugger\RegisterView.cpp" /> <ClCompile Include="Src\Debugger\RegisterWindow.cpp" /> + <ClCompile Include="Src\GLInterface\WGL.cpp" /> <ClCompile Include="Src\stdafx.cpp"> <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">Create</PrecompiledHeader> <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='DebugFast|Win32'">Create</PrecompiledHeader> @@ -326,6 +329,9 @@ xcopy "$(SolutionDir)..\Externals\SDL\$(PlatformName)\*.dll" "$(TargetDir)" /e / <ClInclude Include="Src\WiimoteConfigDiag.h" /> <ClInclude Include="Src\WXInputBase.h" /> <ClInclude Include="Src\WxUtils.h" /> + <ClInclude Include="Src\GLInterface.h" /> + <ClInclude Include="Src\GLInterface\InterfaceBase.h" /> + <ClInclude Include="Src\GLInterface\WGL.h" /> </ItemGroup> <ItemGroup> <None Include="..\..\..\Installer\Dolphin.ico" /> @@ -387,4 +393,4 @@ xcopy "$(SolutionDir)..\Externals\SDL\$(PlatformName)\*.dll" "$(TargetDir)" /e / <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" /> <ImportGroup Label="ExtensionTargets"> </ImportGroup> -</Project>
\ No newline at end of file +</Project> diff --git a/Source/Core/DolphinWX/DolphinWX.rc b/Source/Core/DolphinWX/DolphinWX.rc index e9c06a8fa9..550e08c35a 100644 --- a/Source/Core/DolphinWX/DolphinWX.rc +++ b/Source/Core/DolphinWX/DolphinWX.rc @@ -2,3 +2,7 @@ // #include "resource.h" IDI_ICON1 ICON "..\\..\\..\\Installer\\Dolphin.ico" +"dolphin" ICON "..\\..\\..\\Installer\\Dolphin.ico" +#define wxUSE_NO_MANIFEST 1 +#include <wx/msw/wx.rc> + diff --git a/Source/Core/DolphinWX/Src/AboutDolphin.cpp b/Source/Core/DolphinWX/Src/AboutDolphin.cpp index d13c12ee7f..5e1825b6ae 100644 --- a/Source/Core/DolphinWX/Src/AboutDolphin.cpp +++ b/Source/Core/DolphinWX/Src/AboutDolphin.cpp @@ -31,7 +31,7 @@ AboutDolphin::AboutDolphin(wxWindow *parent, wxWindowID id, wxBitmap(iDolphinLogo)); std::string Text = "Dolphin " SCM_DESC_STR "\n" - "Copyright (c) 2003-2011+ Dolphin Team\n" + "Copyright (c) 2003-2013+ Dolphin Team\n" "\n" "Branch: " SCM_BRANCH_STR "\n" "Revision: " SCM_REV_STR "\n" diff --git a/Source/Core/DolphinWX/Src/CheatsWindow.cpp b/Source/Core/DolphinWX/Src/CheatsWindow.cpp index eb25117533..dec6648461 100644 --- a/Source/Core/DolphinWX/Src/CheatsWindow.cpp +++ b/Source/Core/DolphinWX/Src/CheatsWindow.cpp @@ -36,7 +36,7 @@ extern CFrame* main_frame; static wxCheatsWindow *g_cheat_window; wxCheatsWindow::wxCheatsWindow(wxWindow* const parent) - : wxDialog(parent, wxID_ANY, _("Cheats Manager"), wxDefaultPosition, wxDefaultSize) + : wxDialog(parent, wxID_ANY, _("Cheats Manager"), wxDefaultPosition, wxDefaultSize, wxDEFAULT_DIALOG_STYLE|wxRESIZE_BORDER|wxMAXIMIZE_BOX|wxMINIMIZE_BOX|wxDIALOG_NO_PARENT) { ::g_cheat_window = this; @@ -57,6 +57,7 @@ wxCheatsWindow::wxCheatsWindow(wxWindow* const parent) } } + SetSize(wxSize(-1, 600)); Center(); Show(); } diff --git a/Source/Core/DolphinWX/Src/ConfigMain.cpp b/Source/Core/DolphinWX/Src/ConfigMain.cpp index 2534c4a9db..76508daf7c 100644 --- a/Source/Core/DolphinWX/Src/ConfigMain.cpp +++ b/Source/Core/DolphinWX/Src/ConfigMain.cpp @@ -125,6 +125,7 @@ EVT_SLIDER(ID_VOLUME, CConfigMain::AudioSettingsChanged) EVT_CHECKBOX(ID_INTERFACE_CONFIRMSTOP, CConfigMain::DisplaySettingsChanged) EVT_CHECKBOX(ID_INTERFACE_USEPANICHANDLERS, CConfigMain::DisplaySettingsChanged) +EVT_CHECKBOX(ID_INTERFACE_ONSCREENDISPLAYMESSAGES, CConfigMain::DisplaySettingsChanged) EVT_RADIOBOX(ID_INTERFACE_THEME, CConfigMain::DisplaySettingsChanged) EVT_CHOICE(ID_INTERFACE_LANG, CConfigMain::DisplaySettingsChanged) EVT_BUTTON(ID_HOTKEY_CONFIG, CConfigMain::DisplaySettingsChanged) @@ -337,6 +338,7 @@ void CConfigMain::InitializeGUIValues() // Display - Interface ConfirmStop->SetValue(startup_params.bConfirmStop); UsePanicHandlers->SetValue(startup_params.bUsePanicHandlers); + OnScreenDisplayMessages->SetValue(startup_params.bOnScreenDisplayMessages); Theme->SetSelection(startup_params.iTheme); // need redesign for (unsigned int i = 0; i < sizeof(langIds) / sizeof(wxLanguage); i++) @@ -490,6 +492,7 @@ void CConfigMain::InitializeGUITooltips() // Display - Interface ConfirmStop->SetToolTip(_("Show a confirmation box before stopping a game.")); UsePanicHandlers->SetToolTip(_("Show a message box when a potentially serious error has occured.\nDisabling this may avoid annoying and non-fatal messages, but it may also mean that Dolphin suddenly crashes without any explanation at all.")); + OnScreenDisplayMessages->SetToolTip(_("Show messages on the emulation screen area.\nThese messages include memory card writes, video backend and CPU information, and JIT cache clearing.")); // Display - Themes: Copyright notice Theme->SetItemToolTip(0, _("Created by Milosz Wlazlo [miloszwl@miloszwl.com, miloszwl.deviantart.com]")); @@ -579,6 +582,8 @@ void CConfigMain::CreateGUIControls() wxDefaultPosition, wxDefaultSize, 0, wxDefaultValidator); UsePanicHandlers = new wxCheckBox(DisplayPage, ID_INTERFACE_USEPANICHANDLERS, _("Use Panic Handlers"), wxDefaultPosition, wxDefaultSize, 0, wxDefaultValidator); + OnScreenDisplayMessages = new wxCheckBox(DisplayPage, ID_INTERFACE_ONSCREENDISPLAYMESSAGES, + _("On-Screen Display Messages"), wxDefaultPosition, wxDefaultSize, 0, wxDefaultValidator); wxBoxSizer* sInterface = new wxBoxSizer(wxHORIZONTAL); sInterface->Add(TEXT_BOX(DisplayPage, _("Language:")), 0, wxALIGN_CENTER_VERTICAL | wxALL, 5); @@ -588,6 +593,7 @@ void CConfigMain::CreateGUIControls() sbInterface = new wxStaticBoxSizer(wxVERTICAL, DisplayPage, _("Interface Settings")); sbInterface->Add(ConfirmStop, 0, wxALL, 5); sbInterface->Add(UsePanicHandlers, 0, wxALL, 5); + sbInterface->Add(OnScreenDisplayMessages, 0, wxALL, 5); sbInterface->Add(Theme, 0, wxEXPAND | wxALL, 5); sbInterface->Add(sInterface, 0, wxEXPAND | wxALL, 5); @@ -865,6 +871,10 @@ void CConfigMain::DisplaySettingsChanged(wxCommandEvent& event) SConfig::GetInstance().m_LocalCoreStartupParameter.bUsePanicHandlers = UsePanicHandlers->IsChecked(); SetEnableAlert(UsePanicHandlers->IsChecked()); break; + case ID_INTERFACE_ONSCREENDISPLAYMESSAGES: + SConfig::GetInstance().m_LocalCoreStartupParameter.bOnScreenDisplayMessages = OnScreenDisplayMessages->IsChecked(); + SetEnableAlert(OnScreenDisplayMessages->IsChecked()); + break; case ID_INTERFACE_THEME: SConfig::GetInstance().m_LocalCoreStartupParameter.iTheme = Theme->GetSelection(); main_frame->InitBitmaps(); @@ -891,7 +901,8 @@ void CConfigMain::AudioSettingsChanged(wxCommandEvent& event) { case ID_DSPENGINE: SConfig::GetInstance().m_LocalCoreStartupParameter.bDSPHLE = DSPEngine->GetSelection() == 0; - ac_Config.m_EnableJIT = DSPEngine->GetSelection() == 1; + if (!DSPEngine->GetSelection() == 0) + ac_Config.m_EnableJIT = DSPEngine->GetSelection() == 1; ac_Config.Update(); break; diff --git a/Source/Core/DolphinWX/Src/ConfigMain.h b/Source/Core/DolphinWX/Src/ConfigMain.h index eae9f8996d..9b5dbf4243 100644 --- a/Source/Core/DolphinWX/Src/ConfigMain.h +++ b/Source/Core/DolphinWX/Src/ConfigMain.h @@ -86,6 +86,7 @@ private: // Interface settings ID_INTERFACE_CONFIRMSTOP, ID_INTERFACE_USEPANICHANDLERS, + ID_INTERFACE_ONSCREENDISPLAYMESSAGES, ID_INTERFACE_THEME, ID_INTERFACE_LANG, ID_HOTKEY_CONFIG, @@ -163,6 +164,7 @@ private: // Interface wxCheckBox* ConfirmStop; wxCheckBox* UsePanicHandlers; + wxCheckBox* OnScreenDisplayMessages; wxRadioBox* Theme; wxChoice* InterfaceLang; wxButton* HotkeyConfig; diff --git a/Source/Core/DolphinWX/Src/Debugger/CodeWindow.cpp b/Source/Core/DolphinWX/Src/Debugger/CodeWindow.cpp index 0b6b366c88..2917f1637d 100644 --- a/Source/Core/DolphinWX/Src/Debugger/CodeWindow.cpp +++ b/Source/Core/DolphinWX/Src/Debugger/CodeWindow.cpp @@ -319,7 +319,7 @@ void CCodeWindow::UpdateLists() { int idx = callers->Append(wxString::FromAscii(StringFromFormat ("< %s (%08x)", caller_symbol->name.c_str(), caller_addr).c_str())); - callers->SetClientData(idx, (void*)caller_addr); + callers->SetClientData(idx, (void*)(u64)caller_addr); } } @@ -332,7 +332,7 @@ void CCodeWindow::UpdateLists() { int idx = calls->Append(wxString::FromAscii(StringFromFormat ("> %s (%08x)", call_symbol->name.c_str(), call_addr).c_str())); - calls->SetClientData(idx, (void*)call_addr); + calls->SetClientData(idx, (void*)(u64)call_addr); } } } diff --git a/Source/Core/DolphinWX/Src/Debugger/DSPDebugWindow.cpp b/Source/Core/DolphinWX/Src/Debugger/DSPDebugWindow.cpp index cec986ad90..a4591d3994 100644 --- a/Source/Core/DolphinWX/Src/Debugger/DSPDebugWindow.cpp +++ b/Source/Core/DolphinWX/Src/Debugger/DSPDebugWindow.cpp @@ -139,7 +139,7 @@ void DSPDebuggerLLE::OnChangeState(wxCommandEvent& event) if (DSPCore_GetState() == DSPCORE_STEPPING) { DSPCore_Step(); - Refresh(); + Update(); } break; @@ -155,10 +155,10 @@ void DSPDebuggerLLE::OnChangeState(wxCommandEvent& event) void Host_RefreshDSPDebuggerWindow() { if (m_DebuggerFrame) - m_DebuggerFrame->Refresh(); + m_DebuggerFrame->Update(); } -void DSPDebuggerLLE::Refresh() +void DSPDebuggerLLE::Update() { #if defined __WXGTK__ if (!wxIsMainThread()) diff --git a/Source/Core/DolphinWX/Src/Debugger/DSPDebugWindow.h b/Source/Core/DolphinWX/Src/Debugger/DSPDebugWindow.h index 95bd3b4286..0e4feccef2 100644 --- a/Source/Core/DolphinWX/Src/Debugger/DSPDebugWindow.h +++ b/Source/Core/DolphinWX/Src/Debugger/DSPDebugWindow.h @@ -50,7 +50,7 @@ public: DSPDebuggerLLE(wxWindow *parent, wxWindowID id = wxID_ANY); virtual ~DSPDebuggerLLE(); - void Refresh(); + void Update(); private: DECLARE_EVENT_TABLE(); diff --git a/Source/Core/DolphinWX/Src/FifoPlayerDlg.cpp b/Source/Core/DolphinWX/Src/FifoPlayerDlg.cpp index cb467389ee..b5caf139d6 100644 --- a/Source/Core/DolphinWX/Src/FifoPlayerDlg.cpp +++ b/Source/Core/DolphinWX/Src/FifoPlayerDlg.cpp @@ -23,6 +23,7 @@ #include "FifoPlayer/FifoRecorder.h" #include "OpcodeDecoding.h" #include <wx/spinctrl.h> +#include <wx/clipbrd.h> DECLARE_EVENT_TYPE(RECORDING_FINISHED_EVENT, -1) DEFINE_EVENT_TYPE(RECORDING_FINISHED_EVENT) @@ -323,6 +324,13 @@ void FifoPlayerDlg::CreateGUIControls() m_searchField->Connect(wxEVT_COMMAND_TEXT_ENTER, wxCommandEventHandler(FifoPlayerDlg::OnBeginSearch), NULL, this); m_searchField->Connect(wxEVT_COMMAND_TEXT_UPDATED, wxCommandEventHandler(FifoPlayerDlg::OnSearchFieldTextChanged), NULL, this); + // Setup command copying + wxAcceleratorEntry entry; + entry.Set(wxACCEL_CTRL, (int)'C', wxID_COPY); + wxAcceleratorTable accel(1, &entry); + m_objectCmdList->SetAcceleratorTable(accel); + m_objectCmdList->Connect(wxID_COPY, wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler(FifoPlayerDlg::OnObjectCmdListSelectionCopy), NULL, this); + Connect(RECORDING_FINISHED_EVENT, wxCommandEventHandler(FifoPlayerDlg::OnRecordingFinished), NULL, this); Connect(FRAME_WRITTEN_EVENT, wxCommandEventHandler(FifoPlayerDlg::OnFrameWritten), NULL, this); @@ -616,7 +624,6 @@ void FifoPlayerDlg::OnObjectListSelectionChanged(wxCommandEvent& event) int cmd = *objectdata++; int stream_size = Common::swap16(objectdata); objectdata += 2; - int vertex_size = (objectdata_end - objectdata) / stream_size; wxString newLabel = wxString::Format(wxT("%08X: %02X %04X "), obj_offset, cmd, stream_size); if ((objectdata_end - objectdata) % stream_size) newLabel += _("NOTE: Stream size doesn't match actual data length\n"); while (objectdata < objectdata_end) @@ -763,6 +770,15 @@ void FifoPlayerDlg::OnObjectCmdListSelectionChanged(wxCommandEvent& event) Fit(); } +void FifoPlayerDlg::OnObjectCmdListSelectionCopy(wxCommandEvent& WXUNUSED(event)) +{ + if (wxTheClipboard->Open()) + { + wxTheClipboard->SetData(new wxTextDataObject(m_objectCmdList->GetStringSelection())); + wxTheClipboard->Close(); + } +} + void FifoPlayerDlg::OnCloseClick(wxCommandEvent& WXUNUSED(event)) { Hide(); diff --git a/Source/Core/DolphinWX/Src/FifoPlayerDlg.h b/Source/Core/DolphinWX/Src/FifoPlayerDlg.h index 4e2c24fdd6..eb5f9a33e9 100644 --- a/Source/Core/DolphinWX/Src/FifoPlayerDlg.h +++ b/Source/Core/DolphinWX/Src/FifoPlayerDlg.h @@ -57,6 +57,7 @@ private: void OnFrameListSelectionChanged(wxCommandEvent& event); void OnObjectListSelectionChanged(wxCommandEvent& event); void OnObjectCmdListSelectionChanged(wxCommandEvent& event); + void OnObjectCmdListSelectionCopy(wxCommandEvent& WXUNUSED(event)); void UpdatePlayGui(); void UpdateRecorderGui(); diff --git a/Source/Core/DolphinWX/Src/Frame.cpp b/Source/Core/DolphinWX/Src/Frame.cpp index 6b0e7b7678..c9408203ea 100644 --- a/Source/Core/DolphinWX/Src/Frame.cpp +++ b/Source/Core/DolphinWX/Src/Frame.cpp @@ -26,7 +26,6 @@ #include "Common.h" // Common #include "FileUtil.h" #include "Timer.h" -#include "Setup.h" #include "Globals.h" // Local #include "Frame.h" @@ -72,30 +71,7 @@ extern "C" { }; -// Windows functions. Setting the cursor with wxSetCursor() did not work in -// this instance. Probably because it's somehow reset from the WndProc() in -// the child window #ifdef _WIN32 -// Declare a blank icon and one that will be the normal cursor -HCURSOR hCursor = NULL, hCursorBlank = NULL; - -// Create the default cursor -void CreateCursor() -{ - hCursor = LoadCursor( NULL, IDC_ARROW ); -} - -void MSWSetCursor(bool Show) -{ - if(Show) - SetCursor(hCursor); - else - { - SetCursor(hCursorBlank); - //wxSetCursor(wxCursor(wxNullCursor)); - } -} - // I could not use FindItemByHWND() instead of this, it crashed on that occation I used it */ HWND MSWGetParent_(HWND Parent) { @@ -134,10 +110,11 @@ CPanel::CPanel( case WM_USER_SETCURSOR: if (SConfig::GetInstance().m_LocalCoreStartupParameter.bHideCursor && - main_frame->RendererHasFocus() && Core::GetState() == Core::CORE_RUN) - MSWSetCursor(!SConfig::GetInstance().m_LocalCoreStartupParameter.bHideCursor); + main_frame->RendererHasFocus() && Core::GetState() == Core::CORE_RUN && + SConfig::GetInstance().m_LocalCoreStartupParameter.bHideCursor) + SetCursor(wxCURSOR_BLANK); else - MSWSetCursor(true); + SetCursor(wxNullCursor); break; case WIIMOTE_DISCONNECT: @@ -244,6 +221,8 @@ EVT_MENU(IDM_PLAYRECORD, CFrame::OnPlayRecording) EVT_MENU(IDM_RECORDEXPORT, CFrame::OnRecordExport) EVT_MENU(IDM_RECORDREADONLY, CFrame::OnRecordReadOnly) EVT_MENU(IDM_TASINPUT, CFrame::OnTASInput) +EVT_MENU(IDM_TOGGLE_PAUSEMOVIE, CFrame::OnTogglePauseMovie) +EVT_MENU(IDM_SHOWLAG, CFrame::OnShowLag) EVT_MENU(IDM_FRAMESTEP, CFrame::OnFrameStep) EVT_MENU(IDM_SCREENSHOT, CFrame::OnScreenshot) EVT_MENU(wxID_PREFERENCES, CFrame::OnConfigMain) @@ -434,9 +413,7 @@ CFrame::CFrame(wxFrame* parent, // Commit m_Mgr->Update(); - // Create cursors #ifdef _WIN32 - CreateCursor(); SetToolTip(wxT("")); GetToolTip()->SetAutoPop(25000); #endif @@ -456,13 +433,6 @@ CFrame::CFrame(wxFrame* parent, // Update controls UpdateGUI(); - - // If we are rerecording create the status bar now instead of later when a game starts - #ifdef RERECORDING - ModifyStatusBar(); - // It's to early for the OnHostMessage(), we will update the status when Ctrl or Space is pressed - //Core::WriteStatus(); - #endif } // Destructor CFrame::~CFrame() @@ -500,20 +470,6 @@ void CFrame::OnActive(wxActivateEvent& event) { if (event.GetActive() && event.GetEventObject() == m_RenderFrame) { - // 32x32, 8bpp b/w image - // We want all transparent, so we can just use the same buffer for - // the "image" as for the transparency mask - static const char cursor_data[32 * 32] = { 0 }; - -#ifdef __WXGTK__ - wxCursor cursor_transparent = wxCursor(cursor_data, 32, 32, 6, 14, - cursor_data, wxWHITE, wxBLACK); -#else - wxBitmap cursor_bitmap(cursor_data, 32, 32); - cursor_bitmap.SetMask(new wxMask(cursor_bitmap)); - wxCursor cursor_transparent = wxCursor(cursor_bitmap.ConvertToImage()); -#endif - #ifdef __WXMSW__ ::SetFocus((HWND)m_RenderParent->GetHandle()); #else @@ -522,7 +478,7 @@ void CFrame::OnActive(wxActivateEvent& event) if (SConfig::GetInstance().m_LocalCoreStartupParameter.bHideCursor && Core::GetState() == Core::CORE_RUN) - m_RenderParent->SetCursor(cursor_transparent); + m_RenderParent->SetCursor(wxCURSOR_BLANK); } else { @@ -652,12 +608,12 @@ void CFrame::OnHostMessage(wxCommandEvent& event) } break; -#ifdef __WXGTK__ case WM_USER_CREATE: if (SConfig::GetInstance().m_LocalCoreStartupParameter.bHideCursor) m_RenderParent->SetCursor(wxCURSOR_BLANK); break; +#ifdef __WXGTK__ case IDM_PANIC: { wxString caption = event.GetString().BeforeFirst(':'); diff --git a/Source/Core/DolphinWX/Src/Frame.h b/Source/Core/DolphinWX/Src/Frame.h index 770d459220..8c8285f842 100644 --- a/Source/Core/DolphinWX/Src/Frame.h +++ b/Source/Core/DolphinWX/Src/Frame.h @@ -297,6 +297,8 @@ private: void OnRecordExport(wxCommandEvent& event); void OnRecordReadOnly(wxCommandEvent& event); void OnTASInput(wxCommandEvent& event); + void OnTogglePauseMovie(wxCommandEvent& event); + void OnShowLag(wxCommandEvent& event); void OnChangeDisc(wxCommandEvent& event); void OnScreenshot(wxCommandEvent& event); void OnActive(wxActivateEvent& event); diff --git a/Source/Core/DolphinWX/Src/FrameTools.cpp b/Source/Core/DolphinWX/Src/FrameTools.cpp index d24bd2f23e..7b595c485e 100644 --- a/Source/Core/DolphinWX/Src/FrameTools.cpp +++ b/Source/Core/DolphinWX/Src/FrameTools.cpp @@ -27,9 +27,6 @@ window handle that is returned by CreateWindow() can be accessed from Core::GetWindowHandle(). */ - -#include "Setup.h" // Common - #include "NetWindow.h" #include "Common.h" // Common #include "FileUtil.h" @@ -142,9 +139,13 @@ void CFrame::CreateMenu() emulationMenu->Append(IDM_RECORDEXPORT, GetMenuLabel(HK_EXPORT_RECORDING)); emulationMenu->Append(IDM_RECORDREADONLY, GetMenuLabel(HK_READ_ONLY_MODE), wxEmptyString, wxITEM_CHECK); emulationMenu->Append(IDM_TASINPUT, _("TAS Input")); + emulationMenu->AppendCheckItem(IDM_TOGGLE_PAUSEMOVIE, _("Pause at end of movie")); + emulationMenu->Check(IDM_TOGGLE_PAUSEMOVIE, SConfig::GetInstance().m_PauseMovie); + emulationMenu->AppendCheckItem(IDM_SHOWLAG, _("Show lag counter")); + emulationMenu->Check(IDM_SHOWLAG, SConfig::GetInstance().m_ShowLag); emulationMenu->Check(IDM_RECORDREADONLY, true); emulationMenu->AppendSeparator(); - + emulationMenu->Append(IDM_FRAMESTEP, GetMenuLabel(HK_FRAME_ADVANCE), wxEmptyString); wxMenu *skippingMenu = new wxMenu; @@ -162,7 +163,7 @@ void CFrame::CreateMenu() emulationMenu->Append(IDM_SAVESTATE, _("Sa&ve State"), saveMenu); saveMenu->Append(IDM_SAVESTATEFILE, _("Save State...")); - loadMenu->Append(IDM_UNDOSAVESTATE, _("Last Overwritten State") + wxString(wxT("\tShift+F12"))); + loadMenu->Append(IDM_UNDOSAVESTATE, _("Last Overwritten State") + wxString(wxT("\tF12"))); saveMenu->AppendSeparator(); loadMenu->Append(IDM_LOADSTATEFILE, _("Load State...")); @@ -173,7 +174,7 @@ void CFrame::CreateMenu() else loadMenu->Append(IDM_LOADLASTSTATE, _("Last Saved State") + wxString(wxT("\tF11"))); - loadMenu->Append(IDM_UNDOLOADSTATE, _("Undo Load State") + wxString(wxT("\tF12"))); + loadMenu->Append(IDM_UNDOLOADSTATE, _("Undo Load State") + wxString(wxT("\tShift+F12"))); loadMenu->AppendSeparator(); for (int i = 1; i <= 8; i++) { @@ -702,6 +703,18 @@ void CFrame::OnTASInput(wxCommandEvent& event) g_TASInputDlg->Show(true); } +void CFrame::OnTogglePauseMovie(wxCommandEvent& WXUNUSED (event)) +{ + SConfig::GetInstance().m_PauseMovie = !SConfig::GetInstance().m_PauseMovie; + SConfig::GetInstance().SaveSettings(); +} + +void CFrame::OnShowLag(wxCommandEvent& WXUNUSED (event)) +{ + SConfig::GetInstance().m_ShowLag = !SConfig::GetInstance().m_ShowLag; + SConfig::GetInstance().SaveSettings(); +} + void CFrame::OnFrameStep(wxCommandEvent& event) { bool wasPaused = (Core::GetState() == Core::CORE_PAUSE); @@ -732,7 +745,7 @@ void CFrame::OnRecord(wxCommandEvent& WXUNUSED (event)) } for (int i = 0; i < 4; i++) { - if (SConfig::GetInstance().m_SIDevice[i] == SIDEVICE_GC_CONTROLLER) + if (SConfig::GetInstance().m_SIDevice[i] == SIDEVICE_GC_CONTROLLER || SConfig::GetInstance().m_SIDevice[i] == SIDEVICE_GC_TARUKONGA) controllers |= (1 << i); if (g_wiimote_sources[i] != WIIMOTE_SRC_NONE) @@ -1042,27 +1055,14 @@ void CFrame::DoPause() { Core::SetState(Core::CORE_PAUSE); if (SConfig::GetInstance().m_LocalCoreStartupParameter.bHideCursor) - m_RenderParent->SetCursor(wxCURSOR_ARROW); + m_RenderParent->SetCursor(wxNullCursor); } else { - // 32x32, 8bpp b/w image - // We want all transparent, so we can just use the same buffer for - // the "image" as for the transparency mask - static const char cursor_data[32 * 32] = { 0 }; -#ifdef __WXGTK__ - wxCursor cursor_transparent = wxCursor(cursor_data, 32, 32, 6, 14, - cursor_data, wxWHITE, wxBLACK); -#else - wxBitmap cursor_bitmap(cursor_data, 32, 32); - cursor_bitmap.SetMask(new wxMask(cursor_bitmap)); - wxCursor cursor_transparent = wxCursor(cursor_bitmap.ConvertToImage()); -#endif - Core::SetState(Core::CORE_RUN); if (SConfig::GetInstance().m_LocalCoreStartupParameter.bHideCursor && RendererHasFocus()) - m_RenderParent->SetCursor(cursor_transparent); + m_RenderParent->SetCursor(wxCURSOR_BLANK); } UpdateGUI(); } @@ -1138,10 +1138,13 @@ void CFrame::DoStop() wxMouseEventHandler(CFrame::OnMouse), (wxObject*)0, this); if (SConfig::GetInstance().m_LocalCoreStartupParameter.bHideCursor) - m_RenderParent->SetCursor(wxCURSOR_ARROW); + m_RenderParent->SetCursor(wxNullCursor); DoFullscreen(false); if (!SConfig::GetInstance().m_LocalCoreStartupParameter.bRenderToMain) m_RenderFrame->Destroy(); + else + // Make sure the window is not longer set to stay on top + m_RenderFrame->SetWindowStyle(m_RenderFrame->GetWindowStyle() & ~wxSTAY_ON_TOP); m_RenderParent = NULL; // Clean framerate indications from the status bar. @@ -1289,7 +1292,7 @@ void CFrame::OnHelp(wxCommandEvent& event) } break; case IDM_HELPWEBSITE: - WxUtils::Launch("http://www.dolphin-emulator.com/"); + WxUtils::Launch("http://dolphin-emu.org/"); break; case IDM_HELPGOOGLECODE: WxUtils::Launch("http://code.google.com/p/dolphin-emu/"); @@ -1307,9 +1310,8 @@ void CFrame::StatusBarMessage(const char * Text, ...) const int MAX_BYTES = 1024*10; char Str[MAX_BYTES]; va_list ArgPtr; - int Cnt; va_start(ArgPtr, Text); - Cnt = vsnprintf(Str, MAX_BYTES, Text, ArgPtr); + vsnprintf(Str, MAX_BYTES, Text, ArgPtr); va_end(ArgPtr); if (this->GetStatusBar()->IsEnabled()) this->GetStatusBar()->SetStatusText(wxString::FromAscii(Str),0); diff --git a/Source/Core/DolphinWX/Src/GLInterface.h b/Source/Core/DolphinWX/Src/GLInterface.h new file mode 100644 index 0000000000..a81f17104c --- /dev/null +++ b/Source/Core/DolphinWX/Src/GLInterface.h @@ -0,0 +1,75 @@ +// 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/ +#ifndef _GLINTERFACE_H_ +#define _GLINTERFACE_H_ + +#include "Thread.h" + +#if defined(USE_EGL) && USE_EGL +#include "GLInterface/EGL.h" +#elif defined(USE_WX) && USE_WX +#include "GLInterface/WX.h" +#elif defined(__APPLE__) +#include "GLInterface/AGL.h" +#elif defined(_WIN32) +#include "GLInterface/WGL.h" +#elif defined(HAVE_X11) && HAVE_X11 +#include "GLInterface/GLX.h" +#endif + +typedef struct { +#if defined(USE_EGL) && USE_EGL // This is currently a X11/EGL implementation for desktop + int screen; + Display *dpy; + Display *evdpy; + Window win; + Window parent; + EGLSurface egl_surf; + EGLContext egl_ctx; + EGLDisplay egl_dpy; + XVisualInfo *vi; + XSetWindowAttributes attr; + std::thread xEventThread; + int x, y; + unsigned int width, height; +#elif defined(USE_WX) && USE_WX + wxGLCanvas *glCanvas; + wxGLContext *glCtxt; + wxPanel *panel; +#elif defined(__APPLE__) + NSWindow *cocoaWin; + NSOpenGLContext *cocoaCtx; +#elif defined(HAVE_X11) && HAVE_X11 + int screen; + Window win; + Window parent; + // dpy used for glx stuff, evdpy for window events etc. + // evdpy is to be used by XEventThread only + Display *dpy, *evdpy; + XVisualInfo *vi; + GLXContext ctx; + XSetWindowAttributes attr; + std::thread xEventThread; + int x, y; + unsigned int width, height; +#endif +} GLWindow; + +extern cInterfaceBase *GLInterface; +extern GLWindow GLWin; + +#endif diff --git a/Source/Core/DolphinWX/Src/GLInterface/AGL.cpp b/Source/Core/DolphinWX/Src/GLInterface/AGL.cpp new file mode 100644 index 0000000000..30ff4a31cf --- /dev/null +++ b/Source/Core/DolphinWX/Src/GLInterface/AGL.cpp @@ -0,0 +1,123 @@ +// 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 "VideoConfig.h" +#include "Host.h" +#include "RenderBase.h" + +#include "VertexShaderManager.h" +#include "../GLInterface.h" +#include "AGL.h" + +void cInterfaceAGL::Swap() +{ + [GLWin.cocoaCtx flushBuffer]; +} + +// Show the current FPS +void cInterfaceAGL::UpdateFPSDisplay(const char *text) +{ + [GLWin.cocoaWin setTitle: [NSString stringWithUTF8String: text]]; +} + +// Create rendering window. +// Call browser: Core.cpp:EmuThread() > main.cpp:Video_Initialize() +bool cInterfaceAGL::Create(void *&window_handle) +{ + int _tx, _ty, _twidth, _theight; + Host_GetRenderWindowSize(_tx, _ty, _twidth, _theight); + + // Control window size and picture scaling + s_backbuffer_width = _twidth; + s_backbuffer_height = _theight; + + NSRect size; + NSUInteger style = NSMiniaturizableWindowMask; + NSOpenGLPixelFormatAttribute attr[2] = { NSOpenGLPFADoubleBuffer, 0 }; + NSOpenGLPixelFormat *fmt = [[NSOpenGLPixelFormat alloc] + initWithAttributes: attr]; + if (fmt == nil) { + ERROR_LOG(VIDEO, "failed to create pixel format"); + return NULL; + } + + GLWin.cocoaCtx = [[NSOpenGLContext alloc] + initWithFormat: fmt shareContext: nil]; + [fmt release]; + if (GLWin.cocoaCtx == nil) { + ERROR_LOG(VIDEO, "failed to create context"); + return NULL; + } + + if (SConfig::GetInstance().m_LocalCoreStartupParameter.bFullscreen) { + size = [[NSScreen mainScreen] frame]; + style |= NSBorderlessWindowMask; + } else { + size = NSMakeRect(_tx, _ty, _twidth, _theight); + style |= NSResizableWindowMask | NSTitledWindowMask; + } + + GLWin.cocoaWin = [[NSWindow alloc] initWithContentRect: size + styleMask: style backing: NSBackingStoreBuffered defer: NO]; + if (GLWin.cocoaWin == nil) { + ERROR_LOG(VIDEO, "failed to create window"); + return NULL; + } + + if (SConfig::GetInstance().m_LocalCoreStartupParameter.bFullscreen) { + CGDisplayCapture(CGMainDisplayID()); + [GLWin.cocoaWin setLevel: CGShieldingWindowLevel()]; + } + + [GLWin.cocoaCtx setView: [GLWin.cocoaWin contentView]]; + [GLWin.cocoaWin makeKeyAndOrderFront: nil]; + + return true; +} + +bool cInterfaceAGL::MakeCurrent() +{ + [GLWin.cocoaCtx makeCurrentContext]; + return true; +} + +// Update window width, size and etc. Called from Render.cpp +void cInterfaceAGL::Update() +{ + int width, height; + + width = [[GLWin.cocoaWin contentView] frame].size.width; + height = [[GLWin.cocoaWin contentView] frame].size.height; + if (width == s_backbuffer_width && height == s_backbuffer_height) + return; + + [GLWin.cocoaCtx setView: [GLWin.cocoaWin contentView]]; + [GLWin.cocoaCtx update]; + [GLWin.cocoaCtx makeCurrentContext]; + s_backbuffer_width = width; + s_backbuffer_height = height; +} + +// Close backend +void cInterfaceAGL::Shutdown() +{ + [GLWin.cocoaWin close]; + [GLWin.cocoaCtx clearDrawable]; + [GLWin.cocoaCtx release]; +} + + diff --git a/Source/Core/DolphinWX/Src/GLInterface/AGL.h b/Source/Core/DolphinWX/Src/GLInterface/AGL.h new file mode 100644 index 0000000000..e03256ab4e --- /dev/null +++ b/Source/Core/DolphinWX/Src/GLInterface/AGL.h @@ -0,0 +1,37 @@ +// 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/ +#ifndef _INTERFACEAGL_H_ +#define _INTERFACEAGL_H_ + +#ifdef __APPLE__ +#include <GL/glew.h> +#import <AppKit/AppKit.h> +#endif + +#include "InterfaceBase.h" + +class cInterfaceAGL : public cInterfaceBase +{ +public: + void Swap(); + void UpdateFPSDisplay(const char *Text); + bool Create(void *&window_handle); + bool MakeCurrent(); + void Shutdown(); +}; +#endif + diff --git a/Source/Core/DolphinWX/Src/GLInterface/EGL.cpp b/Source/Core/DolphinWX/Src/GLInterface/EGL.cpp new file mode 100644 index 0000000000..b8716ab467 --- /dev/null +++ b/Source/Core/DolphinWX/Src/GLInterface/EGL.cpp @@ -0,0 +1,190 @@ +// 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 "Host.h" +#include "RenderBase.h" + +#include "../GLInterface.h" +#include "EGL.h" + +// Show the current FPS +void cInterfaceEGL::UpdateFPSDisplay(const char *text) +{ + XStoreName(GLWin.dpy, GLWin.win, text); +} +void cInterfaceEGL::Swap() +{ + eglSwapBuffers(GLWin.egl_dpy, GLWin.egl_surf); +} + +// Create rendering window. +// Call browser: Core.cpp:EmuThread() > main.cpp:Video_Initialize() +bool cInterfaceEGL::Create(void *&window_handle) +{ + int _tx, _ty, _twidth, _theight; + Host_GetRenderWindowSize(_tx, _ty, _twidth, _theight); + + // Control window size and picture scaling + s_backbuffer_width = _twidth; + s_backbuffer_height = _theight; + + const char *s; + EGLint egl_major, egl_minor; + + GLWin.dpy = XOpenDisplay(NULL); + + if (!GLWin.dpy) { + printf("Error: couldn't open display\n"); + return false; + } + + GLWin.egl_dpy = eglGetDisplay(GLWin.dpy); + if (!GLWin.egl_dpy) { + printf("Error: eglGetDisplay() failed\n"); + return false; + } + + if (!eglInitialize(GLWin.egl_dpy, &egl_major, &egl_minor)) { + printf("Error: eglInitialize() failed\n"); + return false; + } + + s = eglQueryString(GLWin.egl_dpy, EGL_VERSION); + printf("EGL_VERSION = %s\n", s); + + s = eglQueryString(GLWin.egl_dpy, EGL_VENDOR); + printf("EGL_VENDOR = %s\n", s); + + s = eglQueryString(GLWin.egl_dpy, EGL_EXTENSIONS); + printf("EGL_EXTENSIONS = %s\n", s); + + s = eglQueryString(GLWin.egl_dpy, EGL_CLIENT_APIS); + printf("EGL_CLIENT_APIS = %s\n", s); + + // attributes for a visual in RGBA format with at least + // 8 bits per color and a 24 bit depth buffer + int attribs[] = { + EGL_RED_SIZE, 8, + EGL_GREEN_SIZE, 8, + EGL_BLUE_SIZE, 8, + EGL_DEPTH_SIZE, 24, +#ifdef USE_GLES + EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT, +#else + EGL_RENDERABLE_TYPE, EGL_OPENGL_BIT, +#endif + EGL_NONE }; + + static const EGLint ctx_attribs[] = { +#ifdef USE_GLES + EGL_CONTEXT_CLIENT_VERSION, 2, +#endif + EGL_NONE + }; + + GLWin.evdpy = XOpenDisplay(NULL); + GLWin.parent = (Window)window_handle; + GLWin.screen = DefaultScreen(GLWin.dpy); + if (GLWin.parent == 0) + GLWin.parent = RootWindow(GLWin.dpy, GLWin.screen); + + XVisualInfo visTemplate; + int num_visuals; + EGLConfig config; + EGLint num_configs; + EGLint vid; + + if (!eglChooseConfig( GLWin.egl_dpy, attribs, &config, 1, &num_configs)) { + printf("Error: couldn't get an EGL visual config\n"); + exit(1); + } + + if (!eglGetConfigAttrib(GLWin.egl_dpy, config, EGL_NATIVE_VISUAL_ID, &vid)) { + printf("Error: eglGetConfigAttrib() failed\n"); + exit(1); + } + + /* The X window visual must match the EGL config */ + visTemplate.visualid = vid; + GLWin.vi = XGetVisualInfo(GLWin.dpy, VisualIDMask, &visTemplate, &num_visuals); + if (!GLWin.vi) { + printf("Error: couldn't get X visual\n"); + exit(1); + } + + GLWin.x = _tx; + GLWin.y = _ty; + GLWin.width = _twidth; + GLWin.height = _theight; + + XWindow.CreateXWindow(); +#ifdef USE_GLES + eglBindAPI(EGL_OPENGL_ES_API); +#else + eglBindAPI(EGL_OPENGL_API); +#endif + GLWin.egl_ctx = eglCreateContext(GLWin.egl_dpy, config, EGL_NO_CONTEXT, ctx_attribs ); + if (!GLWin.egl_ctx) { + printf("Error: eglCreateContext failed\n"); + exit(1); + } + + GLWin.egl_surf = eglCreateWindowSurface(GLWin.egl_dpy, config, GLWin.win, NULL); + if (!GLWin.egl_surf) { + printf("Error: eglCreateWindowSurface failed\n"); + exit(1); + } + + if (!eglMakeCurrent(GLWin.egl_dpy, GLWin.egl_surf, GLWin.egl_surf, GLWin.egl_ctx)) { + + printf("Error: eglMakeCurrent() failed\n"); + return false; + } + + + printf("GL_VENDOR: %s\n", glGetString(GL_VENDOR)); + printf("GL_RENDERER: %s\n", glGetString(GL_RENDERER)); + printf("GL_VERSION: %s\n", glGetString(GL_VERSION)); + printf("GL_EXTENSIONS: %s\n", glGetString(GL_EXTENSIONS)); + /* Set initial projection/viewing transformation. + * We can't be sure we'll get a ConfigureNotify event when the window + * first appears. + */ + glViewport(0, 0, (GLint) _twidth, (GLint) _theight); + window_handle = (void *)GLWin.win; + return true; +} + +bool cInterfaceEGL::MakeCurrent() +{ + return eglMakeCurrent(GLWin.egl_dpy, GLWin.egl_surf, GLWin.egl_surf, GLWin.egl_ctx); +} +// Close backend +void cInterfaceEGL::Shutdown() +{ + XWindow.DestroyXWindow(); + if (GLWin.egl_ctx && !eglMakeCurrent(GLWin.egl_dpy, GLWin.egl_surf, GLWin.egl_surf, GLWin.egl_ctx)) + NOTICE_LOG(VIDEO, "Could not release drawing context."); + if (GLWin.egl_ctx) + { + eglDestroyContext(GLWin.egl_dpy, GLWin.egl_ctx); + eglDestroySurface(GLWin.egl_dpy, GLWin.egl_surf); + eglTerminate(GLWin.egl_dpy); + GLWin.egl_ctx = NULL; + } +} + diff --git a/Source/Core/DolphinWX/Src/GLInterface/EGL.h b/Source/Core/DolphinWX/Src/GLInterface/EGL.h new file mode 100644 index 0000000000..c4b6a00b6c --- /dev/null +++ b/Source/Core/DolphinWX/Src/GLInterface/EGL.h @@ -0,0 +1,44 @@ +// 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/ +#ifndef _INTERFACEGLX_H_ +#define _INTERFACEGLX_H_ + +#include <EGL/egl.h> +#ifdef USE_GLES +#include <GLES2/gl2.h> +#else +#include <GL/glxew.h> +#include <GL/gl.h> +#endif + +#include "X11_Util.h" +#include "InterfaceBase.h" + +class cInterfaceEGL : public cInterfaceBase +{ +private: + cX11Window XWindow; +public: + friend class cX11Window; + void Swap(); + void UpdateFPSDisplay(const char *Text); + bool Create(void *&window_handle); + bool MakeCurrent(); + void Shutdown(); +}; +#endif + diff --git a/Source/Core/DolphinWX/Src/GLInterface/GLX.cpp b/Source/Core/DolphinWX/Src/GLInterface/GLX.cpp new file mode 100644 index 0000000000..ef60873531 --- /dev/null +++ b/Source/Core/DolphinWX/Src/GLInterface/GLX.cpp @@ -0,0 +1,151 @@ +// 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 "Host.h" +#include "RenderBase.h" +#include "VideoConfig.h" + +#include "../GLInterface.h" +#include "GLX.h" + +// Show the current FPS +void cInterfaceGLX::UpdateFPSDisplay(const char *text) +{ + XStoreName(GLWin.dpy, GLWin.win, text); +} +void cInterfaceGLX::Swap() +{ + glXSwapBuffers(GLWin.dpy, GLWin.win); +} + +// Create rendering window. +// Call browser: Core.cpp:EmuThread() > main.cpp:Video_Initialize() +bool cInterfaceGLX::Create(void *&window_handle) +{ + int _tx, _ty, _twidth, _theight; + Host_GetRenderWindowSize(_tx, _ty, _twidth, _theight); + + // Control window size and picture scaling + s_backbuffer_width = _twidth; + s_backbuffer_height = _theight; + + int glxMajorVersion, glxMinorVersion; + + // attributes for a single buffered visual in RGBA format with at least + // 8 bits per color and a 24 bit depth buffer + int attrListSgl[] = {GLX_RGBA, GLX_RED_SIZE, 8, + GLX_GREEN_SIZE, 8, + GLX_BLUE_SIZE, 8, + GLX_DEPTH_SIZE, 24, + None}; + + // attributes for a double buffered visual in RGBA format with at least + // 8 bits per color and a 24 bit depth buffer + int attrListDbl[] = {GLX_RGBA, GLX_DOUBLEBUFFER, + GLX_RED_SIZE, 8, + GLX_GREEN_SIZE, 8, + GLX_BLUE_SIZE, 8, + GLX_DEPTH_SIZE, 24, + GLX_SAMPLE_BUFFERS_ARB, g_Config.iMultisampleMode != MULTISAMPLE_OFF?1:0, + GLX_SAMPLES_ARB, g_Config.iMultisampleMode != MULTISAMPLE_OFF?1:0, + None }; + + int attrListDefault[] = { + GLX_RGBA, + GLX_RED_SIZE, 1, + GLX_GREEN_SIZE, 1, + GLX_BLUE_SIZE, 1, + GLX_DOUBLEBUFFER, + GLX_DEPTH_SIZE, 1, + None }; + + GLWin.dpy = XOpenDisplay(0); + GLWin.evdpy = XOpenDisplay(0); + GLWin.parent = (Window)window_handle; + GLWin.screen = DefaultScreen(GLWin.dpy); + if (GLWin.parent == 0) + GLWin.parent = RootWindow(GLWin.dpy, GLWin.screen); + + glXQueryVersion(GLWin.dpy, &glxMajorVersion, &glxMinorVersion); + NOTICE_LOG(VIDEO, "glX-Version %d.%d", glxMajorVersion, glxMinorVersion); + + // Get an appropriate visual + GLWin.vi = glXChooseVisual(GLWin.dpy, GLWin.screen, attrListDbl); + if (GLWin.vi == NULL) + { + GLWin.vi = glXChooseVisual(GLWin.dpy, GLWin.screen, attrListSgl); + if (GLWin.vi != NULL) + { + ERROR_LOG(VIDEO, "Only single buffered visual!"); + } + else + { + GLWin.vi = glXChooseVisual(GLWin.dpy, GLWin.screen, attrListDefault); + if (GLWin.vi == NULL) + { + ERROR_LOG(VIDEO, "Could not choose visual (glXChooseVisual)"); + return false; + } + } + } + else + NOTICE_LOG(VIDEO, "Got double buffered visual!"); + + // Create a GLX context. + GLWin.ctx = glXCreateContext(GLWin.dpy, GLWin.vi, 0, GL_TRUE); + if (!GLWin.ctx) + { + PanicAlert("Unable to create GLX context."); + return false; + } + + GLWin.x = _tx; + GLWin.y = _ty; + GLWin.width = _twidth; + GLWin.height = _theight; + + XWindow.CreateXWindow(); + window_handle = (void *)GLWin.win; + return true; +} + +bool cInterfaceGLX::MakeCurrent() +{ + // connect the glx-context to the window + #if defined(HAVE_WX) && (HAVE_WX) + Host_GetRenderWindowSize(GLWin.x, GLWin.y, + (int&)GLWin.width, (int&)GLWin.height); + XMoveResizeWindow(GLWin.dpy, GLWin.win, GLWin.x, GLWin.y, + GLWin.width, GLWin.height); + #endif + return glXMakeCurrent(GLWin.dpy, GLWin.win, GLWin.ctx); +} +// Close backend +void cInterfaceGLX::Shutdown() +{ + XWindow.DestroyXWindow(); + if (GLWin.ctx && !glXMakeCurrent(GLWin.dpy, None, NULL)) + NOTICE_LOG(VIDEO, "Could not release drawing context."); + if (GLWin.ctx) + { + glXDestroyContext(GLWin.dpy, GLWin.ctx); + XCloseDisplay(GLWin.dpy); + XCloseDisplay(GLWin.evdpy); + GLWin.ctx = NULL; + } +} + diff --git a/Source/Core/DolphinWX/Src/GLInterface/GLX.h b/Source/Core/DolphinWX/Src/GLInterface/GLX.h new file mode 100644 index 0000000000..73a6690ec5 --- /dev/null +++ b/Source/Core/DolphinWX/Src/GLInterface/GLX.h @@ -0,0 +1,41 @@ +// 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/ +#ifndef _INTERFACEGLX_H_ +#define _INTERFACEGLX_H_ + +#include <GL/glxew.h> +#include <GL/gl.h> +#include <X11/Xlib.h> +#include <X11/keysym.h> + +#include "X11_Util.h" +#include "InterfaceBase.h" + +class cInterfaceGLX : public cInterfaceBase +{ +private: + cX11Window XWindow; +public: + friend class cX11Window; + void Swap(); + void UpdateFPSDisplay(const char *Text); + bool Create(void *&window_handle); + bool MakeCurrent(); + void Shutdown(); +}; +#endif + diff --git a/Source/Core/DolphinWX/Src/GLInterface/InterfaceBase.h b/Source/Core/DolphinWX/Src/GLInterface/InterfaceBase.h new file mode 100644 index 0000000000..3e4f10fcd4 --- /dev/null +++ b/Source/Core/DolphinWX/Src/GLInterface/InterfaceBase.h @@ -0,0 +1,38 @@ +// 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/ +#ifndef _GLINTERFACEBASE_H_ +#define _GLINTERFACEBASE_H_ +class cInterfaceBase +{ +protected: + // Window dimensions. + u32 s_backbuffer_width; + u32 s_backbuffer_height; +public: + virtual void Swap() = 0; + virtual void UpdateFPSDisplay(const char *Text) = 0; + virtual bool Create(void *&window_handle) = 0; + virtual bool MakeCurrent() = 0; + virtual void Shutdown() = 0; + + virtual u32 GetBackBufferWidth() { return s_backbuffer_width; } + virtual u32 GetBackBufferHeight() { return s_backbuffer_height; } + virtual void SetBackBufferDimensions(u32 W, u32 H) {s_backbuffer_width = W; s_backbuffer_height = H; } + virtual void Update() { } + virtual bool PeekMessages() { return false; } +}; +#endif diff --git a/Source/Core/DolphinWX/Src/GLInterface/WGL.cpp b/Source/Core/DolphinWX/Src/GLInterface/WGL.cpp new file mode 100644 index 0000000000..c97cb48bdf --- /dev/null +++ b/Source/Core/DolphinWX/Src/GLInterface/WGL.cpp @@ -0,0 +1,179 @@ +// 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 "VideoConfig.h" +#include "Host.h" +#include "RenderBase.h" + +#include "VertexShaderManager.h" +#include "../GLInterface.h" +#include "WGL.h" + +#include "EmuWindow.h" +static HDC hDC = NULL; // Private GDI Device Context +static HGLRC hRC = NULL; // Permanent Rendering Context + +void cInterfaceWGL::Swap() +{ + SwapBuffers(hDC); +} + +// Draw messages on top of the screen +bool cInterfaceWGL::PeekMessages() +{ + // TODO: peekmessage + MSG msg; + while (PeekMessage(&msg, 0, 0, 0, PM_REMOVE)) + { + if (msg.message == WM_QUIT) + return FALSE; + TranslateMessage(&msg); + DispatchMessage(&msg); + } + return TRUE; +} + +// Show the current FPS +void cInterfaceWGL::UpdateFPSDisplay(const char *text) +{ + TCHAR temp[512]; + swprintf_s(temp, sizeof(temp)/sizeof(TCHAR), _T("%hs"), text); + EmuWindow::SetWindowText(temp); +} + +// Create rendering window. +// Call browser: Core.cpp:EmuThread() > main.cpp:Video_Initialize() +bool cInterfaceWGL::Create(void *&window_handle) +{ + int _tx, _ty, _twidth, _theight; + Host_GetRenderWindowSize(_tx, _ty, _twidth, _theight); + + // Control window size and picture scaling + s_backbuffer_width = _twidth; + s_backbuffer_height = _theight; + + window_handle = (void*)EmuWindow::Create((HWND)window_handle, GetModuleHandle(0), _T("Please wait...")); + if (window_handle == NULL) + { + Host_SysMessage("failed to create window"); + return false; + } + + // Show the window + EmuWindow::Show(); + + PIXELFORMATDESCRIPTOR pfd = // pfd Tells Windows How We Want Things To Be + { + sizeof(PIXELFORMATDESCRIPTOR), // Size Of This Pixel Format Descriptor + 1, // Version Number + PFD_DRAW_TO_WINDOW | // Format Must Support Window + PFD_SUPPORT_OPENGL | // Format Must Support OpenGL + PFD_DOUBLEBUFFER, // Must Support Double Buffering + PFD_TYPE_RGBA, // Request An RGBA Format + 32, // Select Our Color Depth + 0, 0, 0, 0, 0, 0, // Color Bits Ignored + 0, // 8bit Alpha Buffer + 0, // Shift Bit Ignored + 0, // No Accumulation Buffer + 0, 0, 0, 0, // Accumulation Bits Ignored + 24, // 24Bit Z-Buffer (Depth Buffer) + 8, // 8bit Stencil Buffer + 0, // No Auxiliary Buffer + PFD_MAIN_PLANE, // Main Drawing Layer + 0, // Reserved + 0, 0, 0 // Layer Masks Ignored + }; + + GLuint PixelFormat; // Holds The Results After Searching For A Match + + if (!(hDC=GetDC(EmuWindow::GetWnd()))) { + PanicAlert("(1) Can't create an OpenGL Device context. Fail."); + return false; + } + if (!(PixelFormat = ChoosePixelFormat(hDC, &pfd))) { + PanicAlert("(2) Can't find a suitable PixelFormat."); + return false; + } + if (!SetPixelFormat(hDC, PixelFormat, &pfd)) { + PanicAlert("(3) Can't set the PixelFormat."); + return false; + } + if (!(hRC = wglCreateContext(hDC))) { + PanicAlert("(4) Can't create an OpenGL rendering context."); + return false; + } + return true; +} + +bool cInterfaceWGL::MakeCurrent() +{ + return wglMakeCurrent(hDC, hRC) ? true : false; +} + +// Update window width, size and etc. Called from Render.cpp +void cInterfaceWGL::Update() +{ + RECT rcWindow; + if (!EmuWindow::GetParentWnd()) + { + // We are not rendering to a child window - use client size. + GetClientRect(EmuWindow::GetWnd(), &rcWindow); + } + else + { + // We are rendering to a child window - use parent size. + GetWindowRect(EmuWindow::GetParentWnd(), &rcWindow); + } + + // Get the new window width and height + // See below for documentation + int width = rcWindow.right - rcWindow.left; + int height = rcWindow.bottom - rcWindow.top; + + // If we are rendering to a child window + if (EmuWindow::GetParentWnd() != 0 && + (s_backbuffer_width != width || s_backbuffer_height != height) && + width >= 4 && height >= 4) + { + ::MoveWindow(EmuWindow::GetWnd(), 0, 0, width, height, FALSE); + s_backbuffer_width = width; + s_backbuffer_height = height; + } +} + +// Close backend +void cInterfaceWGL::Shutdown() +{ + if (hRC) + { + if (!wglMakeCurrent(NULL, NULL)) + NOTICE_LOG(VIDEO, "Could not release drawing context."); + + if (!wglDeleteContext(hRC)) + ERROR_LOG(VIDEO, "Release Rendering Context Failed."); + + hRC = NULL; + } + + if (hDC && !ReleaseDC(EmuWindow::GetWnd(), hDC)) + { + ERROR_LOG(VIDEO, "Release Device Context Failed."); + hDC = NULL; + } +} + + diff --git a/Source/Core/DolphinWX/Src/GLInterface/WGL.h b/Source/Core/DolphinWX/Src/GLInterface/WGL.h new file mode 100644 index 0000000000..184ddd475f --- /dev/null +++ b/Source/Core/DolphinWX/Src/GLInterface/WGL.h @@ -0,0 +1,41 @@ +// 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/ +#ifndef _INTERFACEWGL_H_ +#define _INTERFACEWGL_H_ + +#ifdef _WIN32 +#define GLEW_STATIC +#include <GL/glew.h> +#include <GL/wglew.h> +#endif + +#include "InterfaceBase.h" + +class cInterfaceWGL : public cInterfaceBase +{ +public: + void Swap(); + void UpdateFPSDisplay(const char *Text); + bool Create(void *&window_handle); + bool MakeCurrent(); + void Shutdown(); + + void Update(); + bool PeekMessages(); +}; +#endif + diff --git a/Source/Core/DolphinWX/Src/GLInterface/WX.cpp b/Source/Core/DolphinWX/Src/GLInterface/WX.cpp new file mode 100644 index 0000000000..0db1f8d632 --- /dev/null +++ b/Source/Core/DolphinWX/Src/GLInterface/WX.cpp @@ -0,0 +1,82 @@ +// 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 "VideoConfig.h" +#include "Host.h" +#include "RenderBase.h" + +#include "VertexShaderManager.h" +#include "../GLInterface.h" +#include "WX.h" + +void cInterfaceWX::Swap() +{ + GLWin.glCanvas->SwapBuffers(); +} + +void cInterfaceWX::UpdateFPSDisplay(const char *text) +{ + // Handled by Host_UpdateTitle() +} + +// Create rendering window. +// Call browser: Core.cpp:EmuThread() > main.cpp:Video_Initialize() +bool cInterfaceWX::Create(void *&window_handle) +{ + int _tx, _ty, _twidth, _theight; + Host_GetRenderWindowSize(_tx, _ty, _twidth, _theight); + + // Control window size and picture scaling + s_backbuffer_width = _twidth; + s_backbuffer_height = _theight; + + GLWin.panel = (wxPanel *)window_handle; + GLWin.glCanvas = new wxGLCanvas(GLWin.panel, wxID_ANY, NULL, + wxPoint(0, 0), wxSize(_twidth, _theight)); + GLWin.glCanvas->Show(true); + if (GLWin.glCtxt == NULL) // XXX dirty hack + GLWin.glCtxt = new wxGLContext(GLWin.glCanvas); +} + +bool cInterfaceWX::MakeCurrent() +{ + return GLWin.glCanvas->SetCurrent(*GLWin.glCtxt); +} + +// Update window width, size and etc. Called from Render.cpp +void cInterfaceWX::Update() +{ + int width, height; + + GLWin.panel->GetSize(&width, &height); + if (width == s_backbuffer_width && height == s_backbuffer_height) + return; + + GLWin.glCanvas->SetFocus(); + GLWin.glCanvas->SetSize(0, 0, width, height); + GLWin.glCtxt->SetCurrent(*GLWin.glCanvas); + s_backbuffer_width = width; + s_backbuffer_height = height; +} + +// Close backend +void cInterfaceWX::Shutdown() +{ + GLWin.glCanvas->Hide(); +} + + diff --git a/Source/Core/DolphinWX/Src/GLInterface/WX.h b/Source/Core/DolphinWX/Src/GLInterface/WX.h new file mode 100644 index 0000000000..7772f864e5 --- /dev/null +++ b/Source/Core/DolphinWX/Src/GLInterface/WX.h @@ -0,0 +1,47 @@ +// 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/ +#ifndef _INTERFACEWX_H_ +#define _INTERFACEWX_H_ + +#if defined HAVE_X11 && HAVE_X11 +#include <GL/glxew.h> +#include <GL/gl.h> +#elif defined __APPLE__ +#include <GL/glew.h> +#import <AppKit/AppKit.h> +#endif + +#if defined USE_WX && USE_WX +#include "wx/wx.h" +#include "wx/glcanvas.h" +#endif + +#include "InterfaceBase.h" + +class cInterfaceWX : public cInterfaceBase +{ +public: + void Swap(); + void UpdateFPSDisplay(const char *Text); + bool Create(void *&window_handle); + bool MakeCurrent(); + void Shutdown(); + + void Update(); +}; +#endif + diff --git a/Source/Core/DolphinWX/Src/GLInterface/X11_Util.cpp b/Source/Core/DolphinWX/Src/GLInterface/X11_Util.cpp new file mode 100644 index 0000000000..9372c4d644 --- /dev/null +++ b/Source/Core/DolphinWX/Src/GLInterface/X11_Util.cpp @@ -0,0 +1,213 @@ +// 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 "Host.h" +#include "RenderBase.h" +#include "VideoConfig.h" +#include "../GLInterface.h" +#include "VertexShaderManager.h" + +void cX11Window::CreateXWindow(void) +{ + Atom wmProtocols[1]; + + // Setup window attributes + GLWin.attr.colormap = XCreateColormap(GLWin.evdpy, + GLWin.parent, GLWin.vi->visual, AllocNone); + GLWin.attr.event_mask = KeyPressMask | StructureNotifyMask | FocusChangeMask; + GLWin.attr.background_pixel = BlackPixel(GLWin.evdpy, GLWin.screen); + GLWin.attr.border_pixel = 0; + + // Create the window + GLWin.win = XCreateWindow(GLWin.evdpy, GLWin.parent, + GLWin.x, GLWin.y, GLWin.width, GLWin.height, 0, + GLWin.vi->depth, InputOutput, GLWin.vi->visual, + CWBorderPixel | CWBackPixel | CWColormap | CWEventMask, &GLWin.attr); + wmProtocols[0] = XInternAtom(GLWin.evdpy, "WM_DELETE_WINDOW", True); + XSetWMProtocols(GLWin.evdpy, GLWin.win, wmProtocols, 1); + XSetStandardProperties(GLWin.evdpy, GLWin.win, "GPU", "GPU", None, NULL, 0, NULL); + XMapRaised(GLWin.evdpy, GLWin.win); + XSync(GLWin.evdpy, True); + + GLWin.xEventThread = std::thread(&cX11Window::XEventThread, this); +} + +void cX11Window::DestroyXWindow(void) +{ + XUnmapWindow(GLWin.dpy, GLWin.win); + GLWin.win = 0; + if (GLWin.xEventThread.joinable()) + GLWin.xEventThread.join(); + XFreeColormap(GLWin.evdpy, GLWin.attr.colormap); +} + +void cX11Window::XEventThread() +{ + // Free look variables + static bool mouseLookEnabled = false; + static bool mouseMoveEnabled = false; + static float lastMouse[2]; + while (GLWin.win) + { + XEvent event; + KeySym key; + for (int num_events = XPending(GLWin.evdpy); num_events > 0; num_events--) + { + XNextEvent(GLWin.evdpy, &event); + switch(event.type) { + case KeyPress: + key = XLookupKeysym((XKeyEvent*)&event, 0); + switch (key) + { + case XK_3: + OSDChoice = 1; + // Toggle native resolution + g_Config.iEFBScale = g_Config.iEFBScale + 1; + if (g_Config.iEFBScale > 7) g_Config.iEFBScale = 0; + break; + case XK_4: + OSDChoice = 2; + // Toggle aspect ratio + g_Config.iAspectRatio = (g_Config.iAspectRatio + 1) & 3; + break; + case XK_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 XK_6: + OSDChoice = 4; + g_Config.bDisableFog = !g_Config.bDisableFog; + break; + default: + break; + } + if (g_Config.bFreeLook) + { + static float debugSpeed = 1.0f; + switch (key) + { + case XK_parenleft: + debugSpeed /= 2.0f; + break; + case XK_parenright: + debugSpeed *= 2.0f; + break; + case XK_w: + VertexShaderManager::TranslateView(0.0f, debugSpeed); + break; + case XK_s: + VertexShaderManager::TranslateView(0.0f, -debugSpeed); + break; + case XK_a: + VertexShaderManager::TranslateView(debugSpeed, 0.0f); + break; + case XK_d: + VertexShaderManager::TranslateView(-debugSpeed, 0.0f); + break; + case XK_r: + VertexShaderManager::ResetView(); + break; + } + } + break; + case ButtonPress: + if (g_Config.bFreeLook) + { + switch (event.xbutton.button) + { + case 2: // Middle button + lastMouse[0] = event.xbutton.x; + lastMouse[1] = event.xbutton.y; + mouseMoveEnabled = true; + break; + case 3: // Right button + lastMouse[0] = event.xbutton.x; + lastMouse[1] = event.xbutton.y; + mouseLookEnabled = true; + break; + } + } + break; + case ButtonRelease: + if (g_Config.bFreeLook) + { + switch (event.xbutton.button) + { + case 2: // Middle button + mouseMoveEnabled = false; + break; + case 3: // Right button + mouseLookEnabled = false; + break; + } + } + break; + case MotionNotify: + if (g_Config.bFreeLook) + { + if (mouseLookEnabled) + { + VertexShaderManager::RotateView((event.xmotion.x - lastMouse[0]) / 200.0f, + (event.xmotion.y - lastMouse[1]) / 200.0f); + lastMouse[0] = event.xmotion.x; + lastMouse[1] = event.xmotion.y; + } + + if (mouseMoveEnabled) + { + VertexShaderManager::TranslateView((event.xmotion.x - lastMouse[0]) / 50.0f, + (event.xmotion.y - lastMouse[1]) / 50.0f); + lastMouse[0] = event.xmotion.x; + lastMouse[1] = event.xmotion.y; + } + } + break; + case ConfigureNotify: + Window winDummy; + unsigned int borderDummy, depthDummy; + XGetGeometry(GLWin.evdpy, GLWin.win, &winDummy, &GLWin.x, &GLWin.y, + &GLWin.width, &GLWin.height, &borderDummy, &depthDummy); + GLInterface->SetBackBufferDimensions(GLWin.width, GLWin.height); + break; + case ClientMessage: + if ((unsigned long) event.xclient.data.l[0] == + XInternAtom(GLWin.evdpy, "WM_DELETE_WINDOW", False)) + Host_Message(WM_USER_STOP); + if ((unsigned long) event.xclient.data.l[0] == + XInternAtom(GLWin.evdpy, "RESIZE", False)) + XMoveResizeWindow(GLWin.evdpy, GLWin.win, + event.xclient.data.l[1], event.xclient.data.l[2], + event.xclient.data.l[3], event.xclient.data.l[4]); + break; + default: + break; + } + } + Common::SleepCurrentThread(20); + } +} + + diff --git a/Source/Core/DolphinWX/Src/GLInterface/X11_Util.h b/Source/Core/DolphinWX/Src/GLInterface/X11_Util.h new file mode 100644 index 0000000000..9e6f6d5e3c --- /dev/null +++ b/Source/Core/DolphinWX/Src/GLInterface/X11_Util.h @@ -0,0 +1,31 @@ +// 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/ +#ifndef _X11_UTIL_H_ +#define _X11_UTIL_H_ + +#include <X11/Xlib.h> +#include <X11/keysym.h> + +class cX11Window +{ +private: + void XEventThread(); +public: + void CreateXWindow(void); + void DestroyXWindow(void); +}; +#endif diff --git a/Source/Core/DolphinWX/Src/GameListCtrl.cpp b/Source/Core/DolphinWX/Src/GameListCtrl.cpp index 4a7d7d5dce..fbefb1c769 100644 --- a/Source/Core/DolphinWX/Src/GameListCtrl.cpp +++ b/Source/Core/DolphinWX/Src/GameListCtrl.cpp @@ -51,6 +51,7 @@ size_t CGameListCtrl::m_currentItem = 0; size_t CGameListCtrl::m_numberItem = 0; std::string CGameListCtrl::m_currentFilename; +bool sorted = false; static int CompareGameListItems(const GameListItem* iso1, const GameListItem* iso2, long sortData = CGameListCtrl::COLUMN_TITLE) @@ -284,6 +285,7 @@ void CGameListCtrl::Update() InitBitmaps(); // add columns + InsertColumn(COLUMN_DUMMY,_T("")); InsertColumn(COLUMN_PLATFORM, _T("")); InsertColumn(COLUMN_BANNER, _("Banner")); InsertColumn(COLUMN_TITLE, _("Title")); @@ -303,6 +305,7 @@ void CGameListCtrl::Update() #endif // set initial sizes for columns + SetColumnWidth(COLUMN_DUMMY,0); SetColumnWidth(COLUMN_PLATFORM, 35 + platform_padding); SetColumnWidth(COLUMN_BANNER, 96 + platform_padding); SetColumnWidth(COLUMN_TITLE, 200 + platform_padding); @@ -319,10 +322,17 @@ void CGameListCtrl::Update() } // Sort items by Title + if (!sorted) + last_column = 0; + sorted = false; wxListEvent event; - event.m_col = COLUMN_TITLE; last_column = 0; + event.m_col = SConfig::GetInstance().m_ListSort2; OnColumnClick(event); + event.m_col = SConfig::GetInstance().m_ListSort; + OnColumnClick(event); + sorted = true; + SetColumnWidth(COLUMN_SIZE, wxLIST_AUTOSIZE); } else @@ -414,9 +424,11 @@ void CGameListCtrl::InsertItemInReportView(long _Index) GameListItem& rISOFile = *m_ISOFiles[_Index]; m_gamePath.append(rISOFile.GetFileName() + '\n'); - // Insert a first row with the platform image, that will be used as the Index - long ItemIndex = InsertItem(_Index, wxEmptyString, - m_PlatformImageIndex[rISOFile.GetPlatform()]); + // Insert a first row with nothing in it, that will be used as the Index + long ItemIndex = InsertItem(_Index, wxEmptyString); + + // Insert the platform's image in the first (visible) column + SetItemColumnImage(_Index, COLUMN_PLATFORM, m_PlatformImageIndex[rISOFile.GetPlatform()]); if (rISOFile.GetImage().IsOk()) ImageIndex = m_imageListSmall->Add(rISOFile.GetImage()); @@ -652,7 +664,11 @@ void CGameListCtrl::ScanForISOs() for (std::vector<std::string>::const_iterator iter = drives.begin(); iter != drives.end(); ++iter) { + #ifdef __APPLE__ std::auto_ptr<GameListItem> gli(new GameListItem(*iter)); + #else + std::unique_ptr<GameListItem> gli(new GameListItem(*iter)); + #endif if (gli->IsValid()) m_ISOFiles.push_back(gli.release()); @@ -697,17 +713,25 @@ void CGameListCtrl::OnColumnClick(wxListEvent& event) if(event.GetColumn() != COLUMN_BANNER) { int current_column = event.GetColumn(); - - if(last_column == current_column) + if (sorted) { - last_sort = -last_sort; + if (last_column == current_column) + { + last_sort = -last_sort; + } + else + { + SConfig::GetInstance().m_ListSort2 = last_sort; + last_column = current_column; + last_sort = current_column; + } + SConfig::GetInstance().m_ListSort = last_sort; } else { - last_column = current_column; last_sort = current_column; + last_column = current_column; } - caller = this; SortItems(wxListCompare, last_sort); } @@ -904,7 +928,8 @@ void CGameListCtrl::OnRightClick(wxMouseEvent& event) { if (selected_iso->IsCompressed()) popupMenu->Append(IDM_COMPRESSGCM, _("Decompress ISO...")); - else + else if (selected_iso->GetFileName().substr(selected_iso->GetFileName().find_last_of(".")) != ".ciso" + && selected_iso->GetFileName().substr(selected_iso->GetFileName().find_last_of(".")) != ".wbfs") popupMenu->Append(IDM_COMPRESSGCM, _("Compress ISO...")); } else popupMenu->Append(IDM_LIST_INSTALLWAD, _("Install to Wii Menu")); @@ -1055,7 +1080,7 @@ void CGameListCtrl::OnWiki(wxCommandEvent& WXUNUSED (event)) if (!iso) return; - std::string wikiUrl = "http://api.dolphin-emulator.com/wiki.html?id=[GAME_ID]&name=[GAME_NAME]"; + std::string wikiUrl = "http://wiki.dolphin-emu.org/dolphin-redirect.php?gameid=[GAME_ID]"; wikiUrl = ReplaceAll(wikiUrl, "[GAME_ID]", UriEncode(iso->GetUniqueID())); if (UriEncode(iso->GetName(0)).length() < 100) wikiUrl = ReplaceAll(wikiUrl, "[GAME_NAME]", UriEncode(iso->GetName(0))); diff --git a/Source/Core/DolphinWX/Src/GameListCtrl.h b/Source/Core/DolphinWX/Src/GameListCtrl.h index 274cfdb7ee..5d97c12724 100644 --- a/Source/Core/DolphinWX/Src/GameListCtrl.h +++ b/Source/Core/DolphinWX/Src/GameListCtrl.h @@ -57,7 +57,8 @@ public: enum { - COLUMN_PLATFORM = 0, + COLUMN_DUMMY = 0, + COLUMN_PLATFORM, COLUMN_BANNER, COLUMN_TITLE, COLUMN_NOTES, diff --git a/Source/Core/DolphinWX/Src/Globals.h b/Source/Core/DolphinWX/Src/Globals.h index 8089a2622c..36a37de6cc 100644 --- a/Source/Core/DolphinWX/Src/Globals.h +++ b/Source/Core/DolphinWX/Src/Globals.h @@ -80,6 +80,8 @@ enum IDM_RECORDEXPORT, IDM_RECORDREADONLY, IDM_TASINPUT, + IDM_TOGGLE_PAUSEMOVIE, + IDM_SHOWLAG, IDM_FRAMESTEP, IDM_SCREENSHOT, IDM_BROWSE, diff --git a/Source/Core/DolphinWX/Src/ISOFile.cpp b/Source/Core/DolphinWX/Src/ISOFile.cpp index 9734e97131..a3d3761e62 100644 --- a/Source/Core/DolphinWX/Src/ISOFile.cpp +++ b/Source/Core/DolphinWX/Src/ISOFile.cpp @@ -285,7 +285,7 @@ bool GameListItem::GetName(std::wstring& wName, int index) const index++; if ((index >=0) && (index < 10)) { - if (m_wNames.size() > index) + if (m_wNames.size() > (size_t)index) { wName = m_wNames[index]; return true; diff --git a/Source/Core/DolphinWX/Src/ISOProperties.cpp b/Source/Core/DolphinWX/Src/ISOProperties.cpp index f004989055..61139d985f 100644 --- a/Source/Core/DolphinWX/Src/ISOProperties.cpp +++ b/Source/Core/DolphinWX/Src/ISOProperties.cpp @@ -687,14 +687,13 @@ void CISOProperties::OnExtractFile(wxCommandEvent& WXUNUSED (event)) void CISOProperties::ExportDir(const char* _rFullPath, const char* _rExportFolder, const int partitionNum) { char exportName[512]; - u32 index[2] = {0, 0}, offsetShift = 0; + u32 index[2] = {0, 0}; std::vector<const DiscIO::SFileInfo *> fst; DiscIO::IFileSystem *FS = 0; if (DiscIO::IsVolumeWiiDisc(OpenISO)) { FS = WiiDisc.at(partitionNum).FileSystem; - offsetShift = 2; } else FS = pFileSystem; diff --git a/Source/Core/DolphinWX/Src/Main.cpp b/Source/Core/DolphinWX/Src/Main.cpp index d38c90e07f..fc3e2c41a7 100644 --- a/Source/Core/DolphinWX/Src/Main.cpp +++ b/Source/Core/DolphinWX/Src/Main.cpp @@ -28,7 +28,6 @@ #include "CPUDetect.h" #include "IniFile.h" #include "FileUtil.h" -#include "Setup.h" #include "Host.h" // Core #include "HW/Wiimote.h" @@ -46,6 +45,15 @@ #include <wx/intl.h> +// Nvidia drivers >= v302 will check if the application exports a global +// variable named NvOptimusEnablement to know if it should run the app in high +// performance graphics mode or using the IGP. +#ifdef WIN32 +extern "C" { + __declspec(dllexport) DWORD NvOptimusEnablement = 1; +} +#endif + // ------------ // Main window @@ -116,37 +124,37 @@ bool DolphinApp::OnInit() { { wxCMD_LINE_SWITCH, "h", "help", - _("Show this help message"), + "Show this help message", wxCMD_LINE_VAL_NONE, wxCMD_LINE_OPTION_HELP }, { wxCMD_LINE_SWITCH, "d", "debugger", - _("Opens the debugger"), + "Opens the debugger", wxCMD_LINE_VAL_NONE, wxCMD_LINE_PARAM_OPTIONAL }, { wxCMD_LINE_SWITCH, "l", "logger", - _("Opens the logger"), + "Opens the logger", wxCMD_LINE_VAL_NONE, wxCMD_LINE_PARAM_OPTIONAL }, { wxCMD_LINE_OPTION, "e", "exec", - _("Loads the specified file (DOL,ELF,GCM,ISO,WAD)"), + "Loads the specified file (DOL,ELF,GCM,ISO,WAD)", wxCMD_LINE_VAL_STRING, wxCMD_LINE_PARAM_OPTIONAL }, { wxCMD_LINE_SWITCH, "b", "batch", - _("Exit Dolphin with emulator"), + "Exit Dolphin with emulator", wxCMD_LINE_VAL_NONE, wxCMD_LINE_PARAM_OPTIONAL }, { wxCMD_LINE_OPTION, "V", "video_backend", - _("Specify a video backend"), + "Specify a video backend", wxCMD_LINE_VAL_STRING, wxCMD_LINE_PARAM_OPTIONAL }, { wxCMD_LINE_OPTION, "A", "audio_emulation", - _("Low level (LLE) or high level (HLE) audio"), + "Low level (LLE) or high level (HLE) audio", wxCMD_LINE_VAL_STRING, wxCMD_LINE_PARAM_OPTIONAL }, { @@ -167,7 +175,6 @@ bool DolphinApp::OnInit() BatchMode = parser.Found(wxT("batch")); selectVideoBackend = parser.Found(wxT("video_backend"), &videoBackendName); - // TODO: This currently has no effect. Implement or delete. selectAudioEmulation = parser.Found(wxT("audio_emulation"), &audioEmulationName); #endif // wxUSE_CMDLINE_PARSER @@ -237,6 +244,14 @@ bool DolphinApp::OnInit() SConfig::GetInstance().m_LocalCoreStartupParameter.m_strVideoBackend = std::string(videoBackendName.mb_str()); + if (selectAudioEmulation) + { + if (audioEmulationName == "HLE") + SConfig::GetInstance().m_LocalCoreStartupParameter.bDSPHLE = true; + else if (audioEmulationName == "LLE") + SConfig::GetInstance().m_LocalCoreStartupParameter.bDSPHLE = false; + } + VideoBackend::ActivateBackend(SConfig::GetInstance().m_LocalCoreStartupParameter.m_strVideoBackend); // Enable the PNG image handler for screenshots diff --git a/Source/Core/DolphinWX/Src/MemcardManager.cpp b/Source/Core/DolphinWX/Src/MemcardManager.cpp index bf47a23c53..76c77a0543 100644 --- a/Source/Core/DolphinWX/Src/MemcardManager.cpp +++ b/Source/Core/DolphinWX/Src/MemcardManager.cpp @@ -520,6 +520,7 @@ void CMemcardManager::CopyDeleteClick(wxCommandEvent& event) ? wxString::FromAscii("") : wxString::From8BitData(DefaultIOPath.c_str()), wxEmptyString, wxEmptyString, + _("GameCube Savegame files(*.gci;*.gcs;*.sav)") + wxString(wxT("|*.gci;*.gcs;*.sav|")) + _("Native GCI files(*.gci)") + wxString(wxT("|*.gci|")) + _("MadCatz Gameshark files(*.gcs)") + wxString(wxT("|*.gcs|")) + _("Datel MaxDrive/Pro files(*.sav)") + wxString(wxT("|*.sav")), diff --git a/Source/Core/DolphinWX/Src/TASInputDlg.cpp b/Source/Core/DolphinWX/Src/TASInputDlg.cpp index e566068ff1..b4f4c77397 100644 --- a/Source/Core/DolphinWX/Src/TASInputDlg.cpp +++ b/Source/Core/DolphinWX/Src/TASInputDlg.cpp @@ -751,7 +751,6 @@ void TASInputDlg::OnMouseUpR(wxMouseEvent& event) return; } - wxPoint ptM(event.GetPosition()); *x = 128; *y = 128; diff --git a/Source/Core/DolphinWX/Src/VideoConfigDiag.h b/Source/Core/DolphinWX/Src/VideoConfigDiag.h index ce16138b5c..c7a19c6cb8 100644 --- a/Source/Core/DolphinWX/Src/VideoConfigDiag.h +++ b/Source/Core/DolphinWX/Src/VideoConfigDiag.h @@ -112,7 +112,7 @@ protected: void Event_ProgressiveScan(wxCommandEvent &ev) { SConfig::GetInstance().m_SYSCONF->SetData("IPL.PGS", ev.GetInt()); - SConfig::GetInstance().m_LocalCoreStartupParameter.bProgressive = !!ev.GetInt(); + SConfig::GetInstance().m_LocalCoreStartupParameter.bProgressive = ev.IsChecked(); ev.Skip(); } diff --git a/Source/Core/DolphinWX/Src/WiimoteConfigDiag.h b/Source/Core/DolphinWX/Src/WiimoteConfigDiag.h index faa17dff2e..2b2e60de4a 100644 --- a/Source/Core/DolphinWX/Src/WiimoteConfigDiag.h +++ b/Source/Core/DolphinWX/Src/WiimoteConfigDiag.h @@ -61,7 +61,7 @@ public: } void OnReconnectOnLoad(wxCommandEvent& event) { - SConfig::GetInstance().m_WiimoteReconnectOnLoad = event.GetInt(); + SConfig::GetInstance().m_WiimoteReconnectOnLoad = event.IsChecked(); event.Skip(); } diff --git a/Source/Core/DolphinWX/Src/X11Utils.cpp b/Source/Core/DolphinWX/Src/X11Utils.cpp index fe4cd70829..da21c41cb2 100644 --- a/Source/Core/DolphinWX/Src/X11Utils.cpp +++ b/Source/Core/DolphinWX/Src/X11Utils.cpp @@ -225,7 +225,7 @@ void XRRConfiguration::Update() } else sscanf(SConfig::GetInstance().m_LocalCoreStartupParameter.strFullscreenResolution.c_str(), - "%a[^:]: %ux%u", &output_name, &fullWidth, &fullHeight); + "%m[^:]: %ux%u", &output_name, &fullWidth, &fullHeight); for (int i = 0; i < screenResources->noutput; i++) { diff --git a/Source/Core/InputCommon/Src/ControllerInterface/Xlib/Xlib.cpp b/Source/Core/InputCommon/Src/ControllerInterface/Xlib/Xlib.cpp index 450080bfd2..c2030a059d 100644 --- a/Source/Core/InputCommon/Src/ControllerInterface/Xlib/Xlib.cpp +++ b/Source/Core/InputCommon/Src/ControllerInterface/Xlib/Xlib.cpp @@ -1,5 +1,7 @@ #include "Xlib.h" +#include <X11/XKBlib.h> + namespace ciface { namespace Xlib @@ -93,7 +95,7 @@ KeyboardMouse::Key::Key(Display* const display, KeyCode keycode, const char* key KeySym keysym = 0; do { - keysym = XKeycodeToKeysym(m_display, keycode, i); + keysym = XkbKeycodeToKeysym(m_display, keycode, i, 0); i++; } while (keysym == NoSymbol && i < 8); diff --git a/Source/Core/VideoCommon/Src/BPFunctions.cpp b/Source/Core/VideoCommon/Src/BPFunctions.cpp index cddeae3000..b9a76ba7b6 100644 --- a/Source/Core/VideoCommon/Src/BPFunctions.cpp +++ b/Source/Core/VideoCommon/Src/BPFunctions.cpp @@ -236,7 +236,7 @@ bool GetConfig(const int &type) case CONFIG_DISABLEFOG: return g_ActiveConfig.bDisableFog; case CONFIG_SHOWEFBREGIONS: - return false; + return g_ActiveConfig.bShowEFBCopyRegions; default: PanicAlert("GetConfig Error: Unknown Config Type!"); return false; diff --git a/Source/Core/VideoCommon/Src/BPStructs.cpp b/Source/Core/VideoCommon/Src/BPStructs.cpp index 179196e412..0bde9cc613 100644 --- a/Source/Core/VideoCommon/Src/BPStructs.cpp +++ b/Source/Core/VideoCommon/Src/BPStructs.cpp @@ -34,9 +34,9 @@ using namespace BPFunctions; -u32 mapTexAddress; -bool mapTexFound; -int numWrites; +static u32 mapTexAddress; +static bool mapTexFound; +static int numWrites; extern volatile bool g_bSkipCurrentFrame; @@ -81,6 +81,9 @@ void BPWritten(const BPCmd& bp) just stuff geometry in them and don't put state changes there ---------------------------------------------------------------------------------------------------------------- */ + + // check for invalid state, else unneeded configuration are built + g_video_backend->CheckInvalidState(); // Debugging only, this lets you skip a bp update //static int times = 0; diff --git a/Source/Core/VideoCommon/Src/DLCache.cpp b/Source/Core/VideoCommon/Src/DLCache.cpp index 5499fa26f1..c828ea3a03 100644 --- a/Source/Core/VideoCommon/Src/DLCache.cpp +++ b/Source/Core/VideoCommon/Src/DLCache.cpp @@ -361,9 +361,9 @@ u32 AnalyzeAndRunDisplayList(u32 address, u32 size, CachedDisplayList *dl) (cmd_byte & GX_PRIMITIVE_MASK) >> GX_PRIMITIVE_SHIFT, numVertices); num_draw_call++; - const int tc[12] = { + const u32 tc[12] = { g_VtxDesc.Position, g_VtxDesc.Normal, g_VtxDesc.Color0, g_VtxDesc.Color1, g_VtxDesc.Tex0Coord, g_VtxDesc.Tex1Coord, - g_VtxDesc.Tex2Coord, g_VtxDesc.Tex3Coord, g_VtxDesc.Tex4Coord, g_VtxDesc.Tex5Coord, g_VtxDesc.Tex6Coord, (const int)((g_VtxDesc.Hex >> 31) & 3) + g_VtxDesc.Tex2Coord, g_VtxDesc.Tex3Coord, g_VtxDesc.Tex4Coord, g_VtxDesc.Tex5Coord, g_VtxDesc.Tex6Coord, (const u32)((g_VtxDesc.Hex >> 31) & 3) }; for(int i = 0; i < 12; i++) { @@ -563,9 +563,9 @@ void CompileAndRunDisplayList(u32 address, u32 size, CachedDisplayList *dl) dl->InsertRegion(NewRegion); memcpy(NewRegion->start_address, StartAddress, Vdatasize); emitter.ABI_CallFunctionCCCP((void *)&VertexLoaderManager::RunCompiledVertices, cmd_byte & GX_VAT_MASK, (cmd_byte & GX_PRIMITIVE_MASK) >> GX_PRIMITIVE_SHIFT, numVertices, NewRegion->start_address); - const int tc[12] = { + const u32 tc[12] = { g_VtxDesc.Position, g_VtxDesc.Normal, g_VtxDesc.Color0, g_VtxDesc.Color1, g_VtxDesc.Tex0Coord, g_VtxDesc.Tex1Coord, - g_VtxDesc.Tex2Coord, g_VtxDesc.Tex3Coord, g_VtxDesc.Tex4Coord, g_VtxDesc.Tex5Coord, g_VtxDesc.Tex6Coord, (const int)((g_VtxDesc.Hex >> 31) & 3) + g_VtxDesc.Tex2Coord, g_VtxDesc.Tex3Coord, g_VtxDesc.Tex4Coord, g_VtxDesc.Tex5Coord, g_VtxDesc.Tex6Coord, (const u32)((g_VtxDesc.Hex >> 31) & 3) }; for(int i = 0; i < 12; i++) { diff --git a/Source/Core/VideoCommon/Src/Debugger.h b/Source/Core/VideoCommon/Src/Debugger.h index bcce50f223..fde31e4268 100644 --- a/Source/Core/VideoCommon/Src/Debugger.h +++ b/Source/Core/VideoCommon/Src/Debugger.h @@ -72,21 +72,9 @@ void GFXDebuggerCheckAndPause(bool update); void GFXDebuggerToPause(bool update); void GFXDebuggerUpdateScreen(); -#undef ENABLE_GFX_DEBUGGER -#if defined(_DEBUG) || defined(DEBUGFAST) -#define ENABLE_GFX_DEBUGGER -#endif - -#ifdef ENABLE_GFX_DEBUGGER #define GFX_DEBUGGER_PAUSE_AT(event,update) {if (((GFXDebuggerToPauseAtNext & event) && --GFXDebuggerEventToPauseCount<=0) || GFXDebuggerPauseFlag) GFXDebuggerToPause(update);} #define GFX_DEBUGGER_PAUSE_LOG_AT(event,update,dumpfunc) {if (((GFXDebuggerToPauseAtNext & event) && --GFXDebuggerEventToPauseCount<=0) || GFXDebuggerPauseFlag) {{dumpfunc};GFXDebuggerToPause(update);}} #define GFX_DEBUGGER_LOG_AT(event,dumpfunc) {if (( GFXDebuggerToPauseAtNext & event ) ) {{dumpfunc};}} -#else -// Disable debugging calls in Release build -#define GFX_DEBUGGER_PAUSE_AT(event,update) -#define GFX_DEBUGGER_PAUSE_LOG_AT(event,update,dumpfunc) -#define GFX_DEBUGGER_LOG_AT(event,dumpfunc) -#endif // ENABLE_GFX_DEBUGGER #endif // _GFX_DEBUGGER_H_ diff --git a/Source/Core/VideoCommon/Src/Fifo.cpp b/Source/Core/VideoCommon/Src/Fifo.cpp index 565684297a..50aa21ebbf 100644 --- a/Source/Core/VideoCommon/Src/Fifo.cpp +++ b/Source/Core/VideoCommon/Src/Fifo.cpp @@ -16,7 +16,6 @@ // http://code.google.com/p/dolphin-emu/ #include "VideoConfig.h" -#include "Setup.h" #include "MemoryUtil.h" #include "Thread.h" #include "Atomic.h" diff --git a/Source/Core/VideoCommon/Src/FramebufferManagerBase.cpp b/Source/Core/VideoCommon/Src/FramebufferManagerBase.cpp index b234a7c865..c883714daf 100644 --- a/Source/Core/VideoCommon/Src/FramebufferManagerBase.cpp +++ b/Source/Core/VideoCommon/Src/FramebufferManagerBase.cpp @@ -10,6 +10,9 @@ XFBSourceBase *FramebufferManagerBase::m_realXFBSource; // Only used in Real XFB FramebufferManagerBase::VirtualXFBListType FramebufferManagerBase::m_virtualXFBList; // Only used in Virtual XFB mode const XFBSourceBase* FramebufferManagerBase::m_overlappingXFBArray[MAX_VIRTUAL_XFB]; +unsigned int FramebufferManagerBase::s_last_xfb_width = 1; +unsigned int FramebufferManagerBase::s_last_xfb_height = 1; + FramebufferManagerBase::FramebufferManagerBase() { m_realXFBSource = NULL; @@ -226,3 +229,31 @@ void FramebufferManagerBase::ReplaceVirtualXFB() } } } + +int FramebufferManagerBase::ScaleToVirtualXfbWidth(int x, unsigned int backbuffer_width) +{ + if (g_ActiveConfig.RealXFBEnabled()) + return x; + + if (g_ActiveConfig.b3DVision) + { + // This works, yet the version in the else doesn't. No idea why. + return x * (int)backbuffer_width / (int)FramebufferManagerBase::LastXfbWidth(); + } + else + return x * (int)Renderer::GetTargetRectangle().GetWidth() / (int)FramebufferManagerBase::LastXfbWidth(); +} + +int FramebufferManagerBase::ScaleToVirtualXfbHeight(int y, unsigned int backbuffer_height) +{ + if (g_ActiveConfig.RealXFBEnabled()) + return y; + + if (g_ActiveConfig.b3DVision) + { + // This works, yet the version in the else doesn't. No idea why. + return y * (int)backbuffer_height / (int)FramebufferManagerBase::LastXfbHeight(); + } + else + return y * (int)Renderer::GetTargetRectangle().GetHeight() / (int)FramebufferManagerBase::LastXfbHeight(); +} diff --git a/Source/Core/VideoCommon/Src/FramebufferManagerBase.h b/Source/Core/VideoCommon/Src/FramebufferManagerBase.h index 26d360647d..e529bb1a39 100644 --- a/Source/Core/VideoCommon/Src/FramebufferManagerBase.h +++ b/Source/Core/VideoCommon/Src/FramebufferManagerBase.h @@ -50,6 +50,14 @@ public: static void CopyToXFB(u32 xfbAddr, u32 fbWidth, u32 fbHeight, const EFBRectangle& sourceRc,float Gamma); static const XFBSourceBase* const* GetXFBSource(u32 xfbAddr, u32 fbWidth, u32 fbHeight, u32 &xfbCount); + static void SetLastXfbWidth(unsigned int width) { s_last_xfb_width = width; } + static void SetLastXfbHeight(unsigned int height) { s_last_xfb_height = height; } + static unsigned int LastXfbWidth() { return s_last_xfb_width; } + static unsigned int LastXfbHeight() { return s_last_xfb_height; } + + static int ScaleToVirtualXfbWidth(int x, unsigned int backbuffer_width); + static int ScaleToVirtualXfbHeight(int y, unsigned int backbuffer_height); + protected: struct VirtualXFB { @@ -85,6 +93,9 @@ private: static VirtualXFBListType m_virtualXFBList; // Only used in Virtual XFB mode static const XFBSourceBase* m_overlappingXFBArray[MAX_VIRTUAL_XFB]; + + static unsigned int s_last_xfb_width; + static unsigned int s_last_xfb_height; }; extern FramebufferManagerBase *g_framebuffer_manager; diff --git a/Source/Core/VideoCommon/Src/MainBase.cpp b/Source/Core/VideoCommon/Src/MainBase.cpp index cb6dc7ae5b..726ef71b38 100644 --- a/Source/Core/VideoCommon/Src/MainBase.cpp +++ b/Source/Core/VideoCommon/Src/MainBase.cpp @@ -180,6 +180,7 @@ void VideoBackendHardware::InitializeShared() memset((void*)&s_beginFieldArgs, 0, sizeof(s_beginFieldArgs)); memset(&s_accessEFBArgs, 0, sizeof(s_accessEFBArgs)); s_AccessEFBResult = 0; + m_invalid = false; } // Run from the CPU thread @@ -198,16 +199,25 @@ void VideoBackendHardware::DoState(PointerWrap& p) // Refresh state. if (p.GetMode() == PointerWrap::MODE_READ) { - BPReload(); + m_invalid = true; RecomputeCachedArraybases(); // Clear all caches that touch RAM // (? these don't appear to touch any emulation state that gets saved. moved to on load only.) - TextureCache::Invalidate(); VertexLoaderManager::MarkAllDirty(); } } +void VideoBackendHardware::CheckInvalidState() { + if (m_invalid) + { + m_invalid = false; + + BPReload(); + TextureCache::Invalidate(); + } +} + void VideoBackendHardware::PauseAndLock(bool doLock, bool unpauseOnUnlock) { Fifo_PauseAndLock(doLock, unpauseOnUnlock); diff --git a/Source/Core/VideoCommon/Src/OnScreenDisplay.cpp b/Source/Core/VideoCommon/Src/OnScreenDisplay.cpp index f24bfc31b3..10cf5b84af 100644 --- a/Source/Core/VideoCommon/Src/OnScreenDisplay.cpp +++ b/Source/Core/VideoCommon/Src/OnScreenDisplay.cpp @@ -19,6 +19,7 @@ #include "Common.h" +#include "ConfigManager.h" #include "OnScreenDisplay.h" #include "RenderBase.h" #include "Timer.h" @@ -47,6 +48,8 @@ void AddMessage(const char* pstr, u32 ms) void DrawMessages() { + if(!SConfig::GetInstance().m_LocalCoreStartupParameter.bOnScreenDisplayMessages) return; + if (s_listMsgs.size() > 0) { int left = 25, top = 15; diff --git a/Source/Core/VideoCommon/Src/PixelShaderGen.cpp b/Source/Core/VideoCommon/Src/PixelShaderGen.cpp index b2bada299f..52c4633ced 100644 --- a/Source/Core/VideoCommon/Src/PixelShaderGen.cpp +++ b/Source/Core/VideoCommon/Src/PixelShaderGen.cpp @@ -129,15 +129,11 @@ void GetPixelShaderId(PIXELSHADERUID *uid, DSTALPHA_MODE dstAlphaMode, u32 compo return; } + // numtexgens should be <= 8 for (unsigned int i = 0; i < bpmem.genMode.numtexgens; ++i) - { - if (18+i < 32) - uid->values[0] |= xfregs.texMtxInfo[i].projection << (18+i); // 1 - else - uid->values[1] |= xfregs.texMtxInfo[i].projection << (i - 14); // 1 - } + uid->values[0] |= xfregs.texMtxInfo[i].projection << (18+i); // 1 - uid->values[1] = bpmem.genMode.numindstages << 2; // 3 + uid->values[1] = bpmem.genMode.numindstages; // 3 u32 indirectStagesUsed = 0; for (unsigned int i = 0; i < bpmem.genMode.numindstages; ++i) if (bpmem.tevind[i].IsActive() && bpmem.tevind[i].bt < bpmem.genMode.numindstages) @@ -145,20 +141,20 @@ void GetPixelShaderId(PIXELSHADERUID *uid, DSTALPHA_MODE dstAlphaMode, u32 compo assert(indirectStagesUsed == (indirectStagesUsed & 0xF)); - uid->values[1] |= indirectStagesUsed << 5; // 4; + uid->values[1] |= indirectStagesUsed << 3; // 4; for (unsigned int i = 0; i < bpmem.genMode.numindstages; ++i) { if (indirectStagesUsed & (1 << i)) { - uid->values[1] |= (bpmem.tevindref.getTexCoord(i) < bpmem.genMode.numtexgens) << (9 + 3*i); // 1 + uid->values[1] |= (bpmem.tevindref.getTexCoord(i) < bpmem.genMode.numtexgens) << (7 + 3*i); // 1 if (bpmem.tevindref.getTexCoord(i) < bpmem.genMode.numtexgens) - uid->values[1] |= bpmem.tevindref.getTexCoord(i) << (10 + 3*i); // 2 + uid->values[1] |= bpmem.tevindref.getTexCoord(i) << (8 + 3*i); // 2 } } u32* ptr = &uid->values[2]; - for (unsigned int i = 0; i < bpmem.genMode.numtevstages+1; ++i) + for (int i = 0; i < bpmem.genMode.numtevstages+1; ++i) { StageHash(i, ptr); ptr += 4; // max: ptr = &uid->values[66] @@ -780,7 +776,6 @@ const char *GeneratePixelShaderCode(DSTALPHA_MODE dstAlphaMode, API_TYPE ApiType WRITE(p, "void main()\n{\n"); } - char* pmainstart = p; int Pretest = AlphaPreTest(); if(Pretest >= 0 && !DepthTextureEnable) { diff --git a/Source/Core/VideoCommon/Src/PixelShaderManager.cpp b/Source/Core/VideoCommon/Src/PixelShaderManager.cpp index e7086da7b3..e56f646c15 100644 --- a/Source/Core/VideoCommon/Src/PixelShaderManager.cpp +++ b/Source/Core/VideoCommon/Src/PixelShaderManager.cpp @@ -304,6 +304,7 @@ void PixelShaderManager::SetConstants() float GC_ALIGNED16(material[4]); float NormalizationCoef = 1 / 255.0f; + // TODO: This code is wrong. i goes out of range for xfregs.ambColor. for (int i = 0; i < 4; ++i) { if (nMaterialsChanged & (1 << i)) diff --git a/Source/Core/VideoCommon/Src/RenderBase.cpp b/Source/Core/VideoCommon/Src/RenderBase.cpp index 0bd1c89118..577570c568 100644 --- a/Source/Core/VideoCommon/Src/RenderBase.cpp +++ b/Source/Core/VideoCommon/Src/RenderBase.cpp @@ -67,12 +67,7 @@ int Renderer::s_target_height; int Renderer::s_backbuffer_width; int Renderer::s_backbuffer_height; -// ratio of backbuffer size and render area size -float Renderer::xScale; -float Renderer::yScale; - -unsigned int Renderer::s_XFB_width; -unsigned int Renderer::s_XFB_height; +TargetRectangle Renderer::target_rc; int Renderer::s_LastEFBScale; @@ -81,6 +76,11 @@ bool Renderer::XFBWrited; bool Renderer::s_EnableDLCachingAfterRecording; unsigned int Renderer::prev_efb_format = (unsigned int)-1; +unsigned int Renderer::efb_scale_numeratorX = 1; +unsigned int Renderer::efb_scale_numeratorY = 1; +unsigned int Renderer::efb_scale_denominatorX = 1; +unsigned int Renderer::efb_scale_denominatorY = 1; +unsigned int Renderer::ssaa_multiplier = 1; Renderer::Renderer() : frame_data(NULL), bLastFrameDumped(false) @@ -98,6 +98,8 @@ Renderer::~Renderer() // invalidate previous efb format prev_efb_format = (unsigned int)-1; + efb_scale_numeratorX = efb_scale_numeratorY = efb_scale_denominatorX = efb_scale_denominatorY = ssaa_multiplier = 1; + #if defined _WIN32 || defined HAVE_LIBAV if (g_ActiveConfig.bDumpFrames && bLastFrameDumped && bAVIDumping) AVIDump::Stop(); @@ -121,64 +123,117 @@ void Renderer::RenderToXFB(u32 xfbAddr, u32 fbWidth, u32 fbHeight, const EFBRect VideoFifo_CheckSwapRequestAt(xfbAddr, fbWidth, fbHeight); XFBWrited = true; - // XXX: Without the VI, how would we know what kind of field this is? So - // just use progressive. if (g_ActiveConfig.bUseXFB) { FramebufferManagerBase::CopyToXFB(xfbAddr, fbWidth, fbHeight, sourceRc,Gamma); } else { + // XXX: Without the VI, how would we know what kind of field this is? So + // just use progressive. g_renderer->Swap(xfbAddr, FIELD_PROGRESSIVE, fbWidth, fbHeight,sourceRc,Gamma); Common::AtomicStoreRelease(s_swapRequested, false); } } -void Renderer::CalculateTargetScale(int x, int y, int &scaledX, int &scaledY) +int Renderer::EFBToScaledX(int x) { switch (g_ActiveConfig.iEFBScale) { + case 0: // fractional + return (int)ssaa_multiplier * FramebufferManagerBase::ScaleToVirtualXfbWidth(x, s_backbuffer_width); + + default: + return x * (int)ssaa_multiplier * (int)efb_scale_numeratorX / (int)efb_scale_denominatorX; + }; +} + +int Renderer::EFBToScaledY(int y) +{ + switch (g_ActiveConfig.iEFBScale) + { + case 0: // fractional + return (int)ssaa_multiplier * FramebufferManagerBase::ScaleToVirtualXfbHeight(y, s_backbuffer_height); + + default: + return y * (int)ssaa_multiplier * (int)efb_scale_numeratorY / (int)efb_scale_denominatorY; + }; +} + +void Renderer::CalculateTargetScale(int x, int y, int &scaledX, int &scaledY) +{ + if (g_ActiveConfig.iEFBScale == 0 || g_ActiveConfig.iEFBScale == 1) + { + scaledX = x; + scaledY = y; + } + else + { + scaledX = x * (int)efb_scale_numeratorX / (int)efb_scale_denominatorX; + scaledY = y * (int)efb_scale_numeratorY / (int)efb_scale_denominatorY; + } +} + +// return true if target size changed +bool Renderer::CalculateTargetSize(unsigned int framebuffer_width, unsigned int framebuffer_height, int multiplier) +{ + int newEFBWidth, newEFBHeight; + + // TODO: Ugly. Clean up + switch (s_LastEFBScale) + { + case 2: // 1x + efb_scale_numeratorX = efb_scale_numeratorY = 1; + efb_scale_denominatorX = efb_scale_denominatorY = 1; + break; + case 3: // 1.5x - scaledX = (x / 2) * 3; - scaledY = (y / 2) * 3; + efb_scale_numeratorX = efb_scale_numeratorY = 3; + efb_scale_denominatorX = efb_scale_denominatorY = 2; break; + case 4: // 2x - scaledX = x * 2; - scaledY = y * 2; + efb_scale_numeratorX = efb_scale_numeratorY = 2; + efb_scale_denominatorX = efb_scale_denominatorY = 1; break; + case 5: // 2.5x - scaledX = (x / 2) * 5; - scaledY = (y / 2) * 5; + efb_scale_numeratorX = efb_scale_numeratorY = 5; + efb_scale_denominatorX = efb_scale_denominatorY = 2; break; + case 6: // 3x - scaledX = x * 3; - scaledY = y * 3; + efb_scale_numeratorX = efb_scale_numeratorY = 3; + efb_scale_denominatorX = efb_scale_denominatorY = 1; break; + case 7: // 4x - scaledX = x * 4; - scaledY = y * 4; + efb_scale_numeratorX = efb_scale_numeratorY = 4; + efb_scale_denominatorX = efb_scale_denominatorY = 1; break; - default: - scaledX = x; - scaledY = y; + + default: // fractional & integral handled later break; - }; -} + } -// return true if target size changed -bool Renderer::CalculateTargetSize(int multiplier) -{ - int newEFBWidth, newEFBHeight; switch (s_LastEFBScale) { case 0: // fractional - newEFBWidth = (int)(EFB_WIDTH * xScale); - newEFBHeight = (int)(EFB_HEIGHT * yScale); - break; case 1: // integral - newEFBWidth = EFB_WIDTH * (int)ceilf(xScale); - newEFBHeight = EFB_HEIGHT * (int)ceilf(yScale); + newEFBWidth = FramebufferManagerBase::ScaleToVirtualXfbWidth(EFB_WIDTH, framebuffer_width); + newEFBHeight = FramebufferManagerBase::ScaleToVirtualXfbHeight(EFB_HEIGHT, framebuffer_height); + + if (s_LastEFBScale == 1) + { + newEFBWidth = ((newEFBWidth-1) / EFB_WIDTH + 1) * EFB_WIDTH; + newEFBHeight = ((newEFBHeight-1) / EFB_HEIGHT + 1) * EFB_HEIGHT; + } + efb_scale_numeratorX = newEFBWidth; + efb_scale_denominatorX = EFB_WIDTH; + efb_scale_numeratorY = newEFBHeight; + efb_scale_denominatorY = EFB_HEIGHT; break; + default: CalculateTargetScale(EFB_WIDTH, EFB_HEIGHT, newEFBWidth, newEFBHeight); break; @@ -186,6 +241,7 @@ bool Renderer::CalculateTargetSize(int multiplier) newEFBWidth *= multiplier; newEFBHeight *= multiplier; + ssaa_multiplier = multiplier; if (newEFBWidth != s_target_width || newEFBHeight != s_target_height) { @@ -311,27 +367,125 @@ void Renderer::DrawDebugText() } } -void Renderer::CalculateXYScale(const TargetRectangle& dst_rect) +// TODO: remove +extern bool g_aspect_wide; + +void Renderer::UpdateDrawRectangle(int backbuffer_width, int backbuffer_height) { - if (g_ActiveConfig.bUseXFB && g_ActiveConfig.bUseRealXFB) + float FloatGLWidth = (float)backbuffer_width; + float FloatGLHeight = (float)backbuffer_height; + float FloatXOffset = 0; + float FloatYOffset = 0; + + // The rendering window size + const float WinWidth = FloatGLWidth; + const float WinHeight = FloatGLHeight; + + // Handle aspect ratio. + // Default to auto. + bool use16_9 = g_aspect_wide; + + // Update aspect ratio hack values + // Won't take effect until next frame + // Don't know if there is a better place for this code so there isn't a 1 frame delay + if ( g_ActiveConfig.bWidescreenHack ) { - xScale = 1.0f; - yScale = 1.0f; + float source_aspect = use16_9 ? (16.0f / 9.0f) : (4.0f / 3.0f); + float target_aspect; + + switch ( g_ActiveConfig.iAspectRatio ) + { + case ASPECT_FORCE_16_9 : + target_aspect = 16.0f / 9.0f; + break; + case ASPECT_FORCE_4_3 : + target_aspect = 4.0f / 3.0f; + break; + case ASPECT_STRETCH : + target_aspect = WinWidth / WinHeight; + break; + default : + // ASPECT_AUTO == no hacking + target_aspect = source_aspect; + break; + } + + float adjust = source_aspect / target_aspect; + if ( adjust > 1 ) + { + // Vert+ + g_Config.fAspectRatioHackW = 1; + g_Config.fAspectRatioHackH = 1/adjust; + } + else + { + // Hor+ + g_Config.fAspectRatioHackW = adjust; + g_Config.fAspectRatioHackH = 1; + } } else { - if (g_ActiveConfig.b3DVision) + // Hack is disabled + g_Config.fAspectRatioHackW = 1; + g_Config.fAspectRatioHackH = 1; + } + + // Check for force-settings and override. + if (g_ActiveConfig.iAspectRatio == ASPECT_FORCE_16_9) + use16_9 = true; + else if (g_ActiveConfig.iAspectRatio == ASPECT_FORCE_4_3) + use16_9 = false; + + if (g_ActiveConfig.iAspectRatio != ASPECT_STRETCH) + { + // The rendering window aspect ratio as a proportion of the 4:3 or 16:9 ratio + float Ratio = (WinWidth / WinHeight) / (!use16_9 ? (4.0f / 3.0f) : (16.0f / 9.0f)); + // Check if height or width is the limiting factor. If ratio > 1 the picture is too wide and have to limit the width. + if (Ratio > 1.0f) { - // This works, yet the version in the else doesn't. No idea why. - xScale = (float)(s_backbuffer_width-1) / (float)(s_XFB_width-1); - yScale = (float)(s_backbuffer_height-1) / (float)(s_XFB_height-1); + // Scale down and center in the X direction. + FloatGLWidth /= Ratio; + FloatXOffset = (WinWidth - FloatGLWidth) / 2.0f; } + // The window is too high, we have to limit the height else { - xScale = (float)(dst_rect.right - dst_rect.left - 1) / (float)(s_XFB_width-1); - yScale = (float)(dst_rect.bottom - dst_rect.top - 1) / (float)(s_XFB_height-1); + // Scale down and center in the Y direction. + FloatGLHeight *= Ratio; + FloatYOffset = FloatYOffset + (WinHeight - FloatGLHeight) / 2.0f; } } + + // ----------------------------------------------------------------------- + // Crop the picture from 4:3 to 5:4 or from 16:9 to 16:10. + // Output: FloatGLWidth, FloatGLHeight, FloatXOffset, FloatYOffset + // ------------------ + if (g_ActiveConfig.iAspectRatio != ASPECT_STRETCH && g_ActiveConfig.bCrop) + { + float Ratio = !use16_9 ? ((4.0f / 3.0f) / (5.0f / 4.0f)) : (((16.0f / 9.0f) / (16.0f / 10.0f))); + // The width and height we will add (calculate this before FloatGLWidth and FloatGLHeight is adjusted) + float IncreasedWidth = (Ratio - 1.0f) * FloatGLWidth; + float IncreasedHeight = (Ratio - 1.0f) * FloatGLHeight; + // The new width and height + FloatGLWidth = FloatGLWidth * Ratio; + FloatGLHeight = FloatGLHeight * Ratio; + // Adjust the X and Y offset + FloatXOffset = FloatXOffset - (IncreasedWidth * 0.5f); + FloatYOffset = FloatYOffset - (IncreasedHeight * 0.5f); + } + + int XOffset = (int)(FloatXOffset + 0.5f); + int YOffset = (int)(FloatYOffset + 0.5f); + int iWhidth = (int)ceil(FloatGLWidth); + int iHeight = (int)ceil(FloatGLHeight); + iWhidth -= iWhidth % 4; // ensure divisibility by 4 to make it compatible with all the video encoders + iHeight -= iHeight % 4; + + target_rc.left = XOffset; + target_rc.top = YOffset; + target_rc.right = XOffset + iWhidth; + target_rc.bottom = YOffset + iHeight; } void Renderer::SetWindowSize(int width, int height) diff --git a/Source/Core/VideoCommon/Src/RenderBase.h b/Source/Core/VideoCommon/Src/RenderBase.h index e8d4c55a20..4da80c9752 100644 --- a/Source/Core/VideoCommon/Src/RenderBase.h +++ b/Source/Core/VideoCommon/Src/RenderBase.h @@ -74,10 +74,6 @@ public: static int GetBackbufferWidth() { return s_backbuffer_width; } static int GetBackbufferHeight() { return s_backbuffer_height; } - // XFB scale - TODO: Remove this and add two XFBToScaled functions instead - static float GetXFBScaleX() { return xScale; } - static float GetXFBScaleY() { return yScale; } - static void SetWindowSize(int width, int height); // EFB coordinate conversion functions @@ -85,9 +81,13 @@ public: // Use this to convert a whole native EFB rect to backbuffer coordinates virtual TargetRectangle ConvertEFBRectangle(const EFBRectangle& rc) = 0; + static const TargetRectangle& GetTargetRectangle() { return target_rc; } + static void UpdateDrawRectangle(int backbuffer_width, int backbuffer_height); + + // Use this to upscale native EFB coordinates to IDEAL internal resolution - static unsigned int EFBToScaledX(int x) { return x * GetTargetWidth() / EFB_WIDTH; } - static unsigned int EFBToScaledY(int y) { return y * GetTargetHeight() / EFB_HEIGHT; } + static int EFBToScaledX(int x); + static int EFBToScaledY(int y); // Floating point versions of the above - only use them if really necessary static float EFBToScaledXf(float x) { return x * ((float)GetTargetWidth() / (float)EFB_WIDTH); } @@ -133,8 +133,7 @@ public: protected: static void CalculateTargetScale(int x, int y, int &scaledX, int &scaledY); - static bool CalculateTargetSize(int multiplier = 1); - static void CalculateXYScale(const TargetRectangle& dst_rect); + static bool CalculateTargetSize(unsigned int framebuffer_width, unsigned int framebuffer_height, int multiplier = 1); static void CheckFifoRecording(); static void RecordVideoMemory(); @@ -159,12 +158,7 @@ protected: static int s_backbuffer_width; static int s_backbuffer_height; - // ratio of backbuffer size and render area size - TODO: Remove these! - static float xScale; - static float yScale; - - static unsigned int s_XFB_width; - static unsigned int s_XFB_height; + static TargetRectangle target_rc; // can probably eliminate this static var static int s_LastEFBScale; @@ -176,6 +170,11 @@ protected: private: static unsigned int prev_efb_format; + static unsigned int efb_scale_numeratorX; + static unsigned int efb_scale_numeratorY; + static unsigned int efb_scale_denominatorX; + static unsigned int efb_scale_denominatorY; + static unsigned int ssaa_multiplier; }; extern Renderer *g_renderer; diff --git a/Source/Core/VideoCommon/Src/TextureCacheBase.cpp b/Source/Core/VideoCommon/Src/TextureCacheBase.cpp index a5c390df3d..9fc18ef1bd 100644 --- a/Source/Core/VideoCommon/Src/TextureCacheBase.cpp +++ b/Source/Core/VideoCommon/Src/TextureCacheBase.cpp @@ -205,8 +205,11 @@ void TextureCache::ClearRenderTargets() tcend = textures.end(); for (; iter!=tcend; ++iter) - if (iter->second->type != TCET_EC_DYNAMIC) - iter->second->type = TCET_NORMAL; + if (iter->second->type == TCET_EC_VRAM) + { + delete iter->second; + textures.erase(iter++); + } } bool TextureCache::CheckForCustomTextureLODs(u64 tex_hash, int texformat, unsigned int levels) @@ -374,7 +377,7 @@ TextureCache::TCacheEntryBase* TextureCache::Load(unsigned int stage, // // TODO: Don't we need to force texture decoding to RGBA8 for dynamic EFB copies? // TODO: Actually, it should be enough if the internal texture format matches... - if ((entry->type == TCET_NORMAL && width == entry->native_width && height == entry->native_height && full_format == entry->format && entry->num_mipmaps == maxlevel) + if ((entry->type == TCET_NORMAL && width == entry->virtual_width && height == entry->virtual_height && full_format == entry->format && entry->num_mipmaps == maxlevel) || (entry->type == TCET_EC_DYNAMIC && entry->native_width == width && entry->native_height == height)) { // reuse the texture @@ -393,14 +396,21 @@ TextureCache::TCacheEntryBase* TextureCache::Load(unsigned int stage, pcfmt = LoadCustomTexture(tex_hash, texformat, 0, width, height); if (pcfmt != PC_TEX_FMT_NONE) { - expandedWidth = width; - expandedHeight = height; + if (expandedWidth != width || expandedHeight != height) + { + expandedWidth = width; + expandedHeight = height; + + // If we thought we could reuse the texture before, make sure to delete it now! + delete entry; + entry = NULL; + } using_custom_texture = true; } } - // TODO: RGBA8 textures are stored non-continuously in tmem, that might cause problems when preloading is enabled - if (pcfmt == PC_TEX_FMT_NONE) + // TODO: RGBA8 textures are stored non-continuously in tmem, that might cause problems here when preloading is enabled + if (!using_custom_texture) pcfmt = TexDecoder_Decode(temp, src_data, expandedWidth, expandedHeight, texformat, tlutaddr, tlutfmt, g_ActiveConfig.backend_info.bUseRGBATextures); @@ -782,7 +792,7 @@ void TextureCache::CopyRenderTargetToTexture(u32 dstAddr, unsigned int dstFormat textures[dstAddr] = entry = g_texture_cache->CreateRenderTargetTexture(scaled_tex_w, scaled_tex_h); // TODO: Using the wrong dstFormat, dumb... - entry->SetGeneralParameters(dstAddr, 0, dstFormat, 0); + entry->SetGeneralParameters(dstAddr, 0, dstFormat, 1); entry->SetDimensions(tex_w, tex_h, scaled_tex_w, scaled_tex_h); entry->SetHashes(TEXHASH_INVALID); entry->type = TCET_EC_VRAM; diff --git a/Source/Core/VideoCommon/Src/VertexLoader.cpp b/Source/Core/VideoCommon/Src/VertexLoader.cpp index fb34ce1bc1..5bffab8ee7 100644 --- a/Source/Core/VideoCommon/Src/VertexLoader.cpp +++ b/Source/Core/VideoCommon/Src/VertexLoader.cpp @@ -224,14 +224,14 @@ void VertexLoader::CompileVertexTranslator() #endif // Colors - const int col[2] = {m_VtxDesc.Color0, m_VtxDesc.Color1}; + const u32 col[2] = {m_VtxDesc.Color0, m_VtxDesc.Color1}; // TextureCoord // Since m_VtxDesc.Text7Coord is broken across a 32 bit word boundary, retrieve its value manually. // If we didn't do this, the vertex format would be read as one bit offset from where it should be, making // 01 become 00, and 10/11 become 01 - const int tc[8] = { + const u32 tc[8] = { m_VtxDesc.Tex0Coord, m_VtxDesc.Tex1Coord, m_VtxDesc.Tex2Coord, m_VtxDesc.Tex3Coord, - m_VtxDesc.Tex4Coord, m_VtxDesc.Tex5Coord, m_VtxDesc.Tex6Coord, (const int)((m_VtxDesc.Hex >> 31) & 3) + m_VtxDesc.Tex4Coord, m_VtxDesc.Tex5Coord, m_VtxDesc.Tex6Coord, (const u32)((m_VtxDesc.Hex >> 31) & 3) }; // Reset pipeline @@ -770,7 +770,7 @@ void VertexLoader::AppendToString(std::string *dest) const dest->append(StringFromFormat("Nrm: %i %s-%s ", m_VtxAttr.NormalElements, posMode[m_VtxDesc.Normal], posFormats[m_VtxAttr.NormalFormat])); } - int color_mode[2] = {m_VtxDesc.Color0, m_VtxDesc.Color1}; + u32 color_mode[2] = {m_VtxDesc.Color0, m_VtxDesc.Color1}; for (int i = 0; i < 2; i++) { if (color_mode[i]) @@ -778,7 +778,7 @@ void VertexLoader::AppendToString(std::string *dest) const dest->append(StringFromFormat("C%i: %i %s-%s ", i, m_VtxAttr.color[i].Elements, posMode[color_mode[i]], colorFormat[m_VtxAttr.color[i].Comp])); } } - int tex_mode[8] = { + u32 tex_mode[8] = { m_VtxDesc.Tex0Coord, m_VtxDesc.Tex1Coord, m_VtxDesc.Tex2Coord, m_VtxDesc.Tex3Coord, m_VtxDesc.Tex4Coord, m_VtxDesc.Tex5Coord, m_VtxDesc.Tex6Coord, m_VtxDesc.Tex7Coord }; diff --git a/Source/Core/VideoCommon/Src/VertexLoaderManager.cpp b/Source/Core/VideoCommon/Src/VertexLoaderManager.cpp index 316941a639..153e69a8c3 100644 --- a/Source/Core/VideoCommon/Src/VertexLoaderManager.cpp +++ b/Source/Core/VideoCommon/Src/VertexLoaderManager.cpp @@ -19,9 +19,12 @@ #ifdef _MSC_VER #include <hash_map> using stdext::hash_map; -#else +#elif defined __APPLE__ #include <ext/hash_map> using __gnu_cxx::hash_map; +#else +#include <unordered_map> +using std::unordered_map; #endif #include <map> #include <vector> @@ -45,7 +48,12 @@ namespace stdext { } } #else -namespace __gnu_cxx { +#ifdef __APPLE__ +namespace __gnu_cxx +#else +namespace std +#endif +{ template<> struct hash<VertexLoaderUID> { size_t operator()(const VertexLoaderUID& uid) const { return uid.GetHash(); @@ -54,10 +62,15 @@ namespace __gnu_cxx { } #endif +#if defined _MSC_VER || defined __APPLE__ +typedef hash_map<VertexLoaderUID, VertexLoader*> VertexLoaderMap; +#else +typedef unordered_map<VertexLoaderUID, VertexLoader*> VertexLoaderMap; +#endif + namespace VertexLoaderManager { -typedef hash_map<VertexLoaderUID, VertexLoader*> VertexLoaderMap; static VertexLoaderMap g_VertexLoaderMap; // TODO - change into array of pointers. Keep a map of all seen so far. diff --git a/Source/Core/VideoCommon/Src/VertexManagerBase.cpp b/Source/Core/VideoCommon/Src/VertexManagerBase.cpp index 4118e3dcbd..5be72e4fcf 100644 --- a/Source/Core/VideoCommon/Src/VertexManagerBase.cpp +++ b/Source/Core/VideoCommon/Src/VertexManagerBase.cpp @@ -9,6 +9,7 @@ #include "NativeVertexFormat.h" #include "TextureCacheBase.h" #include "RenderBase.h" +#include "BPStructs.h" #include "VertexManagerBase.h" #include "VideoConfig.h" @@ -159,6 +160,9 @@ void VertexManager::AddVertices(int primitive, int numVertices) void VertexManager::Flush() { + // loading a state will invalidate BP, so check for it + g_video_backend->CheckInvalidState(); + g_vertex_manager->vFlush(); } diff --git a/Source/Core/VideoCommon/Src/VertexManagerBase.h b/Source/Core/VideoCommon/Src/VertexManagerBase.h index bc30fa3fba..f3a4aa72e3 100644 --- a/Source/Core/VideoCommon/Src/VertexManagerBase.h +++ b/Source/Core/VideoCommon/Src/VertexManagerBase.h @@ -21,7 +21,7 @@ public: // values from DX11 backend MAXVBUFFERSIZE = 0x50000, - MAXIBUFFERSIZE = 0x10000, + MAXIBUFFERSIZE = 0xFFFF, }; VertexManager(); @@ -46,7 +46,8 @@ public: static u8* GetVertexBuffer() { return LocalVBuffer; } static void DoState(PointerWrap& p); - + virtual void CreateDeviceObjects(){}; + virtual void DestroyDeviceObjects(){}; protected: // TODO: make private after Flush() is merged static void ResetBuffer(); diff --git a/Source/Core/VideoCommon/Src/VertexShaderManager.cpp b/Source/Core/VideoCommon/Src/VertexShaderManager.cpp index fbd5d9e779..5beaefb631 100644 --- a/Source/Core/VideoCommon/Src/VertexShaderManager.cpp +++ b/Source/Core/VideoCommon/Src/VertexShaderManager.cpp @@ -209,6 +209,7 @@ void VertexShaderManager::SetConstants() int endn = (nPostTransformMatricesChanged[1] + 3 ) / 4; const float* pstart = (const float*)&xfmem[XFMEM_POSTMATRICES + startn * 4]; SetMultiVSConstant4fv(C_POSTTRANSFORMMATRICES + startn, endn - startn, pstart); + nPostTransformMatricesChanged[0] = nPostTransformMatricesChanged[1] = -1; } if (nLightsChanged[0] >= 0) @@ -252,6 +253,7 @@ void VertexShaderManager::SetConstants() float GC_ALIGNED16(material[4]); float NormalizationCoef = 1 / 255.0f; + // TODO: This code is wrong. i goes out of range for xfregs.ambColor. for (int i = 0; i < 4; ++i) { if (nMaterialsChanged & (1 << i)) diff --git a/Source/Core/VideoCommon/Src/VideoConfig.cpp b/Source/Core/VideoCommon/Src/VideoConfig.cpp index c4aa1cc2b0..128a05177c 100644 --- a/Source/Core/VideoCommon/Src/VideoConfig.cpp +++ b/Source/Core/VideoCommon/Src/VideoConfig.cpp @@ -293,125 +293,3 @@ void VideoConfig::GameIniSave(const char* default_ini, const char* game_ini) iniFile.Save(game_ini); } - - -// TODO: remove -extern bool g_aspect_wide; - -// TODO: Figure out a better place for this function. -void ComputeDrawRectangle(int backbuffer_width, int backbuffer_height, bool flip, TargetRectangle *rc) -{ - float FloatGLWidth = (float)backbuffer_width; - float FloatGLHeight = (float)backbuffer_height; - float FloatXOffset = 0; - float FloatYOffset = 0; - - // The rendering window size - const float WinWidth = FloatGLWidth; - const float WinHeight = FloatGLHeight; - - // Handle aspect ratio. - // Default to auto. - bool use16_9 = g_aspect_wide; - - // Update aspect ratio hack values - // Won't take effect until next frame - // Don't know if there is a better place for this code so there isn't a 1 frame delay - if ( g_ActiveConfig.bWidescreenHack ) - { - float source_aspect = use16_9 ? (16.0f / 9.0f) : (4.0f / 3.0f); - float target_aspect; - - switch ( g_ActiveConfig.iAspectRatio ) - { - case ASPECT_FORCE_16_9 : - target_aspect = 16.0f / 9.0f; - break; - case ASPECT_FORCE_4_3 : - target_aspect = 4.0f / 3.0f; - break; - case ASPECT_STRETCH : - target_aspect = WinWidth / WinHeight; - break; - default : - // ASPECT_AUTO == no hacking - target_aspect = source_aspect; - break; - } - - float adjust = source_aspect / target_aspect; - if ( adjust > 1 ) - { - // Vert+ - g_Config.fAspectRatioHackW = 1; - g_Config.fAspectRatioHackH = 1/adjust; - } - else - { - // Hor+ - g_Config.fAspectRatioHackW = adjust; - g_Config.fAspectRatioHackH = 1; - } - } - else - { - // Hack is disabled - g_Config.fAspectRatioHackW = 1; - g_Config.fAspectRatioHackH = 1; - } - - // Check for force-settings and override. - if (g_ActiveConfig.iAspectRatio == ASPECT_FORCE_16_9) - use16_9 = true; - else if (g_ActiveConfig.iAspectRatio == ASPECT_FORCE_4_3) - use16_9 = false; - - if (g_ActiveConfig.iAspectRatio != ASPECT_STRETCH) - { - // The rendering window aspect ratio as a proportion of the 4:3 or 16:9 ratio - float Ratio = (WinWidth / WinHeight) / (!use16_9 ? (4.0f / 3.0f) : (16.0f / 9.0f)); - // Check if height or width is the limiting factor. If ratio > 1 the picture is too wide and have to limit the width. - if (Ratio > 1.0f) - { - // Scale down and center in the X direction. - FloatGLWidth /= Ratio; - FloatXOffset = (WinWidth - FloatGLWidth) / 2.0f; - } - // The window is too high, we have to limit the height - else - { - // Scale down and center in the Y direction. - FloatGLHeight *= Ratio; - FloatYOffset = FloatYOffset + (WinHeight - FloatGLHeight) / 2.0f; - } - } - - // ----------------------------------------------------------------------- - // Crop the picture from 4:3 to 5:4 or from 16:9 to 16:10. - // Output: FloatGLWidth, FloatGLHeight, FloatXOffset, FloatYOffset - // ------------------ - if (g_ActiveConfig.iAspectRatio != ASPECT_STRETCH && g_ActiveConfig.bCrop) - { - float Ratio = !use16_9 ? ((4.0f / 3.0f) / (5.0f / 4.0f)) : (((16.0f / 9.0f) / (16.0f / 10.0f))); - // The width and height we will add (calculate this before FloatGLWidth and FloatGLHeight is adjusted) - float IncreasedWidth = (Ratio - 1.0f) * FloatGLWidth; - float IncreasedHeight = (Ratio - 1.0f) * FloatGLHeight; - // The new width and height - FloatGLWidth = FloatGLWidth * Ratio; - FloatGLHeight = FloatGLHeight * Ratio; - // Adjust the X and Y offset - FloatXOffset = FloatXOffset - (IncreasedWidth * 0.5f); - FloatYOffset = FloatYOffset - (IncreasedHeight * 0.5f); - } - - int XOffset = (int)(FloatXOffset + 0.5f); - int YOffset = (int)(FloatYOffset + 0.5f); - int iWhidth = (int)ceil(FloatGLWidth); - int iHeight = (int)ceil(FloatGLHeight); - iWhidth -= iWhidth % 4; // ensure divisibility by 4 to make it compatible with all the video encoders - iHeight -= iHeight % 4; - rc->left = XOffset; - rc->top = flip ? (int)(YOffset + iHeight) : YOffset; - rc->right = XOffset + iWhidth; - rc->bottom = flip ? YOffset : (int)(YOffset + iHeight); -} diff --git a/Source/Core/VideoCommon/Src/VideoConfig.h b/Source/Core/VideoCommon/Src/VideoConfig.h index 064f8278a7..8972d60bcb 100644 --- a/Source/Core/VideoCommon/Src/VideoConfig.h +++ b/Source/Core/VideoCommon/Src/VideoConfig.h @@ -170,6 +170,12 @@ struct VideoConfig bool bSupportsGLSLATTRBind; bool bSupportsGLSLCache; } backend_info; + + // Utility + bool RealXFBEnabled() const { return bUseXFB && bUseRealXFB; } + bool VirtualXFBEnabled() const { return bUseXFB && !bUseRealXFB; } + bool EFBCopiesToTextureEnabled() const { return bEFBCopyEnable && bCopyEFBToTexture; } + bool EFBCopiesToRamEnabled() const { return bEFBCopyEnable && !bCopyEFBToTexture; } }; extern VideoConfig g_Config; @@ -178,6 +184,4 @@ extern VideoConfig g_ActiveConfig; // Called every frame. void UpdateActiveConfig(); -void ComputeDrawRectangle(int backbuffer_width, int backbuffer_height, bool flip, TargetRectangle *rc); - #endif // _VIDEO_CONFIG_H_ diff --git a/Source/Core/VideoCommon/Src/XFStructs.cpp b/Source/Core/VideoCommon/Src/XFStructs.cpp index f8330604ad..9f395bfecf 100644 --- a/Source/Core/VideoCommon/Src/XFStructs.cpp +++ b/Source/Core/VideoCommon/Src/XFStructs.cpp @@ -121,18 +121,12 @@ void XFRegWritten(int transferSize, u32 baseAddress, u32 *pData) case XFMEM_SETVIEWPORT+3: case XFMEM_SETVIEWPORT+4: case XFMEM_SETVIEWPORT+5: - { - u8 size = std::min(transferSize * 4, 6 * 4); - if (memcmp((u32*)&xfregs + (address - 0x1000), pData + dataIndex, size)) - { - VertexManager::Flush(); - VertexShaderManager::SetViewportChanged(); - PixelShaderManager::SetViewportChanged(); - } + VertexManager::Flush(); + VertexShaderManager::SetViewportChanged(); + PixelShaderManager::SetViewportChanged(); - nextAddress = XFMEM_SETVIEWPORT + 6; - break; - } + nextAddress = XFMEM_SETVIEWPORT + 6; + break; case XFMEM_SETPROJECTION: case XFMEM_SETPROJECTION+1: @@ -141,21 +135,15 @@ void XFRegWritten(int transferSize, u32 baseAddress, u32 *pData) case XFMEM_SETPROJECTION+4: case XFMEM_SETPROJECTION+5: case XFMEM_SETPROJECTION+6: - { - u8 size = std::min(transferSize * 4, 7 * 4); - if (memcmp((u32*)&xfregs + (address - 0x1000), pData + dataIndex, size)) - { - VertexManager::Flush(); - VertexShaderManager::SetProjectionChanged(); - } + VertexManager::Flush(); + VertexShaderManager::SetProjectionChanged(); - nextAddress = XFMEM_SETPROJECTION + 7; - break; - } + nextAddress = XFMEM_SETPROJECTION + 7; + break; case XFMEM_SETNUMTEXGENS: // GXSetNumTexGens if (xfregs.numTexGen.numTexGens != (newValue & 15)) - VertexManager::Flush(); + VertexManager::Flush(); break; case XFMEM_SETTEXMTXINFO: @@ -166,16 +154,10 @@ void XFRegWritten(int transferSize, u32 baseAddress, u32 *pData) case XFMEM_SETTEXMTXINFO+5: case XFMEM_SETTEXMTXINFO+6: case XFMEM_SETTEXMTXINFO+7: - { - u8 size = std::min(transferSize * 4, 8 * 4); - if (memcmp((u32*)&xfregs + (address - 0x1000), pData + dataIndex, size)) - { - VertexManager::Flush(); - } + VertexManager::Flush(); - nextAddress = XFMEM_SETTEXMTXINFO + 8; - break; - } + nextAddress = XFMEM_SETTEXMTXINFO + 8; + break; case XFMEM_SETPOSMTXINFO: case XFMEM_SETPOSMTXINFO+1: @@ -185,16 +167,10 @@ void XFRegWritten(int transferSize, u32 baseAddress, u32 *pData) case XFMEM_SETPOSMTXINFO+5: case XFMEM_SETPOSMTXINFO+6: case XFMEM_SETPOSMTXINFO+7: - { - u8 size = std::min(transferSize * 4, 8 * 4); - if (memcmp((u32*)&xfregs + (address - 0x1000), pData + dataIndex, size)) - { - VertexManager::Flush(); - } + VertexManager::Flush(); - nextAddress = XFMEM_SETPOSMTXINFO + 8; - break; - } + nextAddress = XFMEM_SETPOSMTXINFO + 8; + break; // -------------- // Unknown Regs @@ -264,15 +240,8 @@ void LoadXFReg(u32 transferSize, u32 baseAddress, u32 *pData) transferSize = 0; } - for (u32 i = 0; i < xfMemTransferSize; ++i) - { - if (((u32*)&xfmem[xfMemBase])[i] != pData[i]) - { - XFMemWritten(xfMemTransferSize, xfMemBase); - memcpy_gc(&xfmem[xfMemBase], pData, xfMemTransferSize * 4); - break; - } - } + XFMemWritten(xfMemTransferSize, xfMemBase); + memcpy_gc(&xfmem[xfMemBase], pData, xfMemTransferSize * 4); pData += xfMemTransferSize; } diff --git a/Source/Core/VideoCommon/VideoCommon.vcxproj b/Source/Core/VideoCommon/VideoCommon.vcxproj index 0869f33ff4..bf9122e6b5 100644 --- a/Source/Core/VideoCommon/VideoCommon.vcxproj +++ b/Source/Core/VideoCommon/VideoCommon.vcxproj @@ -111,7 +111,8 @@ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> <ClCompile> <AdditionalIncludeDirectories>..\Common\Src;..\Core\Src;..\..\..\Externals\SOIL;..\..\..\Externals\CLRun\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> - </ClCompile> + <OpenMPSupport>false</OpenMPSupport> + </ClCompile> <Link> <GenerateDebugInformation>true</GenerateDebugInformation> </Link> @@ -129,7 +130,7 @@ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> <ClCompile> <AdditionalIncludeDirectories>..\Common\Src;..\Core\Src;..\..\..\Externals\SOIL;..\..\..\Externals\CLRun\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> - <OpenMPSupport>true</OpenMPSupport> + <OpenMPSupport>false</OpenMPSupport> </ClCompile> <Link> <GenerateDebugInformation>true</GenerateDebugInformation> @@ -141,7 +142,8 @@ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='DebugFast|Win32'"> <ClCompile> <AdditionalIncludeDirectories>..\Common\Src;..\Core\Src;..\..\..\Externals\SOIL;..\..\..\Externals\CLRun\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> - </ClCompile> + <OpenMPSupport>false</OpenMPSupport> + </ClCompile> <Link> <GenerateDebugInformation>true</GenerateDebugInformation> <EnableCOMDATFolding>true</EnableCOMDATFolding> |
