summaryrefslogtreecommitdiff
path: root/Source/Core
diff options
context:
space:
mode:
authordegasus <wickmarkus@web.de>2012-12-27 10:36:54 +0100
committerdegasus <wickmarkus@web.de>2012-12-27 10:36:54 +0100
commit316a33d1e68ab47b2870345a04bb9dfd4f383f28 (patch)
tree03b40807def9787df30976ecb53f09d6c6084c13 /Source/Core
parent53398ca5d8bc6e73a726c9d803db5a956c22cf6a (diff)
parent94116bf89c917309b7e7b2a2b46bf2f43f3219db (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')
-rw-r--r--Source/Core/AudioCommon/Src/AudioCommon.cpp8
-rw-r--r--Source/Core/AudioCommon/Src/CoreAudioSoundStream.cpp8
-rw-r--r--Source/Core/AudioCommon/Src/CoreAudioSoundStream.h1
-rw-r--r--Source/Core/AudioCommon/Src/OpenALStream.cpp3
-rw-r--r--Source/Core/Common/Src/CDUtils.cpp1
-rw-r--r--Source/Core/Common/Src/CPUDetect.cpp2
-rw-r--r--Source/Core/Common/Src/Common.h5
-rw-r--r--Source/Core/Common/Src/CommonPaths.h1
-rw-r--r--Source/Core/Common/Src/DebugInterface.h2
-rw-r--r--Source/Core/Common/Src/FileUtil.cpp15
-rw-r--r--Source/Core/Common/Src/MathUtil.h2
-rw-r--r--Source/Core/Common/Src/Setup.h41
-rw-r--r--Source/Core/Common/Src/Thread.cpp1
-rw-r--r--Source/Core/Common/Src/Timer.cpp6
-rw-r--r--Source/Core/Common/Src/Timer.h1
-rw-r--r--Source/Core/Common/Src/VideoBackendBase.cpp6
-rw-r--r--Source/Core/Common/Src/VideoBackendBase.h8
-rw-r--r--Source/Core/Common/Src/x64Analyzer.cpp6
-rw-r--r--Source/Core/Common/Src/x64Emitter.cpp2
-rw-r--r--Source/Core/Core/CMakeLists.txt10
-rw-r--r--Source/Core/Core/Core.vcxproj16
-rw-r--r--Source/Core/Core/Core.vcxproj.filters19
-rw-r--r--Source/Core/Core/Src/ActionReplay.cpp2
-rw-r--r--Source/Core/Core/Src/Boot/Boot_BS2Emu.cpp4
-rw-r--r--Source/Core/Core/Src/BootManager.cpp14
-rw-r--r--Source/Core/Core/Src/ConfigManager.cpp28
-rw-r--r--Source/Core/Core/Src/ConfigManager.h7
-rw-r--r--Source/Core/Core/Src/Core.cpp9
-rw-r--r--Source/Core/Core/Src/Core.h15
-rw-r--r--Source/Core/Core/Src/CoreParameter.cpp2
-rw-r--r--Source/Core/Core/Src/CoreParameter.h2
-rw-r--r--Source/Core/Core/Src/CoreRerecording.cpp248
-rw-r--r--Source/Core/Core/Src/CoreTiming.cpp4
-rw-r--r--Source/Core/Core/Src/DSP/DSPAccelerator.cpp3
-rw-r--r--Source/Core/Core/Src/DSP/Jit/DSPJitRegCache.cpp4
-rw-r--r--Source/Core/Core/Src/Debugger/PPCDebugInterface.h2
-rw-r--r--Source/Core/Core/Src/GeckoCode.cpp2
-rw-r--r--Source/Core/Core/Src/GeckoCodeConfig.cpp3
-rw-r--r--Source/Core/Core/Src/HW/AudioInterface.cpp6
-rw-r--r--Source/Core/Core/Src/HW/CPU.cpp5
-rw-r--r--Source/Core/Core/Src/HW/DSP.cpp8
-rw-r--r--Source/Core/Core/Src/HW/DSPHLE/DSPHLE.cpp1
-rw-r--r--Source/Core/Core/Src/HW/DSPHLE/UCodes/UCode_AX.cpp934
-rw-r--r--Source/Core/Core/Src/HW/DSPHLE/UCodes/UCode_AX.h170
-rw-r--r--Source/Core/Core/Src/HW/DSPHLE/UCodes/UCode_AXWii.cpp15
-rw-r--r--Source/Core/Core/Src/HW/DSPHLE/UCodes/UCode_AXWii.h2
-rw-r--r--Source/Core/Core/Src/HW/DSPHLE/UCodes/UCode_AXWii_ADPCM.h (renamed from Source/Core/Core/Src/HW/DSPHLE/UCodes/UCode_AX_ADPCM.h)0
-rw-r--r--Source/Core/Core/Src/HW/DSPHLE/UCodes/UCode_AXWii_Structs.h (renamed from Source/Core/Core/Src/HW/DSPHLE/UCodes/UCode_AXStructs.h)0
-rw-r--r--Source/Core/Core/Src/HW/DSPHLE/UCodes/UCode_AXWii_Voice.h271
-rw-r--r--Source/Core/Core/Src/HW/DSPHLE/UCodes/UCode_AX_Structs.h392
-rw-r--r--Source/Core/Core/Src/HW/DSPHLE/UCodes/UCode_AX_Voice.h536
-rw-r--r--Source/Core/Core/Src/HW/DSPHLE/UCodes/UCode_NewAXWii.cpp383
-rw-r--r--Source/Core/Core/Src/HW/DSPHLE/UCodes/UCode_NewAXWii.h80
-rw-r--r--Source/Core/Core/Src/HW/DSPHLE/UCodes/UCodes.cpp11
-rw-r--r--Source/Core/Core/Src/HW/DSPLLE/DSPDebugInterface.cpp2
-rw-r--r--Source/Core/Core/Src/HW/DSPLLE/DSPDebugInterface.h2
-rw-r--r--Source/Core/Core/Src/HW/DVDInterface.cpp12
-rw-r--r--Source/Core/Core/Src/HW/EXI_DeviceMemoryCard.cpp3
-rw-r--r--Source/Core/Core/Src/HW/GCMemcard.cpp94
-rw-r--r--Source/Core/Core/Src/HW/GCMemcard.h6
-rw-r--r--Source/Core/Core/Src/HW/Memmap.cpp2
-rw-r--r--Source/Core/Core/Src/HW/SI.cpp2
-rw-r--r--Source/Core/Core/Src/HW/SI_DeviceAMBaseboard.cpp4
-rw-r--r--Source/Core/Core/Src/HW/SI_DeviceGCController.cpp6
-rw-r--r--Source/Core/Core/Src/HW/Wiimote.cpp6
-rw-r--r--Source/Core/Core/Src/HW/WiimoteEmu/EmuSubroutines.cpp70
-rw-r--r--Source/Core/Core/Src/HW/WiimoteEmu/WiimoteEmu.cpp4
-rw-r--r--Source/Core/Core/Src/HW/WiimoteReal/IOdarwin.mm8
-rw-r--r--Source/Core/Core/Src/HW/WiimoteReal/WiimoteReal.cpp4
-rw-r--r--Source/Core/Core/Src/IPC_HLE/WII_IPC_HLE.cpp2
-rw-r--r--Source/Core/Core/Src/IPC_HLE/WII_IPC_HLE_Device.h9
-rw-r--r--Source/Core/Core/Src/IPC_HLE/WII_IPC_HLE_Device_FileIO.cpp10
-rw-r--r--Source/Core/Core/Src/IPC_HLE/WII_IPC_HLE_Device_es.cpp60
-rw-r--r--Source/Core/Core/Src/IPC_HLE/WII_IPC_HLE_Device_net.cpp29
-rw-r--r--Source/Core/Core/Src/IPC_HLE/WII_IPC_HLE_Device_usb.cpp105
-rw-r--r--Source/Core/Core/Src/IPC_HLE/WII_IPC_HLE_WiiMote.cpp1
-rw-r--r--Source/Core/Core/Src/Movie.cpp487
-rw-r--r--Source/Core/Core/Src/Movie.h65
-rw-r--r--Source/Core/Core/Src/PowerPC/Interpreter/Interpreter_Tables.cpp2
-rw-r--r--Source/Core/Core/Src/PowerPC/Jit64/Jit64_Tables.cpp2
-rw-r--r--Source/Core/Core/Src/PowerPC/Jit64/Jit_Integer.cpp8
-rw-r--r--Source/Core/Core/Src/PowerPC/Jit64IL/IR_X86.cpp4
-rw-r--r--Source/Core/Core/Src/PowerPC/Jit64IL/JitIL_Tables.cpp2
-rw-r--r--Source/Core/Core/Src/State.cpp34
-rw-r--r--Source/Core/DolphinWX/CMakeLists.txt29
-rw-r--r--Source/Core/DolphinWX/Dolphin.vcxproj20
-rw-r--r--Source/Core/DolphinWX/DolphinWX.rc4
-rw-r--r--Source/Core/DolphinWX/Src/AboutDolphin.cpp2
-rw-r--r--Source/Core/DolphinWX/Src/CheatsWindow.cpp3
-rw-r--r--Source/Core/DolphinWX/Src/ConfigMain.cpp13
-rw-r--r--Source/Core/DolphinWX/Src/ConfigMain.h2
-rw-r--r--Source/Core/DolphinWX/Src/Debugger/CodeWindow.cpp4
-rw-r--r--Source/Core/DolphinWX/Src/Debugger/DSPDebugWindow.cpp6
-rw-r--r--Source/Core/DolphinWX/Src/Debugger/DSPDebugWindow.h2
-rw-r--r--Source/Core/DolphinWX/Src/FifoPlayerDlg.cpp18
-rw-r--r--Source/Core/DolphinWX/Src/FifoPlayerDlg.h1
-rw-r--r--Source/Core/DolphinWX/Src/Frame.cpp60
-rw-r--r--Source/Core/DolphinWX/Src/Frame.h2
-rw-r--r--Source/Core/DolphinWX/Src/FrameTools.cpp54
-rw-r--r--Source/Core/DolphinWX/Src/GLInterface.h75
-rw-r--r--Source/Core/DolphinWX/Src/GLInterface/AGL.cpp123
-rw-r--r--Source/Core/DolphinWX/Src/GLInterface/AGL.h37
-rw-r--r--Source/Core/DolphinWX/Src/GLInterface/EGL.cpp190
-rw-r--r--Source/Core/DolphinWX/Src/GLInterface/EGL.h44
-rw-r--r--Source/Core/DolphinWX/Src/GLInterface/GLX.cpp151
-rw-r--r--Source/Core/DolphinWX/Src/GLInterface/GLX.h41
-rw-r--r--Source/Core/DolphinWX/Src/GLInterface/InterfaceBase.h38
-rw-r--r--Source/Core/DolphinWX/Src/GLInterface/WGL.cpp179
-rw-r--r--Source/Core/DolphinWX/Src/GLInterface/WGL.h41
-rw-r--r--Source/Core/DolphinWX/Src/GLInterface/WX.cpp82
-rw-r--r--Source/Core/DolphinWX/Src/GLInterface/WX.h47
-rw-r--r--Source/Core/DolphinWX/Src/GLInterface/X11_Util.cpp213
-rw-r--r--Source/Core/DolphinWX/Src/GLInterface/X11_Util.h31
-rw-r--r--Source/Core/DolphinWX/Src/GameListCtrl.cpp47
-rw-r--r--Source/Core/DolphinWX/Src/GameListCtrl.h3
-rw-r--r--Source/Core/DolphinWX/Src/Globals.h2
-rw-r--r--Source/Core/DolphinWX/Src/ISOFile.cpp2
-rw-r--r--Source/Core/DolphinWX/Src/ISOProperties.cpp3
-rw-r--r--Source/Core/DolphinWX/Src/Main.cpp33
-rw-r--r--Source/Core/DolphinWX/Src/MemcardManager.cpp1
-rw-r--r--Source/Core/DolphinWX/Src/TASInputDlg.cpp1
-rw-r--r--Source/Core/DolphinWX/Src/VideoConfigDiag.h2
-rw-r--r--Source/Core/DolphinWX/Src/WiimoteConfigDiag.h2
-rw-r--r--Source/Core/DolphinWX/Src/X11Utils.cpp2
-rw-r--r--Source/Core/InputCommon/Src/ControllerInterface/Xlib/Xlib.cpp4
-rw-r--r--Source/Core/VideoCommon/Src/BPFunctions.cpp2
-rw-r--r--Source/Core/VideoCommon/Src/BPStructs.cpp9
-rw-r--r--Source/Core/VideoCommon/Src/DLCache.cpp8
-rw-r--r--Source/Core/VideoCommon/Src/Debugger.h12
-rw-r--r--Source/Core/VideoCommon/Src/Fifo.cpp1
-rw-r--r--Source/Core/VideoCommon/Src/FramebufferManagerBase.cpp31
-rw-r--r--Source/Core/VideoCommon/Src/FramebufferManagerBase.h11
-rw-r--r--Source/Core/VideoCommon/Src/MainBase.cpp14
-rw-r--r--Source/Core/VideoCommon/Src/OnScreenDisplay.cpp3
-rw-r--r--Source/Core/VideoCommon/Src/PixelShaderGen.cpp19
-rw-r--r--Source/Core/VideoCommon/Src/PixelShaderManager.cpp1
-rw-r--r--Source/Core/VideoCommon/Src/RenderBase.cpp240
-rw-r--r--Source/Core/VideoCommon/Src/RenderBase.h27
-rw-r--r--Source/Core/VideoCommon/Src/TextureCacheBase.cpp26
-rw-r--r--Source/Core/VideoCommon/Src/VertexLoader.cpp10
-rw-r--r--Source/Core/VideoCommon/Src/VertexLoaderManager.cpp19
-rw-r--r--Source/Core/VideoCommon/Src/VertexManagerBase.cpp4
-rw-r--r--Source/Core/VideoCommon/Src/VertexManagerBase.h5
-rw-r--r--Source/Core/VideoCommon/Src/VertexShaderManager.cpp2
-rw-r--r--Source/Core/VideoCommon/Src/VideoConfig.cpp122
-rw-r--r--Source/Core/VideoCommon/Src/VideoConfig.h8
-rw-r--r--Source/Core/VideoCommon/Src/XFStructs.cpp67
-rw-r--r--Source/Core/VideoCommon/VideoCommon.vcxproj8
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>