diff options
Diffstat (limited to 'Source/Core')
160 files changed, 3760 insertions, 2438 deletions
diff --git a/Source/Core/AudioCommon/AudioCommon.vcxproj b/Source/Core/AudioCommon/AudioCommon.vcxproj index a82ab9aecc..0c5f256c19 100644 --- a/Source/Core/AudioCommon/AudioCommon.vcxproj +++ b/Source/Core/AudioCommon/AudioCommon.vcxproj @@ -210,7 +210,6 @@ </ItemGroup> <ItemGroup> <None Include="CMakeLists.txt" /> - <None Include="Src\SConscript" /> </ItemGroup> <ItemGroup> <ProjectReference Include="..\Common\Common.vcxproj"> diff --git a/Source/Core/AudioCommon/AudioCommon.vcxproj.filters b/Source/Core/AudioCommon/AudioCommon.vcxproj.filters index f3fd6b4aaa..7e098ecb85 100644 --- a/Source/Core/AudioCommon/AudioCommon.vcxproj.filters +++ b/Source/Core/AudioCommon/AudioCommon.vcxproj.filters @@ -46,7 +46,6 @@ </ClInclude> </ItemGroup> <ItemGroup> - <None Include="Src\SConscript" /> <None Include="CMakeLists.txt" /> </ItemGroup> <ItemGroup> diff --git a/Source/Core/AudioCommon/SConscript b/Source/Core/AudioCommon/SConscript deleted file mode 100644 index 5c953c4e58..0000000000 --- a/Source/Core/AudioCommon/SConscript +++ /dev/null @@ -1,29 +0,0 @@ -# -*- python -*- - -Import('env') -import sys - -files = [ - 'Src/AudioCommon.cpp', - 'Src/AudioCommonConfig.cpp', - 'Src/Mixer.cpp', - 'Src/NullSoundStream.cpp', - 'Src/WaveFile.cpp', - ] - -if sys.platform == 'darwin': - files += ['Src/CoreAudioSoundStream.cpp'] -elif sys.platform == 'win32': - files += ['Src/DSoundStream.cpp'] - files += ['Src/XAudio2Stream.cpp'] -else: - if env['HAVE_ALSA']: - files += ['Src/AlsaSoundStream.cpp'] - if env['HAVE_AO']: - files += ['Src/AOSoundStream.cpp'] - if env['HAVE_OPENAL']: - files += ['Src/OpenALStream.cpp', 'Src/aldlist.cpp'] - if env['HAVE_PULSEAUDIO']: - files += ['Src/PulseAudioStream.cpp'] - -env['LIBS'] += env.StaticLibrary('audiocommon', files) diff --git a/Source/Core/AudioCommon/Src/AudioCommonConfig.cpp b/Source/Core/AudioCommon/Src/AudioCommonConfig.cpp index 533c6b4313..08902e1c3f 100644 --- a/Source/Core/AudioCommon/Src/AudioCommonConfig.cpp +++ b/Source/Core/AudioCommon/Src/AudioCommonConfig.cpp @@ -31,7 +31,6 @@ void AudioCommonConfig::Load() IniFile file; file.Load(File::GetUserPath(F_DSPCONFIG_IDX)); - file.Get("Config", "EnableDTKMusic", &m_EnableDTKMusic, true); file.Get("Config", "EnableJIT", &m_EnableJIT, true); file.Get("Config", "DumpAudio", &m_DumpAudio, false); #if defined __linux__ && HAVE_ALSA @@ -53,7 +52,6 @@ void AudioCommonConfig::SaveSettings() IniFile file; file.Load(File::GetUserPath(F_DSPCONFIG_IDX)); - file.Set("Config", "EnableDTKMusic", m_EnableDTKMusic); file.Set("Config", "EnableJIT", m_EnableJIT); file.Set("Config", "DumpAudio", m_DumpAudio); file.Set("Config", "Backend", sBackend); @@ -67,7 +65,6 @@ void AudioCommonConfig::SaveSettings() void AudioCommonConfig::Update() { if (soundStream) { soundStream->GetMixer()->SetThrottle(SConfig::GetInstance().m_Framelimit == 2); - soundStream->GetMixer()->SetDTKMusic(m_EnableDTKMusic); soundStream->SetVolume(m_Volume); } } diff --git a/Source/Core/AudioCommon/Src/AudioCommonConfig.h b/Source/Core/AudioCommon/Src/AudioCommonConfig.h index 076ef2d4e1..76c50c6408 100644 --- a/Source/Core/AudioCommon/Src/AudioCommonConfig.h +++ b/Source/Core/AudioCommon/Src/AudioCommonConfig.h @@ -33,7 +33,6 @@ struct AudioCommonConfig { - bool m_EnableDTKMusic; bool m_EnableJIT; bool m_DumpAudio; int m_Volume; diff --git a/Source/Core/AudioCommon/Src/Mixer.cpp b/Source/Core/AudioCommon/Src/Mixer.cpp index 6ee0ddbf7a..8340df8b59 100644 --- a/Source/Core/AudioCommon/Src/Mixer.cpp +++ b/Source/Core/AudioCommon/Src/Mixer.cpp @@ -136,8 +136,7 @@ unsigned int CMixer::Mix(short* samples, unsigned int numSamples) if (m_AIplaying) { Premix(samples, numLeft); - if (m_EnableDTKMusic) - AudioInterface::Callback_GetStreaming(samples, numLeft, m_sampleRate); + AudioInterface::Callback_GetStreaming(samples, numLeft, m_sampleRate); g_wave_writer.AddStereoSamples(samples, numLeft); } @@ -147,11 +146,8 @@ unsigned int CMixer::Mix(short* samples, unsigned int numSamples) Premix(samples, numSamples); // Add the DTK Music - if (m_EnableDTKMusic) - { - // Re-sampling is done inside - AudioInterface::Callback_GetStreaming(samples, numSamples, m_sampleRate); - } + // Re-sampling is done inside + AudioInterface::Callback_GetStreaming(samples, numSamples, m_sampleRate); } diff --git a/Source/Core/AudioCommon/Src/Mixer.h b/Source/Core/AudioCommon/Src/Mixer.h index 95d89d7334..f850b58add 100644 --- a/Source/Core/AudioCommon/Src/Mixer.h +++ b/Source/Core/AudioCommon/Src/Mixer.h @@ -61,7 +61,6 @@ public: unsigned int GetSampleRate() {return m_sampleRate;} void SetThrottle(bool use) { m_throttle = use;} - void SetDTKMusic(bool use) { m_EnableDTKMusic = use;} // TODO: do we need this bool IsHLEReady() { return m_HLEready;} @@ -103,7 +102,6 @@ protected: bool m_HLEready; bool m_logAudio; - bool m_EnableDTKMusic; bool m_throttle; short m_buffer[MAX_SAMPLES * 2]; diff --git a/Source/Core/Common/Common.vcxproj b/Source/Core/Common/Common.vcxproj index a67da7fcf9..626204f344 100644 --- a/Source/Core/Common/Common.vcxproj +++ b/Source/Core/Common/Common.vcxproj @@ -108,27 +108,21 @@ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" /> <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='DebugFast|x64'" /> <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> - <ClCompile> - <AdditionalIncludeDirectories>.\Src;..\..\..\Externals/CLRun/include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> - </ClCompile> + <ClCompile /> <Link> <GenerateDebugInformation>true</GenerateDebugInformation> </Link> <Lib /> </ItemDefinitionGroup> <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> - <ClCompile> - <AdditionalIncludeDirectories>.\Src;..\..\..\Externals/CLRun/include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> - </ClCompile> + <ClCompile /> <Link> <GenerateDebugInformation>true</GenerateDebugInformation> </Link> <Lib /> </ItemDefinitionGroup> <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> - <ClCompile> - <AdditionalIncludeDirectories>.\Src;..\..\..\Externals/CLRun/include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> - </ClCompile> + <ClCompile /> <Link> <GenerateDebugInformation>true</GenerateDebugInformation> <EnableCOMDATFolding>true</EnableCOMDATFolding> @@ -137,9 +131,7 @@ <Lib /> </ItemDefinitionGroup> <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='DebugFast|Win32'"> - <ClCompile> - <AdditionalIncludeDirectories>.\Src;..\..\..\Externals/CLRun/include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> - </ClCompile> + <ClCompile /> <Link> <GenerateDebugInformation>true</GenerateDebugInformation> <EnableCOMDATFolding>true</EnableCOMDATFolding> @@ -148,9 +140,7 @@ <Lib /> </ItemDefinitionGroup> <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> - <ClCompile> - <AdditionalIncludeDirectories>.\Src;..\..\..\Externals/CLRun/include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> - </ClCompile> + <ClCompile /> <Link> <GenerateDebugInformation>true</GenerateDebugInformation> <EnableCOMDATFolding>true</EnableCOMDATFolding> @@ -159,9 +149,7 @@ <Lib /> </ItemDefinitionGroup> <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='DebugFast|x64'"> - <ClCompile> - <AdditionalIncludeDirectories>.\Src;..\..\..\Externals/CLRun/include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> - </ClCompile> + <ClCompile /> <Link> <GenerateDebugInformation>true</GenerateDebugInformation> <EnableCOMDATFolding>true</EnableCOMDATFolding> @@ -270,7 +258,6 @@ </ItemGroup> <ItemGroup> <None Include="CMakeLists.txt" /> - <None Include="Src\SConscript" /> </ItemGroup> <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" /> <ImportGroup Label="ExtensionTargets"> diff --git a/Source/Core/Common/Common.vcxproj.filters b/Source/Core/Common/Common.vcxproj.filters index 852ce5e6ad..6ae75788ce 100644 --- a/Source/Core/Common/Common.vcxproj.filters +++ b/Source/Core/Common/Common.vcxproj.filters @@ -126,7 +126,6 @@ </ItemGroup> <ItemGroup> <None Include="CMakeLists.txt" /> - <None Include="Src\SConscript" /> </ItemGroup> <ItemGroup> <Filter Include="Crypto"> diff --git a/Source/Core/Common/SConscript b/Source/Core/Common/SConscript deleted file mode 100644 index f26dfc044c..0000000000 --- a/Source/Core/Common/SConscript +++ /dev/null @@ -1,60 +0,0 @@ -# -*- python -*- - -Import('env') -import os -import sys - -out_contents =\ - '#define SCM_REV_STR "' + env['gitrev'] + '"\n' +\ - '#define SCM_DESC_STR "' + env['gitdesc'] + '"\n' +\ - '#define SCM_BRANCH_STR "' + env['gitbranch'] + '"\n' +\ - '#define SCM_IS_MASTER ' + ('1' if env['gitbranch'] == 'master' else '0') + '\n\n' - -Execute(Delete('Src/scmrev.h')) -outfile = open('Src/scmrev.h', 'w') -outfile.write(out_contents) -outfile.close() - -files = [ - 'Src/ABI.cpp', - 'Src/BreakPoints.cpp', - 'Src/CDUtils.cpp', - 'Src/CPUDetect.cpp', - 'Src/ColorUtil.cpp', - 'Src/ConsoleListener.cpp', - 'Src/Crypto/aes_cbc.cpp', - 'Src/Crypto/aes_core.cpp', - 'Src/Crypto/bn.cpp', - 'Src/Crypto/ec.cpp', - 'Src/Crypto/md5.cpp', - 'Src/Crypto/sha1.cpp', - 'Src/FileSearch.cpp', - 'Src/FileUtil.cpp', - 'Src/Hash.cpp', - 'Src/IniFile.cpp', - 'Src/LogManager.cpp', - 'Src/MathUtil.cpp', - 'Src/MemArena.cpp', - 'Src/MemoryUtil.cpp', - 'Src/Misc.cpp', - 'Src/MsgHandler.cpp', - 'Src/NandPaths.cpp', - 'Src/SDCardUtil.cpp', - 'Src/StringUtil.cpp', - 'Src/SymbolDB.cpp', - 'Src/SysConf.cpp', - 'Src/Thread.cpp', - 'Src/Thunk.cpp', - 'Src/Timer.cpp', - 'Src/Version.cpp', - 'Src/VideoBackendBase.cpp', - 'Src/x64Analyzer.cpp', - 'Src/x64Emitter.cpp', - ] - -if sys.platform == 'win32': - files += ['Src/ExtendedTrace.cpp'] - files += ['Src/stdafx.cpp'] - -env['CPPPATH'] += ['Src'] -env['LIBS'] += env.StaticLibrary('common', files) diff --git a/Source/Core/Common/SVNRevGen.vcxproj b/Source/Core/Common/SVNRevGen.vcxproj index 61e3aedb7b..803e059d19 100644 --- a/Source/Core/Common/SVNRevGen.vcxproj +++ b/Source/Core/Common/SVNRevGen.vcxproj @@ -7,13 +7,11 @@ </ProjectConfiguration> </ItemGroup> <ItemGroup> - <CustomBuild Include="make_scmrev.h.js"> - <Command Condition="'$(Configuration)|$(Platform)'=='Release|x64'">cscript /nologo /E:JScript "make_scmrev.h.js"</Command> - <Message Condition="'$(Configuration)|$(Platform)'=='Release|x64'">Updating scmrev.h</Message> - <Outputs Condition="'$(Configuration)|$(Platform)'=='Release|x64'">dummy</Outputs> - </CustomBuild> + <None Include="make_scmrev.h.js"> + </None> </ItemGroup> <ItemGroup> + <ClInclude Include="force_rebuild.h" /> <ClInclude Include="Src\scmrev.h" /> </ItemGroup> <PropertyGroup Label="Globals"> @@ -37,25 +35,9 @@ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" /> <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" /> <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> - <ClCompile> - <WarningLevel>Level3</WarningLevel> - <Optimization>MaxSpeed</Optimization> - <FunctionLevelLinking>true</FunctionLevelLinking> - <IntrinsicFunctions>true</IntrinsicFunctions> - </ClCompile> - <Link> - <GenerateDebugInformation>true</GenerateDebugInformation> - <EnableCOMDATFolding>true</EnableCOMDATFolding> - <OptimizeReferences>true</OptimizeReferences> - </Link> <PreBuildEvent> - <Command> - </Command> + <Command>cscript /nologo /E:JScript "make_scmrev.h.js"</Command> </PreBuildEvent> - <CustomBuild> - <Outputs> - </Outputs> - </CustomBuild> </ItemDefinitionGroup> <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" /> <ImportGroup Label="ExtensionTargets"> diff --git a/Source/Core/Common/Src/BreakPoints.cpp b/Source/Core/Common/Src/BreakPoints.cpp index 45a0b52daf..1700276d85 100644 --- a/Source/Core/Common/Src/BreakPoints.cpp +++ b/Source/Core/Common/Src/BreakPoints.cpp @@ -18,6 +18,7 @@ #include "Common.h" #include "DebugInterface.h" #include "BreakPoints.h" +#include "../../Core/Src/PowerPC/JitCommon/JitBase.h" #include <sstream> bool BreakPoints::IsAddressBreakPoint(u32 _iAddress) @@ -70,7 +71,11 @@ void BreakPoints::AddFromStrings(const TBreakPointsStr& bps) void BreakPoints::Add(const TBreakPoint& bp) { if (!IsAddressBreakPoint(bp.iAddress)) + { m_BreakPoints.push_back(bp); + if (jit) + jit->GetBlockCache()->InvalidateICache(bp.iAddress, 4); + } } void BreakPoints::Add(u32 em_address, bool temp) @@ -83,21 +88,35 @@ void BreakPoints::Add(u32 em_address, bool temp) pt.iAddress = em_address; m_BreakPoints.push_back(pt); + + if (jit) + jit->GetBlockCache()->InvalidateICache(em_address, 4); } } -void BreakPoints::Remove(u32 _iAddress) +void BreakPoints::Remove(u32 em_address) { for (TBreakPoints::iterator i = m_BreakPoints.begin(); i != m_BreakPoints.end(); ++i) { - if (i->iAddress == _iAddress) + if (i->iAddress == em_address) { m_BreakPoints.erase(i); + if (jit) + jit->GetBlockCache()->InvalidateICache(em_address, 4); return; } } } +void BreakPoints::Clear() +{ + for (TBreakPoints::iterator i = m_BreakPoints.begin(); i != m_BreakPoints.end(); ++i) + { + if (jit) + jit->GetBlockCache()->InvalidateICache(i->iAddress, 4); + m_BreakPoints.erase(i); + } +} MemChecks::TMemChecksStr MemChecks::GetStrings() const { diff --git a/Source/Core/Common/Src/BreakPoints.h b/Source/Core/Common/Src/BreakPoints.h index a97452cde6..c742f812a7 100644 --- a/Source/Core/Common/Src/BreakPoints.h +++ b/Source/Core/Common/Src/BreakPoints.h @@ -78,7 +78,7 @@ public: // Remove Breakpoint void Remove(u32 _iAddress); - void Clear() { m_BreakPoints.clear(); }; + void Clear(); void DeleteByAddress(u32 _Address); diff --git a/Source/Core/Common/Src/Common.h b/Source/Core/Common/Src/Common.h index db889f7ddf..960bf75559 100644 --- a/Source/Core/Common/Src/Common.h +++ b/Source/Core/Common/Src/Common.h @@ -103,8 +103,6 @@ private: //CrtDebugBreak breakAt(614); #endif // end DEBUG/FAST -#elif defined HAVE_CONFIG_H -#include "config.h" // SCons autoconfiguration defines #endif // Windows compatibility diff --git a/Source/Core/Common/Src/CommonFuncs.h b/Source/Core/Common/Src/CommonFuncs.h index 74d317d95f..585fe0999a 100644 --- a/Source/Core/Common/Src/CommonFuncs.h +++ b/Source/Core/Common/Src/CommonFuncs.h @@ -21,6 +21,7 @@ #ifdef _WIN32 #define SLEEP(x) Sleep(x) #else +#include <unistd.h> #define SLEEP(x) usleep(x*1000) #endif diff --git a/Source/Core/Common/Src/CommonPaths.h b/Source/Core/Common/Src/CommonPaths.h index f8aad00a89..389d10a35d 100644 --- a/Source/Core/Common/Src/CommonPaths.h +++ b/Source/Core/Common/Src/CommonPaths.h @@ -121,6 +121,8 @@ #define GC_MEMCARDA "MemoryCardA" #define GC_MEMCARDB "MemoryCardB" +#define WII_STATE "state.dat" + #define WII_SETTING "setting.txt" #define GECKO_CODE_HANDLER "codehandler.bin" diff --git a/Source/Core/Common/Src/LinearDiskCache.h b/Source/Core/Common/Src/LinearDiskCache.h index f6e0d95f8c..4c746e9b75 100644 --- a/Source/Core/Common/Src/LinearDiskCache.h +++ b/Source/Core/Common/Src/LinearDiskCache.h @@ -24,7 +24,7 @@ // Increment this every time you change shader generation code. enum { - LINEAR_DISKCACHE_VER = 6972 + LINEAR_DISKCACHE_VER = 6975 }; // On disk format: diff --git a/Source/Core/Common/Src/MathUtil.h b/Source/Core/Common/Src/MathUtil.h index ecace1fb4a..a6290ff602 100644 --- a/Source/Core/Common/Src/MathUtil.h +++ b/Source/Core/Common/Src/MathUtil.h @@ -161,6 +161,7 @@ void LoadDefaultSSEState(); float MathFloatVectorSum(const std::vector<float>&); #define ROUND_UP(x, a) (((x) + (a) - 1) & ~((a) - 1)) +#define ROUND_DOWN(x, a) ((x) & ~((a) - 1)) // Tiny matrix/vector library. diff --git a/Source/Core/Common/Src/MemoryUtil.cpp b/Source/Core/Common/Src/MemoryUtil.cpp index 3e3cafa335..ebfa380be4 100644 --- a/Source/Core/Common/Src/MemoryUtil.cpp +++ b/Source/Core/Common/Src/MemoryUtil.cpp @@ -1,207 +1,207 @@ -// Copyright (C) 2003 Dolphin Project. - -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, version 2.0. - -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License 2.0 for more details. - -// A copy of the GPL 2.0 should have been included with the program. -// If not, see http://www.gnu.org/licenses/ - -// Official SVN repository and contact information can be found at -// http://code.google.com/p/dolphin-emu/ - -#include "Common.h" -#include "MemoryUtil.h" -#include "StringUtil.h" - -#ifdef _WIN32 -#include <windows.h> -#include <psapi.h> -#else -#include <errno.h> -#include <stdio.h> -#endif - -#if !defined(_WIN32) && defined(__x86_64__) && !defined(MAP_32BIT) -#include <unistd.h> -#define PAGE_MASK (getpagesize() - 1) -#define round_page(x) ((((unsigned long)(x)) + PAGE_MASK) & ~(PAGE_MASK)) -#endif - -// This is purposely not a full wrapper for virtualalloc/mmap, but it -// provides exactly the primitive operations that Dolphin needs. - -void* AllocateExecutableMemory(size_t size, bool low) -{ +// Copyright (C) 2003 Dolphin Project.
+
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, version 2.0.
+
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License 2.0 for more details.
+
+// A copy of the GPL 2.0 should have been included with the program.
+// If not, see http://www.gnu.org/licenses/
+
+// Official SVN repository and contact information can be found at
+// http://code.google.com/p/dolphin-emu/
+
+#include "Common.h"
+#include "MemoryUtil.h"
+#include "StringUtil.h"
+
+#ifdef _WIN32
+#include <windows.h>
+#include <psapi.h>
+#else
+#include <errno.h>
+#include <stdio.h>
+#endif
+
+#if !defined(_WIN32) && defined(__x86_64__) && !defined(MAP_32BIT)
+#include <unistd.h>
+#define PAGE_MASK (getpagesize() - 1)
+#define round_page(x) ((((unsigned long)(x)) + PAGE_MASK) & ~(PAGE_MASK))
+#endif
+
+// This is purposely not a full wrapper for virtualalloc/mmap, but it
+// provides exactly the primitive operations that Dolphin needs.
+
+void* AllocateExecutableMemory(size_t size, bool low)
+{
#if defined(_WIN32)
void* ptr = VirtualAlloc(0, size, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
-#else - static char *map_hint = 0; -#if defined(__x86_64__) && !defined(MAP_32BIT) - // This OS has no flag to enforce allocation below the 4 GB boundary, - // but if we hint that we want a low address it is very likely we will - // get one. - // An older version of this code used MAP_FIXED, but that has the side - // effect of discarding already mapped pages that happen to be in the - // requested virtual memory range (such as the emulated RAM, sometimes). - if (low && (!map_hint)) - map_hint = (char*)round_page(512*1024*1024); /* 0.5 GB rounded up to the next page */ -#endif - void* ptr = mmap(map_hint, size, PROT_READ | PROT_WRITE | PROT_EXEC, - MAP_ANON | MAP_PRIVATE -#if defined(__x86_64__) && defined(MAP_32BIT) - | (low ? MAP_32BIT : 0) -#endif - , -1, 0); -#endif /* defined(_WIN32) */ - - // printf("Mapped executable memory at %p (size %ld)\n", ptr, - // (unsigned long)size); - -#if defined(__FreeBSD__) - if (ptr == MAP_FAILED) - { - ptr = NULL; -#else - if (ptr == NULL) - { -#endif - PanicAlert("Failed to allocate executable memory"); - } -#if !defined(_WIN32) && defined(__x86_64__) && !defined(MAP_32BIT) - else - { - if (low) - { - map_hint += size; - map_hint = (char*)round_page(map_hint); /* round up to the next page */ - // printf("Next map will (hopefully) be at %p\n", map_hint); - } - } -#endif - -#if defined(_M_X64) - if ((u64)ptr >= 0x80000000 && low == true) - PanicAlert("Executable memory ended up above 2GB!"); -#endif - - return ptr; -} - -void* AllocateMemoryPages(size_t size) -{ -#ifdef _WIN32 - void* ptr = VirtualAlloc(0, size, MEM_COMMIT, PAGE_READWRITE); -#else - void* ptr = mmap(0, size, PROT_READ | PROT_WRITE, - MAP_ANON | MAP_PRIVATE, -1, 0); -#endif - - // printf("Mapped memory at %p (size %ld)\n", ptr, - // (unsigned long)size); - - if (ptr == NULL) - PanicAlert("Failed to allocate raw memory"); - - return ptr; -} - -void* AllocateAlignedMemory(size_t size,size_t alignment) -{ -#ifdef _WIN32 - void* ptr = _aligned_malloc(size,alignment); -#else - void* ptr = NULL; - posix_memalign(&ptr, alignment, size); -; -#endif - - // printf("Mapped memory at %p (size %ld)\n", ptr, - // (unsigned long)size); - - if (ptr == NULL) - PanicAlert("Failed to allocate aligned memory"); - - return ptr; -} - -void FreeMemoryPages(void* ptr, size_t size) -{ - if (ptr) - { -#ifdef _WIN32 - - if (!VirtualFree(ptr, 0, MEM_RELEASE)) - PanicAlert("FreeMemoryPages failed!\n%s", GetLastErrorMsg()); - ptr = NULL; // Is this our responsibility? - -#else - munmap(ptr, size); -#endif - } -} - -void FreeAlignedMemory(void* ptr) -{ - if (ptr) - { -#ifdef _WIN32 - - _aligned_free(ptr); - -#else - free(ptr); -#endif - } -} - -void WriteProtectMemory(void* ptr, size_t size, bool allowExecute) -{ -#ifdef _WIN32 - DWORD oldValue; - if (!VirtualProtect(ptr, size, allowExecute ? PAGE_EXECUTE_READ : PAGE_READONLY, &oldValue)) - PanicAlert("WriteProtectMemory failed!\n%s", GetLastErrorMsg()); -#else - mprotect(ptr, size, allowExecute ? (PROT_READ | PROT_EXEC) : PROT_READ); -#endif -} - -void UnWriteProtectMemory(void* ptr, size_t size, bool allowExecute) -{ -#ifdef _WIN32 - DWORD oldValue; - if (!VirtualProtect(ptr, size, allowExecute ? PAGE_EXECUTE_READWRITE : PAGE_READWRITE, &oldValue)) - PanicAlert("UnWriteProtectMemory failed!\n%s", GetLastErrorMsg()); -#else - mprotect(ptr, size, allowExecute ? (PROT_READ | PROT_WRITE | PROT_EXEC) : PROT_WRITE | PROT_READ); -#endif -} - -std::string MemUsage() -{ -#ifdef _WIN32 -#pragma comment(lib, "psapi") - DWORD processID = GetCurrentProcessId(); - HANDLE hProcess; - PROCESS_MEMORY_COUNTERS pmc; - std::string Ret; - - // Print information about the memory usage of the process. - - hProcess = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, processID); - if (NULL == hProcess) return "MemUsage Error"; - - if (GetProcessMemoryInfo(hProcess, &pmc, sizeof(pmc))) - Ret = StringFromFormat("%s K", ThousandSeparate(pmc.WorkingSetSize / 1024, 7).c_str()); - - CloseHandle(hProcess); - return Ret; -#else - return ""; -#endif -} +#else
+ static char *map_hint = 0;
+#if defined(__x86_64__) && !defined(MAP_32BIT)
+ // This OS has no flag to enforce allocation below the 4 GB boundary,
+ // but if we hint that we want a low address it is very likely we will
+ // get one.
+ // An older version of this code used MAP_FIXED, but that has the side
+ // effect of discarding already mapped pages that happen to be in the
+ // requested virtual memory range (such as the emulated RAM, sometimes).
+ if (low && (!map_hint))
+ map_hint = (char*)round_page(512*1024*1024); /* 0.5 GB rounded up to the next page */
+#endif
+ void* ptr = mmap(map_hint, size, PROT_READ | PROT_WRITE | PROT_EXEC,
+ MAP_ANON | MAP_PRIVATE
+#if defined(__x86_64__) && defined(MAP_32BIT)
+ | (low ? MAP_32BIT : 0)
+#endif
+ , -1, 0);
+#endif /* defined(_WIN32) */
+
+ // printf("Mapped executable memory at %p (size %ld)\n", ptr,
+ // (unsigned long)size);
+
+#if defined(__FreeBSD__)
+ if (ptr == MAP_FAILED)
+ {
+ ptr = NULL;
+#else
+ if (ptr == NULL)
+ {
+#endif
+ PanicAlert("Failed to allocate executable memory");
+ }
+#if !defined(_WIN32) && defined(__x86_64__) && !defined(MAP_32BIT)
+ else
+ {
+ if (low)
+ {
+ map_hint += size;
+ map_hint = (char*)round_page(map_hint); /* round up to the next page */
+ // printf("Next map will (hopefully) be at %p\n", map_hint);
+ }
+ }
+#endif
+
+#if defined(_M_X64)
+ if ((u64)ptr >= 0x80000000 && low == true)
+ PanicAlert("Executable memory ended up above 2GB!");
+#endif
+
+ return ptr;
+}
+
+void* AllocateMemoryPages(size_t size)
+{
+#ifdef _WIN32
+ void* ptr = VirtualAlloc(0, size, MEM_COMMIT, PAGE_READWRITE);
+#else
+ void* ptr = mmap(0, size, PROT_READ | PROT_WRITE,
+ MAP_ANON | MAP_PRIVATE, -1, 0);
+#endif
+
+ // printf("Mapped memory at %p (size %ld)\n", ptr,
+ // (unsigned long)size);
+
+ if (ptr == NULL)
+ PanicAlert("Failed to allocate raw memory");
+
+ return ptr;
+}
+
+void* AllocateAlignedMemory(size_t size,size_t alignment)
+{
+#ifdef _WIN32
+ void* ptr = _aligned_malloc(size,alignment);
+#else
+ void* ptr = NULL;
+ posix_memalign(&ptr, alignment, size);
+;
+#endif
+
+ // printf("Mapped memory at %p (size %ld)\n", ptr,
+ // (unsigned long)size);
+
+ if (ptr == NULL)
+ PanicAlert("Failed to allocate aligned memory");
+
+ return ptr;
+}
+
+void FreeMemoryPages(void* ptr, size_t size)
+{
+ if (ptr)
+ {
+#ifdef _WIN32
+
+ if (!VirtualFree(ptr, 0, MEM_RELEASE))
+ PanicAlert("FreeMemoryPages failed!\n%s", GetLastErrorMsg());
+ ptr = NULL; // Is this our responsibility?
+
+#else
+ munmap(ptr, size);
+#endif
+ }
+}
+
+void FreeAlignedMemory(void* ptr)
+{
+ if (ptr)
+ {
+#ifdef _WIN32
+
+ _aligned_free(ptr);
+
+#else
+ free(ptr);
+#endif
+ }
+}
+
+void WriteProtectMemory(void* ptr, size_t size, bool allowExecute)
+{
+#ifdef _WIN32
+ DWORD oldValue;
+ if (!VirtualProtect(ptr, size, allowExecute ? PAGE_EXECUTE_READ : PAGE_READONLY, &oldValue))
+ PanicAlert("WriteProtectMemory failed!\n%s", GetLastErrorMsg());
+#else
+ mprotect(ptr, size, allowExecute ? (PROT_READ | PROT_EXEC) : PROT_READ);
+#endif
+}
+
+void UnWriteProtectMemory(void* ptr, size_t size, bool allowExecute)
+{
+#ifdef _WIN32
+ DWORD oldValue;
+ if (!VirtualProtect(ptr, size, allowExecute ? PAGE_EXECUTE_READWRITE : PAGE_READWRITE, &oldValue))
+ PanicAlert("UnWriteProtectMemory failed!\n%s", GetLastErrorMsg());
+#else
+ mprotect(ptr, size, allowExecute ? (PROT_READ | PROT_WRITE | PROT_EXEC) : PROT_WRITE | PROT_READ);
+#endif
+}
+
+std::string MemUsage()
+{
+#ifdef _WIN32
+#pragma comment(lib, "psapi")
+ DWORD processID = GetCurrentProcessId();
+ HANDLE hProcess;
+ PROCESS_MEMORY_COUNTERS pmc;
+ std::string Ret;
+
+ // Print information about the memory usage of the process.
+
+ hProcess = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, processID);
+ if (NULL == hProcess) return "MemUsage Error";
+
+ if (GetProcessMemoryInfo(hProcess, &pmc, sizeof(pmc)))
+ Ret = StringFromFormat("%s K", ThousandSeparate(pmc.WorkingSetSize / 1024, 7).c_str());
+
+ CloseHandle(hProcess);
+ return Ret;
+#else
+ return "";
+#endif
+}
diff --git a/Source/Core/Common/Src/SysConf.cpp b/Source/Core/Common/Src/SysConf.cpp index ed8a4953e5..97170e5ff1 100644 --- a/Source/Core/Common/Src/SysConf.cpp +++ b/Source/Core/Common/Src/SysConf.cpp @@ -387,7 +387,7 @@ bool SysConf::SaveToFile(const char *filename) } else if (i->type == Type_SmallArray) { - const u8 len = i->dataLength; + const u8 len = (u8)(i->dataLength); f.WriteArray(&len, 1); } diff --git a/Source/Core/Common/Src/VideoBackendBase.h b/Source/Core/Common/Src/VideoBackendBase.h index 28c8f23246..96f639832b 100644 --- a/Source/Core/Common/Src/VideoBackendBase.h +++ b/Source/Core/Common/Src/VideoBackendBase.h @@ -119,6 +119,7 @@ public: virtual void Video_GatherPipeBursted() = 0; virtual bool Video_IsPossibleWaitingSetDrawDone() = 0; + virtual bool Video_IsHiWatermarkActive() = 0; virtual void Video_AbortFrame() = 0; virtual readFn16 Video_CPRead16() = 0; @@ -159,6 +160,7 @@ class VideoBackendHardware : public VideoBackend void Video_GatherPipeBursted(); bool Video_IsPossibleWaitingSetDrawDone(); + bool Video_IsHiWatermarkActive(); void Video_AbortFrame(); readFn16 Video_CPRead16(); diff --git a/Source/Core/Core/Core.vcxproj b/Source/Core/Core/Core.vcxproj index ebc99609ae..8708d705a7 100644 --- a/Source/Core/Core/Core.vcxproj +++ b/Source/Core/Core/Core.vcxproj @@ -576,7 +576,6 @@ <ItemGroup> <None Include="CMakeLists.txt" /> <None Include="Src\HW\DSPHLE\UCodes\UCode_Zelda_Obsolete.txt" /> - <None Include="Src\SConscript" /> </ItemGroup> <ItemGroup> <ProjectReference Include="..\..\..\Externals\Bochs_disasm\Bochs_disasm.vcxproj"> diff --git a/Source/Core/Core/Core.vcxproj.filters b/Source/Core/Core/Core.vcxproj.filters index 4be518a554..de98a57e9d 100644 --- a/Source/Core/Core/Core.vcxproj.filters +++ b/Source/Core/Core/Core.vcxproj.filters @@ -1051,7 +1051,6 @@ </ItemGroup> <ItemGroup> <None Include="CMakeLists.txt" /> - <None Include="Src\SConscript" /> <None Include="Src\HW\DSPHLE\UCodes\UCode_Zelda_Obsolete.txt"> <Filter>HW %28Flipper/Hollywood%29\DSP Interface + HLE\HLE\uCodes</Filter> </None> diff --git a/Source/Core/Core/SConscript b/Source/Core/Core/SConscript deleted file mode 100644 index 3dafad8a62..0000000000 --- a/Source/Core/Core/SConscript +++ /dev/null @@ -1,215 +0,0 @@ -# -*- python -*- - -Import('env') -import sys - -files = [ - 'Src/ARDecrypt.cpp', - 'Src/ActionReplay.cpp', - 'Src/Boot/Boot.cpp', - 'Src/Boot/Boot_BS2Emu.cpp', - 'Src/Boot/Boot_DOL.cpp', - 'Src/Boot/Boot_ELF.cpp', - 'Src/Boot/Boot_WiiWAD.cpp', - 'Src/Boot/ElfReader.cpp', - 'Src/BootManager.cpp', - 'Src/ConfigManager.cpp', - 'Src/Console.cpp', - 'Src/Core.cpp', - 'Src/CoreParameter.cpp', - 'Src/CoreRerecording.cpp', - 'Src/CoreTiming.cpp', - 'Src/DSP/DSPAccelerator.cpp', - 'Src/DSP/DSPAnalyzer.cpp', - 'Src/DSP/DSPCodeUtil.cpp', - 'Src/DSP/DSPCore.cpp', - 'Src/DSP/DSPEmitter.cpp', - 'Src/DSP/DSPHWInterface.cpp', - 'Src/DSP/DSPIntCCUtil.cpp', - 'Src/DSP/DSPIntExtOps.cpp', - 'Src/DSP/DSPInterpreter.cpp', - 'Src/DSP/DSPMemoryMap.cpp', - 'Src/DSP/DSPStacks.cpp', - 'Src/DSP/DSPTables.cpp', - 'Src/DSP/DspIntArithmetic.cpp', - 'Src/DSP/DspIntBranch.cpp', - 'Src/DSP/DspIntLoadStore.cpp', - 'Src/DSP/DspIntMisc.cpp', - 'Src/DSP/DspIntMultiplier.cpp', - 'Src/DSP/Jit/DSPJitArithmetic.cpp', - 'Src/DSP/Jit/DSPJitBranch.cpp', - 'Src/DSP/Jit/DSPJitCCUtil.cpp', - 'Src/DSP/Jit/DSPJitExtOps.cpp', - 'Src/DSP/Jit/DSPJitLoadStore.cpp', - 'Src/DSP/Jit/DSPJitMisc.cpp', - 'Src/DSP/Jit/DSPJitMultiplier.cpp', - 'Src/DSP/Jit/DSPJitRegCache.cpp', - 'Src/DSP/Jit/DSPJitUtil.cpp', - 'Src/DSP/LabelMap.cpp', - 'Src/DSP/assemble.cpp', - 'Src/DSP/disassemble.cpp', - 'Src/DSPEmulator.cpp', - 'Src/Debugger/Debugger_SymbolMap.cpp', - 'Src/Debugger/Dump.cpp', - 'Src/Debugger/PPCDebugInterface.cpp', - 'Src/FifoPlayer/FifoAnalyzer.cpp', - 'Src/FifoPlayer/FifoDataFile.cpp', - 'Src/FifoPlayer/FifoPlaybackAnalyzer.cpp', - 'Src/FifoPlayer/FifoPlayer.cpp', - 'Src/FifoPlayer/FifoRecordAnalyzer.cpp', - 'Src/FifoPlayer/FifoRecorder.cpp', - 'Src/GeckoCode.cpp', - 'Src/GeckoCodeConfig.cpp', - 'Src/HLE/HLE.cpp', - 'Src/HLE/HLE_Misc.cpp', - 'Src/HLE/HLE_OS.cpp', - 'Src/HW/AudioInterface.cpp', - 'Src/HW/CPU.cpp', - 'Src/HW/DSP.cpp', - 'Src/HW/DSPHLE/DSPHLE.cpp', - 'Src/HW/DSPHLE/HLEMixer.cpp', - 'Src/HW/DSPHLE/MailHandler.cpp', - 'Src/HW/DSPHLE/UCodes/UCode_AX.cpp', - 'Src/HW/DSPHLE/UCodes/UCode_AXWii.cpp', - 'Src/HW/DSPHLE/UCodes/UCode_CARD.cpp', - 'Src/HW/DSPHLE/UCodes/UCode_GBA.cpp', - 'Src/HW/DSPHLE/UCodes/UCode_InitAudioSystem.cpp', - 'Src/HW/DSPHLE/UCodes/UCode_ROM.cpp', - 'Src/HW/DSPHLE/UCodes/UCode_Zelda.cpp', - 'Src/HW/DSPHLE/UCodes/UCode_Zelda_ADPCM.cpp', - 'Src/HW/DSPHLE/UCodes/UCode_Zelda_Synth.cpp', - 'Src/HW/DSPHLE/UCodes/UCode_Zelda_Voice.cpp', - 'Src/HW/DSPHLE/UCodes/UCodes.cpp', - 'Src/HW/DSPLLE/DSPDebugInterface.cpp', - 'Src/HW/DSPLLE/DSPHost.cpp', - 'Src/HW/DSPLLE/DSPLLE.cpp', - #'Src/HW/DSPLLE/DSPLLEGlobals.cpp', - 'Src/HW/DSPLLE/DSPLLETools.cpp', - 'Src/HW/DSPLLE/DSPSymbols.cpp', - 'Src/HW/DVDInterface.cpp', - 'Src/HW/EXI.cpp', - 'Src/HW/EXI_Channel.cpp', - 'Src/HW/EXI_Device.cpp', - 'Src/HW/EXI_DeviceAD16.cpp', - 'Src/HW/EXI_DeviceAMBaseboard.cpp', - 'Src/HW/EXI_DeviceEthernet.cpp', - 'Src/HW/EXI_DeviceGecko.cpp', - 'Src/HW/EXI_DeviceIPL.cpp', - 'Src/HW/EXI_DeviceMemoryCard.cpp', - 'Src/HW/EXI_DeviceMic.cpp', - 'Src/HW/GCMemcard.cpp', - 'Src/HW/GCPad.cpp', - 'Src/HW/GCPadEmu.cpp', - 'Src/HW/GPFifo.cpp', - 'Src/HW/HW.cpp', - 'Src/HW/Memmap.cpp', - 'Src/HW/MemmapFunctions.cpp', - 'Src/HW/MemoryInterface.cpp', - 'Src/HW/ProcessorInterface.cpp', - 'Src/HW/SI.cpp', - 'Src/HW/SI_Device.cpp', - 'Src/HW/SI_DeviceAMBaseboard.cpp', - 'Src/HW/SI_DeviceGBA.cpp', - 'Src/HW/SI_DeviceGCController.cpp', - 'Src/HW/Sram.cpp', - 'Src/HW/StreamADPCM.cpp', - 'Src/HW/SystemTimers.cpp', - 'Src/HW/VideoInterface.cpp', - 'Src/HW/WII_IOB.cpp', - 'Src/HW/WII_IPC.cpp', - 'Src/HW/Wiimote.cpp', - 'Src/HW/WiimoteEmu/Attachment/Attachment.cpp', - 'Src/HW/WiimoteEmu/Attachment/Classic.cpp', - 'Src/HW/WiimoteEmu/Attachment/Drums.cpp', - 'Src/HW/WiimoteEmu/Attachment/Guitar.cpp', - 'Src/HW/WiimoteEmu/Attachment/Nunchuk.cpp', - 'Src/HW/WiimoteEmu/Attachment/Turntable.cpp', - 'Src/HW/WiimoteEmu/EmuSubroutines.cpp', - 'Src/HW/WiimoteEmu/Encryption.cpp', - 'Src/HW/WiimoteEmu/Speaker.cpp', - 'Src/HW/WiimoteEmu/WiimoteEmu.cpp', - 'Src/HW/WiimoteReal/WiimoteReal.cpp', - 'Src/IPC_HLE/WII_IPC_HLE.cpp', - 'Src/IPC_HLE/WII_IPC_HLE_Device_DI.cpp', - 'Src/IPC_HLE/WII_IPC_HLE_Device_FileIO.cpp', - 'Src/IPC_HLE/WII_IPC_HLE_Device_es.cpp', - 'Src/IPC_HLE/WII_IPC_HLE_Device_fs.cpp', - 'Src/IPC_HLE/WII_IPC_HLE_Device_net.cpp', - 'Src/IPC_HLE/WII_IPC_HLE_Device_sdio_slot0.cpp', - 'Src/IPC_HLE/WII_IPC_HLE_Device_usb.cpp', - 'Src/IPC_HLE/WII_IPC_HLE_Device_usb_kbd.cpp', - 'Src/IPC_HLE/WII_IPC_HLE_WiiMote.cpp', - 'Src/IPC_HLE/WiiMote_HID_Attr.cpp', - 'Src/MemTools.cpp', - 'Src/Movie.cpp', - 'Src/NetPlay.cpp', - 'Src/NetPlayClient.cpp', - 'Src/NetPlayServer.cpp', - 'Src/PatchEngine.cpp', - 'Src/PowerPC/Interpreter/Interpreter.cpp', - 'Src/PowerPC/Interpreter/Interpreter_Branch.cpp', - 'Src/PowerPC/Interpreter/Interpreter_FloatingPoint.cpp', - 'Src/PowerPC/Interpreter/Interpreter_Integer.cpp', - 'Src/PowerPC/Interpreter/Interpreter_LoadStore.cpp', - 'Src/PowerPC/Interpreter/Interpreter_LoadStorePaired.cpp', - 'Src/PowerPC/Interpreter/Interpreter_Paired.cpp', - 'Src/PowerPC/Interpreter/Interpreter_SystemRegisters.cpp', - 'Src/PowerPC/Interpreter/Interpreter_Tables.cpp', - 'Src/PowerPC/Jit64/Jit.cpp', - 'Src/PowerPC/Jit64/Jit64_Tables.cpp', - 'Src/PowerPC/Jit64/JitAsm.cpp', - 'Src/PowerPC/Jit64/JitRegCache.cpp', - 'Src/PowerPC/Jit64/Jit_Branch.cpp', - 'Src/PowerPC/Jit64/Jit_FloatingPoint.cpp', - 'Src/PowerPC/Jit64/Jit_Integer.cpp', - 'Src/PowerPC/Jit64/Jit_LoadStore.cpp', - 'Src/PowerPC/Jit64/Jit_LoadStoreFloating.cpp', - 'Src/PowerPC/Jit64/Jit_LoadStorePaired.cpp', - 'Src/PowerPC/Jit64/Jit_Paired.cpp', - 'Src/PowerPC/Jit64/Jit_SystemRegisters.cpp', - 'Src/PowerPC/Jit64IL/IR.cpp', - 'Src/PowerPC/Jit64IL/IR_X86.cpp', - 'Src/PowerPC/Jit64IL/JitIL.cpp', - 'Src/PowerPC/Jit64IL/JitILAsm.cpp', - 'Src/PowerPC/Jit64IL/JitIL_Branch.cpp', - 'Src/PowerPC/Jit64IL/JitIL_FloatingPoint.cpp', - 'Src/PowerPC/Jit64IL/JitIL_Integer.cpp', - 'Src/PowerPC/Jit64IL/JitIL_LoadStore.cpp', - 'Src/PowerPC/Jit64IL/JitIL_LoadStoreFloating.cpp', - 'Src/PowerPC/Jit64IL/JitIL_LoadStorePaired.cpp', - 'Src/PowerPC/Jit64IL/JitIL_Paired.cpp', - 'Src/PowerPC/Jit64IL/JitIL_SystemRegisters.cpp', - 'Src/PowerPC/Jit64IL/JitIL_Tables.cpp', - 'Src/PowerPC/JitCommon/JitAsmCommon.cpp', - 'Src/PowerPC/JitCommon/JitBackpatch.cpp', - 'Src/PowerPC/JitCommon/JitBase.cpp', - 'Src/PowerPC/JitCommon/JitCache.cpp', - 'Src/PowerPC/JitCommon/Jit_Util.cpp', - 'Src/PowerPC/LUT_frsqrtex.cpp', - 'Src/PowerPC/PPCAnalyst.cpp', - 'Src/PowerPC/PPCCache.cpp', - 'Src/PowerPC/PPCSymbolDB.cpp', - 'Src/PowerPC/PPCTables.cpp', - 'Src/PowerPC/PowerPC.cpp', - 'Src/PowerPC/Profiler.cpp', - 'Src/PowerPC/SignatureDB.cpp', - 'Src/State.cpp', - 'Src/Tracer.cpp', - 'Src/VolumeHandler.cpp', - ] - -if sys.platform == 'win32': - files += ['Src/HW/BBA-TAP/TAP_Win32.cpp'] - files += ['Src/HW/WiimoteReal/IOWin.cpp'] - files += ['Src/stdafx.cpp'] -elif sys.platform == 'darwin': - files += ['Src/HW/BBA-TAP/TAP_Apple.cpp'] - files += ['Src/HW/WiimoteReal/IOdarwin.mm'] -elif sys.platform == 'linux2' and env['HAVE_BLUEZ']: - files += ['Src/HW/BBA-TAP/TAP_Unix.cpp'] - files += ['Src/HW/WiimoteReal/IODummy.cpp'] -else: - files += ['Src/HW/BBA-TAP/TAP_Unix.cpp'] - files += ['Src/HW/WiimoteReal/IODummy.cpp'] - -env['LIBS'] += env.StaticLibrary('core', files) diff --git a/Source/Core/Core/Src/Boot/Boot.cpp b/Source/Core/Core/Src/Boot/Boot.cpp index 3dcbf5730c..be82d217dc 100644 --- a/Source/Core/Core/Src/Boot/Boot.cpp +++ b/Source/Core/Core/Src/Boot/Boot.cpp @@ -19,6 +19,7 @@ #include "Common.h" // Common #include "StringUtil.h" #include "FileUtil.h" +#include "MathUtil.h" #include "../HLE/HLE.h" // Core #include "../PowerPC/PowerPC.h" @@ -68,13 +69,13 @@ void CBoot::Load_FST(bool _bIsWii) u32 fstSize = VolumeHandler::Read32(0x0428) << shift; u32 maxFstSize = VolumeHandler::Read32(0x042c) << shift; - u32 arenaHigh = 0x817FFFF4 - maxFstSize; + u32 arenaHigh = ROUND_DOWN(0x817FFFFF - maxFstSize, 0x20); Memory::Write_U32(arenaHigh, 0x00000034); // load FST VolumeHandler::ReadToPtr(Memory::GetPointer(arenaHigh), fstOffset, fstSize); Memory::Write_U32(arenaHigh, 0x00000038); - Memory::Write_U32(maxFstSize, 0x0000003c); + Memory::Write_U32(maxFstSize, 0x0000003c); } void CBoot::UpdateDebugger_MapLoaded(const char *_gameID) @@ -227,7 +228,9 @@ bool CBoot::BootUp() // setup the map from ISOFile ID VolumeHandler::SetVolumeName(_StartupPara.m_strFilename); - VideoInterface::SetRegionReg((char)VolumeHandler::GetVolume()->GetUniqueID().at(3)); + std::string unique_id = VolumeHandler::GetVolume()->GetUniqueID(); + if (unique_id.size() >= 4) + VideoInterface::SetRegionReg(unique_id.at(3)); DVDInterface::SetDiscInside(VolumeHandler::IsValid()); diff --git a/Source/Core/Core/Src/Boot/Boot_BS2Emu.cpp b/Source/Core/Core/Src/Boot/Boot_BS2Emu.cpp index 2c72be3a4e..23fe212f06 100644 --- a/Source/Core/Core/Src/Boot/Boot_BS2Emu.cpp +++ b/Source/Core/Core/Src/Boot/Boot_BS2Emu.cpp @@ -297,6 +297,7 @@ bool CBoot::SetupWiiMemory(unsigned int _CountryCode) Memory::Write_U32(0x00000000, 0x000030c4); // EXI Memory::Write_U32(0x00000000, 0x000030dc); // Time Memory::Write_U32(0x00000000, 0x000030d8); // Time + Memory::Write_U16(0x8201, 0x000030e6); // Dev console / debug capable Memory::Write_U32(0x00000000, 0x000030f0); // Apploader Memory::Write_U32(0x01800000, 0x00003100); // BAT Memory::Write_U32(0x01800000, 0x00003104); // BAT @@ -309,7 +310,7 @@ bool CBoot::SetupWiiMemory(unsigned int _CountryCode) Memory::Write_U32(0x93ae0000, 0x00003128); // Init - MEM2 high Memory::Write_U32(0x93ae0000, 0x00003130); // IOS MEM2 low Memory::Write_U32(0x93b00000, 0x00003134); // IOS MEM2 high - Memory::Write_U32(0x00000011, 0x00003138); // Console type + Memory::Write_U32(0x00000012, 0x00003138); // Console type // 40 is copied from 88 after running apploader Memory::Write_U32(0x00090204, 0x00003140); // IOS revision (IOS9, v2.4) Memory::Write_U32(0x00062507, 0x00003144); // IOS date in USA format (June 25, 2007) diff --git a/Source/Core/Core/Src/Boot/Boot_ELF.cpp b/Source/Core/Core/Src/Boot/Boot_ELF.cpp index c80bc0e7c8..9fa86a9183 100644 --- a/Source/Core/Core/Src/Boot/Boot_ELF.cpp +++ b/Source/Core/Core/Src/Boot/Boot_ELF.cpp @@ -34,12 +34,35 @@ bool CBoot::IsElfWii(const char *filename) File::IOFile f(filename, "rb"); f.ReadBytes(mem, (size_t)filesize); } + + // Use the same method as the DOL loader uses: search for mfspr from HID4, + // which should only be used in Wii ELFs. + // + // Likely to have some false positives/negatives, patches implementing a + // better heuristic are welcome. + u32 HID4_pattern = 0x7c13fba6; + u32 HID4_mask = 0xfc1fffff; ElfReader reader(mem); - // TODO: Find a more reliable way to distinguish. - bool isWii = reader.GetEntryPoint() >= 0x80004000; + bool isWii = false; + + for (int i = 0; i < reader.GetNumSections(); ++i) + { + if (reader.IsCodeSection(i)) + { + for (unsigned int j = 0; j < reader.GetSectionSize(i) / sizeof (u32); ++j) + { + u32 word = Common::swap32(((u32*)reader.GetSectionDataPtr(i))[j]); + if ((word & HID4_mask) == HID4_pattern) + { + isWii = true; + break; + } + } + } + } + delete[] mem; - return isWii; } diff --git a/Source/Core/Core/Src/Boot/Boot_WiiWAD.cpp b/Source/Core/Core/Src/Boot/Boot_WiiWAD.cpp index 05559281c2..d3fa172621 100644 --- a/Source/Core/Core/Src/Boot/Boot_WiiWAD.cpp +++ b/Source/Core/Core/Src/Boot/Boot_WiiWAD.cpp @@ -32,8 +32,57 @@ #include "VolumeCreator.h" #include "CommonPaths.h" +static u32 state_checksum(u32 *buf, int len) +{ + u32 checksum = 0; + len = len>>2; + + for(int i=0; i<len; i++) + { + checksum += buf[i]; + } + + return checksum; +} + +typedef struct { + u32 checksum; + u8 flags; + u8 type; + u8 discstate; + u8 returnto; + u32 unknown[6]; +} StateFlags; + bool CBoot::Boot_WiiWAD(const char* _pFilename) { + + std::string state_filename(Common::GetTitleDataPath(TITLEID_SYSMENU) + WII_STATE); + + if (File::Exists(state_filename)) + { + File::IOFile state_file(state_filename, "r+b"); + StateFlags state; + state_file.ReadBytes(&state, sizeof(StateFlags)); + + state.type = 0x03; // TYPE_RETURN + state.checksum = state_checksum((u32*)&state.flags, sizeof(StateFlags)-4); + + state_file.Seek(0, SEEK_SET); + state_file.WriteBytes(&state, sizeof(StateFlags)); + } + else + { + File::CreateFullPath(state_filename); + File::IOFile state_file(state_filename, "a+b"); + StateFlags state; + memset(&state,0,sizeof(StateFlags)); + state.type = 0x03; // TYPE_RETURN + state.discstate = 0x01; // DISCSTATE_WII + state.checksum = state_checksum((u32*)&state.flags, sizeof(StateFlags)-4); + state_file.WriteBytes(&state, sizeof(StateFlags)); + } + const DiscIO::INANDContentLoader& ContentLoader = DiscIO::CNANDContentManager::Access().GetNANDLoader(_pFilename); if (!ContentLoader.IsValid()) return false; diff --git a/Source/Core/Core/Src/Boot/ElfReader.h b/Source/Core/Core/Src/Boot/ElfReader.h index 0d46bb390a..6a3c559296 100644 --- a/Source/Core/Core/Src/Boot/ElfReader.h +++ b/Source/Core/Core/Src/Boot/ElfReader.h @@ -59,7 +59,6 @@ public: bool LoadInto(u32 vaddr); bool LoadSymbols(); -private: int GetNumSegments() const { return (int)(header->e_phnum); } int GetNumSections() const { return (int)(header->e_shnum); } const u8 *GetPtr(int offset) const { return (u8*)base + offset; } @@ -73,6 +72,10 @@ private: else return 0; } + bool IsCodeSection(int section) const + { + return sections[section].sh_type == SHT_PROGBITS; + } const u8 *GetSegmentPtr(int segment) { return GetPtr(segments[segment].p_offset); diff --git a/Source/Core/Core/Src/BootManager.cpp b/Source/Core/Core/Src/BootManager.cpp index ed415a4ae9..640c2eecdc 100644 --- a/Source/Core/Core/Src/BootManager.cpp +++ b/Source/Core/Core/Src/BootManager.cpp @@ -74,9 +74,6 @@ bool BootCore(const std::string& _rFilename) StartUp.bRunCompareServer = false; StartUp.hInstance = Host_GetInstance(); - #if defined(_WIN32) && defined(_M_X64) - StartUp.bUseFastMem = true; - #endif // If for example the ISO file is bad we return here if (!StartUp.AutoSetup(SCoreStartupParameter::BOOT_DEFAULT)) return false; diff --git a/Source/Core/Core/Src/ConfigManager.cpp b/Source/Core/Core/Src/ConfigManager.cpp index da8337bd04..d197e51b90 100644 --- a/Source/Core/Core/Src/ConfigManager.cpp +++ b/Source/Core/Core/Src/ConfigManager.cpp @@ -190,6 +190,7 @@ void SConfig::SaveSettings() ini.Set("Display", "RenderWindowWidth", m_LocalCoreStartupParameter.iRenderWindowWidth); ini.Set("Display", "RenderWindowHeight", m_LocalCoreStartupParameter.iRenderWindowHeight); ini.Set("Display", "RenderWindowAutoSize", m_LocalCoreStartupParameter.bRenderWindowAutoSize); + ini.Set("Display", "KeepWindowOnTop", m_LocalCoreStartupParameter.bKeepWindowOnTop); ini.Set("Display", "ProgressiveScan", m_LocalCoreStartupParameter.bProgressive); ini.Set("Display", "DisableScreenSaver", m_LocalCoreStartupParameter.bDisableScreenSaver); ini.Set("Display", "ForceNTSCJ", m_LocalCoreStartupParameter.bForceNTSCJ); @@ -319,6 +320,7 @@ void SConfig::LoadSettings() ini.Get("Display", "RenderWindowWidth", &m_LocalCoreStartupParameter.iRenderWindowWidth, 640); ini.Get("Display", "RenderWindowHeight", &m_LocalCoreStartupParameter.iRenderWindowHeight, 480); ini.Get("Display", "RenderWindowAutoSize", &m_LocalCoreStartupParameter.bRenderWindowAutoSize, false); + ini.Get("Display", "KeepWindowOnTop", &m_LocalCoreStartupParameter.bKeepWindowOnTop, false); ini.Get("Display", "ProgressiveScan", &m_LocalCoreStartupParameter.bProgressive, false); ini.Get("Display", "DisableScreenSaver", &m_LocalCoreStartupParameter.bDisableScreenSaver, true); ini.Get("Display", "ForceNTSCJ", &m_LocalCoreStartupParameter.bForceNTSCJ, false); diff --git a/Source/Core/Core/Src/Core.cpp b/Source/Core/Core/Src/Core.cpp index bd4267c074..52eec29030 100644 --- a/Source/Core/Core/Src/Core.cpp +++ b/Source/Core/Core/Src/Core.cpp @@ -129,11 +129,19 @@ void DisplayMessage(const char *message, int time_in_ms) SCoreStartupParameter& _CoreParameter = SConfig::GetInstance().m_LocalCoreStartupParameter; + // Actually displaying non-ASCII could cause things to go pear-shaped + for (const char *c = message; *c != '\0'; ++c) + if (*c < ' ') + return; + g_video_backend->Video_AddMessage(message, time_in_ms); + if (_CoreParameter.bRenderToMain && - SConfig::GetInstance().m_InterfaceStatusbar) { - Host_UpdateStatusBar(message); - } else + SConfig::GetInstance().m_InterfaceStatusbar) + { + Host_UpdateStatusBar(message); + } + else Host_UpdateTitle(message); } @@ -285,8 +293,9 @@ void CpuThread() if (_CoreParameter.bLockThreads) Common::SetCurrentThreadAffinity(1); // Force to first core - if (_CoreParameter.bUseFastMem) + #if defined(_WIN32) && defined(_M_X64) EMM::InstallExceptionHandler(); // Let's run under memory watch + #endif if (!g_stateFileName.empty()) State::LoadAs(g_stateFileName); diff --git a/Source/Core/Core/Src/CoreParameter.cpp b/Source/Core/Core/Src/CoreParameter.cpp index c608905e39..ba72d47ffb 100644 --- a/Source/Core/Core/Src/CoreParameter.cpp +++ b/Source/Core/Core/Src/CoreParameter.cpp @@ -45,8 +45,7 @@ SCoreStartupParameter::SCoreStartupParameter() bEnableFPRF(false), bCPUThread(true), bDSPThread(false), bDSPHLE(true), bSkipIdle(true), bNTSC(false), bForceNTSCJ(false), - bHLE_BS2(true), bUseFastMem(false), - bLockThreads(false), + bHLE_BS2(true), bLockThreads(false), bEnableCheats(false), bMergeBlocks(false), bRunCompareServer(false), bRunCompareClient(false), @@ -57,7 +56,7 @@ SCoreStartupParameter::SCoreStartupParameter() bAutoHideCursor(false), bUsePanicHandlers(true), iRenderWindowXPos(-1), iRenderWindowYPos(-1), iRenderWindowWidth(640), iRenderWindowHeight(480), - bRenderWindowAutoSize(false), + bRenderWindowAutoSize(false), bKeepWindowOnTop(false), bFullscreen(false), bRenderToMain(false), bProgressive(false), bDisableScreenSaver(false), iTheme(0), @@ -127,6 +126,7 @@ bool SCoreStartupParameter::AutoSetup(EBootBS2 _BootBS2) SplitPath(m_strFilename, NULL, NULL, &Extension); if (!strcasecmp(Extension.c_str(), ".gcm") || !strcasecmp(Extension.c_str(), ".iso") || + !strcasecmp(Extension.c_str(), ".wbfs") || !strcasecmp(Extension.c_str(), ".ciso") || !strcasecmp(Extension.c_str(), ".gcz") || bootDrive) diff --git a/Source/Core/Core/Src/CoreParameter.h b/Source/Core/Core/Src/CoreParameter.h index af885efcad..2eb261b589 100644 --- a/Source/Core/Core/Src/CoreParameter.h +++ b/Source/Core/Core/Src/CoreParameter.h @@ -103,7 +103,6 @@ struct SCoreStartupParameter bool bNTSC; bool bForceNTSCJ; bool bHLE_BS2; - bool bUseFastMem; bool bLockThreads; bool bEnableCheats; bool bMergeBlocks; @@ -133,7 +132,7 @@ struct SCoreStartupParameter std::string strFullscreenResolution; int iRenderWindowXPos, iRenderWindowYPos; int iRenderWindowWidth, iRenderWindowHeight; - bool bRenderWindowAutoSize; + bool bRenderWindowAutoSize, bKeepWindowOnTop; bool bFullscreen, bRenderToMain; bool bProgressive, bDisableScreenSaver; diff --git a/Source/Core/Core/Src/FifoPlayer/FifoAnalyzer.cpp b/Source/Core/Core/Src/FifoPlayer/FifoAnalyzer.cpp index 58ad9eded3..f074b6d88b 100644 --- a/Source/Core/Core/Src/FifoPlayer/FifoAnalyzer.cpp +++ b/Source/Core/Core/Src/FifoPlayer/FifoAnalyzer.cpp @@ -153,17 +153,17 @@ void CalculateVertexElementSizes(int sizes[], int vatIndex, const CPMemory &cpMe const VAT &vtxAttr = cpMem.vtxAttr[vatIndex]; // Colors - const int colDesc[2] = {vtxDesc.Color0, vtxDesc.Color1}; - const int colComp[2] = {vtxAttr.g0.Color0Comp, vtxAttr.g0.Color1Comp}; + const u32 colDesc[2] = {vtxDesc.Color0, vtxDesc.Color1}; + const u32 colComp[2] = {vtxAttr.g0.Color0Comp, vtxAttr.g0.Color1Comp}; - const int tcElements[8] = + const u32 tcElements[8] = { vtxAttr.g0.Tex0CoordElements, vtxAttr.g1.Tex1CoordElements, vtxAttr.g1.Tex2CoordElements, vtxAttr.g1.Tex3CoordElements, vtxAttr.g1.Tex4CoordElements, vtxAttr.g2.Tex5CoordElements, vtxAttr.g2.Tex6CoordElements, vtxAttr.g2.Tex7CoordElements }; - const int tcFormat[8] = + const u32 tcFormat[8] = { vtxAttr.g0.Tex0CoordFormat, vtxAttr.g1.Tex1CoordFormat, vtxAttr.g1.Tex2CoordFormat, vtxAttr.g1.Tex3CoordFormat, vtxAttr.g1.Tex4CoordFormat, vtxAttr.g2.Tex5CoordFormat, diff --git a/Source/Core/Core/Src/FifoPlayer/FifoPlaybackAnalyzer.cpp b/Source/Core/Core/Src/FifoPlayer/FifoPlaybackAnalyzer.cpp index 4aea2acc98..a8ba627019 100644 --- a/Source/Core/Core/Src/FifoPlayer/FifoPlaybackAnalyzer.cpp +++ b/Source/Core/Core/Src/FifoPlayer/FifoPlaybackAnalyzer.cpp @@ -71,10 +71,10 @@ void FifoPlaybackAnalyzer::AnalyzeFrames(FifoDataFile *file, std::vector<Analyze u32 cmdStart = 0; u32 nextMemUpdate = 0; - + // Debugging vector<CmdData> prevCmds; - + while (cmdStart < frame.fifoDataSize) { // Add memory updates that have occured before this point in the frame @@ -83,9 +83,9 @@ void FifoPlaybackAnalyzer::AnalyzeFrames(FifoDataFile *file, std::vector<Analyze AddMemoryUpdate(frame.memoryUpdates[nextMemUpdate], analyzed); ++nextMemUpdate; } - + bool wasDrawing = m_DrawingObject; - + u32 cmdSize = DecodeCommand(&frame.fifoData[cmdStart]); #if (LOG_FIFO_CMDS) @@ -95,7 +95,7 @@ void FifoPlaybackAnalyzer::AnalyzeFrames(FifoDataFile *file, std::vector<Analyze cmdData.size = cmdSize; prevCmds.push_back(cmdData); #endif - + // Check for error if (cmdSize == 0) { diff --git a/Source/Core/Core/Src/FifoPlayer/FifoPlayer.cpp b/Source/Core/Core/Src/FifoPlayer/FifoPlayer.cpp index 3acdfa41cb..ff90736fec 100644 --- a/Source/Core/Core/Src/FifoPlayer/FifoPlayer.cpp +++ b/Source/Core/Core/Src/FifoPlayer/FifoPlayer.cpp @@ -94,8 +94,9 @@ bool FifoPlayer::Play() if (m_EarlyMemoryUpdates && m_CurrentFrame == m_FrameRangeStart) WriteAllMemoryUpdates(); - WriteFrame(m_File->GetFrame(m_CurrentFrame), m_FrameInfo[m_CurrentFrame]); - ++m_CurrentFrame; + WriteFrame(m_File->GetFrame(m_CurrentFrame), m_FrameInfo[m_CurrentFrame]); + + ++m_CurrentFrame; } } } diff --git a/Source/Core/Core/Src/FifoPlayer/FifoPlayer.h b/Source/Core/Core/Src/FifoPlayer/FifoPlayer.h index 486c3c69e4..9db6c0d980 100644 --- a/Source/Core/Core/Src/FifoPlayer/FifoPlayer.h +++ b/Source/Core/Core/Src/FifoPlayer/FifoPlayer.h @@ -44,6 +44,8 @@ public: u32 GetFrameObjectCount(); u32 GetCurrentFrameNum() { return m_CurrentFrame; } + const AnalyzedFrameInfo& GetAnalyzedFrameInfo(u32 frame) { return m_FrameInfo[frame]; } + // Frame range u32 GetFrameRangeStart() { return m_FrameRangeStart; } void SetFrameRangeStart(u32 start); diff --git a/Source/Core/Core/Src/GeckoCode.cpp b/Source/Core/Core/Src/GeckoCode.cpp index c0b7af3779..35b2f53392 100644 --- a/Source/Core/Core/Src/GeckoCode.cpp +++ b/Source/Core/Core/Src/GeckoCode.cpp @@ -253,9 +253,12 @@ bool RunActiveCodes() void RunCodeHandler() { - if (SConfig::GetInstance().m_LocalCoreStartupParameter.bEnableCheats) + if (SConfig::GetInstance().m_LocalCoreStartupParameter.bEnableCheats && active_codes.size() > 0) { - if (!code_handler_installed) + u8 *gameId = Memory::GetPointer(0x80000000); + u8 *wiirdId = Memory::GetPointer(0x80001800); + + if (!code_handler_installed || memcmp(gameId, wiirdId, 6)) code_handler_installed = InstallCodeHandler(); if (code_handler_installed) diff --git a/Source/Core/Core/Src/HW/AudioInterface.cpp b/Source/Core/Core/Src/HW/AudioInterface.cpp index 40b0c620b3..f4141818ae 100644 --- a/Source/Core/Core/Src/HW/AudioInterface.cpp +++ b/Source/Core/Core/Src/HW/AudioInterface.cpp @@ -234,8 +234,8 @@ void Write32(const u32 _Value, const u32 _Address) m_Control.PSTAT = tmpAICtrl.PSTAT; g_LastCPUTime = CoreTiming::GetTicks(); - // Tell Drive Interface to stop streaming - if (!tmpAICtrl.PSTAT) DVDInterface::g_bStream = false; + // Tell Drive Interface to start/stop streaming + DVDInterface::g_bStream = tmpAICtrl.PSTAT; } // AI Interrupt @@ -293,6 +293,11 @@ static void GenerateAudioInterrupt() UpdateInterrupts(); } +void GenerateAISInterrupt() +{ + GenerateAudioInterrupt(); +} + void Callback_GetSampleRate(unsigned int &_AISampleRate, unsigned int &_DACSampleRate) { _AISampleRate = g_AISSampleRate; diff --git a/Source/Core/Core/Src/HW/AudioInterface.h b/Source/Core/Core/Src/HW/AudioInterface.h index 8f01e9f7e7..1504198621 100644 --- a/Source/Core/Core/Src/HW/AudioInterface.h +++ b/Source/Core/Core/Src/HW/AudioInterface.h @@ -43,6 +43,8 @@ void Write32(const u32 _iValue, const u32 _iAddress); // Get the audio rates (48000 or 32000 only) unsigned int GetAIDSampleRate(); +void GenerateAISInterrupt(); + } // namespace #endif diff --git a/Source/Core/Core/Src/HW/DSP.cpp b/Source/Core/Core/Src/HW/DSP.cpp index 4ae15253cc..cd136df53b 100644 --- a/Source/Core/Core/Src/HW/DSP.cpp +++ b/Source/Core/Core/Src/HW/DSP.cpp @@ -354,7 +354,7 @@ void Read16(u16& _uReturnValue, const u32 _iAddress) // AI case AUDIO_DMA_BLOCKS_LEFT: - _uReturnValue = g_audioDMA.BlocksLeft; + _uReturnValue = g_audioDMA.BlocksLeft > 0 ? g_audioDMA.BlocksLeft - 1 : 0; // AUDIO_DMA_BLOCKS_LEFT is zero based break; case AUDIO_DMA_START_LO: @@ -435,10 +435,10 @@ void Write16(const u16 _Value, const u32 _Address) if (tmpControl.ARAM) g_dspState.DSPControl.ARAM = 0; if (tmpControl.DSP) g_dspState.DSPControl.DSP = 0; - // g_ARAM + // g_ARAM (line below should be commented out to emulate the DMA wait time) g_dspState.DSPControl.DMAState = 0; // keep g_ARAM DMA State zero - // unknown + // unknown g_dspState.DSPControl.unk3 = tmpControl.unk3; g_dspState.DSPControl.pad = tmpControl.pad; if (g_dspState.DSPControl.pad != 0) @@ -453,13 +453,30 @@ void Write16(const u16 _Value, const u32 _Address) // ARAM // DMA back and forth between ARAM and RAM case AR_INFO: - //PanicAlert("write %x %x", _Value,PowerPC::ppcState.pc); + //PanicAlert("AR_INFO %x PC: %x", _Value, PowerPC::ppcState.pc); + ERROR_LOG(DSPINTERFACE, "AR_INFO %x PC: %x", _Value, PowerPC::ppcState.pc); g_ARAM_Info.Hex = _Value; + + // 0x43 + // Monster Hunter Tri, DKCR + + // 0x43, 0x63: + // Rebel Strike, Clone Wars, WWE DOR2, Mario Golf + + // 0x43, 0x64, 0x63 + // Transworld Surf, Smashing Drive, SSBM, Cel Damage + // __OSInitAudioSystem sets to 0x43 -> expects 16bit adressing and mapping to dsp iram? // __OSCheckSize sets = 0x20 | 3 (keeps upper bits) // 0x23 -> Zelda standard mode (standard ARAM access ??) - // 0x43 -> Set by Eternal Darkness and SSBB + // 0x43 -> Set by __OSInitAudioSystem + // 0x58 -> Transworld Surf, Cel Damage, SSBM + // 0x60 -> Transworld Surf, Cel Damage, SSBM // 0x63 -> ARCheckSize Mode (access AR-registers ??) or no exception ?? + // 0x64 -> Transworld Surf, Cel Damage, SSBM + + // 0x00 -> Switch to external ARAM + // 0x04 -> Switch to internal ARAM break; case AR_MODE: @@ -620,7 +637,7 @@ void GenerateDSPInterrupt(DSPInterruptType type, bool _bSet) switch (type) { case INT_DSP: g_dspState.DSPControl.DSP = _bSet ? 1 : 0; break; - case INT_ARAM: g_dspState.DSPControl.ARAM = _bSet ? 1 : 0; break; + case INT_ARAM: g_dspState.DSPControl.ARAM = _bSet ? 1 : 0; if (_bSet) g_dspState.DSPControl.DMAState = 0; break; case INT_AID: g_dspState.DSPControl.AID = _bSet ? 1 : 0; break; } @@ -672,7 +689,7 @@ void UpdateAudioDMA() { // Send silence. Yeah, it's a bit of a waste to sample rate convert // silence. or hm. Maybe we shouldn't do this :) - // dsp->DSP_SendAIBuffer(0, AudioInterface::GetDSPSampleRate()); + //dsp_emulator->DSP_SendAIBuffer(0, AudioInterface::GetAIDSampleRate()); } } @@ -682,44 +699,95 @@ void Do_ARAM_DMA() // seems like a good estimate CoreTiming::ScheduleEvent_Threadsafe(g_arDMA.Cnt.count >> 1, et_GenerateDSPInterrupt, INT_ARAM | (1<<16)); + // Uncomment the line below to emulate the DMA wait time. + //g_dspState.DSPControl.DMAState = 1; + // Real hardware DMAs in 32byte chunks, but we can get by with 8byte chunks if (g_arDMA.Cnt.dir) { // ARAM -> MRAM - INFO_LOG(DSPINTERFACE, "DMA %08x bytes from ARAM %08x to MRAM %08x", - g_arDMA.Cnt.count, g_arDMA.ARAddr, g_arDMA.MMAddr); + INFO_LOG(DSPINTERFACE, "DMA %08x bytes from ARAM %08x to MRAM %08x PC: %08x", + g_arDMA.Cnt.count, g_arDMA.ARAddr, g_arDMA.MMAddr, PC); + + // Outgoing data from ARAM is mirrored every 64MB (verified on real HW) + g_arDMA.ARAddr &= 0x3ffffff; + g_arDMA.MMAddr &= 0x3ffffff; - while (g_arDMA.Cnt.count) + if (g_arDMA.ARAddr < g_ARAM.size) + { + while (g_arDMA.Cnt.count) + { + if ((g_ARAM_Info.Hex & 0xf) == 3) + { + Memory::Write_U64_Swap(*(u64*)&g_ARAM.ptr[g_arDMA.ARAddr & g_ARAM.mask], g_arDMA.MMAddr); + } + else if ((g_ARAM_Info.Hex & 0xf) == 4) + { + Memory::Write_U64_Swap(*(u64*)&g_ARAM.ptr[g_arDMA.ARAddr & g_ARAM.mask], g_arDMA.MMAddr); + } + else + Memory::Write_U64_Swap(*(u64*)&g_ARAM.ptr[g_arDMA.ARAddr & g_ARAM.mask], g_arDMA.MMAddr); + g_arDMA.MMAddr += 8; + g_arDMA.ARAddr += 8; + g_arDMA.Cnt.count -= 8; + } + } + else { - if (g_arDMA.ARAddr < g_ARAM.size) + // Assuming no external ARAM installed; returns zeroes on out of bounds reads (verified on real HW) + while (g_arDMA.Cnt.count) { - Memory::Write_U64_Swap(*(u64*)&g_ARAM.ptr[g_arDMA.ARAddr], g_arDMA.MMAddr); + Memory::Write_U64(0, g_arDMA.MMAddr); g_arDMA.MMAddr += 8; g_arDMA.ARAddr += 8; + g_arDMA.Cnt.count -= 8; } - g_arDMA.Cnt.count -= 8; } } else { // MRAM -> ARAM - INFO_LOG(DSPINTERFACE, "DMA %08x bytes from MRAM %08x to ARAM %08x", - g_arDMA.Cnt.count, g_arDMA.MMAddr, g_arDMA.ARAddr); + INFO_LOG(DSPINTERFACE, "DMA %08x bytes from MRAM %08x to ARAM %08x PC: %08x", + g_arDMA.Cnt.count, g_arDMA.MMAddr, g_arDMA.ARAddr, PC); + + // Incoming data into ARAM is mirrored every 64MB (verified on real HW) + g_arDMA.ARAddr &= 0x3ffffff; + g_arDMA.MMAddr &= 0x3ffffff; - while (g_arDMA.Cnt.count) + if (g_arDMA.ARAddr < g_ARAM.size) { - if (g_arDMA.ARAddr < g_ARAM.size) + while (g_arDMA.Cnt.count) { - *(u64*)&g_ARAM.ptr[g_arDMA.ARAddr] = Common::swap64(Memory::Read_U64(g_arDMA.MMAddr)); + if ((g_ARAM_Info.Hex & 0xf) == 3) + { + *(u64*)&g_ARAM.ptr[g_arDMA.ARAddr & g_ARAM.mask] = Common::swap64(Memory::Read_U64(g_arDMA.MMAddr)); + } + else if ((g_ARAM_Info.Hex & 0xf) == 4) + { + if (g_arDMA.ARAddr < 0x400000) + { + *(u64*)&g_ARAM.ptr[(g_arDMA.ARAddr + 0x400000) & g_ARAM.mask] = Common::swap64(Memory::Read_U64(g_arDMA.MMAddr)); + } + *(u64*)&g_ARAM.ptr[g_arDMA.ARAddr & g_ARAM.mask] = Common::swap64(Memory::Read_U64(g_arDMA.MMAddr)); + } + else + *(u64*)&g_ARAM.ptr[g_arDMA.ARAddr & g_ARAM.mask] = Common::swap64(Memory::Read_U64(g_arDMA.MMAddr)); + g_arDMA.MMAddr += 8; g_arDMA.ARAddr += 8; + g_arDMA.Cnt.count -= 8; } - g_arDMA.Cnt.count -= 8; + } + else + { + // Assuming no external ARAM installed; writes nothing to ARAM when out of bounds (verified on real HW) + g_arDMA.MMAddr += g_arDMA.Cnt.count; + g_arDMA.ARAddr += g_arDMA.Cnt.count; + g_arDMA.Cnt.count = 0; } } } - // (shuffle2) I still don't believe that this hack is actually needed... :( // Maybe the wii sports ucode is processed incorrectly? // (LM) It just means that dsp reads via '0xffdd' on WII can end up in EXRAM or main RAM diff --git a/Source/Core/Core/Src/HW/DSPLLE/DSPLLE.cpp b/Source/Core/Core/Src/HW/DSPLLE/DSPLLE.cpp index a795b4966d..c3b6a2d674 100644 --- a/Source/Core/Core/Src/HW/DSPLLE/DSPLLE.cpp +++ b/Source/Core/Core/Src/HW/DSPLLE/DSPLLE.cpp @@ -24,6 +24,8 @@ #include "Thread.h" #include "ChunkFile.h" #include "IniFile.h" +#include "ConfigManager.h" +#include "CPUDetect.h" #include "DSPLLEGlobals.h" // Local #include "DSP/DSPInterpreter.h" @@ -84,6 +86,27 @@ void DSPLLE::dsp_thread(DSPLLE *dsp_lle) { Common::SetCurrentThreadName("DSP thread"); + if (SConfig::GetInstance().m_LocalCoreStartupParameter.bLockThreads) + { + if (cpu_info.num_cores > 3) + { + // HACK (delroth): there is no way to know where hyperthreads are in + // the current Dolphin version. + bool windows = false; +#ifdef _WIN32 + windows = true; +#endif + + u8 core_id; + if (windows && cpu_info.num_cores > 4) // Probably HT + core_id = 5; // 3rd non HT core + else + core_id = 3; // 3rd core + + Common::SetCurrentThreadAffinity(1 << core_id); + } + } + while (dsp_lle->m_bIsRunning) { int cycles = (int)dsp_lle->m_cycle_count; diff --git a/Source/Core/Core/Src/HW/DVDInterface.cpp b/Source/Core/Core/Src/HW/DVDInterface.cpp index 205cd00448..cb400f43a9 100644 --- a/Source/Core/Core/Src/HW/DVDInterface.cpp +++ b/Source/Core/Core/Src/HW/DVDInterface.cpp @@ -28,6 +28,7 @@ #include "Thread.h" #include "Memmap.h" #include "../VolumeHandler.h" +#include "AudioInterface.h" // Disc transfer rate measured in bytes per second static const u32 DISC_TRANSFER_RATE_GC = 3125 * 1024; @@ -201,9 +202,11 @@ static UDICR m_DICR; static UDIIMMBUF m_DIIMMBUF; static UDICFG m_DICFG; -static u32 AudioStart; +static u32 LoopStart; static u32 AudioPos; -static u32 AudioLength; +static u32 CurrentStart; +static u32 LoopLength; +static u32 CurrentLength; u32 g_ErrorCode = 0; bool g_bDiscInside = false; @@ -238,12 +241,16 @@ void DoState(PointerWrap &p) p.Do(m_DIIMMBUF); p.Do(m_DICFG); - p.Do(AudioStart); + p.Do(LoopStart); p.Do(AudioPos); - p.Do(AudioLength); + p.Do(LoopLength); p.Do(g_ErrorCode); p.Do(g_bDiscInside); + p.Do(g_bStream); + + p.Do(CurrentStart); + p.Do(CurrentLength); } void TransferComplete(u64 userdata, int cyclesLate) @@ -266,9 +273,13 @@ void Init() m_DICFG.Hex = 0; m_DICFG.CONFIG = 1; // Disable bootrom descrambler - AudioStart = 0; - AudioPos = 0; - AudioLength = 0; + AudioPos = 0; + LoopStart = 0; + LoopLength = 0; + CurrentStart = 0; + CurrentLength = 0; + + g_bStream = false; ejectDisc = CoreTiming::RegisterEvent("EjectDisc", EjectDiscCallback); insertDisc = CoreTiming::RegisterEvent("InsertDisc", InsertDiscCallback); @@ -351,33 +362,46 @@ bool DVDRead(u32 _iDVDOffset, u32 _iRamAddress, u32 _iLength) bool DVDReadADPCM(u8* _pDestBuffer, u32 _iNumSamples) { + _iNumSamples &= ~31; + if (AudioPos == 0) { - //MessageBox(0,"DVD: Trying to stream from 0", "bah", 0); memset(_pDestBuffer, 0, _iNumSamples); // probably __AI_SRC_INIT :P - return false; } - _iNumSamples &= ~31; + else { - std::lock_guard<std::mutex> lk(dvdread_section); - VolumeHandler::ReadToPtr(_pDestBuffer, AudioPos, _iNumSamples); + std::lock_guard<std::mutex> lk(dvdread_section); + VolumeHandler::ReadToPtr(_pDestBuffer, AudioPos, _iNumSamples); } - // - // FIX THIS - // // loop check - // - AudioPos += _iNumSamples; - if (AudioPos >= AudioStart + AudioLength) + if (g_bStream) { - g_bStream = false; // Starfox Adventures - AudioPos = AudioStart; - NGCADPCM::InitFilter(); - } + AudioPos += _iNumSamples; + + if (AudioPos >= CurrentStart + CurrentLength) + { + if (LoopStart == 0) + { + AudioPos = 0; + CurrentStart = 0; + CurrentLength = 0; + } + else + { + AudioPos = LoopStart; + CurrentStart = LoopStart; + CurrentLength = LoopLength; + } + NGCADPCM::InitFilter(); + AudioInterface::GenerateAISInterrupt(); + } - //WARN_LOG(DVDINTERFACE,"ReadADPCM"); - return true; + //WARN_LOG(DVDINTERFACE,"ReadADPCM"); + return true; + } + else + return false; } void Read32(u32& _uReturnValue, const u32 _iAddress) @@ -813,28 +837,69 @@ void ExecuteCommand(UDICR& _DICR) // m_DICMDBUF[2].Hex = Length of the stream case 0xE1: { - // ugly hack to catch the disable command - if (m_DICMDBUF[1].Hex != 0) - { - AudioPos = m_DICMDBUF[1].Hex << 2; - AudioStart = AudioPos; - AudioLength = m_DICMDBUF[2].Hex; - NGCADPCM::InitFilter(); + u32 pos = m_DICMDBUF[1].Hex << 2; + u32 length = m_DICMDBUF[2].Hex; + // Start playing + if (!g_bStream && m_DICMDBUF[0].CMDBYTE1 == 0 && pos != 0 && length != 0) + { + AudioPos = pos; + CurrentStart = pos; + CurrentLength = length; + NGCADPCM::InitFilter(); g_bStream = true; + } - WARN_LOG(DVDINTERFACE, "(Audio) Stream subcmd = %02x offset = %08x length=%08x", - m_DICMDBUF[0].CMDBYTE1, AudioPos, AudioLength); + LoopStart = pos; + LoopLength = length; + g_bStream = (m_DICMDBUF[0].CMDBYTE1 == 0); // This command can start/stop the stream + + // Stop stream + if (m_DICMDBUF[0].CMDBYTE1 == 1) + { + AudioPos = 0; + LoopStart = 0; + LoopLength = 0; + CurrentStart = 0; + CurrentLength = 0; } - else - WARN_LOG(DVDINTERFACE, "(Audio) Off?"); + + WARN_LOG(DVDINTERFACE, "(Audio) Stream subcmd = %08x offset = %08x length=%08x", + m_DICMDBUF[0].Hex, m_DICMDBUF[1].Hex << 2, m_DICMDBUF[2].Hex); } break; // Request Audio Status (Immediate) case 0xE2: - m_DIIMMBUF.Hex = g_bStream ? 1 : 0; - //WARN_LOG(DVDINTERFACE, "(Audio): Request Audio status %s", g_bStream? "on":"off"); + { + switch (m_DICMDBUF[0].CMDBYTE1) + { + case 0x00: // Returns streaming status + m_DIIMMBUF.Hex = (AudioPos == 0) ? 0 : 1; + break; + case 0x01: // Returns the current offset + if (g_bStream) + m_DIIMMBUF.Hex = (AudioPos - CurrentStart) >> 2; + else + m_DIIMMBUF.Hex = 0; + break; + case 0x02: // Returns the start offset + if (g_bStream) + m_DIIMMBUF.Hex = CurrentStart >> 2; + else + m_DIIMMBUF.Hex = 0; + break; + case 0x03: // Returns the total length + if (g_bStream) + m_DIIMMBUF.Hex = CurrentLength; + else + m_DIIMMBUF.Hex = 0; + break; + default: + WARN_LOG(DVDINTERFACE, "(Audio): Subcommand: %02x Request Audio status %s", m_DICMDBUF[0].CMDBYTE1, g_bStream? "on":"off"); + break; + } + } break; case DVDLowStopMotor: diff --git a/Source/Core/Core/Src/HW/EXI_DeviceIPL.cpp b/Source/Core/Core/Src/HW/EXI_DeviceIPL.cpp index 144270e798..ec8c29cc77 100644 --- a/Source/Core/Core/Src/HW/EXI_DeviceIPL.cpp +++ b/Source/Core/Core/Src/HW/EXI_DeviceIPL.cpp @@ -109,7 +109,7 @@ CEXIIPL::CEXIIPL() : if (SConfig::GetInstance().m_LocalCoreStartupParameter.bHLE_BS2) { // Copy header - memcpy(m_pIPL, m_bNTSC ? iplverNTSC : iplverPAL, sizeof(m_bNTSC ? iplverNTSC : iplverPAL)); + memcpy(m_pIPL, m_bNTSC ? iplverNTSC : iplverPAL, m_bNTSC ? sizeof(iplverNTSC) : sizeof(iplverPAL)); // Load fonts LoadFileToIPL((File::GetSysDirectory() + GC_SYS_DIR + DIR_SEP + FONT_SJIS), 0x1aff00); @@ -197,7 +197,7 @@ void CEXIIPL::TransferByte(u8& _uByte) // The first 4 bytes must be the address // If we haven't read it, do it now - if (m_uPosition < 4) + if (m_uPosition <= 3) { m_uAddress <<= 8; m_uAddress |= _uByte; @@ -207,137 +207,156 @@ void CEXIIPL::TransferByte(u8& _uByte) // Check if the command is complete if (m_uPosition == 3) { - // Get the time ... + // Get the time ... + u32 &rtc = *((u32 *)&m_RTC); if (SConfig::GetInstance().m_LocalCoreStartupParameter.bWii) - *((u32 *)&m_RTC) = Common::swap32(CEXIIPL::GetGCTime() - cWiiBias); // Subtract Wii bias - else - *((u32 *)&m_RTC) = Common::swap32(CEXIIPL::GetGCTime()); - -#if MAX_LOGLEVEL >= INFO_LEVEL - - if ((m_uAddress & 0xF0000000) == 0xb0000000) - { - INFO_LOG(EXPANSIONINTERFACE, "EXI IPL-DEV: WII something"); - } - else if ((m_uAddress & 0xF0000000) == 0x30000000) - { - // wii stuff perhaps wii SRAM? - INFO_LOG(EXPANSIONINTERFACE, "EXI IPL-DEV: WII something (perhaps SRAM?)"); - } - else if ((m_uAddress & 0x60000000) == 0) - { - INFO_LOG(EXPANSIONINTERFACE, "EXI IPL-DEV: IPL access"); - } - else if ((m_uAddress & 0x7FFFFF00) == 0x20000000) - { - INFO_LOG(EXPANSIONINTERFACE, "EXI IPL-DEV: RTC access"); - } - else if ((m_uAddress & 0x7FFFFF00) == 0x20000100) - { - INFO_LOG(EXPANSIONINTERFACE, "EXI IPL-DEV: SRAM access"); - } - else if ((m_uAddress & 0x7FFFFF00) == 0x20010000) - { - DEBUG_LOG(EXPANSIONINTERFACE, "EXI IPL-DEV: UART"); - } - else if ((m_uAddress & 0x7FFFFF00) == 0x20011300) { - DEBUG_LOG(EXPANSIONINTERFACE, "EXI IPL-DEV: UART Barnacle"); + // Subtract Wii bias + rtc = Common::swap32(CEXIIPL::GetGCTime() - cWiiBias); } - else if ((m_uAddress & 0x7FFFFF00) == 0x20010300) - { - DEBUG_LOG(EXPANSIONINTERFACE, "EXI IPL-DEV: UART Other?"); - } - else if (((m_uAddress & 0x7FFFFF00) == 0x21000000) || - ((m_uAddress & 0x7FFFFF00) == 0x21000100) || - ((m_uAddress & 0x7FFFFF00) == 0x21000800)) - { - ERROR_LOG(EXPANSIONINTERFACE, "EXI IPL-DEV: RTC flags (WII only) - not implemented"); - } else { - //_dbg_assert_(EXPANSIONINTERFACE, 0); - _dbg_assert_msg_(EXPANSIONINTERFACE, 0, "EXI IPL-DEV: illegal access address %08x", m_uAddress); - ERROR_LOG(EXPANSIONINTERFACE, "EXI IPL-DEV: illegal address %08x", m_uAddress); + rtc = Common::swap32(CEXIIPL::GetGCTime()); } -#endif - } - } - else - { - // --- Encrypted ROM --- - // atm we pre-decrypt the whole thing, see CEXIIPL ctor - if ((m_uAddress & 0x60000000) == 0) - { - if ((m_uAddress & 0x80000000) == 0) - { - u32 position = ((m_uAddress >> 6) & ROM_MASK) + m_uRWOffset; - // Technically we should apply descrambling here, if it's currently enabled. - _uByte = m_pIPL[position]; + // Log the command + std::string device_name; - if ((position >= 0x001AFF00) && (position <= 0x001FF474) && !m_FontsLoaded) + switch (CommandRegion()) + { + case REGION_RTC: + device_name = "RTC"; + break; + case REGION_SRAM: + device_name = "SRAM"; + break; + case REGION_UART: + device_name = "UART"; + break; + case REGION_EUART: + case REGION_EUART_UNK: + device_name = "EUART"; + break; + case REGION_UART_UNK: + device_name = "UART Other?"; + break; + case REGION_BARNACLE: + device_name = "UART Barnacle"; + break; + case REGION_WRTC0: + case REGION_WRTC1: + case REGION_WRTC2: + device_name = "Wii RTC flags - not implemented"; + break; + default: + if ((m_uAddress >> 6) < ROM_SIZE) { - PanicAlertT("Error: Trying to access %s fonts but they are not loaded. Games may not show fonts correctly, or crash.", - (position >= 0x001FCF00)?"ANSI":"SJIS"); - m_FontsLoaded = true; // Don't be a nag :p + device_name = "ROM"; } + else + { + device_name = "illegal address"; + _dbg_assert_msg_(EXPANSIONINTERFACE, 0, + "EXI IPL-DEV: %s %08x", device_name.c_str(), m_uAddress); + } + break; } - } - // --- Real Time Clock (RTC) --- - else if ((m_uAddress & 0x7FFFFF00) == 0x20000000) + + DEBUG_LOG(EXPANSIONINTERFACE, "%s %s %08x", device_name.c_str(), + IsWriteCommand() ? "write" : "read", m_uAddress); + } + } + else + { + // Actually read or write a byte + switch (CommandRegion()) { - if (m_uAddress & 0x80000000) + case REGION_RTC: + if (IsWriteCommand()) m_RTC[(m_uAddress & 0x03) + m_uRWOffset] = _uByte; else _uByte = m_RTC[(m_uAddress & 0x03) + m_uRWOffset]; - } - // --- SRAM --- - else if ((m_uAddress & 0x7FFFFF00) == 0x20000100) - { - if (m_uAddress & 0x80000000) + break; + + case REGION_SRAM: + if (IsWriteCommand()) g_SRAM.p_SRAM[(m_uAddress & 0x3F) + m_uRWOffset] = _uByte; else _uByte = g_SRAM.p_SRAM[(m_uAddress & 0x3F) + m_uRWOffset]; - } - // --- UART --- - else if ((m_uAddress & 0x7FFFFF00) == 0x20010000) - { - if (m_uAddress & 0x80000000) + break; + + case REGION_UART: + case REGION_EUART: + if (IsWriteCommand()) { - m_szBuffer[m_count++] = _uByte; + if (_uByte != '\0') + m_szBuffer[m_count++] = _uByte; if ((m_count >= 256) || (_uByte == 0xD)) { m_szBuffer[m_count] = 0x00; - INFO_LOG(OSREPORT, "%s", m_szBuffer); + NOTICE_LOG(OSREPORT, "%s", m_szBuffer); memset(m_szBuffer, 0, sizeof(m_szBuffer)); m_count = 0; } } else - _uByte = 0x01; // dunno - } - else if ((m_uAddress & 0x7FFFFF00) == 0x20011300) - { - INFO_LOG(OSREPORT, "UART Barnacle %x", _uByte); - } - else if ((m_uAddress & 0x7FFFFF00) == 0x20010300) - { - INFO_LOG(OSREPORT, "UART? %x", _uByte); + { + // "Queue Length"... return 0 cause we're instant + _uByte = 0; + } + break; + + case REGION_EUART_UNK: + // Writes 0xf2 then 0xf3 on EUART init. Just need to return non-zero + // so we can leave the byte untouched. + break; + + case REGION_UART_UNK: + DEBUG_LOG(OSREPORT, "UART? %x", _uByte); _uByte = 0xff; + break; + + case REGION_BARNACLE: + DEBUG_LOG(OSREPORT, "UART Barnacle %x", _uByte); + break; + + case REGION_WRTC0: + case REGION_WRTC1: + case REGION_WRTC2: + // WII only RTC flags... afaik just the wii menu initialize it + default: + if ((m_uAddress >> 6) < ROM_SIZE) + { + if (!IsWriteCommand()) + { + u32 position = ((m_uAddress >> 6) & ROM_MASK) + m_uRWOffset; + + // Technically we should descramble here iff descrambling logic is enabled. + // At the moment, we pre-decrypt the whole thing and + // ignore the "enabled" bit - see CEXIIPL::CEXIIPL + _uByte = m_pIPL[position]; + + if ((position >= 0x001AFF00) && (position <= 0x001FF474) && !m_FontsLoaded) + { + PanicAlertT( + "Error: Trying to access %s fonts but they are not loaded. " + "Games may not show fonts correctly, or crash.", + (position >= 0x001FCF00) ? "ANSI" : "SJIS"); + m_FontsLoaded = true; // Don't be a nag :p + } + } + } + else + { + NOTICE_LOG(OSREPORT, "EXI IPL-DEV: %s %x at %08x", + IsWriteCommand() ? "write" : "read", _uByte, m_uAddress); + } + break; } - else if (((m_uAddress & 0x7FFFFF00) == 0x21000000) || - ((m_uAddress & 0x7FFFFF00) == 0x21000100) || - ((m_uAddress & 0x7FFFFF00) == 0x21000800)) - { - // WII only RTC flags... afaik just the wii menu initialize it -// if (m_uAddress & 0x80000000) -// g_SRAM.p_SRAM[(m_uAddress & 0x3F) + m_uRWOffset] = _uByte; -// else -// _uByte = g_SRAM.p_SRAM[(m_uAddress & 0x3F) + m_uRWOffset]; - } + m_uRWOffset++; } + m_uPosition++; } diff --git a/Source/Core/Core/Src/HW/EXI_DeviceIPL.h b/Source/Core/Core/Src/HW/EXI_DeviceIPL.h index bcc04c2e8f..4788f21adb 100644 --- a/Source/Core/Core/Src/HW/EXI_DeviceIPL.h +++ b/Source/Core/Core/Src/HW/EXI_DeviceIPL.h @@ -43,6 +43,20 @@ private: ROM_MASK = (ROM_SIZE - 1) }; + enum + { + REGION_RTC = 0x200000, + REGION_SRAM = 0x200001, + REGION_UART = 0x200100, + REGION_UART_UNK = 0x200103, + REGION_BARNACLE = 0x200113, + REGION_WRTC0 = 0x210000, + REGION_WRTC1 = 0x210001, + REGION_WRTC2 = 0x210008, + REGION_EUART_UNK= 0x300000, + REGION_EUART = 0x300001 + }; + // Region bool m_bNTSC; @@ -63,6 +77,8 @@ private: bool m_FontsLoaded; virtual void TransferByte(u8 &_uByte); + bool IsWriteCommand() const { return !!(m_uAddress & (1 << 31)); } + u32 const CommandRegion() const { return (m_uAddress & ~(1 << 31)) >> 8; } void LoadFileToIPL(std::string filename, u32 offset); }; diff --git a/Source/Core/Core/Src/HW/EXI_DeviceMemoryCard.cpp b/Source/Core/Core/Src/HW/EXI_DeviceMemoryCard.cpp index e7f052b864..14a155a0ff 100644 --- a/Source/Core/Core/Src/HW/EXI_DeviceMemoryCard.cpp +++ b/Source/Core/Core/Src/HW/EXI_DeviceMemoryCard.cpp @@ -103,7 +103,7 @@ CEXIMemoryCard::CEXIMemoryCard(const int index) void innerFlush(FlushData* data) { - File::IOFile pFile(data->filename, "wb"); + File::IOFile pFile(data->filename, "r+b"); if (!pFile) { std::string dir; diff --git a/Source/Core/Core/Src/HW/GCMemcard.cpp b/Source/Core/Core/Src/HW/GCMemcard.cpp index cab7d950a2..5ba0c2aaa6 100644 --- a/Source/Core/Core/Src/HW/GCMemcard.cpp +++ b/Source/Core/Core/Src/HW/GCMemcard.cpp @@ -16,7 +16,6 @@ // http://code.google.com/p/dolphin-emu/ #include "GCMemcard.h" #include "ColorUtil.h" - static void ByteSwap(u8 *valueA, u8 *valueB) { u8 tmp = *valueA; @@ -64,7 +63,6 @@ void decodeCI8image(u32* dst, u8* src, u16* pal, int width, int height) GCMemcard::GCMemcard(const char *filename, bool forceCreation, bool sjis) : m_valid(false) , m_fileName(filename) - , mc_data(NULL) { File::IOFile mcdFile(m_fileName, "r+b"); if (!mcdFile.IsOpen()) @@ -210,22 +208,49 @@ GCMemcard::GCMemcard(const char *filename, bool forceCreation, bool sjis) mcdFile.Seek(0xa000, SEEK_SET); maxBlock = (u32)m_sizeMb * MBIT_TO_BLOCKS; - mc_data_size = (maxBlock - MC_FST_BLOCKS) * BLOCK_SIZE; - mc_data = new u8[mc_data_size]; - - if (mcdFile.ReadBytes(mc_data, mc_data_size)) + mc_data_blocks.reserve(maxBlock - MC_FST_BLOCKS); + + m_valid = true; + for (u32 i = MC_FST_BLOCKS; i < maxBlock; ++i) + { + GCMBlock b; + if (mcdFile.ReadBytes(b.block, BLOCK_SIZE)) + { + mc_data_blocks.push_back(b); + } + else + { + PanicAlertT("Failed to read block %d of the save data\nMemcard may be truncated\nFilePosition:%llx", i, mcdFile.Tell()); + m_valid = false; + break; + } + } + + mcdFile.Close(); + + if (BE16(dir.UpdateCounter) > (BE16(dir_backup.UpdateCounter))) { - m_valid = true; + CurrentDir = &dir; + PreviousDir = &dir_backup; } else { - PanicAlertT("Failed to read save data\n(0xA000-)\nMemcard may be truncated"); + CurrentDir = &dir_backup; + PreviousDir = &dir; + } + if (BE16(bat.UpdateCounter) > BE16(bat_backup.UpdateCounter)) + { + CurrentBat = &bat; + PreviousBat = &bat_backup; + } + else + { + CurrentBat = &bat_backup; + PreviousBat = &bat; } - - mcdFile.Close(); } -bool GCMemcard::IsAsciiEncoding() +bool GCMemcard::IsAsciiEncoding() const { return hdr.Encoding == 0; } @@ -240,7 +265,10 @@ bool GCMemcard::Save() mcdFile.WriteBytes(&dir_backup, BLOCK_SIZE); mcdFile.WriteBytes(&bat, BLOCK_SIZE); mcdFile.WriteBytes(&bat_backup, BLOCK_SIZE); - mcdFile.WriteBytes(mc_data, mc_data_size); + for (int i = 0; i < maxBlock - MC_FST_BLOCKS; ++i) + { + mcdFile.WriteBytes(mc_data_blocks[i].block, BLOCK_SIZE); + } return mcdFile.Close(); } @@ -267,7 +295,7 @@ void GCMemcard::calc_checksumsBE(u16 *buf, u32 length, u16 *csum, u16 *inv_csum) } } -u32 GCMemcard::TestChecksums() +u32 GCMemcard::TestChecksums() const { u16 csum=0, csum_inv=0; @@ -306,7 +334,7 @@ bool GCMemcard::FixChecksums() return true; } -u8 GCMemcard::GetNumFiles() +u8 GCMemcard::GetNumFiles() const { if (!m_valid) return 0; @@ -314,21 +342,42 @@ u8 GCMemcard::GetNumFiles() u8 j = 0; for (int i = 0; i < DIRLEN; i++) { - if (BE32(dir.Dir[i].Gamecode)!= 0xFFFFFFFF) + if (BE32(CurrentDir->Dir[i].Gamecode)!= 0xFFFFFFFF) j++; } return j; } -u16 GCMemcard::GetFreeBlocks() +u8 GCMemcard::GetFileIndex(u8 fileNumber) const +{ + if (m_valid) + { + + u8 j = 0; + for (u8 i = 0; i < DIRLEN; i++) + { + if (BE32(CurrentDir->Dir[i].Gamecode)!= 0xFFFFFFFF) + { + if (j == fileNumber) + { + return i; + } + j++; + } + } + } + return 0xFF; +} + +u16 GCMemcard::GetFreeBlocks() const { if (!m_valid) return 0; - return BE16(bat.FreeBlocks); + return BE16(CurrentBat->FreeBlocks); } -u8 GCMemcard::TitlePresent(DEntry d) +u8 GCMemcard::TitlePresent(DEntry d) const { if (!m_valid) return DIRLEN; @@ -336,8 +385,8 @@ u8 GCMemcard::TitlePresent(DEntry d) u8 i = 0; while(i < DIRLEN) { - if ((BE32(dir.Dir[i].Gamecode) == BE32(d.Gamecode)) && - (!memcmp(dir.Dir[i].Filename, d.Filename, 32))) + if ((BE32(CurrentDir->Dir[i].Gamecode) == BE32(d.Gamecode)) && + (!memcmp(CurrentDir->Dir[i].Filename, d.Filename, 32))) { break; } @@ -346,208 +395,247 @@ u8 GCMemcard::TitlePresent(DEntry d) return i; } -// DEntry functions, all take u8 index < DIRLEN (127) -// Functions that have ascii output take a char *buffer - -bool GCMemcard::DEntry_GameCode(u8 index, char *buffer) +bool GCMemcard::GCI_FileName(u8 index, std::string &filename) const { - if (!m_valid) + if (!m_valid || index > DIRLEN || (BE32(CurrentDir->Dir[index].Gamecode) == 0xFFFFFFFF)) return false; - - memcpy(buffer, dir.Dir[index].Gamecode, 4); - buffer[4] = 0; + filename = std::string((char*)CurrentDir->Dir[index].Gamecode, 4) + '_' + (char*)CurrentDir->Dir[index].Filename + ".gci"; return true; } -bool GCMemcard::DEntry_Markercode(u8 index, char *buffer) +// DEntry functions, all take u8 index < DIRLEN (127) +// Functions that have ascii output take a char *buffer + +std::string GCMemcard::DEntry_GameCode(u8 index) const { - if (!m_valid) - return false; + if (!m_valid || index > DIRLEN) + return ""; + return std::string((const char*)CurrentDir->Dir[index].Gamecode, 4); +} - memcpy(buffer, dir.Dir[index].Markercode, 2); - buffer[2] = 0; - return true; +std::string GCMemcard::DEntry_Makercode(u8 index) const +{ + if (!m_valid || index > DIRLEN) + return ""; + return std::string((const char*)CurrentDir->Dir[index].Makercode, 2); } -bool GCMemcard::DEntry_BIFlags(u8 index, char *buffer) + +std::string GCMemcard::DEntry_BIFlags(u8 index) const { - if (!m_valid) - return false; + if (!m_valid || index > DIRLEN) + return ""; - int x = dir.Dir[index].BIFlags; + std::string flags; + int x = CurrentDir->Dir[index].BIFlags; for (int i = 0; i < 8; i++) { - buffer[i] = (x & 0x80) ? '1' : '0'; + flags.push_back((x & 0x80) ? '1' : '0'); x = x << 1; } - buffer[8] = 0; - return true; + flags.push_back(0); + return flags; } -bool GCMemcard::DEntry_FileName(u8 index, char *buffer) +std::string GCMemcard::DEntry_FileName(u8 index) const { - if (!m_valid) - return false; - - memcpy (buffer, (const char*)dir.Dir[index].Filename, DENTRY_STRLEN); - buffer[31] = 0; - return true; + if (!m_valid || index > DIRLEN) + return ""; + return std::string((const char*)CurrentDir->Dir[index].Filename, DENTRY_STRLEN); } -u32 GCMemcard::DEntry_ModTime(u8 index) +u32 GCMemcard::DEntry_ModTime(u8 index) const { - return BE32(dir.Dir[index].ModTime); + if (!m_valid || index > DIRLEN) + return 0xFFFFFFFF; + return BE32(CurrentDir->Dir[index].ModTime); } -u32 GCMemcard::DEntry_ImageOffset(u8 index) +u32 GCMemcard::DEntry_ImageOffset(u8 index) const { - return BE32(dir.Dir[index].ImageOffset); + if (!m_valid || index > DIRLEN) + return 0xFFFFFFFF; + return BE32(CurrentDir->Dir[index].ImageOffset); } -bool GCMemcard::DEntry_IconFmt(u8 index, char *buffer) +std::string GCMemcard::DEntry_IconFmt(u8 index) const { - if (!m_valid) return false; - - int x = dir.Dir[index].IconFmt[0]; + if (!m_valid || index > DIRLEN) + return ""; + int x = CurrentDir->Dir[index].IconFmt[0]; + std::string format; for(int i = 0; i < 16; i++) { - if (i == 8) x = dir.Dir[index].IconFmt[1]; - buffer[i] = (x & 0x80) ? '1' : '0'; + if (i == 8) x = CurrentDir->Dir[index].IconFmt[1]; + format.push_back((x & 0x80) ? '1' : '0'); x = x << 1; } - buffer[16] = 0; - return true; - + format.push_back(0); + return format; } -u16 GCMemcard::DEntry_AnimSpeed(u8 index) +u16 GCMemcard::DEntry_AnimSpeed(u8 index) const { - return BE16(dir.Dir[index].AnimSpeed); + if (!m_valid || index > DIRLEN) + return 0xFF; + return BE16(CurrentDir->Dir[index].AnimSpeed); } -bool GCMemcard::DEntry_Permissions(u8 index, char *fn) +std::string GCMemcard::DEntry_Permissions(u8 index) const { - if (!m_valid) return false; - fn[0] = (dir.Dir[index].Permissions & 16) ? 'x' : 'M'; - fn[1] = (dir.Dir[index].Permissions & 8) ? 'x' : 'C'; - fn[2] = (dir.Dir[index].Permissions & 4) ? 'P' : 'x'; - fn[3] = 0; - return true; + if (!m_valid || index > DIRLEN) + return ""; + u8 Permissions = CurrentDir->Dir[index].Permissions; + std::string permissionsString; + permissionsString.push_back((Permissions & 16) ? 'x' : 'M'); + permissionsString.push_back((Permissions & 8) ? 'x' : 'C'); + permissionsString.push_back((Permissions & 4) ? 'P' : 'x'); + permissionsString.push_back(0); + return permissionsString; } -u8 GCMemcard::DEntry_CopyCounter(u8 index) +u8 GCMemcard::DEntry_CopyCounter(u8 index) const { - return dir.Dir[index].CopyCounter; + if (!m_valid || index > DIRLEN) + return 0xFF; + return CurrentDir->Dir[index].CopyCounter; } -u16 GCMemcard::DEntry_FirstBlock(u8 index) +u16 GCMemcard::DEntry_FirstBlock(u8 index) const { - if (!m_valid) + if (!m_valid || index > DIRLEN) return 0xFFFF; - u16 block = BE16(dir.Dir[index].FirstBlock); + u16 block = BE16(CurrentDir->Dir[index].FirstBlock); if (block > (u16) maxBlock) return 0xFFFF; return block; } -u16 GCMemcard::DEntry_BlockCount(u8 index) +u16 GCMemcard::DEntry_BlockCount(u8 index) const { - if (!m_valid) + if (!m_valid || index > DIRLEN) return 0xFFFF; - u16 blocks = BE16(dir.Dir[index].BlockCount); + u16 blocks = BE16(CurrentDir->Dir[index].BlockCount); if (blocks > (u16) maxBlock) return 0xFFFF; return blocks; } -u32 GCMemcard::DEntry_CommentsAddress(u8 index) +u32 GCMemcard::DEntry_CommentsAddress(u8 index) const { - return BE32(dir.Dir[index].CommentsAddr); + if (!m_valid || index > DIRLEN) + return 0xFFFF; + return BE32(CurrentDir->Dir[index].CommentsAddr); } -bool GCMemcard::DEntry_Comment1(u8 index, char* buffer) +std::string GCMemcard::GetSaveComment1(u8 index) const { - if (!m_valid) - return false; + if (!m_valid || index > DIRLEN) + return ""; - u32 Comment1 = BE32(dir.Dir[index].CommentsAddr); - u32 DataBlock = BE16(dir.Dir[index].FirstBlock) - MC_FST_BLOCKS; + u32 Comment1 = BE32(CurrentDir->Dir[index].CommentsAddr); + u32 DataBlock = BE16(CurrentDir->Dir[index].FirstBlock) - MC_FST_BLOCKS; if ((DataBlock > maxBlock) || (Comment1 == 0xFFFFFFFF)) { - buffer[0] = 0; - return false; + return ""; } - memcpy(buffer, mc_data + (DataBlock * BLOCK_SIZE) + Comment1, DENTRY_STRLEN); - buffer[31] = 0; - return true; + return std::string((const char *)mc_data_blocks[DataBlock].block + Comment1, DENTRY_STRLEN); } -bool GCMemcard::DEntry_Comment2(u8 index, char* buffer) +std::string GCMemcard::GetSaveComment2(u8 index) const { - if (!m_valid) - return false; + if (!m_valid || index > DIRLEN) + return ""; - u32 Comment1 = BE32(dir.Dir[index].CommentsAddr); + u32 Comment1 = BE32(CurrentDir->Dir[index].CommentsAddr); u32 Comment2 = Comment1 + DENTRY_STRLEN; - u32 DataBlock = BE16(dir.Dir[index].FirstBlock) - MC_FST_BLOCKS; + u32 DataBlock = BE16(CurrentDir->Dir[index].FirstBlock) - MC_FST_BLOCKS; if ((DataBlock > maxBlock) || (Comment1 == 0xFFFFFFFF)) { - buffer[0] = 0; - return false; + return ""; } - memcpy(buffer, mc_data + (DataBlock * BLOCK_SIZE) + Comment2, DENTRY_STRLEN); - buffer[31] = 0; - return true; + return std::string((const char *)mc_data_blocks[DataBlock].block + Comment2, DENTRY_STRLEN); } -bool GCMemcard::DEntry_Copy(u8 index, GCMemcard::DEntry& info) +bool GCMemcard::GetDEntry(u8 index, DEntry &dest) const { - if (!m_valid) + if (!m_valid || index > DIRLEN) return false; - - info = dir.Dir[index]; + dest = CurrentDir->Dir[index]; return true; } -u32 GCMemcard::DEntry_GetSaveData(u8 index, u8* dest, bool old) +u16 GCMemcard::BlockAlloc::GetNextBlock(u16 Block) const +{ + if ((Block < MC_FST_BLOCKS) || (Block > 4091)) + return 0; + return Common::swap16(Map[Block-MC_FST_BLOCKS]); +} + +u16 GCMemcard::BlockAlloc::NextFreeBlock(u16 StartingBlock) const +{ + if (FreeBlocks) + { + for (u16 i = StartingBlock; i < BAT_SIZE; ++i) + if (Map[i-MC_FST_BLOCKS] == 0) + return i; + for (u16 i = 0; i < StartingBlock; ++i) + if (Map[i-MC_FST_BLOCKS] == 0) + return i; + } + return 0xFFFF; +} + +bool GCMemcard::BlockAlloc::ClearBlocks(u16 FirstBlock, u16 BlockCount) +{ + std::vector<u16> blocks; + while (FirstBlock != 0xFFFF && FirstBlock != 0) + { + blocks.push_back(FirstBlock); + FirstBlock = GetNextBlock(FirstBlock); + } + if (FirstBlock > 0) + { + size_t length = blocks.size(); + if (length != BlockCount) + { + return false; + } + for (int i = 0; i < length; ++i) + Map[blocks.at(i)-MC_FST_BLOCKS] = 0; + FreeBlocks = BE16(BE16(FreeBlocks) + BlockCount); + + return true; + } + return false; +} + +u32 GCMemcard::GetSaveData(u8 index, std::vector<GCMBlock> & Blocks) const { if (!m_valid) return NOMEMCARD; u16 block = DEntry_FirstBlock(index); - u16 saveLength = DEntry_BlockCount(index); + u16 BlockCount = DEntry_BlockCount(index); u16 memcardSize = BE16(hdr.SizeMb) * MBIT_TO_BLOCKS; - if ((block == 0xFFFF) || (saveLength == 0xFFFF) - || (block + saveLength > memcardSize)) + if ((block == 0xFFFF) || (BlockCount == 0xFFFF)) { return FAIL; } - if (!old) + u16 nextBlock = block; + for (int i = 0; i < BlockCount; ++i) { - memcpy(dest, mc_data + BLOCK_SIZE * (block - MC_FST_BLOCKS), saveLength * BLOCK_SIZE); - } - else - { - if (block == 0) return FAIL; - while (block != 0xffff) - { - memcpy(dest, mc_data + BLOCK_SIZE * (block - MC_FST_BLOCKS), BLOCK_SIZE); - dest += BLOCK_SIZE; - - u16 nextblock = Common::swap16(bat.Map[block - MC_FST_BLOCKS]); - if (block + saveLength != memcardSize && nextblock > 0) - {//Fixes for older memcards that were not initialized with FF - block = nextblock; - } - else break; - } + if ((!nextBlock) || (nextBlock == 0xFFFF)) + return FAIL; + Blocks.push_back(mc_data_blocks[nextBlock-MC_FST_BLOCKS]); + nextBlock = CurrentBat->GetNextBlock(nextBlock); } return SUCCESS; } // End DEntry functions -u32 GCMemcard::ImportFile(DEntry& direntry, u8* contents, int remove) +u32 GCMemcard::ImportFile(DEntry& direntry, std::vector<GCMBlock> &saveBlocks) { if (!m_valid) return NOMEMCARD; @@ -556,86 +644,81 @@ u32 GCMemcard::ImportFile(DEntry& direntry, u8* contents, int remove) { return OUTOFDIRENTRIES; } - if (BE16(bat.FreeBlocks) < BE16(direntry.BlockCount)) + if (BE16(CurrentBat->FreeBlocks) < BE16(direntry.BlockCount)) { return OUTOFBLOCKS; } - if (!remove && (TitlePresent(direntry) != DIRLEN)) + if (TitlePresent(direntry) != DIRLEN) { return TITLEPRESENT; } - // find first free data block -- assume no freespace fragmentation - int totalspace = (((u32)BE16(hdr.SizeMb) * MBIT_TO_BLOCKS) - MC_FST_BLOCKS); - int firstFree1 = BE16(bat.LastAllocated) + 1; - int firstFree2 = 0; - for (int i = 0; i < DIRLEN; i++) - { - if (BE32(dir.Dir[i].Gamecode) == 0xFFFFFFFF) - { - break; - } - else - { - firstFree2 = max<int>(firstFree2, - (int)(BE16(dir.Dir[i].FirstBlock) + BE16(dir.Dir[i].BlockCount))); - } - } - firstFree1 = max<int>(firstFree1, firstFree2); - + // find first free data block + u16 firstBlock = CurrentBat->NextFreeBlock(BE16(CurrentBat->LastAllocated)); + if (firstBlock == 0xFFFF) + return OUTOFBLOCKS; + Directory UpdatedDir = *CurrentDir; + // find first free dir entry int index = -1; for (int i=0; i < DIRLEN; i++) { - if (BE32(dir.Dir[i].Gamecode) == 0xFFFFFFFF) + if (BE32(UpdatedDir.Dir[i].Gamecode) == 0xFFFFFFFF) { index = i; - dir.Dir[i] = direntry; - *(u16*)&dir.Dir[i].FirstBlock = BE16(firstFree1); - if (!remove) - { - dir.Dir[i].CopyCounter = dir.Dir[i].CopyCounter+1; - } - dir_backup = dir; + UpdatedDir.Dir[i] = direntry; + *(u16*)&UpdatedDir.Dir[i].FirstBlock = BE16(firstBlock); + UpdatedDir.Dir[i].CopyCounter = UpdatedDir.Dir[i].CopyCounter+1; break; } } - - // keep assuming no freespace fragmentation, and copy over all the data - u8 *destination = mc_data + (firstFree1 - MC_FST_BLOCKS) * BLOCK_SIZE; - - int fileBlocks = BE16(direntry.BlockCount); - memcpy(destination, contents, BLOCK_SIZE * fileBlocks); - bat_backup = bat; - u16 last = BE16(bat_backup.LastAllocated); - u16 i = (last - 4); - int j = 2; - while(j < BE16(direntry.BlockCount) + 1) - { - bat_backup.Map[i] = BE16(last + (u16)j); - i++; - j++; + UpdatedDir.UpdateCounter = BE16(BE16(UpdatedDir.UpdateCounter) + 1); + *PreviousDir = UpdatedDir; + if (PreviousDir == &dir ) + { + CurrentDir = &dir; + PreviousDir = &dir_backup; } - bat_backup.Map[i++] = 0xFFFF; - //Set bat.map to 0 for each block that was removed - for (int k = 0; k < remove; k++) + else { - bat_backup.Map[i++] = 0x0000; + CurrentDir = &dir_backup; + PreviousDir = &dir; } - //update last allocated block - *(u16*)&bat_backup.LastAllocated = BE16(BE16(bat_backup.LastAllocated) + j - 1); - //update freespace counter - *(u16*)&bat_backup.FreeBlocks = BE16(totalspace - firstFree1 - fileBlocks + MC_FST_BLOCKS); + int fileBlocks = BE16(direntry.BlockCount); + + BlockAlloc UpdatedBat = *CurrentBat; + u16 nextBlock; + // keep assuming no freespace fragmentation, and copy over all the data + for (int i = 0; i < fileBlocks; ++i) + { + if (firstBlock == 0xFFFF) + PanicAlert("Fatal Error"); + mc_data_blocks[firstBlock - MC_FST_BLOCKS] = saveBlocks[i]; + if (i == fileBlocks-1) + nextBlock = 0xFFFF; + else + nextBlock = UpdatedBat.NextFreeBlock(firstBlock+1); + UpdatedBat.Map[firstBlock - MC_FST_BLOCKS] = BE16(nextBlock); + UpdatedBat.LastAllocated = BE16(firstBlock); + firstBlock = nextBlock; + } - if (!remove) - { // ... and dir update counter - *(u16*)&dir_backup.UpdateCounter = BE16(BE16(dir_backup.UpdateCounter) + 1); - // ... and bat update counter - *(u16*)&bat_backup.UpdateCounter = BE16(BE16(bat_backup.UpdateCounter) + 1); + UpdatedBat.FreeBlocks = BE16(BE16(UpdatedBat.FreeBlocks) - fileBlocks); + UpdatedBat.UpdateCounter = BE16(BE16(UpdatedBat.UpdateCounter) + 1); + *PreviousBat = UpdatedBat; + if (PreviousBat == &bat ) + { + CurrentBat = &bat; + PreviousBat = &bat_backup; + } + else + { + CurrentBat = &bat_backup; + PreviousBat = &bat; } - bat = bat_backup; + return SUCCESS; } @@ -643,107 +726,93 @@ u32 GCMemcard::RemoveFile(u8 index) //index in the directory array { if (!m_valid) return NOMEMCARD; - - //error checking - u16 startingblock = 0; - for (int i = 0; i < DIRLEN; i++) + if (index >= DIRLEN) + return DELETE_FAIL; + + u16 startingblock = BE16(dir.Dir[index].FirstBlock); + u16 numberofblocks = BE16(dir.Dir[index].BlockCount); + + BlockAlloc UpdatedBat = *CurrentBat; + if (!UpdatedBat.ClearBlocks(startingblock, numberofblocks)) + return DELETE_FAIL; + UpdatedBat.UpdateCounter = BE16(BE16(UpdatedBat.UpdateCounter) + 1); + *PreviousBat = UpdatedBat; + if (PreviousBat == &bat ) { - if (startingblock > BE16(dir.Dir[i].FirstBlock)) - return DELETE_FAIL; - startingblock = BE16(dir.Dir[i].FirstBlock); + CurrentBat = &bat; + PreviousBat = &bat_backup; } - - //backup the directory and bat (not really needed here but meh :P - dir_backup = dir; - bat_backup = bat; - - //free the blocks - int blocks_left = BE16(dir.Dir[index].BlockCount); - *(u16*)&bat.LastAllocated = BE16(BE16(dir.Dir[index].FirstBlock) - 1); - - u8 nextIndex = index + 1; - memset(&(dir.Dir[index]), 0xFF, DENTRY_SIZE); - - while (nextIndex < DIRLEN) + else { - DEntry * tempDEntry = new DEntry; - DEntry_Copy(nextIndex, *tempDEntry); - u8 * tempSaveData = NULL; - //Only get file data if it is a valid dir entry - if (BE16(tempDEntry->FirstBlock) != 0xFFFF) - { - *(u16*)&bat.FreeBlocks = BE16(BE16(bat.FreeBlocks) - BE16(tempDEntry->BlockCount)); - - u16 size = DEntry_BlockCount(nextIndex); - if (size != 0xFFFF) - { - tempSaveData = new u8[size * BLOCK_SIZE]; - switch (DEntry_GetSaveData(nextIndex, tempSaveData, true)) - { - case NOMEMCARD: - delete[] tempSaveData; - tempSaveData = NULL; - break; - case FAIL: - delete[] tempSaveData; - delete tempDEntry; - return FAIL; - } - } - } - memset(&(dir.Dir[nextIndex]), 0xFF, DENTRY_SIZE); - //Only call import file if DEntry_GetSaveData returns SUCCESS - if (tempSaveData != NULL) - { - ImportFile(*tempDEntry, tempSaveData, blocks_left); - delete[] tempSaveData; - } - delete tempDEntry; - nextIndex++; + CurrentBat = &bat_backup; + PreviousBat = &bat; + } + Directory UpdatedDir = *CurrentDir; + /* + // TODO: determine when this is used, even on the same memory card I have seen + // both update to broken file, and not updated + *(u32*)&UpdatedDir.Dir[index].Gamecode = 0; + *(u16*)&UpdatedDir.Dir[index].Makercode = 0; + memset(UpdatedDir.Dir[index].Filename, 0, 0x20); + strcpy((char*)UpdatedDir.Dir[index].Filename, "Broken File000"); + *(u16*)&UpdatedDir.UpdateCounter = BE16(BE16(UpdatedDir.UpdateCounter) + 1); + + *PreviousDir = UpdatedDir; + if (PreviousDir == &dir ) + { + CurrentDir = &dir; + PreviousDir = &dir_backup; } - //Added to clean up if removing last file - if (BE16(bat.LastAllocated) == (u16)4) + else { - for (int j = 0; j < blocks_left; j++) - { - bat.Map[j] = 0x0000; - } + CurrentDir = &dir_backup; + PreviousDir = &dir; + } + */ + memset(&(UpdatedDir.Dir[index]), 0xFF, DENTRY_SIZE); + UpdatedDir.UpdateCounter = BE16(BE16(UpdatedDir.UpdateCounter) + 1); + *PreviousDir = UpdatedDir; + if (PreviousDir == &dir ) + { + CurrentDir = &dir; + PreviousDir = &dir_backup; + } + else + { + CurrentDir = &dir_backup; + PreviousDir = &dir; } - // increment update counter - *(u16*)&dir.UpdateCounter = BE16(BE16(dir.UpdateCounter) + 1); return SUCCESS; } -u32 GCMemcard::CopyFrom(GCMemcard& source, u8 index) +u32 GCMemcard::CopyFrom(const GCMemcard& source, u8 index) { - if (!m_valid) + if (!m_valid || !source.m_valid) return NOMEMCARD; DEntry tempDEntry; - if (!source.DEntry_Copy(index, tempDEntry)) return NOMEMCARD; + if (!source.GetDEntry(index, tempDEntry)) + return NOMEMCARD; u32 size = source.DEntry_BlockCount(index); if (size == 0xFFFF) return INVALIDFILESIZE; - u8 *tempSaveData = new u8[size * BLOCK_SIZE]; - switch (source.DEntry_GetSaveData(index, tempSaveData, true)) + std::vector<GCMBlock> saveData; + saveData.reserve(size); + switch (source.GetSaveData(index, saveData)) { case FAIL: - delete[] tempSaveData; return FAIL; case NOMEMCARD: - delete[] tempSaveData; return NOMEMCARD; default: - u32 ret = ImportFile(tempDEntry, tempSaveData, 0); - delete[] tempSaveData; - return ret; + return ImportFile(tempDEntry, saveData); } } -u32 GCMemcard::ImportGci(const char *inputFile, std::string outputFile) +u32 GCMemcard::ImportGci(const char *inputFile, const std::string &outputFile) { if (outputFile.empty() && !m_valid) return OPENFAIL; @@ -757,7 +826,7 @@ u32 GCMemcard::ImportGci(const char *inputFile, std::string outputFile) return result; } -u32 GCMemcard::ImportGciInternal(FILE* gcih, const char *inputFile, std::string outputFile) +u32 GCMemcard::ImportGciInternal(FILE* gcih, const char *inputFile, const std::string &outputFile) { File::IOFile gci(gcih); unsigned int offset; @@ -789,8 +858,8 @@ u32 GCMemcard::ImportGciInternal(FILE* gcih, const char *inputFile, std::string } gci.Seek(offset, SEEK_SET); - DEntry *tempDEntry = new DEntry; - gci.ReadBytes(tempDEntry, DENTRY_SIZE); + DEntry tempDEntry; + gci.ReadBytes(&tempDEntry, DENTRY_SIZE); const int fStart = (int)gci.Tell(); gci.Seek(0, SEEK_END); const int length = (int)gci.Tell() - fStart; @@ -798,14 +867,21 @@ u32 GCMemcard::ImportGciInternal(FILE* gcih, const char *inputFile, std::string Gcs_SavConvert(tempDEntry, offset, length); - if (length != BE16(tempDEntry->BlockCount) * BLOCK_SIZE) + if (length != BE16(tempDEntry.BlockCount) * BLOCK_SIZE) return LENGTHFAIL; if (gci.Tell() != offset + DENTRY_SIZE) // Verify correct file position return OPENFAIL; - u32 size = BE16((tempDEntry->BlockCount)) * BLOCK_SIZE; - u8 *tempSaveData = new u8[size]; - gci.ReadBytes(tempSaveData, size); + u32 size = BE16((tempDEntry.BlockCount)); + std::vector<GCMBlock> saveData; + saveData.reserve(size); + + for (int i = 0; i < size; ++i) + { + GCMBlock b; + gci.ReadBytes(b.block, BLOCK_SIZE); + saveData.push_back(b); + } u32 ret; if (!outputFile.empty()) { @@ -813,49 +889,41 @@ u32 GCMemcard::ImportGciInternal(FILE* gcih, const char *inputFile, std::string bool completeWrite = true; if (!gci2) { - delete[] tempSaveData; - delete tempDEntry; return OPENFAIL; } gci2.Seek(0, SEEK_SET); - if (!gci2.WriteBytes(tempDEntry, DENTRY_SIZE)) + if (!gci2.WriteBytes(&tempDEntry, DENTRY_SIZE)) completeWrite = false; - int fileBlocks = BE16(tempDEntry->BlockCount); + int fileBlocks = BE16(tempDEntry.BlockCount); gci2.Seek(DENTRY_SIZE, SEEK_SET); - if (!gci2.WriteBytes(tempSaveData, BLOCK_SIZE * fileBlocks)) + for (int i = 0; i < fileBlocks; ++i) + { + if (!gci2.WriteBytes(saveData[i].block, BLOCK_SIZE)) completeWrite = false; + } + if (completeWrite) ret = GCS; else ret = WRITEFAIL; } else - ret = ImportFile(*tempDEntry, tempSaveData, 0); + ret = ImportFile(tempDEntry, saveData); - delete[] tempSaveData; - delete tempDEntry; return ret; } -u32 GCMemcard::ExportGci(u8 index, const char *fileName, std::string *fileName2) +u32 GCMemcard::ExportGci(u8 index, const char *fileName, const std::string &directory) const { File::IOFile gci; int offset = GCI; - if (!strcasecmp(fileName, ".")) + if (!fileName) { - if (BE32(dir.Dir[index].Gamecode) == 0xFFFFFFFF) return SUCCESS; - - size_t length = fileName2->length() + 42; - char *filename = new char[length]; - char GameCode[5]; - - DEntry_GameCode(index, GameCode); - - sprintf(filename, "%s/%s_%s.gci", fileName2->c_str(), GameCode, dir.Dir[index].Filename); - gci.Open(filename, "wb"); - delete[] filename; + std::string gciFilename; + if (!GCI_FileName(index, gciFilename)) return SUCCESS; + gci.Open(directory + DIR_SEP + gciFilename, "wb"); } else { @@ -896,12 +964,12 @@ u32 GCMemcard::ExportGci(u8 index, const char *fileName, std::string *fileName2) } DEntry tempDEntry; - if (!DEntry_Copy(index, tempDEntry)) + if (!GetDEntry(index, tempDEntry)) { return NOMEMCARD; } - Gcs_SavConvert(&tempDEntry, offset); + Gcs_SavConvert(tempDEntry, offset); gci.WriteBytes(&tempDEntry, DENTRY_SIZE); u32 size = DEntry_BlockCount(index); @@ -910,23 +978,21 @@ u32 GCMemcard::ExportGci(u8 index, const char *fileName, std::string *fileName2) return FAIL; } - size *= BLOCK_SIZE; - u8 *tempSaveData = new u8[size]; + std::vector<GCMBlock> saveData; + saveData.reserve(size); - switch(DEntry_GetSaveData(index, tempSaveData, true)) + switch(GetSaveData(index, saveData)) { case FAIL: - delete[] tempSaveData; return FAIL; - case NOMEMCARD: - delete[] tempSaveData; return NOMEMCARD; } gci.Seek(DENTRY_SIZE + offset, SEEK_SET); - gci.WriteBytes(tempSaveData, size); - - delete[] tempSaveData; + for (int i = 0; i < size; ++i) + { + gci.WriteBytes(saveData[i].block, BLOCK_SIZE); + } if (gci.IsGood()) return SUCCESS; @@ -934,7 +1000,7 @@ u32 GCMemcard::ExportGci(u8 index, const char *fileName, std::string *fileName2) return WRITEFAIL; } -void GCMemcard::Gcs_SavConvert(DEntry* tempDEntry, int saveType, int length) +void GCMemcard::Gcs_SavConvert(DEntry &tempDEntry, int saveType, int length) { switch(saveType) { @@ -944,7 +1010,7 @@ void GCMemcard::Gcs_SavConvert(DEntry* tempDEntry, int saveType, int length) // It is stored only within the corresponding GSV file. // If the GCS file is added without using the GameSaves software, // the value stored is always "1" - *(u16*)&tempDEntry->BlockCount = BE16(length / BLOCK_SIZE); + *(u16*)&tempDEntry.BlockCount = BE16(length / BLOCK_SIZE); } break; case SAV: @@ -953,29 +1019,29 @@ void GCMemcard::Gcs_SavConvert(DEntry* tempDEntry, int saveType, int length) // 0x34 and 0x35, 0x36 and 0x37, 0x38 and 0x39, 0x3A and 0x3B, // 0x3C and 0x3D,0x3E and 0x3F. // It seems that sav files also swap the BIFlags... - ByteSwap(&tempDEntry->Unused1, &tempDEntry->BIFlags); - ArrayByteSwap((tempDEntry->ImageOffset)); - ArrayByteSwap(&(tempDEntry->ImageOffset[2])); - ArrayByteSwap((tempDEntry->IconFmt)); - ArrayByteSwap((tempDEntry->AnimSpeed)); - ByteSwap(&tempDEntry->Permissions, &tempDEntry->CopyCounter); - ArrayByteSwap((tempDEntry->FirstBlock)); - ArrayByteSwap((tempDEntry->BlockCount)); - ArrayByteSwap((tempDEntry->Unused2)); - ArrayByteSwap((tempDEntry->CommentsAddr)); - ArrayByteSwap(&(tempDEntry->CommentsAddr[2])); + ByteSwap(&tempDEntry.Unused1, &tempDEntry.BIFlags); + ArrayByteSwap((tempDEntry.ImageOffset)); + ArrayByteSwap(&(tempDEntry.ImageOffset[2])); + ArrayByteSwap((tempDEntry.IconFmt)); + ArrayByteSwap((tempDEntry.AnimSpeed)); + ByteSwap(&tempDEntry.Permissions, &tempDEntry.CopyCounter); + ArrayByteSwap((tempDEntry.FirstBlock)); + ArrayByteSwap((tempDEntry.BlockCount)); + ArrayByteSwap((tempDEntry.Unused2)); + ArrayByteSwap((tempDEntry.CommentsAddr)); + ArrayByteSwap(&(tempDEntry.CommentsAddr[2])); break; default: break; } } -bool GCMemcard::ReadBannerRGBA8(u8 index, u32* buffer) +bool GCMemcard::ReadBannerRGBA8(u8 index, u32* buffer) const { if (!m_valid) return false; - int flags = dir.Dir[index].BIFlags; + int flags = CurrentDir->Dir[index].BIFlags; // Timesplitters 2 is the only game that I see this in // May be a hack if (flags == 0xFB) flags = ~flags; @@ -985,8 +1051,8 @@ bool GCMemcard::ReadBannerRGBA8(u8 index, u32* buffer) if (bnrFormat == 0) return false; - u32 DataOffset = BE32(dir.Dir[index].ImageOffset); - u32 DataBlock = BE16(dir.Dir[index].FirstBlock) - MC_FST_BLOCKS; + u32 DataOffset = BE32(CurrentDir->Dir[index].ImageOffset); + u32 DataBlock = BE16(CurrentDir->Dir[index].FirstBlock) - MC_FST_BLOCKS; if ((DataBlock > maxBlock) || (DataOffset == 0xFFFFFFFF)) { @@ -997,21 +1063,21 @@ bool GCMemcard::ReadBannerRGBA8(u8 index, u32* buffer) if (bnrFormat&1) { - u8 *pxdata = (u8* )(mc_data + (DataBlock * BLOCK_SIZE) + DataOffset); - u16 *paldata = (u16*)(mc_data + (DataBlock * BLOCK_SIZE) + DataOffset + pixels); + u8 *pxdata = (u8* )(mc_data_blocks[DataBlock].block + DataOffset); + u16 *paldata = (u16*)(mc_data_blocks[DataBlock].block + DataOffset + pixels); decodeCI8image(buffer, pxdata, paldata, 96, 32); } else { - u16 *pxdata = (u16*)(mc_data + (DataBlock * BLOCK_SIZE) + DataOffset); + u16 *pxdata = (u16*)(mc_data_blocks[DataBlock].block + DataOffset); decode5A3image(buffer, pxdata, 96, 32); } return true; } -u32 GCMemcard::ReadAnimRGBA8(u8 index, u32* buffer, u8 *delays) +u32 GCMemcard::ReadAnimRGBA8(u8 index, u32* buffer, u8 *delays) const { if (!m_valid) return 0; @@ -1020,24 +1086,24 @@ u32 GCMemcard::ReadAnimRGBA8(u8 index, u32* buffer, u8 *delays) // Sonic Heroes it the only game I have seen that tries to use a CI8 and RGB5A3 icon int fmtCheck = 0; - int formats = BE16(dir.Dir[index].IconFmt); - int fdelays = BE16(dir.Dir[index].AnimSpeed); + int formats = BE16(CurrentDir->Dir[index].IconFmt); + int fdelays = BE16(CurrentDir->Dir[index].AnimSpeed); - int flags = dir.Dir[index].BIFlags; + int flags = CurrentDir->Dir[index].BIFlags; // Timesplitters 2 is the only game that I see this in // May be a hack if (flags == 0xFB) flags = ~flags; int bnrFormat = (flags&3); - u32 DataOffset = BE32(dir.Dir[index].ImageOffset); - u32 DataBlock = BE16(dir.Dir[index].FirstBlock) - MC_FST_BLOCKS; + u32 DataOffset = BE32(CurrentDir->Dir[index].ImageOffset); + u32 DataBlock = BE16(CurrentDir->Dir[index].FirstBlock) - MC_FST_BLOCKS; if ((DataBlock > maxBlock) || (DataOffset == 0xFFFFFFFF)) { return 0; } - u8* animData = (u8*)(mc_data + (DataBlock * BLOCK_SIZE) + DataOffset); + u8* animData = (u8*)(mc_data_blocks[DataBlock].block + DataOffset); switch (bnrFormat) { @@ -1153,17 +1219,13 @@ bool GCMemcard::Format(bool sjis, u16 SizeMb) m_sizeMb = SizeMb; maxBlock = (u32)m_sizeMb * MBIT_TO_BLOCKS; - if (mc_data) + mc_data_blocks.reserve(maxBlock - MC_FST_BLOCKS); + for (u32 i = 0; i < (maxBlock - MC_FST_BLOCKS); ++i) { - delete mc_data; - mc_data = NULL; + GCMBlock b; + mc_data_blocks.push_back(b); } - mc_data_size = BLOCK_SIZE * (m_sizeMb * MBIT_TO_BLOCKS - MC_FST_BLOCKS); - mc_data = new u8[mc_data_size]; - if (!mc_data) - return false; - memset(mc_data, 0xFF, mc_data_size); m_valid = true; return Save(); @@ -1182,8 +1244,8 @@ void GCMemcard::FormatInternal(GCMC_Header &GCP) rand = (((rand * (u64)0x0000000041c64e6dULL) + (u64)0x0000000000003039ULL) >> 16); rand &= (u64)0x0000000000007fffULL; } - *(u32*)&p_hdr->SramBias = g_SRAM.counter_bias; - *(u32*)&p_hdr->SramLang = g_SRAM.lang; + p_hdr->SramBias = g_SRAM.counter_bias; + p_hdr->SramLang = g_SRAM.lang; // TODO: determine the purpose of Unk2 1 works for slot A, 0 works for both slot A and slot B *(u32*)&p_hdr->Unk2 = 0; // = _viReg[55]; static vu16* const _viReg = (u16*)0xCC002000; *(u16*)&p_hdr->deviceID = 0; @@ -1192,15 +1254,15 @@ void GCMemcard::FormatInternal(GCMC_Header &GCP) Directory *p_dir = GCP.dir, *p_dir_backup = GCP.dir_backup; *(u16*)&p_dir->UpdateCounter = 0; - *(u16*)&p_dir_backup->UpdateCounter = BE16(1); + p_dir_backup->UpdateCounter = BE16(1); calc_checksumsBE((u16*)p_dir, 0xFFE, &p_dir->Checksum, &p_dir->Checksum_Inv); calc_checksumsBE((u16*)p_dir_backup, 0xFFE, &p_dir_backup->Checksum, &p_dir_backup->Checksum_Inv); BlockAlloc *p_bat = GCP.bat, *p_bat_backup = GCP.bat_backup; - *(u16*)&p_bat_backup->UpdateCounter = BE16(1); - *(u16*)&p_bat->FreeBlocks = *(u16*)&p_bat_backup->FreeBlocks = BE16(( BE16(p_hdr->SizeMb) * MBIT_TO_BLOCKS) - MC_FST_BLOCKS); - *(u16*)&p_bat->LastAllocated = *(u16*)&p_bat_backup->LastAllocated = BE16(4); + p_bat_backup->UpdateCounter = BE16(1); + p_bat->FreeBlocks = *(u16*)&p_bat_backup->FreeBlocks = BE16(( BE16(p_hdr->SizeMb) * MBIT_TO_BLOCKS) - MC_FST_BLOCKS); + p_bat->LastAllocated = p_bat_backup->LastAllocated = BE16(4); calc_checksumsBE((u16*)p_bat+2, 0xFFE, &p_bat->Checksum, &p_bat->Checksum_Inv); calc_checksumsBE((u16*)p_bat_backup+2, 0xFFE, &p_bat_backup->Checksum, &p_bat_backup->Checksum_Inv); } diff --git a/Source/Core/Core/Src/HW/GCMemcard.h b/Source/Core/Core/Src/HW/GCMemcard.h index 8c7baa4774..be78bb527c 100644 --- a/Source/Core/Core/Src/HW/GCMemcard.h +++ b/Source/Core/Core/Src/HW/GCMemcard.h @@ -19,14 +19,15 @@ #define __GCMEMCARD_h__ #include "Common.h" +#include "CommonPaths.h" #include "Sram.h" #include "StringUtil.h" #include "EXI_DeviceIPL.h" +#define BE64(x) (Common::swap64(x)) #define BE32(x) (Common::swap32(x)) #define BE16(x) (Common::swap16(x)) #define ArrayByteSwap(a) (ByteSwap(a, a+sizeof(u8))); - enum { SLOT_A = 0, @@ -54,6 +55,7 @@ enum DENTRY_STRLEN = 0x20, DENTRY_SIZE = 0x40, BLOCK_SIZE = 0x2000, + BAT_SIZE = 0xFFB, MemCard59Mb = 0x04, MemCard123Mb = 0x08, @@ -75,25 +77,28 @@ private: std::string m_fileName; u32 maxBlock; - u32 mc_data_size; - u8* mc_data; - u16 m_sizeMb; - + struct GCMBlock + { + GCMBlock(){erase();} + void erase() {memset(block, 0xFF, BLOCK_SIZE);} + u8 block[BLOCK_SIZE]; + }; + std::vector<GCMBlock> mc_data_blocks; #pragma pack(push,1) struct Header { //Offset Size Description // Serial in libogc u8 serial[12]; //0x0000 12 ? u64 formatTime; //0x000c 8 time of format (OSTime value) - u8 SramBias[4]; //0x0014 4 sram bias at time of format - u8 SramLang[4]; //0x0018 4 sram language + u32 SramBias; //0x0014 4 sram bias at time of format + u32 SramLang; //0x0018 4 sram language u8 Unk2[4]; //0x001c 4 ? almost always 0 // end Serial in libogc u8 deviceID[2]; //0x0020 2 0 if formated in slot A 1 if formated in slot B u8 SizeMb[2]; //0x0022 2 size of memcard in Mbits u16 Encoding; //0x0024 2 encoding (ASCII or japanese) u8 Unused1[468]; //0x0026 468 unused (0xff) - u8 UpdateCounter[2];//0x01fa 2 update Counter (?, probably unused) + u16 UpdateCounter; //0x01fa 2 update Counter (?, probably unused) u16 Checksum; //0x01fc 2 Additive Checksum u16 Checksum_Inv; //0x01fe 2 Inverse Checksum u8 Unused2[7680]; //0x0200 0x1e00 unused (0xff) @@ -101,7 +106,7 @@ private: struct DEntry { u8 Gamecode[4]; //0x00 0x04 Gamecode - u8 Markercode[2]; //0x04 0x02 Makercode + u8 Makercode[2]; //0x04 0x02 Makercode u8 Unused1; //0x06 0x01 reserved/unused (always 0xff, has no effect) u8 BIFlags; //0x07 0x01 banner gfx format and icon animation (Image Key) // bit(s) description @@ -147,19 +152,25 @@ private: struct Directory { DEntry Dir[DIRLEN]; //0x0000 Directory Entries (max 127) u8 Padding[0x3a]; - u8 UpdateCounter[2];//0x1ffa 2 update Counter + u16 UpdateCounter; //0x1ffa 2 update Counter u16 Checksum; //0x1ffc 2 Additive Checksum u16 Checksum_Inv; //0x1ffe 2 Inverse Checksum } dir, dir_backup; + Directory *CurrentDir, *PreviousDir; struct BlockAlloc { - u16 Checksum; //0x0000 2 Additive Checksum - u16 Checksum_Inv; //0x0002 2 Inverse Checksum - u8 UpdateCounter[2];//0x0004 2 update Counter - u8 FreeBlocks[2]; //0x0006 2 free Blocks - u8 LastAllocated[2];//0x0008 2 last allocated Block - u16 Map[0xFFB]; //0x000a 0x1ff8 Map of allocated Blocks + u16 Checksum; //0x0000 2 Additive Checksum + u16 Checksum_Inv; //0x0002 2 Inverse Checksum + u16 UpdateCounter; //0x0004 2 update Counter + u16 FreeBlocks; //0x0006 2 free Blocks + u16 LastAllocated; //0x0008 2 last allocated Block + u16 Map[BAT_SIZE]; //0x000a 0x1ff8 Map of allocated Blocks + u16 GetNextBlock(u16 Block) const; + u16 NextFreeBlock(u16 StartingBlock=MC_FST_BLOCKS) const; + bool ClearBlocks(u16 StartingBlock, u16 Length); } bat,bat_backup; + + BlockAlloc *CurrentBat, *PreviousBat; struct GCMC_Header { Header *hdr; @@ -168,92 +179,83 @@ private: }; #pragma pack(pop) - u32 ImportGciInternal(FILE* gcih, const char *inputFile, std::string outputFile); + u32 ImportGciInternal(FILE* gcih, const char *inputFile, const std::string &outputFile); static void FormatInternal(GCMC_Header &GCP); public: GCMemcard(const char* fileName, bool forceCreation=false, bool sjis=false); - bool IsValid() { return m_valid; } - bool IsAsciiEncoding(); + bool IsValid() const { return m_valid; } + bool IsAsciiEncoding() const; bool Save(); bool Format(bool sjis = false, u16 SizeMb = MemCard2043Mb); static bool Format(u8 * card_data, bool sjis = false, u16 SizeMb = MemCard2043Mb); static void calc_checksumsBE(u16 *buf, u32 length, u16 *csum, u16 *inv_csum); - u32 TestChecksums(); + u32 TestChecksums() const; bool FixChecksums(); // get number of file entries in the directory - u8 GetNumFiles(); + u8 GetNumFiles() const; + u8 GetFileIndex(u8 fileNumber) const; // get the free blocks from bat - u16 GetFreeBlocks(); + u16 GetFreeBlocks() const; // If title already on memcard returns index, otherwise returns -1 - u8 TitlePresent(DEntry d); - - // DEntry functions, all take u8 index < DIRLEN (127) - // Functions that have ascii output take a char *buffer + u8 TitlePresent(DEntry d) const; - // buffer needs to be a char[5] or bigger - bool DEntry_GameCode(u8 index, char *buffer); - // buffer needs to be a char[2] or bigger - bool DEntry_Markercode(u8 index, char *buffer); - // buffer needs to be a char[9] or bigger - bool DEntry_BIFlags(u8 index, char *buffer); - // buffer needs to be a char[32] or bigger - bool DEntry_FileName(u8 index, char *buffer); - u32 DEntry_ModTime(u8 index); - u32 DEntry_ImageOffset(u8 index); - // buffer needs to be a char[17] or bigger - bool DEntry_IconFmt(u8 index, char *buffer); - u16 DEntry_AnimSpeed(u8 index); - // buffer needs to be a char[4] or bigger - bool DEntry_Permissions(u8 index, char *buffer); - u8 DEntry_CopyCounter(u8 index); + bool GCI_FileName(u8 index, std::string &filename) const; + // DEntry functions, all take u8 index < DIRLEN (127) + std::string DEntry_GameCode(u8 index) const; + std::string DEntry_Makercode(u8 index) const; + std::string DEntry_BIFlags(u8 index) const; + std::string DEntry_FileName(u8 index) const; + 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_Permissions(u8 index) const; + u8 DEntry_CopyCounter(u8 index) const; // get first block for file - u16 DEntry_FirstBlock(u8 index); + u16 DEntry_FirstBlock(u8 index) const; // get file length in blocks - u16 DEntry_BlockCount(u8 index); - u32 DEntry_CommentsAddress(u8 index); - // buffer needs to be a char[32] or bigger - bool DEntry_Comment1(u8 index, char *buffer); - // buffer needs to be a char[32] or bigger - bool DEntry_Comment2(u8 index, char *buffer); + u16 DEntry_BlockCount(u8 index) const; + u32 DEntry_CommentsAddress(u8 index) const; + std::string GetSaveComment1(u8 index) const; + std::string GetSaveComment2(u8 index) const; // Copies a DEntry from u8 index to DEntry& data - bool DEntry_Copy(u8 index, DEntry& data); + bool GetDEntry(u8 index, DEntry &dest) const; // assumes there's enough space in buffer // old determines if function uses old or new method of copying data // some functions only work with old way, some only work with new way // TODO: find a function that works for all calls or split into 2 functions - u32 DEntry_GetSaveData(u8 index, u8* buffer, bool old); + u32 GetSaveData(u8 index, std::vector<GCMBlock> &saveBlocks) const; // adds the file to the directory and copies its contents - // if remove > 0 it will pad bat.map with 0's sizeof remove - u32 ImportFile(DEntry& direntry, u8* contents, int remove); + u32 ImportFile(DEntry& direntry, std::vector<GCMBlock> &saveBlocks); // delete a file from the directory u32 RemoveFile(u8 index); // reads a save from another memcard, and imports the data into this memcard - u32 CopyFrom(GCMemcard& source, u8 index); + u32 CopyFrom(const GCMemcard& source, u8 index); // reads a .gci/.gcs/.sav file and calls ImportFile or saves out a gci file - u32 ImportGci(const char* inputFile, std::string outputFile); + u32 ImportGci(const char* inputFile,const std::string &outputFile); // writes a .gci file to disk containing index - u32 ExportGci(u8 index, const char* fileName, std::string* fileName2); + u32 ExportGci(u8 index, const char* fileName, const std::string &directory) const; // GCI files are untouched, SAV files are byteswapped // GCS files have the block count set, default is 1 (For export as GCS) - void Gcs_SavConvert(DEntry* tempDEntry, int saveType, int length = BLOCK_SIZE); + static void Gcs_SavConvert(DEntry &tempDEntry, int saveType, int length = BLOCK_SIZE); // reads the banner image - bool ReadBannerRGBA8(u8 index, u32* buffer); + bool ReadBannerRGBA8(u8 index, u32* buffer) const; // reads the animation frames - u32 ReadAnimRGBA8(u8 index, u32* buffer, u8 *delays); + u32 ReadAnimRGBA8(u8 index, u32* buffer, u8 *delays) const; }; #endif diff --git a/Source/Core/Core/Src/HW/GPFifo.cpp b/Source/Core/Core/Src/HW/GPFifo.cpp index 4d72317e0d..3af387792f 100644 --- a/Source/Core/Core/Src/HW/GPFifo.cpp +++ b/Source/Core/Core/Src/HW/GPFifo.cpp @@ -19,9 +19,9 @@ #include "ChunkFile.h" #include "ProcessorInterface.h" #include "Memmap.h" -#include "../PowerPC/PowerPC.h" - #include "VideoBackendBase.h" +#include "../PowerPC/JitCommon/JitBase.h" +#include "../PowerPC/PowerPC.h" #include "GPFifo.h" @@ -96,6 +96,15 @@ void STACKALIGN CheckGatherPipe() // move back the spill bytes memmove(m_gatherPipe, m_gatherPipe + cnt, m_gatherPipeCount); + + // Profile where the FIFO writes are occurring. + if (jit && (jit->js.fifoWriteAddresses.find(PC)) == (jit->js.fifoWriteAddresses.end())) + { + jit->js.fifoWriteAddresses.insert(PC); + + // Invalidate the JIT block so that it gets recompiled with the external exception check included. + jit->GetBlockCache()->InvalidateICache(PC, 4); + } } } diff --git a/Source/Core/Core/Src/HW/WiimoteEmu/EmuSubroutines.cpp b/Source/Core/Core/Src/HW/WiimoteEmu/EmuSubroutines.cpp index 6b6519d7b2..e7036c8fcb 100644 --- a/Source/Core/Core/Src/HW/WiimoteEmu/EmuSubroutines.cpp +++ b/Source/Core/Core/Src/HW/WiimoteEmu/EmuSubroutines.cpp @@ -427,6 +427,7 @@ void Wiimote::ReadData(const wm_read_data* const rd) if (address + size > WIIMOTE_EEPROM_SIZE) { PanicAlert("ReadData: address + size out of bounds"); + delete [] block; return; } // generate a read error diff --git a/Source/Core/Core/Src/HW/WiimoteReal/IOdarwin.mm b/Source/Core/Core/Src/HW/WiimoteReal/IOdarwin.mm index a899dac201..8e3586f7d9 100644 --- a/Source/Core/Core/Src/HW/WiimoteReal/IOdarwin.mm +++ b/Source/Core/Core/Src/HW/WiimoteReal/IOdarwin.mm @@ -127,11 +127,6 @@ int FindWiimotes(Wiimote **wm, int max_wiimotes) bti = [[IOBluetoothDeviceInquiry alloc] init]; [bti setDelegate: sbt]; [bti setInquiryLength: 5]; - [bti setSearchCriteria: kBluetoothServiceClassMajorAny - majorDeviceClass: kBluetoothDeviceClassMajorPeripheral - minorDeviceClass: kBluetoothDeviceClassMinorAny - ]; - [bti setUpdateNewDeviceNames: NO]; if ([bti start] == kIOReturnSuccess) [bti retain]; @@ -149,6 +144,9 @@ int FindWiimotes(Wiimote **wm, int max_wiimotes) en = [[bti foundDevices] objectEnumerator]; for (int i = 0; i < found_devices; i++) { + IOBluetoothDevice *dev = [en nextObject]; + if (!IsValidBluetoothName([[dev name] UTF8String])) + continue; // Find an unused slot for (int k = 0; k < MAX_WIIMOTES; k++) { if (wm[k] != NULL || @@ -156,7 +154,7 @@ int FindWiimotes(Wiimote **wm, int max_wiimotes) continue; wm[k] = new Wiimote(k); - wm[k]->btd = [en nextObject]; + wm[k]->btd = dev; found_wiimotes++; break; } @@ -177,10 +175,6 @@ bool Wiimote::Connect() if (IsConnected()) return false; - if ([btd remoteNameRequest:nil] == kIOReturnSuccess) - m_motion_plus_inside = - static_cast<bool>([[btd getName] hasSuffix:@"-TR"]); - [btd openL2CAPChannelSync: &cchan withPSM: kBluetoothL2CAPPSMHIDControl delegate: cbt]; [btd openL2CAPChannelSync: &ichan diff --git a/Source/Core/Core/Src/HW/WiimoteReal/WiimoteReal.cpp b/Source/Core/Core/Src/HW/WiimoteReal/WiimoteReal.cpp index 1ac0823ebb..5e03e36e68 100644 --- a/Source/Core/Core/Src/HW/WiimoteReal/WiimoteReal.cpp +++ b/Source/Core/Core/Src/HW/WiimoteReal/WiimoteReal.cpp @@ -50,7 +50,6 @@ Wiimote::Wiimote(const unsigned int _index) #endif , leds(0), m_last_data_report(Report((u8 *)NULL, 0)) , m_channel(0), m_connected(false) - , m_motion_plus_inside(false) { #if defined(__linux__) && HAVE_BLUEZ bdaddr = (bdaddr_t){{0, 0, 0, 0, 0, 0}}; @@ -143,16 +142,16 @@ void Wiimote::InterruptChannel(const u16 channel, const void* const data, const rpt.second = (u8)size; memcpy(rpt.first, (u8*)data, size); - // Convert output DATA packets to SET_REPORT packets for non-TR - // Wiimotes. Nintendo Wiimotes work without this translation, but 3rd + // Convert output DATA packets to SET_REPORT packets. + // Nintendo Wiimotes work without this translation, but 3rd // party ones don't. - u8 head = m_motion_plus_inside ? 0xa2 : 0x52; if (rpt.first[0] == 0xa2) { - rpt.first[0] = head; + rpt.first[0] = WM_SET_REPORT | WM_BT_OUTPUT; } - if (rpt.first[0] == head && rpt.first[1] == 0x18 && rpt.second == 23) + if (rpt.first[0] == (WM_SET_REPORT | WM_BT_OUTPUT) && + rpt.first[1] == 0x18 && rpt.second == 23) { m_audio_reports.Push(rpt); return; @@ -513,4 +512,19 @@ 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", + }; + for (size_t i = 0; i < ARRAYSIZE(kValidWiiRemoteBluetoothNames); i++) + if (strcmp(name, kValidWiiRemoteBluetoothNames[i]) == 0) + return true; + return false; +} + + }; // end of namespace diff --git a/Source/Core/Core/Src/HW/WiimoteReal/WiimoteReal.h b/Source/Core/Core/Src/HW/WiimoteReal/WiimoteReal.h index 8229abee52..cd1080903f 100644 --- a/Source/Core/Core/Src/HW/WiimoteReal/WiimoteReal.h +++ b/Source/Core/Core/Src/HW/WiimoteReal/WiimoteReal.h @@ -95,7 +95,6 @@ private: void ThreadFunc(); bool m_connected; - bool m_motion_plus_inside; std::thread m_wiimote_thread; Common::FifoQueue<Report> m_read_reports; Common::FifoQueue<Report> m_write_reports; @@ -114,6 +113,8 @@ void StateChange(EMUSTATE_CHANGE newState); int FindWiimotes(Wiimote** wm, int max_wiimotes); +bool IsValidBluetoothName(const char* name); + }; // WiimoteReal #endif diff --git a/Source/Core/Core/Src/HW/WiimoteReal/WiimoteRealBase.h b/Source/Core/Core/Src/HW/WiimoteReal/WiimoteRealBase.h index 6765748e58..4b66eb4930 100644 --- a/Source/Core/Core/Src/HW/WiimoteReal/WiimoteRealBase.h +++ b/Source/Core/Core/Src/HW/WiimoteReal/WiimoteRealBase.h @@ -32,7 +32,14 @@ #define WM_OUTPUT_CHANNEL 0x11 #define WM_INPUT_CHANNEL 0x13 +// The 4 most significant bits of the first byte of an outgoing command must be +// 0x50 if sending on the command channel and 0xA0 if sending on the interrupt +// channel. On Mac we use interrupt channel; on Windows/Linux, command. +#ifndef __APPLE__ #define WM_SET_REPORT 0x50 +#else +#define WM_SET_REPORT 0xA0 +#endif // Commands #define WM_CMD_RUMBLE 0x10 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 6194ae93e0..52dd916fad 100644 --- a/Source/Core/Core/Src/IPC_HLE/WII_IPC_HLE.cpp +++ b/Source/Core/Core/Src/IPC_HLE/WII_IPC_HLE.cpp @@ -69,8 +69,13 @@ TDeviceMap g_DeviceMap; // STATE_TO_SAVE typedef std::map<u32, std::string> TFileNameMap; -TFileNameMap g_FileNameMap; -u32 g_LastDeviceID; + +#define IPC_MAX_FDS 0x18 +#define ES_MAX_COUNT 2 +IWII_IPC_HLE_Device* g_FdMap[IPC_MAX_FDS]; +bool es_inuse[ES_MAX_COUNT]; +IWII_IPC_HLE_Device* es_handles[ES_MAX_COUNT]; + typedef std::deque<u32> ipc_msg_queue; static ipc_msg_queue request_queue; // ppc -> arm @@ -79,14 +84,28 @@ static ipc_msg_queue reply_queue; // arm -> ppc void Init() { _dbg_assert_msg_(WII_IPC_HLE, g_DeviceMap.empty(), "DeviceMap isnt empty on init"); + + u32 i; + for (i=0; i<IPC_MAX_FDS; i++) + { + g_FdMap[i] = NULL; + } - u32 i = IPC_FIRST_HARDWARE_ID; + i = 0; // Build hardware devices g_DeviceMap[i] = new CWII_IPC_HLE_Device_usb_oh1_57e_305(i, std::string("/dev/usb/oh1/57e/305")); i++; g_DeviceMap[i] = new CWII_IPC_HLE_Device_stm_immediate(i, std::string("/dev/stm/immediate")); i++; g_DeviceMap[i] = new CWII_IPC_HLE_Device_stm_eventhook(i, std::string("/dev/stm/eventhook")); i++; g_DeviceMap[i] = new CWII_IPC_HLE_Device_fs(i, std::string("/dev/fs")); i++; - g_DeviceMap[i] = new CWII_IPC_HLE_Device_es(i, std::string("/dev/es")); i++; + + // IOS allows two ES devices at a time< + u32 j; + for (j=0; j<ES_MAX_COUNT; j++) + { + g_DeviceMap[i] = es_handles[j] = new CWII_IPC_HLE_Device_es(i, std::string("/dev/es")); i++; + es_inuse[j] = false; + } + g_DeviceMap[i] = new CWII_IPC_HLE_Device_di(i, std::string("/dev/di")); i++; g_DeviceMap[i] = new CWII_IPC_HLE_Device_net_kd_request(i, std::string("/dev/net/kd/request")); i++; g_DeviceMap[i] = new CWII_IPC_HLE_Device_net_kd_time(i, std::string("/dev/net/kd/time")); i++; @@ -99,13 +118,24 @@ void Init() g_DeviceMap[i] = new CWII_IPC_HLE_Device_stub(i, std::string("/dev/sdio/slot1")); i++; g_DeviceMap[i] = new CWII_IPC_HLE_Device_stub(i, std::string("/dev/usb/hid")); i++; g_DeviceMap[i] = new CWII_IPC_HLE_Device_stub(i, std::string("/dev/usb/oh1")); i++; - g_DeviceMap[i] = new IWII_IPC_HLE_Device(i, std::string("_Unimplemented_Device_")); - - g_LastDeviceID = IPC_FIRST_FILEIO_ID; + g_DeviceMap[i] = new IWII_IPC_HLE_Device(i, std::string("_Unimplemented_Device_")); i++; } void Reset(bool _bHard) { + + u32 i; + for (i=0; i<IPC_MAX_FDS; i++) + { + if (g_FdMap[i] != NULL && !g_FdMap[i]->IsHardware()) + { + // close all files and delete their resources + g_FdMap[i]->Close(0, true); + delete g_FdMap[i]; + } + g_FdMap[i] = NULL; + } + TDeviceMap::iterator itr = g_DeviceMap.begin(); while (itr != g_DeviceMap.end()) { @@ -114,21 +144,17 @@ void Reset(bool _bHard) // Force close itr->second->Close(0, true); // Hardware should not be deleted unless it is a hard reset - if (_bHard || !itr->second->IsHardware()) + if (_bHard) delete itr->second; } ++itr; } - // Skip hardware devices if not a hard reset - itr = (_bHard) ? g_DeviceMap.begin() : g_DeviceMap.lower_bound(IPC_FIRST_FILEIO_ID); - // Erase devices - g_DeviceMap.erase(itr, g_DeviceMap.end()); - g_FileNameMap.clear(); - + if (_bHard) + { + g_DeviceMap.erase(g_DeviceMap.begin(), g_DeviceMap.end()); + } request_queue.clear(); reply_queue.clear(); - - g_LastDeviceID = IPC_FIRST_FILEIO_ID; } void Shutdown() @@ -138,41 +164,53 @@ void Shutdown() void SetDefaultContentFile(const std::string& _rFilename) { - CWII_IPC_HLE_Device_es* pDevice = - (CWII_IPC_HLE_Device_es*)AccessDeviceByID(GetDeviceIDByName(std::string("/dev/es"))); - if (pDevice) - pDevice->LoadWAD(_rFilename); + TDeviceMap::const_iterator itr = g_DeviceMap.begin(); + while (itr != g_DeviceMap.end()) + { + if (itr->second && itr->second->GetDeviceName().find(std::string("/dev/es")) == 0) + { + ((CWII_IPC_HLE_Device_es*)itr->second)->LoadWAD(_rFilename); + } + ++itr; + } } void ES_DIVerify(u8 *_pTMD, u32 _sz) { - CWII_IPC_HLE_Device_es* pDevice = - (CWII_IPC_HLE_Device_es*)AccessDeviceByID(GetDeviceIDByName(std::string("/dev/es"))); - if (pDevice) - pDevice->ES_DIVerify(_pTMD, _sz); - else - ERROR_LOG(WII_IPC_ES, "DIVerify called but /dev/es is not available"); + CWII_IPC_HLE_Device_es::ES_DIVerify(_pTMD, _sz); } void SDIO_EventNotify() { CWII_IPC_HLE_Device_sdio_slot0 *pDevice = - (CWII_IPC_HLE_Device_sdio_slot0*)AccessDeviceByID(GetDeviceIDByName(std::string("/dev/sdio/slot0"))); + (CWII_IPC_HLE_Device_sdio_slot0*)GetDeviceByName(std::string("/dev/sdio/slot0")); if (pDevice) pDevice->EventNotify(); } +int getFreeDeviceId() +{ + u32 i; + for (i=0; i<IPC_MAX_FDS; i++) + { + if (g_FdMap[i] == NULL) + { + return i; + } + } + return -1; +} -int GetDeviceIDByName(const std::string& _rDeviceName) +IWII_IPC_HLE_Device* GetDeviceByName(const std::string& _rDeviceName) { TDeviceMap::const_iterator itr = g_DeviceMap.begin(); - while(itr != g_DeviceMap.end()) + while (itr != g_DeviceMap.end()) { - if (itr->second->GetDeviceName() == _rDeviceName) - return itr->first; + if (itr->second && itr->second->GetDeviceName() == _rDeviceName) + return itr->second; ++itr; } - return -1; + return NULL; } IWII_IPC_HLE_Device* AccessDeviceByID(u32 _ID) @@ -180,17 +218,7 @@ IWII_IPC_HLE_Device* AccessDeviceByID(u32 _ID) if (g_DeviceMap.find(_ID) != g_DeviceMap.end()) return g_DeviceMap[_ID]; - return NULL; -} - -void DeleteDeviceByID(u32 ID) -{ - IWII_IPC_HLE_Device* pDevice = AccessDeviceByID(ID); - if (pDevice) - delete pDevice; - - g_DeviceMap.erase(ID); - g_FileNameMap.erase(ID); + return NULL; } // This is called from ExecuteCommand() COMMAND_OPEN_DEVICE @@ -208,60 +236,86 @@ IWII_IPC_HLE_Device* CreateFileIO(u32 _DeviceID, const std::string& _rDeviceName void DoState(PointerWrap &p) { - p.Do(g_LastDeviceID); + p.Do(request_queue); + p.Do(reply_queue); + + TDeviceMap::const_iterator itr; + + itr = g_DeviceMap.begin(); + while (itr != g_DeviceMap.end()) + { + if (itr->second->IsHardware()) + { + itr->second->DoState(p); + } + ++itr; + } if (p.GetMode() == PointerWrap::MODE_READ) - { - TFileNameMap::const_iterator itr; - // Delete file Handles - itr = g_FileNameMap.begin(); - while (itr != g_FileNameMap.end()) + { + u32 i; + for (i=0; i<IPC_MAX_FDS; i++) { - TDeviceMap::const_iterator devitr = g_DeviceMap.find(itr->first); - if (devitr != g_DeviceMap.end()) + u32 exists; + p.Do(exists); + if (exists) { - if (devitr->second) - delete devitr->second; - g_DeviceMap.erase(itr->first); + u32 isHw; + p.Do(isHw); + if (isHw) + { + u32 hwId; + p.Do(hwId); + g_FdMap[i] = AccessDeviceByID(hwId); + } + else + { + g_FdMap[i] = new CWII_IPC_HLE_Device_FileIO(i, ""); + g_FdMap[i]->DoState(p); + } + } + else + { + g_FdMap[i] = NULL; } - ++itr; } - // Load file names - p.Do(g_FileNameMap); - // Rebuild file handles - itr = g_FileNameMap.begin(); - while (itr != g_FileNameMap.end()) + for (i=0; i<ES_MAX_COUNT; i++) { - g_DeviceMap[itr->first] = new CWII_IPC_HLE_Device_FileIO(itr->first, itr->second); - ++itr; + p.Do(es_inuse[i]); + u32 handleID = es_handles[i]->GetDeviceID(); + p.Do(handleID); + + es_handles[i] = AccessDeviceByID(handleID); } } else { - p.Do(g_FileNameMap); - } - - p.Do(request_queue); - p.Do(reply_queue); - - - TDeviceMap::const_iterator itr; - //first, all the real devices - //(because we need fs to be deserialized first) - itr = g_DeviceMap.begin(); - while (itr != g_DeviceMap.end()) - { - if (itr->second->IsHardware()) - itr->second->DoState(p); - ++itr; - } - //then all the files - itr = g_DeviceMap.begin(); - while (itr != g_DeviceMap.end()) - { - if (!itr->second->IsHardware()) - itr->second->DoState(p); - ++itr; + u32 i; + for (i=0; i<IPC_MAX_FDS; i++) + { + u32 exists = g_FdMap[i] ? 1 : 0; + p.Do(exists); + if (exists) + { + u32 isHw = g_FdMap[i]->IsHardware() ? 1 : 0; + p.Do(isHw); + if (isHw) + { + u32 hwId = g_FdMap[i]->GetDeviceID(); + p.Do(hwId); + } + else + { + g_FdMap[i]->DoState(p); + } + } + } + for (i=0; i<ES_MAX_COUNT; i++) + { + p.Do(es_inuse[i]); + u32 handleID = es_handles[i]->GetDeviceID(); + p.Do(handleID); + } } } @@ -270,67 +324,110 @@ void ExecuteCommand(u32 _Address) bool CmdSuccess = false; ECommandType Command = static_cast<ECommandType>(Memory::Read_U32(_Address)); - int DeviceID = Memory::Read_U32(_Address + 8); - IWII_IPC_HLE_Device* pDevice = AccessDeviceByID(DeviceID); + volatile int DeviceID = Memory::Read_U32(_Address + 8); - INFO_LOG(WII_IPC_HLE, "-->> Execute Command Address: 0x%08x (code: %x, device: %x) ", _Address, Command, DeviceID); + IWII_IPC_HLE_Device* pDevice = (DeviceID >= 0 && DeviceID < IPC_MAX_FDS) ? g_FdMap[DeviceID] : NULL; + + INFO_LOG(WII_IPC_HLE, "-->> Execute Command Address: 0x%08x (code: %x, device: %x) %p", _Address, Command, DeviceID, pDevice); switch (Command) { case COMMAND_OPEN_DEVICE: - { - // Create a new HLE device. The Mode and DeviceName is given to us but we - // generate a DeviceID to be used for access to this device until it is Closed. - std::string DeviceName; - Memory::GetString(DeviceName, Memory::Read_U32(_Address + 0xC)); - - u32 Mode = Memory::Read_U32(_Address + 0x10); - DeviceID = GetDeviceIDByName(DeviceName); - - // check if a device with this name has been created already - if (DeviceName.find("/dev/") == std::string::npos || DeviceID == -1) - { - if (DeviceName.find("/dev/") == 0) + { + u32 Mode = Memory::Read_U32(_Address + 0x10); + DeviceID = getFreeDeviceId(); + + std::string DeviceName; + Memory::GetString(DeviceName, Memory::Read_U32(_Address + 0xC)); + + + WARN_LOG(WII_IPC_HLE, "Tried to open %s as %d", DeviceName.c_str(), DeviceID); + if (DeviceID >= 0) + { + if (DeviceName.find("/dev/es") == 0) + { + u32 j; + for (j=0; j<ES_MAX_COUNT; j++) { - WARN_LOG(WII_IPC_HLE, "Unimplemented device: %s", DeviceName.c_str()); + if (!es_inuse[j]) + { + es_inuse[j] = true; + g_FdMap[DeviceID] = es_handles[j]; + CmdSuccess = es_handles[j]->Open(_Address, Mode); + Memory::Write_U32(DeviceID, _Address+4); + break; + } + } + if (j == ES_MAX_COUNT) + { + Memory::Write_U32(FS_EESEXHAUSTED, _Address + 4); + CmdSuccess = true; + } - pDevice = AccessDeviceByID(GetDeviceIDByName(std::string("_Unimplemented_Device_"))); + } + else if (DeviceName.find("/dev/") == 0) + { + pDevice = GetDeviceByName(DeviceName); + if (pDevice) + { + g_FdMap[DeviceID] = pDevice; CmdSuccess = pDevice->Open(_Address, Mode); + INFO_LOG(WII_IPC_FILEIO, "IOP: ReOpen (Device=%s, DeviceID=%08x, Mode=%i)", + pDevice->GetDeviceName().c_str(), DeviceID, Mode); + Memory::Write_U32(DeviceID, _Address+4); } else { - // create new file handle - u32 CurrentDeviceID = g_LastDeviceID; - pDevice = CreateFileIO(CurrentDeviceID, DeviceName); - g_DeviceMap[CurrentDeviceID] = pDevice; - g_FileNameMap[CurrentDeviceID] = DeviceName; - g_LastDeviceID++; - - CmdSuccess = pDevice->Open(_Address, Mode); - - INFO_LOG(WII_IPC_FILEIO, "IOP: Open File (Device=%s, ID=%08x, Mode=%i)", - pDevice->GetDeviceName().c_str(), CurrentDeviceID, Mode); + WARN_LOG(WII_IPC_HLE, "Unimplemented device: %s", DeviceName.c_str()); + Memory::Write_U32(FS_ENOENT, _Address+4); + CmdSuccess = true; } - } - else - { - // F|RES: prolly the re-open is just a mode change - pDevice = AccessDeviceByID(DeviceID); + } + else + { + IWII_IPC_HLE_Device* pDevice = CreateFileIO(DeviceID, DeviceName); CmdSuccess = pDevice->Open(_Address, Mode); - INFO_LOG(WII_IPC_FILEIO, "IOP: ReOpen (Device=%s, DeviceID=%08x, Mode=%i)", - pDevice->GetDeviceName().c_str(), DeviceID, Mode); - } - } - break; + INFO_LOG(WII_IPC_FILEIO, "IOP: Open File (Device=%s, ID=%08x, Mode=%i)", + pDevice->GetDeviceName().c_str(), DeviceID, Mode); + if (Memory::Read_U32(_Address + 4) == DeviceID) + { + g_FdMap[DeviceID] = pDevice; + } + else + { + delete pDevice; + } + } + } + else + { + Memory::Write_U32(FS_EFDEXHAUSTED, _Address + 4); + CmdSuccess = true; + } + break; + } case COMMAND_CLOSE_DEVICE: - if (pDevice) + { + if (pDevice) { CmdSuccess = pDevice->Close(_Address); + + u32 j; + for (j=0; j<ES_MAX_COUNT; j++) + { + if (es_handles[j] == g_FdMap[DeviceID]) + { + es_inuse[j] = false; + } + } + + g_FdMap[DeviceID] = NULL; + // Don't delete hardware if (!pDevice->IsHardware()) - DeleteDeviceByID(DeviceID); + delete pDevice; } else { @@ -338,50 +435,67 @@ void ExecuteCommand(u32 _Address) CmdSuccess = true; } break; - + } case COMMAND_READ: + { if (pDevice) + { CmdSuccess = pDevice->Read(_Address); + } else { Memory::Write_U32(FS_EINVAL, _Address + 4); CmdSuccess = true; } break; - + } case COMMAND_WRITE: + { if (pDevice) + { CmdSuccess = pDevice->Write(_Address); + } else { Memory::Write_U32(FS_EINVAL, _Address + 4); CmdSuccess = true; } break; - + } case COMMAND_SEEK: + { if (pDevice) + { CmdSuccess = pDevice->Seek(_Address); + } else { Memory::Write_U32(FS_EINVAL, _Address + 4); CmdSuccess = true; } break; - + } case COMMAND_IOCTL: + { if (pDevice) + { CmdSuccess = pDevice->IOCtl(_Address); + } break; - + } case COMMAND_IOCTLV: + { if (pDevice) + { CmdSuccess = pDevice->IOCtlV(_Address); + } break; - + } default: + { _dbg_assert_msg_(WII_IPC_HLE, 0, "Unknown IPC Command %i (0x%08x)", Command, _Address); break; + } } // It seems that the original hardware overwrites the command after it has been @@ -453,9 +567,10 @@ void Update() void UpdateDevices() { // Check if a hardware device must be updated - TDeviceMap::const_iterator itrEnd = g_DeviceMap.lower_bound(IPC_FIRST_FILEIO_ID); - for (TDeviceMap::const_iterator itr = g_DeviceMap.begin(); itr != itrEnd; ++itr) { - if (itr->second->IsOpened() && itr->second->Update()) { + for (TDeviceMap::const_iterator itr = g_DeviceMap.begin(); itr != g_DeviceMap.end(); ++itr) + { + if (itr->second->IsOpened() && itr->second->Update()) + { break; } } diff --git a/Source/Core/Core/Src/IPC_HLE/WII_IPC_HLE.h b/Source/Core/Core/Src/IPC_HLE/WII_IPC_HLE.h index 11420d1cdd..2e056b5bec 100644 --- a/Source/Core/Core/Src/IPC_HLE/WII_IPC_HLE.h +++ b/Source/Core/Core/Src/IPC_HLE/WII_IPC_HLE.h @@ -25,9 +25,9 @@ class IWII_IPC_HLE_Device; namespace WII_IPC_HLE_Interface { -#define IPC_FIRST_HARDWARE_ID 0 // first IPC device ID -#define IPC_FIRST_FILEIO_ID 33 // first IPC file ID - +#define IPC_FIRST_ID 0x00 // first IPC device ID +#define IPC_MAX_FILES 0x10 // first IPC file ID + // Init void Init(); @@ -46,14 +46,13 @@ void ES_DIVerify(u8 *_pTMD, u32 _sz); void SDIO_EventNotify(); -int GetDeviceIDByName(const std::string& _rDeviceName); - -IWII_IPC_HLE_Device* AccessDeviceByID(u32 _ID); - -void DeleteDeviceByID(u32 _ID); IWII_IPC_HLE_Device* CreateFileIO(u32 _DeviceID, const std::string& _rDeviceName); +IWII_IPC_HLE_Device* GetDeviceByName(const std::string& _rDeviceName); +IWII_IPC_HLE_Device* AccessDeviceByID(u32 _ID); +int getFreeDeviceId(); + // Update void Update(); 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 c738a5379d..38cc50e3a8 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 @@ -39,7 +39,7 @@ class PointerWrap; #define FS_ENOENT2 (u32)-106 // File not found #define FS_ENFILE (u32)-107 // Too many fds open #define FS_EFBIG (u32)-108 // max block count reached? -#define FS_ENFILE2 (u32)-109 // Too many fds open +#define FS_EFDEXHAUSTED (u32)-109 // Too many fds open #define FS_ENAMELEN (u32)-110 // pathname is too long #define FS_EFDOPEN (u32)-111 // FD is already open #define FS_EIO2 (u32)-114 // returned on ECC error @@ -47,6 +47,7 @@ class PointerWrap; #define FS_EDIRDEPTH (u32)-116 // max directory depth exceeded #define FS_EBUSY2 (u32)-118 // Resource busy //#define FS_EFATAL (u32)-119 // fatal error not used by IOS as fatal ERROR +#define FS_EESEXHAUSTED (u32)-1016 // Max of 2 ES handles at a time class IWII_IPC_HLE_Device { diff --git a/Source/Core/Core/Src/IPC_HLE/WII_IPC_HLE_Device_DI.cpp b/Source/Core/Core/Src/IPC_HLE/WII_IPC_HLE_Device_DI.cpp index 126f3daeb4..05b365ef01 100644 --- a/Source/Core/Core/Src/IPC_HLE/WII_IPC_HLE_Device_DI.cpp +++ b/Source/Core/Core/Src/IPC_HLE/WII_IPC_HLE_Device_DI.cpp @@ -428,6 +428,16 @@ u32 CWII_IPC_HLE_Device_di::ExecuteCommand(u32 _BufferIn, u32 _BufferInSize, u32 break; case DVDLowAudioBufferConfig: + /* + For more information: http://www.crazynation.org/GC/GC_DD_TECH/GCTech.htm + + Upon Power up or reset , 2 commands must be issued for proper use of audio streaming: + DVDReadDiskID A8000040,00000000,00000020 + DVDLowAudioBufferConfig E4xx00yy,00000000,00000020 + + xx=byte 8 [0 or 1] from the disk header retrieved from DVDReadDiskID + yy=0 (if xx=0) or 0xA (if xx=1) + */ ERROR_LOG(WII_IPC_DVD, "DVDLowAudioBufferConfig"); break; 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 98a85d25ca..9229e930ab 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 @@ -28,7 +28,7 @@ static Common::replace_v replacements; -// This is used by several of the FileIO and /dev/fs/ functions +// This is used by several of the FileIO and /dev/fs functions std::string HLE_IPC_BuildFilename(const char* _pFilename, int _size) { std::string path_full = File::GetUserPath(D_WIIROOT_IDX); @@ -128,7 +128,7 @@ bool CWII_IPC_HLE_Device_FileIO::Open(u32 _CommandAddress, u32 _Mode) // The file must exist before we can open it // It should be created by ISFS_CreateFile, not here - if(File::Exists(m_Filename)) + if (File::Exists(m_Filename)) { INFO_LOG(WII_IPC_FILEIO, "FileIO: Open %s (%s == %08X)", m_Name.c_str(), Modes[_Mode], _Mode); ReturnValue = m_DeviceID; @@ -146,28 +146,31 @@ bool CWII_IPC_HLE_Device_FileIO::Open(u32 _CommandAddress, u32 _Mode) } - bool CWII_IPC_HLE_Device_FileIO::OpenFile() { - switch(m_Mode) + switch (m_Mode) { case ISFS_OPEN_READ: + { m_pFileHandle.Open(m_Filename, "rb"); break; - - // "r+b" is technically wrong, but OPEN_WRITE should not truncate the file as "wb" does. + } case ISFS_OPEN_WRITE: + { m_pFileHandle.Open(m_Filename, "r+b"); break; - + } case ISFS_OPEN_RW: + { m_pFileHandle.Open(m_Filename, "r+b"); break; - + } default: + { PanicAlertT("FileIO: Unknown open mode : 0x%02x", m_Mode); break; } + } return m_pFileHandle.IsOpen(); } @@ -178,21 +181,21 @@ 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); + u32 ReturnValue = FS_RESULT_FATAL; + const s32 SeekPosition = Memory::Read_U32(_CommandAddress + 0xC); + const s32 Mode = Memory::Read_U32(_CommandAddress + 0x10); - if(OpenFile()) + if (OpenFile()) { ReturnValue = FS_RESULT_FATAL; - const u64 fileSize = m_pFileHandle.GetSize(); + const u64 fileSize = m_pFileHandle.GetSize(); INFO_LOG(WII_IPC_FILEIO, "FileIO: Seek Pos: 0x%08x, Mode: %i (%s, Length=0x%08llx)", SeekPosition, Mode, m_Name.c_str(), fileSize); - switch(Mode){ + switch (Mode){ case 0: { - if(SeekPosition >=0 && SeekPosition <= fileSize) + if (SeekPosition >=0 && SeekPosition <= fileSize) { m_SeekPos = SeekPosition; ReturnValue = m_SeekPos; @@ -202,7 +205,7 @@ bool CWII_IPC_HLE_Device_FileIO::Seek(u32 _CommandAddress) case 1: { s32 wantedPos = SeekPosition+m_SeekPos; - if(wantedPos >=0 && wantedPos <= fileSize) + if (wantedPos >=0 && wantedPos <= fileSize) { m_SeekPos = wantedPos; ReturnValue = m_SeekPos; @@ -212,7 +215,7 @@ bool CWII_IPC_HLE_Device_FileIO::Seek(u32 _CommandAddress) case 2: { s32 wantedPos = fileSize+m_SeekPos; - if(wantedPos >=0 && wantedPos <= fileSize) + if (wantedPos >=0 && wantedPos <= fileSize) { m_SeekPos = wantedPos; ReturnValue = m_SeekPos; @@ -244,7 +247,7 @@ bool CWII_IPC_HLE_Device_FileIO::Read(u32 _CommandAddress) const u32 Size = Memory::Read_U32(_CommandAddress + 0x10); - if(OpenFile()) + if (OpenFile()) { if (m_Mode == ISFS_OPEN_WRITE) { @@ -284,7 +287,7 @@ bool CWII_IPC_HLE_Device_FileIO::Write(u32 _CommandAddress) const u32 Size = Memory::Read_U32(_CommandAddress + 0x10); - if(OpenFile()) + if (OpenFile()) { if (m_Mode == ISFS_OPEN_READ) { @@ -318,21 +321,14 @@ bool CWII_IPC_HLE_Device_FileIO::IOCtl(u32 _CommandAddress) #if defined(_DEBUG) || defined(DEBUGFAST) DumpCommands(_CommandAddress); #endif - const u32 Parameter = Memory::Read_U32(_CommandAddress + 0xC); - - //u32 BufferIn = Memory::Read_U32(_CommandAddress + 0x10); - //u32 BufferInSize = Memory::Read_U32(_CommandAddress + 0x14); - //u32 BufferOut = Memory::Read_U32(_CommandAddress + 0x18); - //u32 BufferOutSize = Memory::Read_U32(_CommandAddress + 0x1C); - - // Return Value - u32 ReturnValue = 0; // no error + const u32 Parameter = Memory::Read_U32(_CommandAddress + 0xC); + u32 ReturnValue = 0; - switch(Parameter) + switch (Parameter) { case ISFS_IOCTL_GETFILESTATS: { - if(OpenFile()) + if (OpenFile()) { u32 m_FileLength = (u32)m_pFileHandle.GetSize(); 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 4a8952234d..0d2f6182cc 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 @@ -64,6 +64,8 @@ #include <openssl/sha.h> #include <openssl/objects.h> +std::string CWII_IPC_HLE_Device_es::m_ContentFile; + CWII_IPC_HLE_Device_es::CWII_IPC_HLE_Device_es(u32 _DeviceID, const std::string& _rDeviceName) : IWII_IPC_HLE_Device(_DeviceID, _rDeviceName) , m_pContentLoader(NULL) @@ -276,8 +278,7 @@ bool CWII_IPC_HLE_Device_es::IOCtlV(u32 _CommandAddress) m_ContentAccessMap[CFD].m_Position = 0; m_ContentAccessMap[CFD].m_pContent = AccessContentDevice(m_TitleID).GetContentByIndex(Index); - _dbg_assert_(WII_IPC_ES, m_ContentAccessMap[CFD].m_pContent != NULL); - + if (m_ContentAccessMap[CFD].m_pContent == NULL) CFD = 0xffffffff; //TODO: what is the correct error value here? @@ -775,21 +776,7 @@ bool CWII_IPC_HLE_Device_es::IOCtlV(u32 _CommandAddress) PC = DolLoader.GetEntryPoint() | 0x80000000; IOSv = ContentLoader.GetIosVersion(); bSuccess = true; - // Reset the connection of all connected wiimotes - // ugly haxx - static CWII_IPC_HLE_Device_usb_oh1_57e_305* s_Usb = GetUsbPointer(); - for (unsigned int i = 0; i < 4; i++) - { - if (s_Usb->m_WiiMotes[i].IsConnected()) - { - s_Usb->m_WiiMotes[i].Activate(false); - s_Usb->m_WiiMotes[i].Activate(true); - } - else - { - s_Usb->m_WiiMotes[i].Activate(false); - } - } + } } } @@ -802,8 +789,32 @@ bool CWII_IPC_HLE_Device_es::IOCtlV(u32 _CommandAddress) IOSv = TitleID & 0xffff; } if (!bSuccess) + { PanicAlertT("IOCTL_ES_LAUNCH: Game tried to reload ios or a title that is not available in your nand dump\n" "TitleID %016llx.\n Dolphin will likely hang now", TitleID); + } + else + { + 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()) + { + s_Usb->m_WiiMotes[i].Activate(false); + s_Usb->m_WiiMotes[i].Activate(true); + } + else + { + s_Usb->m_WiiMotes[i].Activate(false); + } + } + + WII_IPC_HLE_Interface::SetDefaultContentFile(tContentFile); + } // Pass the "#002 check" // Apploader should write the IOS version and revision to 0x3140, and compare it // to 0x3188 to pass the check, but we don't do it, and i don't know where to read the IOS rev... diff --git a/Source/Core/Core/Src/IPC_HLE/WII_IPC_HLE_Device_es.h b/Source/Core/Core/Src/IPC_HLE/WII_IPC_HLE_Device_es.h index 69916110f0..5e4ecf7578 100644 --- a/Source/Core/Core/Src/IPC_HLE/WII_IPC_HLE_Device_es.h +++ b/Source/Core/Core/Src/IPC_HLE/WII_IPC_HLE_Device_es.h @@ -37,7 +37,7 @@ public: virtual bool Close(u32 _CommandAddress, bool _bForce); virtual bool IOCtlV(u32 _CommandAddress); - u32 ES_DIVerify(u8 *_pTMD, u32 _sz); + static u32 ES_DIVerify(u8 *_pTMD, u32 _sz); private: enum @@ -135,7 +135,7 @@ private: u64 m_TitleID; u32 AccessIdentID; // This should only be cleared on power reset - std::string m_ContentFile; + static std::string m_ContentFile; static u8 *keyTable[11]; diff --git a/Source/Core/Core/Src/Movie.cpp b/Source/Core/Core/Src/Movie.cpp index 9c2fb02d64..590f8bb5e8 100644 --- a/Source/Core/Core/Src/Movie.cpp +++ b/Source/Core/Core/Src/Movie.cpp @@ -304,7 +304,7 @@ bool BeginRecordingInput(int controllers) g_rerecords = 0; g_playMode = MODE_RECORDING; - delete tmpInput; + delete [] tmpInput; tmpInput = new u8[MAX_DTM_LENGTH]; g_currentByte = g_totalBytes = 0; @@ -627,6 +627,10 @@ void LoadInput(const char *filename) if (!g_bReadOnly) { + if (g_rerecords > tmpHeader.numRerecords) + { + tmpHeader.numRerecords = g_rerecords; + } tmpHeader.numRerecords++; t_record.Seek(0, SEEK_SET); t_record.WriteArray(&tmpHeader, 1); @@ -653,7 +657,7 @@ void LoadInput(const char *filename) g_totalInputCount = tmpHeader.inputCount; g_totalBytes = totalSavedBytes; - delete tmpInput; + delete [] tmpInput; tmpInput = new u8[MAX_DTM_LENGTH]; t_record.ReadArray(tmpInput, (size_t)g_totalBytes); } @@ -707,7 +711,7 @@ void LoadInput(const char *filename) break; } } - delete movInput; + delete [] movInput; } } t_record.Close(); diff --git a/Source/Core/Core/Src/PowerPC/Gekko.h b/Source/Core/Core/Src/PowerPC/Gekko.h index 1ce6fae4cd..8615acd5ed 100644 --- a/Source/Core/Core/Src/PowerPC/Gekko.h +++ b/Source/Core/Core/Src/PowerPC/Gekko.h @@ -181,7 +181,7 @@ union UGeckoInstruction u32 : 11; u32 CRBB : 5; u32 CRBA : 5; - u32 CRBD : 5; + u32 CRBD : 5; u32 : 6; }; @@ -235,9 +235,9 @@ union UGeckoInstruction }; struct { - u32 : 17; - u32 FM : 8; - u32 : 7; + u32 : 17; + u32 FM : 8; + u32 : 7; }; // paired @@ -247,8 +247,8 @@ union UGeckoInstruction u32 Ix : 3; u32 Wx : 1; u32 : 1; - u32 I : 3; - u32 W : 1; + u32 I : 3; + u32 W : 1; u32 : 16; }; @@ -319,7 +319,7 @@ union UReg_XER u32 Hex; UReg_XER(u32 _hex) { Hex = _hex; } - UReg_XER() { Hex = 0; } + UReg_XER() { Hex = 0; } }; // Machine State Register @@ -351,7 +351,7 @@ union UReg_MSR u32 Hex; UReg_MSR(u32 _hex) { Hex = _hex; } - UReg_MSR() { Hex = 0; } + UReg_MSR() { Hex = 0; } }; // Floating Point Status and Control Register @@ -487,13 +487,47 @@ union UReg_SPR1 u32 Hex; struct { - u32 htaborg : 16; - u32 : 7; - u32 htabmask : 9; + u32 htaborg : 16; + u32 : 7; + u32 htabmask : 9; }; }; +// MMCR0 - Monitor Mode Control Register 0 format +union UReg_MMCR0 +{ + u32 Hex; + struct + { + u32 PMC2SELECT : 6; + u32 PMC1SELECT : 7; + u32 PMCTRIGGER : 1; + u32 PMCINTCONTROL : 1; + u32 PMC1INTCONTROL : 1; + u32 THRESHOLD : 6; + u32 INTONBITTRANS : 1; + u32 RTCSELECT : 2; + u32 DISCOUNT : 1; + u32 ENINT : 1; + u32 DMR : 1; + u32 DMS : 1; + u32 DU : 1; + u32 DP : 1; + u32 DIS : 1; + }; +}; +// MMCR1 - Monitor Mode Control Register 1 format +union UReg_MMCR1 +{ + u32 Hex; + struct + { + u32 : 22; + u32 PMC4SELECT : 5; + u32 PMC3SELECT : 5; + }; +}; // Write Pipe Address Register union UReg_WPAR @@ -516,7 +550,7 @@ union UReg_DMAU struct { u32 DMA_LEN_U : 5; - u32 MEM_ADDR : 27; + u32 MEM_ADDR : 27; }; u32 Hex; @@ -533,7 +567,7 @@ union UReg_DMAL u32 DMA_T : 1; u32 DMA_LEN_L : 2; u32 DMA_LD : 1; - u32 LC_ADDR : 27; + u32 LC_ADDR : 27; }; u32 Hex; @@ -545,11 +579,11 @@ union UReg_BAT_Up { struct { - u32 VP : 1; - u32 VS : 1; + u32 VP : 1; + u32 VS : 1; u32 BL : 11; // Block length (aka block size mask) u32 : 4; - u32 BEPI : 15; + u32 BEPI : 15; }; u32 Hex; @@ -561,8 +595,8 @@ union UReg_BAT_Lo { struct { - u32 PP : 2; - u32 : 1; + u32 PP : 2; + u32 : 1; u32 WIMG : 4; u32 : 10; u32 BRPN : 15; // Physical Block Number @@ -586,7 +620,7 @@ union UReg_PTE u64 WIMG : 4; u64 C : 1; u64 R : 1; - u64 : 3; + u64 : 3; u64 RPN : 20; }; @@ -623,16 +657,16 @@ enum // Special purpose register indices enum { - SPR_XER = 1, + SPR_XER = 1, SPR_LR = 8, SPR_CTR = 9, SPR_DSISR = 18, - SPR_DAR = 19, + SPR_DAR = 19, SPR_DEC = 22, - SPR_SDR = 25, + SPR_SDR = 25, SPR_SRR0 = 26, SPR_SRR1 = 27, - SPR_TL = 268, + SPR_TL = 268, SPR_TU = 269, SPR_TL_W = 284, SPR_TU_W = 285, @@ -669,7 +703,17 @@ enum SPR_ECID_U = 924, SPR_ECID_M = 925, SPR_ECID_L = 926, - SPR_L2CR = 1017 + SPR_L2CR = 1017, + + SPR_UMMCR0 = 936, + SPR_MMCR0 = 952, + SPR_PMC1 = 953, + SPR_PMC2 = 954, + + SPR_UMMCR1 = 940, + SPR_MMCR1 = 956, + SPR_PMC3 = 957, + SPR_PMC4 = 958, }; // Exceptions @@ -679,8 +723,9 @@ enum #define EXCEPTION_DSI 0x00000008 #define EXCEPTION_ISI 0x00000010 #define EXCEPTION_ALIGNMENT 0x00000020 -#define EXCEPTION_FPU_UNAVAILABLE 0x00000040 +#define EXCEPTION_FPU_UNAVAILABLE 0x00000040 #define EXCEPTION_PROGRAM 0x00000080 +#define EXCEPTION_PERFORMANCE_MONITOR 0x00000100 inline s32 SignExt16(s16 x) {return (s32)(s16)x;} inline s32 SignExt26(u32 x) {return x & 0x2000000 ? (s32)(x | 0xFC000000) : (s32)(x);} diff --git a/Source/Core/Core/Src/PowerPC/Interpreter/Interpreter_FloatingPoint.cpp b/Source/Core/Core/Src/PowerPC/Interpreter/Interpreter_FloatingPoint.cpp index 3b0ae602cd..1d6ea2e70d 100644 --- a/Source/Core/Core/Src/PowerPC/Interpreter/Interpreter_FloatingPoint.cpp +++ b/Source/Core/Core/Src/PowerPC/Interpreter/Interpreter_FloatingPoint.cpp @@ -42,10 +42,6 @@ using namespace MathUtil; void UpdateSSEState(); -#ifdef _MSC_VER -#pragma float_control(precise, on, push) -#endif - // Extremely rare - actually, never seen. // Star Wars : Rogue Leader spams that at some point :| void Interpreter::Helper_UpdateCR1(double _fValue) @@ -518,8 +514,4 @@ void Interpreter::fsqrtx(UGeckoInstruction _inst) rPS0(_inst.FD) = sqrt(b); UpdateFPRF(rPS0(_inst.FD)); if (_inst.Rc) Helper_UpdateCR1(rPS0(_inst.FD)); -} - -#ifdef _MSC_VER -#pragma float_control(pop) -#endif +}
\ No newline at end of file diff --git a/Source/Core/Core/Src/PowerPC/Interpreter/Interpreter_LoadStore.cpp b/Source/Core/Core/Src/PowerPC/Interpreter/Interpreter_LoadStore.cpp index a7955c0982..10c8fc2e58 100644 --- a/Source/Core/Core/Src/PowerPC/Interpreter/Interpreter_LoadStore.cpp +++ b/Source/Core/Core/Src/PowerPC/Interpreter/Interpreter_LoadStore.cpp @@ -363,28 +363,34 @@ void Interpreter::dcbf(UGeckoInstruction _inst) { NPC = PC + 12; }*/ - // Invalidate the icache on dcbf + // Invalidate the jit block cache on dcbf if (jit) { u32 address = Helper_Get_EA_X(_inst); - jit->GetBlockCache()->InvalidateICache(address & ~0x1f); + jit->GetBlockCache()->InvalidateICache(address & ~0x1f, 32); } } void Interpreter::dcbi(UGeckoInstruction _inst) { // Removes a block from data cache. Since we don't emulate the data cache, we don't need to do anything to the data cache - // However, we invalidate the icache on dcbi + // However, we invalidate the jit block cache on dcbi if (jit) { u32 address = Helper_Get_EA_X(_inst); - jit->GetBlockCache()->InvalidateICache(address & ~0x1f); + jit->GetBlockCache()->InvalidateICache(address & ~0x1f, 32); } } void Interpreter::dcbst(UGeckoInstruction _inst) { // Cache line flush. Since we don't emulate the data cache, we don't need to do anything. + // Invalidate the jit block cache on dcbst in case new code has been loaded via the data cache + if (jit) + { + u32 address = Helper_Get_EA_X(_inst); + jit->GetBlockCache()->InvalidateICache(address & ~0x1f, 32); + } } void Interpreter::dcbt(UGeckoInstruction _inst) diff --git a/Source/Core/Core/Src/PowerPC/Jit64/Jit.cpp b/Source/Core/Core/Src/PowerPC/Jit64/Jit.cpp index 0d31893b53..47e410b2e9 100644 --- a/Source/Core/Core/Src/PowerPC/Jit64/Jit.cpp +++ b/Source/Core/Core/Src/PowerPC/Jit64/Jit.cpp @@ -41,6 +41,10 @@ #include "JitAsm.h" #include "JitRegCache.h" #include "Jit64_Tables.h" +#include "HW/ProcessorInterface.h" +#if defined(_DEBUG) || defined(DEBUGFAST) +#include "PowerPCDisasm.h" +#endif using namespace Gen; using namespace PowerPC; @@ -187,12 +191,7 @@ void Jit64::Init() else jo.enableBlocklink = !Core::g_CoreStartupParameter.bMMU; } -#ifdef _M_X64 - jo.enableFastMem = Core::g_CoreStartupParameter.bUseFastMem; -#else - jo.enableFastMem = false; -#endif - jo.assumeFPLoadFromMem = Core::g_CoreStartupParameter.bUseFastMem; + jo.fpAccurateFcmp = true; // Fallback to Interpreter jo.optimizeGatherPipe = true; jo.fastInterrupts = false; @@ -296,6 +295,10 @@ void Jit64::Cleanup() { if (jo.optimizeGatherPipe && js.fifoBytesThisBlock > 0) ABI_CallFunction((void *)&GPFifo::CheckGatherPipe); + + // SPEED HACK: MMCR0/MMCR1 should be checked at run-time, not at compile time. + if (MMCR0.Hex || MMCR1.Hex) + ABI_CallFunctionCCC((void *)&PowerPC::UpdatePerformanceMonitor, js.downcountAmount, jit->js.numLoadStoreInst, jit->js.numFloatingPointInst); } void Jit64::WriteExit(u32 destination, int exit_num) @@ -334,16 +337,31 @@ void Jit64::WriteExitDestInEAX() void Jit64::WriteRfiExitDestInEAX() { MOV(32, M(&PC), R(EAX)); + MOV(32, M(&NPC), R(EAX)); Cleanup(); + ABI_CallFunction(reinterpret_cast<void *>(&PowerPC::CheckExceptions)); SUB(32, M(&CoreTiming::downcount), js.downcountAmount > 127 ? Imm32(js.downcountAmount) : Imm8(js.downcountAmount)); - JMP(asm_routines.testExceptions, true); + JMP(asm_routines.dispatcher, true); } void Jit64::WriteExceptionExit() { Cleanup(); - SUB(32, M(&CoreTiming::downcount), js.downcountAmount > 127 ? Imm32(js.downcountAmount) : Imm8(js.downcountAmount)); - JMP(asm_routines.testExceptions, true); + MOV(32, R(EAX), M(&PC)); + MOV(32, M(&NPC), R(EAX)); + ABI_CallFunction(reinterpret_cast<void *>(&PowerPC::CheckExceptions)); + SUB(32, M(&CoreTiming::downcount), js.downcountAmount > 127 ? Imm32(js.downcountAmount) : Imm8(js.downcountAmount)); + JMP(asm_routines.dispatcher, true); +} + +void Jit64::WriteExternalExceptionExit() +{ + Cleanup(); + MOV(32, R(EAX), M(&PC)); + MOV(32, M(&NPC), R(EAX)); + ABI_CallFunction(reinterpret_cast<void *>(&PowerPC::CheckExternalExceptions)); + SUB(32, M(&CoreTiming::downcount), js.downcountAmount > 127 ? Imm32(js.downcountAmount) : Imm8(js.downcountAmount)); + JMP(asm_routines.dispatcher, true); } void STACKALIGN Jit64::Run() @@ -412,15 +430,18 @@ const u8* Jit64::DoJit(u32 em_address, PPCAnalyst::CodeBuffer *code_buf, JitBloc if (Core::g_CoreStartupParameter.bEnableDebugging) { // Comment out the following to disable breakpoints (speed-up) - blockSize = 1; - broken_block = true; - Trace(); + if (!Profiler::g_ProfileBlocks) + { + if (GetState() == CPU_STEPPING) + blockSize = 1; + Trace(); + } } if (em_address == 0) { - Core::SetState(Core::CORE_PAUSE); - PanicAlert("ERROR: Compiling at 0. LR=%08x CTR=%08x", LR, CTR); + // Memory exception occurred during instruction fetch + memory_exception = true; } if (Core::g_CoreStartupParameter.bMMU && (em_address & JIT_ICACHE_VMEM_BIT)) @@ -433,12 +454,15 @@ const u8* Jit64::DoJit(u32 em_address, PPCAnalyst::CodeBuffer *code_buf, JitBloc } int size = 0; + js.firstFPInstructionFound = false; js.isLastInstruction = false; js.blockStart = em_address; js.fifoBytesThisBlock = 0; js.curBlock = b; js.block_flags = 0; js.cancel = false; + jit->js.numLoadStoreInst = 0; + jit->js.numFloatingPointInst = 0; // Analyze the block, collect all instructions it is made of (including inlining, // if that is enabled), reorder instructions for optimal performance, and join joinable instructions. @@ -470,16 +494,6 @@ const u8* Jit64::DoJit(u32 em_address, PPCAnalyst::CodeBuffer *code_buf, JitBloc if (ImHereDebug) ABI_CallFunction((void *)&ImHere); //Used to get a trace of the last few blocks before a crash, sometimes VERY useful - if (js.fpa.any) - { - // This block uses FPU - needs to add FP exception bailout - TEST(32, M(&PowerPC::ppcState.msr), Imm32(1 << 13)); //Test FP enabled bit - FixupBranch b1 = J_CC(CC_NZ); - MOV(32, M(&PC), Imm32(js.blockStart)); - JMP(asm_routines.fpException, true); - SetJumpTarget(b1); - } - // Conditionally add profiling code. if (Profiler::g_ProfileBlocks) { ADD(32, M(&b->runCount), Imm8(1)); @@ -555,18 +569,62 @@ const u8* Jit64::DoJit(u32 em_address, PPCAnalyst::CodeBuffer *code_buf, JitBloc if (!ops[i].skip) { - if (js.memcheck && (opinfo->flags & FL_USE_FPU)) + if ((opinfo->flags & FL_USE_FPU) && !js.firstFPInstructionFound) { + gpr.Flush(FLUSH_ALL); + fpr.Flush(FLUSH_ALL); + //This instruction uses FPU - needs to add FP exception bailout TEST(32, M(&PowerPC::ppcState.msr), Imm32(1 << 13)); // Test FP enabled bit - FixupBranch b1 = J_CC(CC_NZ); + FixupBranch b1 = J_CC(CC_NZ, true); // If a FPU exception occurs, the exception handler will read // from PC. Update PC with the latest value in case that happens. MOV(32, M(&PC), Imm32(ops[i].address)); - SUB(32, M(&CoreTiming::downcount), js.downcountAmount > 127 ? Imm32(js.downcountAmount) : Imm8(js.downcountAmount)); - JMP(asm_routines.fpException, true); + OR(32, M((void *)&PowerPC::ppcState.Exceptions), Imm32(EXCEPTION_FPU_UNAVAILABLE)); + WriteExceptionExit(); + SetJumpTarget(b1); + + js.firstFPInstructionFound = true; + } + + // Add an external exception check if the instruction writes to the FIFO. + if (jit->js.fifoWriteAddresses.find(ops[i].address) != jit->js.fifoWriteAddresses.end()) + { + gpr.Flush(FLUSH_ALL); + fpr.Flush(FLUSH_ALL); + + TEST(32, M((void *)&PowerPC::ppcState.Exceptions), Imm32(EXCEPTION_ISI | EXCEPTION_PROGRAM | EXCEPTION_SYSCALL | EXCEPTION_FPU_UNAVAILABLE | EXCEPTION_DSI | EXCEPTION_ALIGNMENT)); + FixupBranch clearInt = J_CC(CC_NZ, true); + TEST(32, M((void *)&PowerPC::ppcState.Exceptions), Imm32(EXCEPTION_EXTERNAL_INT)); + FixupBranch noExtException = J_CC(CC_Z, true); + TEST(32, M((void *)&PowerPC::ppcState.msr), Imm32(0x0008000)); + FixupBranch noExtIntEnable = J_CC(CC_Z, true); + TEST(32, M((void *)&ProcessorInterface::m_InterruptCause), Imm32(ProcessorInterface::INT_CAUSE_CP | ProcessorInterface::INT_CAUSE_PE_TOKEN | ProcessorInterface::INT_CAUSE_PE_FINISH)); + FixupBranch noCPInt = J_CC(CC_Z, true); + + MOV(32, M(&PC), Imm32(ops[i].address)); + WriteExternalExceptionExit(); + + SetJumpTarget(noCPInt); + SetJumpTarget(noExtIntEnable); + SetJumpTarget(noExtException); + SetJumpTarget(clearInt); + } + + if (Core::g_CoreStartupParameter.bEnableDebugging && breakpoints.IsAddressBreakPoint(ops[i].address) && GetState() != CPU_STEPPING) + { + gpr.Flush(FLUSH_ALL); + fpr.Flush(FLUSH_ALL); + + MOV(32, M(&PC), Imm32(ops[i].address)); + ABI_CallFunction(reinterpret_cast<void *>(&PowerPC::CheckBreakPoints)); + TEST(32, M((void*)PowerPC::GetStatePtr()), Imm32(0xFFFFFFFF)); + FixupBranch noBreakpoint = J_CC(CC_Z); + + WriteExit(ops[i].address, 0); + SetJumpTarget(noBreakpoint); } Jit64Tables::CompileInstruction(ops[i]); @@ -578,7 +636,7 @@ const u8* Jit64::DoJit(u32 em_address, PPCAnalyst::CodeBuffer *code_buf, JitBloc fpr.Flush(FLUSH_ALL); TEST(32, M((void *)&PowerPC::ppcState.Exceptions), Imm32(EXCEPTION_DSI)); - FixupBranch noMemException = J_CC(CC_Z); + FixupBranch noMemException = J_CC(CC_Z, true); // If a memory exception occurs, the exception handler will read // from PC. Update PC with the latest value in case that happens. @@ -586,6 +644,12 @@ const u8* Jit64::DoJit(u32 em_address, PPCAnalyst::CodeBuffer *code_buf, JitBloc WriteExceptionExit(); SetJumpTarget(noMemException); } + + if (opinfo->flags & FL_LOADSTORE) + ++jit->js.numLoadStoreInst; + + if (opinfo->flags & FL_USE_FPU) + ++jit->js.numFloatingPointInst; } #if defined(_DEBUG) || defined(DEBUGFAST) @@ -596,7 +660,6 @@ const u8* Jit64::DoJit(u32 em_address, PPCAnalyst::CodeBuffer *code_buf, JitBloc NOTICE_LOG(DYNA_REC, "Unflushed reg: %s", ppcInst); } #endif - if (js.skipnext) { js.skipnext = false; i++; // Skip next instruction @@ -610,6 +673,7 @@ const u8* Jit64::DoJit(u32 em_address, PPCAnalyst::CodeBuffer *code_buf, JitBloc { // Address of instruction could not be translated MOV(32, M(&NPC), Imm32(js.compilerPC)); + OR(32, M((void *)&PowerPC::ppcState.Exceptions), Imm32(EXCEPTION_ISI)); // Remove the invalid instruction from the icache, forcing a recompile diff --git a/Source/Core/Core/Src/PowerPC/Jit64/Jit.h b/Source/Core/Core/Src/PowerPC/Jit64/Jit.h index c01c1b017b..791934bd18 100644 --- a/Source/Core/Core/Src/PowerPC/Jit64/Jit.h +++ b/Source/Core/Core/Src/PowerPC/Jit64/Jit.h @@ -65,32 +65,6 @@ class Jit64 : public JitBase { private: - struct JitState - { - u32 compilerPC; - u32 next_compilerPC; - u32 blockStart; - bool cancel; - bool skipnext; - UGeckoInstruction next_inst; // for easy peephole opt. - int blockSize; - int instructionNumber; - int downcountAmount; - int block_flags; - - bool isLastInstruction; - bool memcheck; - - int fifoBytesThisBlock; - - PPCAnalyst::BlockStats st; - PPCAnalyst::BlockRegStats gpa; - PPCAnalyst::BlockRegStats fpa; - PPCAnalyst::CodeOp *op; - - JitBlock *curBlock; - }; - GPRRegCache gpr; FPURegCache fpr; @@ -103,8 +77,6 @@ public: Jit64() : code_buffer(32000) {} ~Jit64() {} - JitState js; - void Init(); void Shutdown(); @@ -143,6 +115,7 @@ public: void WriteExit(u32 destination, int exit_num); void WriteExitDestInEAX(); void WriteExceptionExit(); + void WriteExternalExceptionExit(); void WriteRfiExitDestInEAX(); void WriteCallInterpreter(UGeckoInstruction _inst); void Cleanup(); diff --git a/Source/Core/Core/Src/PowerPC/Jit64/Jit64_Tables.cpp b/Source/Core/Core/Src/PowerPC/Jit64/Jit64_Tables.cpp index 93963513ee..1c654a4a9a 100644 --- a/Source/Core/Core/Src/PowerPC/Jit64/Jit64_Tables.cpp +++ b/Source/Core/Core/Src/PowerPC/Jit64/Jit64_Tables.cpp @@ -210,7 +210,7 @@ static GekkoOPTemplate table31[] = {824, &Jit64::srawix}, //"srawix", OPTYPE_INTEGER, FL_OUT_A | FL_IN_B | FL_IN_S | FL_RC_BIT}}, {24, &Jit64::slwx}, //"slwx", OPTYPE_INTEGER, FL_OUT_A | FL_IN_B | FL_IN_S | FL_RC_BIT}}, - {54, &Jit64::DoNothing}, //"dcbst", OPTYPE_DCACHE, 0, 4}}, + {54, &Jit64::Default}, //"dcbst", OPTYPE_DCACHE, 0, 4}}, {86, &Jit64::Default}, //"dcbf", OPTYPE_DCACHE, 0, 4}}, {246, &Jit64::DoNothing}, //"dcbtst", OPTYPE_DCACHE, 0, 1}}, {278, &Jit64::DoNothing}, //"dcbt", OPTYPE_DCACHE, 0, 1}}, diff --git a/Source/Core/Core/Src/PowerPC/Jit64/JitAsm.cpp b/Source/Core/Core/Src/PowerPC/Jit64/JitAsm.cpp index b9aaa2df6a..f7082cd1cc 100644 --- a/Source/Core/Core/Src/PowerPC/Jit64/JitAsm.cpp +++ b/Source/Core/Core/Src/PowerPC/Jit64/JitAsm.cpp @@ -70,7 +70,7 @@ void Jit64AsmRoutineManager::Generate() MOV(64, R(R15), Imm64((u64)jit->GetBlockCache()->GetCodePointers())); //It's below 2GB so 32 bits are good enough #endif - const u8 *outerLoop = GetCodePtr(); + outerLoop = GetCodePtr(); ABI_CallFunction(reinterpret_cast<void *>(&CoreTiming::Advance)); FixupBranch skipToRealDispatch = J(); //skip the sync and compare first time @@ -81,12 +81,15 @@ void Jit64AsmRoutineManager::Generate() if (Core::g_CoreStartupParameter.bEnableDebugging) { + TEST(32, M((void*)PowerPC::GetStatePtr()), Imm32(PowerPC::CPU_STEPPING)); + FixupBranch notStepping = J_CC(CC_Z); ABI_CallFunction(reinterpret_cast<void *>(&PowerPC::CheckBreakPoints)); TEST(32, M((void*)PowerPC::GetStatePtr()), Imm32(0xFFFFFFFF)); FixupBranch noBreakpoint = J_CC(CC_Z); ABI_PopAllCalleeSavedRegsAndAdjustStack(); RET(); SetJumpTarget(noBreakpoint); + SetJumpTarget(notStepping); } SetJumpTarget(skipToRealDispatch); @@ -191,27 +194,17 @@ void Jit64AsmRoutineManager::Generate() #endif JMP(dispatcherNoCheck); // no point in special casing this - //FP blocks test for FPU available, jump here if false - fpException = AlignCode4(); - LOCK(); - OR(32, M((void *)&PowerPC::ppcState.Exceptions), Imm32(EXCEPTION_FPU_UNAVAILABLE)); - ABI_CallFunction(reinterpret_cast<void *>(&PowerPC::CheckExceptions)); - MOV(32, R(EAX), M(&NPC)); - MOV(32, M(&PC), R(EAX)); - JMP(dispatcher, true); - SetJumpTarget(bail); doTiming = GetCodePtr(); - ABI_CallFunction(reinterpret_cast<void *>(&CoreTiming::Advance)); - - testExceptions = GetCodePtr(); + testExternalExceptions = GetCodePtr(); + TEST(32, M((void *)&PowerPC::ppcState.Exceptions), Imm32(EXCEPTION_EXTERNAL_INT | EXCEPTION_PERFORMANCE_MONITOR | EXCEPTION_DECREMENTER)); + FixupBranch noExtException = J_CC(CC_Z); MOV(32, R(EAX), M(&PC)); MOV(32, M(&NPC), R(EAX)); - ABI_CallFunction(reinterpret_cast<void *>(&PowerPC::CheckExceptions)); - MOV(32, R(EAX), M(&NPC)); - MOV(32, M(&PC), R(EAX)); - + ABI_CallFunction(reinterpret_cast<void *>(&PowerPC::CheckExternalExceptions)); + SetJumpTarget(noExtException); + TEST(32, M((void*)PowerPC::GetStatePtr()), Imm32(0xFFFFFFFF)); J_CC(CC_Z, outerLoop, true); diff --git a/Source/Core/Core/Src/PowerPC/Jit64/Jit_Integer.cpp b/Source/Core/Core/Src/PowerPC/Jit64/Jit_Integer.cpp index 4980b4d7a4..5aaf4b99f1 100644 --- a/Source/Core/Core/Src/PowerPC/Jit64/Jit_Integer.cpp +++ b/Source/Core/Core/Src/PowerPC/Jit64/Jit_Integer.cpp @@ -266,7 +266,7 @@ void Jit64::reg_imm(UGeckoInstruction inst) case 15: if (a == 0) { // lis // Merge with next instruction if loading a 32-bits immediate value (lis + addi, lis + ori) - if (!js.isLastInstruction) { + if (!js.isLastInstruction && !Core::g_CoreStartupParameter.bEnableDebugging) { if ((js.next_inst.OPCD == 14) && (js.next_inst.RD == d) && (js.next_inst.RA == d)) { // addi gpr.SetImmediate32(d, ((u32)inst.SIMM_16 << 16) + (u32)(s32)js.next_inst.SIMM_16); js.downcountAmount++; diff --git a/Source/Core/Core/Src/PowerPC/Jit64/Jit_LoadStore.cpp b/Source/Core/Core/Src/PowerPC/Jit64/Jit_LoadStore.cpp index 039300223a..e9de594465 100644 --- a/Source/Core/Core/Src/PowerPC/Jit64/Jit_LoadStore.cpp +++ b/Source/Core/Core/Src/PowerPC/Jit64/Jit_LoadStore.cpp @@ -151,7 +151,7 @@ void Jit64::lXXx(UGeckoInstruction inst) // ! we must continue executing of the loop after exception handling, maybe there is still 0 in r0 //MOV(32, M(&PowerPC::ppcState.pc), Imm32(js.compilerPC)); - JMP(asm_routines.testExceptions, true); + WriteExceptionExit(); SetJumpTarget(noIdle); @@ -352,8 +352,8 @@ void Jit64::stX(UGeckoInstruction inst) } /* // TODO - figure out why Beyond Good and Evil hates this - #ifdef _M_X64 - if (accessSize == 32 && !update && jo.enableFastMem) + #if defined(_WIN32) && defined(_M_X64) + if (accessSize == 32 && !update) { // Fast and daring - requires 64-bit MOV(32, R(EAX), gpr.R(s)); @@ -405,10 +405,13 @@ void Jit64::stXx(UGeckoInstruction inst) gpr.Lock(a, b, s); gpr.FlushLockX(ECX, EDX); - if (inst.SUBOP10 & 32) { + if (inst.SUBOP10 & 32) + { + MEMCHECK_START gpr.BindToRegister(a, true, true); ADD(32, gpr.R(a), gpr.R(b)); MOV(32, R(EDX), gpr.R(a)); + MEMCHECK_END } else { MOV(32, R(EDX), gpr.R(a)); ADD(32, R(EDX), gpr.R(b)); @@ -425,12 +428,6 @@ void Jit64::stXx(UGeckoInstruction inst) MOV(32, R(ECX), gpr.R(s)); SafeWriteRegToReg(ECX, EDX, accessSize, 0); - //MEMCHECK_START - - // TODO: Insert rA update code here - - //MEMCHECK_END - gpr.UnlockAll(); gpr.UnlockAllX(); } @@ -438,6 +435,9 @@ void Jit64::stXx(UGeckoInstruction inst) // A few games use these heavily in video codecs. void Jit64::lmw(UGeckoInstruction inst) { + INSTRUCTION_START + JITDISABLE(LoadStore) + #ifdef _M_X64 gpr.FlushLockX(ECX); MOV(32, R(EAX), Imm32((u32)(s32)inst.SIMM_16)); @@ -458,6 +458,9 @@ void Jit64::lmw(UGeckoInstruction inst) void Jit64::stmw(UGeckoInstruction inst) { + INSTRUCTION_START + JITDISABLE(LoadStore) + #ifdef _M_X64 gpr.FlushLockX(ECX); MOV(32, R(EAX), Imm32((u32)(s32)inst.SIMM_16)); diff --git a/Source/Core/Core/Src/PowerPC/Jit64/Jit_LoadStoreFloating.cpp b/Source/Core/Core/Src/PowerPC/Jit64/Jit_LoadStoreFloating.cpp index 41c9a3ceb7..9f61e097b8 100644 --- a/Source/Core/Core/Src/PowerPC/Jit64/Jit_LoadStoreFloating.cpp +++ b/Source/Core/Core/Src/PowerPC/Jit64/Jit_LoadStoreFloating.cpp @@ -62,14 +62,11 @@ void Jit64::lfs(UGeckoInstruction inst) return; } s32 offset = (s32)(s16)inst.SIMM_16; - if (jo.assumeFPLoadFromMem) - { - UnsafeLoadToEAX(gpr.R(a), 32, offset, false); - } - else - { - SafeLoadToEAX(gpr.R(a), 32, offset, false); - } +#if defined(_WIN32) && defined(_M_X64) + UnsafeLoadToEAX(gpr.R(a), 32, offset, false); +#else + SafeLoadToEAX(gpr.R(a), 32, offset, false); +#endif MEMCHECK_START @@ -219,7 +216,7 @@ void Jit64::stfd(UGeckoInstruction inst) MOVD_xmm(R(EAX), XMM0); UnsafeWriteRegToReg(EAX, ABI_PARAM1, 32, 0); } - FixupBranch exit = J(); + FixupBranch exit = J(true); SetJumpTarget(safe); // Safe but slow routine @@ -240,7 +237,14 @@ void Jit64::stfd(UGeckoInstruction inst) fpr.UnlockAll(); } - +// In Release on 32bit build, +// this seemed to cause a problem with PokePark2 +// at start after talking to first pokemon, +// you run and smash a box, then he goes on about +// following him and then you cant do anything. +// I have enabled interpreter for this function +// in the mean time. +// Parlane void Jit64::stfs(UGeckoInstruction inst) { INSTRUCTION_START diff --git a/Source/Core/Core/Src/PowerPC/Jit64/Jit_SystemRegisters.cpp b/Source/Core/Core/Src/PowerPC/Jit64/Jit_SystemRegisters.cpp index 52c2ef3eee..14827129f8 100644 --- a/Source/Core/Core/Src/PowerPC/Jit64/Jit_SystemRegisters.cpp +++ b/Source/Core/Core/Src/PowerPC/Jit64/Jit_SystemRegisters.cpp @@ -93,6 +93,10 @@ void Jit64::mfspr(UGeckoInstruction inst) case SPR_DEC: case SPR_TL: case SPR_TU: + case SPR_PMC1: + case SPR_PMC2: + case SPR_PMC3: + case SPR_PMC4: Default(inst); return; default: @@ -119,6 +123,7 @@ void Jit64::mtmsr(UGeckoInstruction inst) gpr.Flush(FLUSH_ALL); fpr.Flush(FLUSH_ALL); WriteExit(js.compilerPC + 4, 0); + js.firstFPInstructionFound = false; } void Jit64::mfmsr(UGeckoInstruction inst) diff --git a/Source/Core/Core/Src/PowerPC/Jit64IL/IR.cpp b/Source/Core/Core/Src/PowerPC/Jit64IL/IR.cpp index 3a60a0ae11..2a830a03cf 100644 --- a/Source/Core/Core/Src/PowerPC/Jit64IL/IR.cpp +++ b/Source/Core/Core/Src/PowerPC/Jit64IL/IR.cpp @@ -1212,7 +1212,7 @@ void IRBuilder::simplifyCommutative(unsigned Opcode, InstLoc& Op1, InstLoc& Op2) } bool IRBuilder::maskedValueIsZero(InstLoc Op1, InstLoc Op2) const { - return (~ComputeKnownZeroBits(Op1) & ~ComputeKnownZeroBits(Op1)) == 0; + return (~ComputeKnownZeroBits(Op1) & ~ComputeKnownZeroBits(Op2)) == 0; } // Returns I' if I == (0 - I') @@ -1260,16 +1260,17 @@ static const std::string opcodeNames[] = { "FResult_End", "StorePaired", "StoreSingle", "StoreDouble", "StoreFReg", "FDCmpCR", "CInt16", "CInt32", "SystemCall", "RFIExit", "InterpreterBranch", "IdleBranch", "ShortIdleLoop", - "FPExceptionCheckStart", "FPExceptionCheckEnd", "ISIException", "Tramp", - "BlockStart", "BlockEnd", "Int3", + "FPExceptionCheckStart", "FPExceptionCheckEnd", "ISIException", "ExtExceptionCheck", + "Tramp", "BlockStart", "BlockEnd", "Int3", }; static const unsigned alwaysUsedList[] = { InterpreterFallback, StoreGReg, StoreCR, StoreLink, StoreCTR, StoreMSR, StoreGQR, StoreSRR, StoreCarry, StoreFPRF, Load8, Load16, Load32, Store8, Store16, Store32, StoreSingle, StoreDouble, StorePaired, StoreFReg, FDCmpCR, BlockStart, BlockEnd, IdleBranch, BranchCond, BranchUncond, ShortIdleLoop, - SystemCall, InterpreterBranch, RFIExit, FPExceptionCheckStart, - FPExceptionCheckEnd, ISIException, Int3, Tramp, Nop + SystemCall, InterpreterBranch, RFIExit, FPExceptionCheck, + DSIExceptionCheck, ISIException, ExtExceptionCheck, BreakPointCheck, + Int3, Tramp, Nop }; static const unsigned extra8RegList[] = { LoadGReg, LoadCR, LoadGQR, LoadFReg, LoadFRegDENToZero, diff --git a/Source/Core/Core/Src/PowerPC/Jit64IL/IR.h b/Source/Core/Core/Src/PowerPC/Jit64IL/IR.h index aca3dd0e37..77f7d6977b 100644 --- a/Source/Core/Core/Src/PowerPC/Jit64IL/IR.h +++ b/Source/Core/Core/Src/PowerPC/Jit64IL/IR.h @@ -165,10 +165,10 @@ enum Opcode { ShortIdleLoop, // Idle loop seen in homebrew like wii mahjong, // just a branch - // used for MMU, at least until someone + // used for exception checking, at least until someone // has a better idea of integrating it - FPExceptionCheckStart, FPExceptionCheckEnd, - ISIException, + FPExceptionCheck, DSIExceptionCheck, + ISIException, ExtExceptionCheck, BreakPointCheck, // "Opcode" representing a register too far away to // reference directly; this is a size optimization Tramp, @@ -402,15 +402,21 @@ public: InstLoc EmitSystemCall(InstLoc pc) { return FoldUOp(SystemCall, pc); } - InstLoc EmitFPExceptionCheckStart(InstLoc pc) { - return EmitUOp(FPExceptionCheckStart, pc); + InstLoc EmitFPExceptionCheck(InstLoc pc) { + return EmitUOp(FPExceptionCheck, pc); } - InstLoc EmitFPExceptionCheckEnd(InstLoc pc) { - return EmitUOp(FPExceptionCheckEnd, pc); + InstLoc EmitDSIExceptionCheck(InstLoc pc) { + return EmitUOp(DSIExceptionCheck, pc); } InstLoc EmitISIException(InstLoc dest) { return EmitUOp(ISIException, dest); } + InstLoc EmitExtExceptionCheck(InstLoc pc) { + return EmitUOp(ExtExceptionCheck, pc); + } + InstLoc EmitBreakPointCheck(InstLoc pc) { + return EmitUOp(BreakPointCheck, pc); + } InstLoc EmitRFIExit() { return FoldZeroOp(RFIExit, 0); } diff --git a/Source/Core/Core/Src/PowerPC/Jit64IL/IR_X86.cpp b/Source/Core/Core/Src/PowerPC/Jit64IL/IR_X86.cpp index e1807cfbb4..e91291fa90 100644 --- a/Source/Core/Core/Src/PowerPC/Jit64IL/IR_X86.cpp +++ b/Source/Core/Core/Src/PowerPC/Jit64IL/IR_X86.cpp @@ -50,6 +50,7 @@ The register allocation is linear scan allocation. #include "../../../../Common/Src/CPUDetect.h" #include "MathUtil.h" #include "../../Core.h" +#include "HW/ProcessorInterface.h" static ThunkManager thunks; @@ -758,9 +759,11 @@ static void DoWriteCode(IRBuilder* ibuild, JitIL* Jit, bool UseProfile, bool Mak case RFIExit: case InterpreterBranch: case ShortIdleLoop: - case FPExceptionCheckStart: - case FPExceptionCheckEnd: + case FPExceptionCheck: + case DSIExceptionCheck: case ISIException: + case ExtExceptionCheck: + case BreakPointCheck: case Int3: case Tramp: // No liveness effects @@ -1385,7 +1388,7 @@ static void DoWriteCode(IRBuilder* ibuild, JitIL* Jit, bool UseProfile, bool Mak Jit->MOV(32, R(ECX), regLocForInst(RI, getOp2(I))); RI.Jit->UnsafeWriteRegToReg(EAX, ECX, 32, 0); } - FixupBranch exit = Jit->J(); + FixupBranch exit = Jit->J(true); Jit->SetJumpTarget(safe); // Safe but slow routine OpArg value = fregLocForInst(RI, getOp1(I)); @@ -1866,7 +1869,7 @@ static void DoWriteCode(IRBuilder* ibuild, JitIL* Jit, bool UseProfile, bool Mak Jit->WriteRfiExitDestInOpArg(R(EAX)); break; } - case FPExceptionCheckStart: { + case FPExceptionCheck: { unsigned InstLoc = ibuild->GetImmValue(getOp1(I)); //This instruction uses FPU - needs to add FP exception bailout Jit->TEST(32, M(&PowerPC::ppcState.msr), Imm32(1 << 13)); // Test FP enabled bit @@ -1880,7 +1883,7 @@ static void DoWriteCode(IRBuilder* ibuild, JitIL* Jit, bool UseProfile, bool Mak Jit->SetJumpTarget(b1); break; } - case FPExceptionCheckEnd: { + case DSIExceptionCheck: { unsigned InstLoc = ibuild->GetImmValue(getOp1(I)); Jit->TEST(32, M((void *)&PowerPC::ppcState.Exceptions), Imm32(EXCEPTION_DSI)); FixupBranch noMemException = Jit->J_CC(CC_Z); @@ -1920,6 +1923,38 @@ static void DoWriteCode(IRBuilder* ibuild, JitIL* Jit, bool UseProfile, bool Mak Jit->WriteExceptionExit(); break; } + case ExtExceptionCheck: { + unsigned InstLoc = ibuild->GetImmValue(getOp1(I)); + + Jit->TEST(32, M((void *)&PowerPC::ppcState.Exceptions), Imm32(EXCEPTION_ISI | EXCEPTION_PROGRAM | EXCEPTION_SYSCALL | EXCEPTION_FPU_UNAVAILABLE | EXCEPTION_DSI | EXCEPTION_ALIGNMENT)); + FixupBranch clearInt = Jit->J_CC(CC_NZ); + Jit->TEST(32, M((void *)&PowerPC::ppcState.Exceptions), Imm32(EXCEPTION_EXTERNAL_INT)); + FixupBranch noExtException = Jit->J_CC(CC_Z); + Jit->TEST(32, M((void *)&PowerPC::ppcState.msr), Imm32(0x0008000)); + FixupBranch noExtIntEnable = Jit->J_CC(CC_Z); + Jit->TEST(32, M((void *)&ProcessorInterface::m_InterruptCause), Imm32(ProcessorInterface::INT_CAUSE_CP | ProcessorInterface::INT_CAUSE_PE_TOKEN | ProcessorInterface::INT_CAUSE_PE_FINISH)); + FixupBranch noCPInt = Jit->J_CC(CC_Z); + + Jit->MOV(32, M(&PC), Imm32(InstLoc)); + Jit->WriteExceptionExit(); + + Jit->SetJumpTarget(noCPInt); + Jit->SetJumpTarget(noExtIntEnable); + Jit->SetJumpTarget(noExtException); + Jit->SetJumpTarget(clearInt); + break; + } + case BreakPointCheck: { + unsigned InstLoc = ibuild->GetImmValue(getOp1(I)); + + Jit->MOV(32, M(&PC), Imm32(InstLoc)); + Jit->ABI_CallFunction(reinterpret_cast<void *>(&PowerPC::CheckBreakPoints)); + Jit->TEST(32, M((void*)PowerPC::GetStatePtr()), Imm32(0xFFFFFFFF)); + FixupBranch noBreakpoint = Jit->J_CC(CC_Z); + Jit->WriteExit(InstLoc, 0); + Jit->SetJumpTarget(noBreakpoint); + break; + } case Int3: { Jit->INT3(); break; diff --git a/Source/Core/Core/Src/PowerPC/Jit64IL/JitIL.cpp b/Source/Core/Core/Src/PowerPC/Jit64IL/JitIL.cpp index 75755de5cb..c9d4e44e71 100644 --- a/Source/Core/Core/Src/PowerPC/Jit64IL/JitIL.cpp +++ b/Source/Core/Core/Src/PowerPC/Jit64IL/JitIL.cpp @@ -276,12 +276,6 @@ void JitIL::Init() jo.enableBlocklink = !Core::g_CoreStartupParameter.bMMU; } -#ifdef _M_X64 - jo.enableFastMem = false; -#else - jo.enableFastMem = false; -#endif - jo.assumeFPLoadFromMem = Core::g_CoreStartupParameter.bUseFastMem; jo.fpAccurateFcmp = false; jo.optimizeGatherPipe = true; jo.fastInterrupts = false; @@ -396,6 +390,10 @@ void JitIL::Cleanup() { if (jo.optimizeGatherPipe && js.fifoBytesThisBlock > 0) ABI_CallFunction((void *)&GPFifo::CheckGatherPipe); + + // SPEED HACK: MMCR0/MMCR1 should be checked at run-time, not at compile time. + if (MMCR0.Hex || MMCR1.Hex) + ABI_CallFunctionCCC((void *)&PowerPC::UpdatePerformanceMonitor, js.downcountAmount, jit->js.numLoadStoreInst, jit->js.numFloatingPointInst); } void JitIL::WriteExit(u32 destination, int exit_num) @@ -524,12 +522,19 @@ const u8* JitIL::DoJit(u32 em_address, PPCAnalyst::CodeBuffer *code_buf, JitBloc if (Core::g_CoreStartupParameter.bEnableDebugging) { // Comment out the following to disable breakpoints (speed-up) - blockSize = 1; - Trace(); + if (!Profiler::g_ProfileBlocks) + { + if (GetState() == CPU_STEPPING) + blockSize = 1; + Trace(); + } } if (em_address == 0) - PanicAlert("ERROR : Trying to compile at 0. LR=%08x", LR); + { + // Memory exception occurred during instruction fetch + memory_exception = true; + } if (Core::g_CoreStartupParameter.bMMU && (em_address & JIT_ICACHE_VMEM_BIT)) { @@ -546,6 +551,8 @@ const u8* JitIL::DoJit(u32 em_address, PPCAnalyst::CodeBuffer *code_buf, JitBloc js.fifoBytesThisBlock = 0; js.curBlock = b; js.cancel = false; + jit->js.numLoadStoreInst = 0; + jit->js.numFloatingPointInst = 0; // Analyze the block, collect all instructions it is made of (including inlining, // if that is enabled), reorder instructions for optimal performance, and join joinable instructions. @@ -646,15 +653,31 @@ const u8* JitIL::DoJit(u32 em_address, PPCAnalyst::CodeBuffer *code_buf, JitBloc { if (js.memcheck && (opinfo->flags & FL_USE_FPU)) { - ibuild.EmitFPExceptionCheckStart(ibuild.EmitIntConst(ops[i].address)); + ibuild.EmitFPExceptionCheck(ibuild.EmitIntConst(ops[i].address)); + } + + if (jit->js.fifoWriteAddresses.find(js.compilerPC) != jit->js.fifoWriteAddresses.end()) + { + ibuild.EmitExtExceptionCheck(ibuild.EmitIntConst(ops[i].address)); + } + + if (Core::g_CoreStartupParameter.bEnableDebugging && breakpoints.IsAddressBreakPoint(ops[i].address) && GetState() != CPU_STEPPING) + { + ibuild.EmitBreakPointCheck(ibuild.EmitIntConst(ops[i].address)); } JitILTables::CompileInstruction(ops[i]); if (js.memcheck && (opinfo->flags & FL_LOADSTORE)) { - ibuild.EmitFPExceptionCheckEnd(ibuild.EmitIntConst(ops[i].address)); + ibuild.EmitDSIExceptionCheck(ibuild.EmitIntConst(ops[i].address)); } + + if (opinfo->flags & FL_LOADSTORE) + ++jit->js.numLoadStoreInst; + + if (opinfo->flags & FL_USE_FPU) + ++jit->js.numFloatingPointInst; } } diff --git a/Source/Core/Core/Src/PowerPC/Jit64IL/JitILAsm.cpp b/Source/Core/Core/Src/PowerPC/Jit64IL/JitILAsm.cpp index da94c881e3..d04c58b143 100644 --- a/Source/Core/Core/Src/PowerPC/Jit64IL/JitILAsm.cpp +++ b/Source/Core/Core/Src/PowerPC/Jit64IL/JitILAsm.cpp @@ -83,12 +83,15 @@ void JitILAsmRoutineManager::Generate() if (Core::g_CoreStartupParameter.bEnableDebugging) { + TEST(32, M((void*)PowerPC::GetStatePtr()), Imm32(PowerPC::CPU_STEPPING)); + FixupBranch notStepping = J_CC(CC_Z); ABI_CallFunction(reinterpret_cast<void *>(&PowerPC::CheckBreakPoints)); TEST(32, M((void*)PowerPC::GetStatePtr()), Imm32(0xFFFFFFFF)); FixupBranch noBreakpoint = J_CC(CC_Z); ABI_PopAllCalleeSavedRegsAndAdjustStack(); RET(); SetJumpTarget(noBreakpoint); + SetJumpTarget(notStepping); } SetJumpTarget(skipToRealDispatch); @@ -208,14 +211,14 @@ void JitILAsmRoutineManager::Generate() doTiming = GetCodePtr(); ABI_CallFunction(reinterpret_cast<void *>(&CoreTiming::Advance)); - + testExceptions = GetCodePtr(); MOV(32, R(EAX), M(&PC)); MOV(32, M(&NPC), R(EAX)); ABI_CallFunction(reinterpret_cast<void *>(&PowerPC::CheckExceptions)); MOV(32, R(EAX), M(&NPC)); MOV(32, M(&PC), R(EAX)); - + TEST(32, M((void*)PowerPC::GetStatePtr()), Imm32(0xFFFFFFFF)); J_CC(CC_Z, outerLoop, true); //Landing pad for drec space diff --git a/Source/Core/Core/Src/PowerPC/Jit64IL/JitIL_Integer.cpp b/Source/Core/Core/Src/PowerPC/Jit64IL/JitIL_Integer.cpp index 572cb63861..379aaca48a 100644 --- a/Source/Core/Core/Src/PowerPC/Jit64IL/JitIL_Integer.cpp +++ b/Source/Core/Core/Src/PowerPC/Jit64IL/JitIL_Integer.cpp @@ -493,6 +493,9 @@ void JitIL::srawx(UGeckoInstruction inst) test = ibuild.EmitOr(val, mask2); test = ibuild.EmitICmpUgt(test, mask); ibuild.EmitStoreCarry(test); + + if (inst.Rc) + ComputeRC(ibuild, val); } void JitIL::srawix(UGeckoInstruction inst) diff --git a/Source/Core/Core/Src/PowerPC/Jit64IL/JitIL_Tables.cpp b/Source/Core/Core/Src/PowerPC/Jit64IL/JitIL_Tables.cpp index 68e3e7493c..9b2e3ff466 100644 --- a/Source/Core/Core/Src/PowerPC/Jit64IL/JitIL_Tables.cpp +++ b/Source/Core/Core/Src/PowerPC/Jit64IL/JitIL_Tables.cpp @@ -212,7 +212,7 @@ static GekkoOPTemplate table31[] = {824, &JitIL::srawix}, //"srawix", OPTYPE_INTEGER, FL_OUT_A | FL_IN_B | FL_IN_S | FL_RC_BIT}}, {24, &JitIL::slwx}, //"slwx", OPTYPE_INTEGER, FL_OUT_A | FL_IN_B | FL_IN_S | FL_RC_BIT}}, - {54, &JitIL::DoNothing}, //"dcbst", OPTYPE_DCACHE, 0, 4}}, + {54, &JitIL::Default}, //"dcbst", OPTYPE_DCACHE, 0, 4}}, {86, &JitIL::Default}, //"dcbf", OPTYPE_DCACHE, 0, 4}}, {246, &JitIL::DoNothing}, //"dcbtst", OPTYPE_DCACHE, 0, 1}}, {278, &JitIL::DoNothing}, //"dcbt", OPTYPE_DCACHE, 0, 1}}, diff --git a/Source/Core/Core/Src/PowerPC/JitCommon/JitAsmCommon.h b/Source/Core/Core/Src/PowerPC/JitCommon/JitAsmCommon.h index 7385949ac0..cbec27d2aa 100644 --- a/Source/Core/Core/Src/PowerPC/JitCommon/JitAsmCommon.h +++ b/Source/Core/Core/Src/PowerPC/JitCommon/JitAsmCommon.h @@ -40,12 +40,14 @@ public: const u8 *enterCode; + const u8 *outerLoop; const u8 *dispatcher; const u8 *dispatcherNoCheck; const u8 *dispatcherPcInEAX; const u8 *fpException; const u8 *testExceptions; + const u8 *testExternalExceptions; const u8 *dispatchPcInEAX; const u8 *doTiming; diff --git a/Source/Core/Core/Src/PowerPC/JitCommon/JitBase.cpp b/Source/Core/Core/Src/PowerPC/JitCommon/JitBase.cpp index 7f6cac8dd3..6203a81e15 100644 --- a/Source/Core/Core/Src/PowerPC/JitCommon/JitBase.cpp +++ b/Source/Core/Core/Src/PowerPC/JitCommon/JitBase.cpp @@ -13,6 +13,8 @@ // If not, see http://www.gnu.org/licenses/ #include "JitBase.h" +#include "PowerPCDisasm.h" +#include "disasm.h" JitBase *jit; diff --git a/Source/Core/Core/Src/PowerPC/JitCommon/JitBase.h b/Source/Core/Core/Src/PowerPC/JitCommon/JitBase.h index b832e96e1f..5352c06d04 100644 --- a/Source/Core/Core/Src/PowerPC/JitCommon/JitBase.h +++ b/Source/Core/Core/Src/PowerPC/JitCommon/JitBase.h @@ -28,8 +28,7 @@ #include "JitBackpatch.h" // for EmuCodeBlock #include "JitAsmCommon.h" -#include "PowerPCDisasm.h" -#include "disasm.h" +#include <set> #define JIT_OPCODE 0 @@ -42,10 +41,8 @@ protected: struct JitOptions { bool optimizeStack; - bool assumeFPLoadFromMem; bool enableBlocklink; bool fpAccurateFcmp; - bool enableFastMem; bool optimizeGatherPipe; bool fastInterrupts; bool accurateSinglePrecision; @@ -60,11 +57,16 @@ protected: int blockSize; int instructionNumber; int downcountAmount; + u32 numLoadStoreInst; + u32 numFloatingPointInst; + bool firstFPInstructionFound; bool isLastInstruction; bool forceUnsafeLoad; bool memcheck; + bool skipnext; bool broken_block; + int block_flags; int fifoBytesThisBlock; @@ -75,6 +77,8 @@ protected: u8* rewriteStart; JitBlock *curBlock; + + std::set<u32> fifoWriteAddresses; }; public: diff --git a/Source/Core/Core/Src/PowerPC/JitCommon/JitCache.cpp b/Source/Core/Core/Src/PowerPC/JitCommon/JitCache.cpp index 422369d307..0e06c1f762 100644 --- a/Source/Core/Core/Src/PowerPC/JitCommon/JitCache.cpp +++ b/Source/Core/Core/Src/PowerPC/JitCommon/JitCache.cpp @@ -208,7 +208,11 @@ bool JitBlock::ContainsAddress(u32 em_address) JitBlock &b = blocks[block_num]; b.originalFirstOpcode = Memory::Read_Opcode_JIT(b.originalAddress); Memory::Write_Opcode_JIT(b.originalAddress, (JIT_OPCODE << 26) | block_num); - block_map[std::make_pair(b.originalAddress + 4 * b.originalSize - 1, b.originalAddress)] = block_num; + + // Convert the logical address to a physical address for the block map + u32 pAddr = b.originalAddress & 0x1FFFFFFF; + + block_map[std::make_pair(pAddr + 4 * b.originalSize - 1, pAddr)] = block_num; if (block_link) { for (int i = 0; i < 2; i++) @@ -353,6 +357,24 @@ bool JitBlock::ContainsAddress(u32 em_address) } } + void JitBlockCache::UnlinkBlock(int i) + { + JitBlock &b = blocks[i]; + std::map<u32, int>::iterator iter; + pair<multimap<u32, int>::iterator, multimap<u32, int>::iterator> ppp; + ppp = links_to.equal_range(b.originalAddress); + if (ppp.first == ppp.second) + return; + for (multimap<u32, int>::iterator iter2 = ppp.first; iter2 != ppp.second; ++iter2) { + JitBlock &sourceBlock = blocks[iter2->second]; + for (int e = 0; e < 2; e++) + { + if (sourceBlock.exitAddress[e] == b.originalAddress) + sourceBlock.linkStatus[e] = false; + } + } + } + void JitBlockCache::DestroyBlock(int block_num, bool invalidate) { if (block_num < 0 || block_num >= num_blocks) @@ -375,7 +397,9 @@ bool JitBlock::ContainsAddress(u32 em_address) Memory::WriteUnchecked_U32(b.originalFirstOpcode, b.originalAddress); #endif - // We don't unlink blocks, we just send anyone who tries to run them back to the dispatcher. + UnlinkBlock(block_num); + + // Send anyone who tries to run this block back to the dispatcher. // Not entirely ideal, but .. pretty good. // Spurious entrances from previously linked blocks can only come through checkedEntry XEmitter emit((u8 *)b.checkedEntry); @@ -389,16 +413,38 @@ bool JitBlock::ContainsAddress(u32 em_address) */ } - - void JitBlockCache::InvalidateICache(u32 address) + void JitBlockCache::InvalidateICache(u32 address, const u32 length) { - address &= ~0x1f; + // Convert the logical address to a physical address for the block map + u32 pAddr = address & 0x1FFFFFFF; + // destroy JIT blocks // !! this works correctly under assumption that any two overlapping blocks end at the same address - std::map<pair<u32,u32>, u32>::iterator it1 = block_map.lower_bound(std::make_pair(address, 0)), it2 = it1, it; - while (it2 != block_map.end() && it2->first.second < address + 0x20) + std::map<pair<u32,u32>, u32>::iterator it1 = block_map.lower_bound(std::make_pair(pAddr, 0)), it2 = it1, it; + while (it2 != block_map.end() && it2->first.second < pAddr + length) { - DestroyBlock(it2->second, true); +#ifdef JIT_UNLIMITED_ICACHE + JitBlock &b = blocks[it2->second]; + if (b.originalFirstOpcode != Memory::ReadUnchecked_U32(b.originalAddress)) + { + if (b.originalAddress & JIT_ICACHE_VMEM_BIT) + { + u32 cacheaddr = b.originalAddress & JIT_ICACHE_MASK; + memset(iCacheVMEM + cacheaddr, JIT_ICACHE_INVALID_BYTE, 4); + } + else if (b.originalAddress & JIT_ICACHE_EXRAM_BIT) + { + u32 cacheaddr = b.originalAddress & JIT_ICACHEEX_MASK; + memset(iCacheEx + cacheaddr, JIT_ICACHE_INVALID_BYTE, 4); + } + else + { + u32 cacheaddr = b.originalAddress & JIT_ICACHE_MASK; + memset(iCache + cacheaddr, JIT_ICACHE_INVALID_BYTE, 4); + } +#endif + DestroyBlock(it2->second, true); + } it2++; } if (it1 != it2) @@ -418,17 +464,17 @@ bool JitBlock::ContainsAddress(u32 em_address) if (address & JIT_ICACHE_VMEM_BIT) { u32 cacheaddr = address & JIT_ICACHE_MASK; - memset(iCacheVMEM + cacheaddr, JIT_ICACHE_INVALID_BYTE, 32); + memset(iCacheVMEM + cacheaddr, JIT_ICACHE_INVALID_BYTE, length); } else if (address & JIT_ICACHE_EXRAM_BIT) { u32 cacheaddr = address & JIT_ICACHEEX_MASK; - memset(iCacheEx + cacheaddr, JIT_ICACHE_INVALID_BYTE, 32); + memset(iCacheEx + cacheaddr, JIT_ICACHE_INVALID_BYTE, length); } else { u32 cacheaddr = address & JIT_ICACHE_MASK; - memset(iCache + cacheaddr, JIT_ICACHE_INVALID_BYTE, 32); + memset(iCache + cacheaddr, JIT_ICACHE_INVALID_BYTE, length); } #endif } diff --git a/Source/Core/Core/Src/PowerPC/JitCommon/JitCache.h b/Source/Core/Core/Src/PowerPC/JitCommon/JitCache.h index 91d47a3d0e..16f16d6d14 100644 --- a/Source/Core/Core/Src/PowerPC/JitCommon/JitCache.h +++ b/Source/Core/Core/Src/PowerPC/JitCommon/JitCache.h @@ -87,6 +87,7 @@ class JitBlockCache bool RangeIntersect(int s1, int e1, int s2, int e2) const; void LinkBlockExits(int i); void LinkBlock(int i); + void UnlinkBlock(int i); public: JitBlockCache() : @@ -129,7 +130,7 @@ public: CompiledCode GetCompiledCodeFromBlock(int block_num); // DOES NOT WORK CORRECTLY WITH INLINING - void InvalidateICache(u32 em_address); + void InvalidateICache(u32 address, const u32 length); void DestroyBlock(int block_num, bool invalidate); // Not currently used diff --git a/Source/Core/Core/Src/PowerPC/JitCommon/Jit_Util.cpp b/Source/Core/Core/Src/PowerPC/JitCommon/Jit_Util.cpp index 26abb5a890..333f0cdc05 100644 --- a/Source/Core/Core/Src/PowerPC/JitCommon/Jit_Util.cpp +++ b/Source/Core/Core/Src/PowerPC/JitCommon/Jit_Util.cpp @@ -118,16 +118,18 @@ void EmuCodeBlock::UnsafeLoadToEAX(const Gen::OpArg & opAddress, int accessSize, void EmuCodeBlock::SafeLoadToEAX(const Gen::OpArg & opAddress, int accessSize, s32 offset, bool signExtend) { +#if defined(_WIN32) && defined(_M_X64) #ifdef ENABLE_MEM_CHECK - if (Core::g_CoreStartupParameter.bUseFastMem && (accessSize == 32) && !Core::g_CoreStartupParameter.bMMU && !Core::g_CoreStartupParameter.bEnableDebugging) + if (accessSize == 32 && !Core::g_CoreStartupParameter.bMMU && !Core::g_CoreStartupParameter.bEnableDebugging) #else - if (Core::g_CoreStartupParameter.bUseFastMem && (accessSize == 32) && !Core::g_CoreStartupParameter.bMMU) + if (accessSize == 32 && !Core::g_CoreStartupParameter.bMMU) #endif { // BackPatch only supports 32-bits accesses UnsafeLoadToEAX(opAddress, accessSize, offset, signExtend); } else +#endif { u32 mem_mask = Memory::ADDR_MASK_HW_ACCESS; if (Core::g_CoreStartupParameter.bMMU || Core::g_CoreStartupParameter.iTLBHack) @@ -252,7 +254,7 @@ void EmuCodeBlock::SafeWriteRegToReg(X64Reg reg_value, X64Reg reg_addr, int acce TEST(32, R(reg_addr), Imm32(mem_mask)); FixupBranch fast = J_CC(CC_Z); - + MOV(32, M(&PC), Imm32(jit->js.compilerPC)); // Helps external systems know which instruction triggered the write switch (accessSize) { case 32: ABI_CallFunctionRR(thunks.ProtectFunction(swap ? ((void *)&Memory::Write_U32) : ((void *)&Memory::Write_U32_Swap), 2), reg_value, reg_addr); break; @@ -288,6 +290,7 @@ void EmuCodeBlock::SafeWriteFloatToReg(X64Reg xmm_value, X64Reg reg_addr) MOVSS(M(&float_buffer), xmm_value); MOV(32, R(EAX), M(&float_buffer)); BSWAP(32, EAX); + MOV(32, M(&PC), Imm32(jit->js.compilerPC)); // Helps external systems know which instruction triggered the write ABI_CallFunctionRR(thunks.ProtectFunction(((void *)&Memory::Write_U32), 2), EAX, reg_addr); FixupBranch arg2 = J(); SetJumpTarget(argh); diff --git a/Source/Core/Core/Src/PowerPC/PPCAnalyst.cpp b/Source/Core/Core/Src/PowerPC/PPCAnalyst.cpp index f354ea4291..ddfec1c328 100644 --- a/Source/Core/Core/Src/PowerPC/PPCAnalyst.cpp +++ b/Source/Core/Core/Src/PowerPC/PPCAnalyst.cpp @@ -299,7 +299,7 @@ u32 Flatten(u32 address, int *realsize, BlockStats *st, BlockRegStats *gpa, merged_addresses[0] = address; size_of_merged_addresses = 1; - memset(st, 0, sizeof(st)); + memset(st, 0, sizeof(*st)); // Disabled the following optimization in preference of FAST_ICACHE //UGeckoInstruction previnst = Memory::Read_Opcode_JIT_LC(address - 4); @@ -559,7 +559,7 @@ u32 Flatten(u32 address, int *realsize, BlockStats *st, BlockRegStats *gpa, } else { - // Memory exception occurred + // ISI exception or other critical memory exception occurred (game over) break; } } diff --git a/Source/Core/Core/Src/PowerPC/PPCCache.cpp b/Source/Core/Core/Src/PowerPC/PPCCache.cpp index 704caa4a2c..6956e9db1c 100644 --- a/Source/Core/Core/Src/PowerPC/PPCCache.cpp +++ b/Source/Core/Core/Src/PowerPC/PPCCache.cpp @@ -110,7 +110,7 @@ namespace PowerPC #endif valid[set] = 0; if (jit) - jit->GetBlockCache()->InvalidateICache(addr); + jit->GetBlockCache()->InvalidateICache(addr & ~0x1f, 32); } u32 InstructionCache::ReadInstruction(u32 addr) diff --git a/Source/Core/Core/Src/PowerPC/PowerPC.cpp b/Source/Core/Core/Src/PowerPC/PowerPC.cpp index 2ae520faab..8a7b817212 100644 --- a/Source/Core/Core/Src/PowerPC/PowerPC.cpp +++ b/Source/Core/Core/Src/PowerPC/PowerPC.cpp @@ -289,6 +289,65 @@ void Stop() Host_UpdateDisasmDialog(); } +void UpdatePerformanceMonitor(u32 cycles, u32 num_load_stores, u32 num_fp_inst) +{ + switch (MMCR0.PMC1SELECT) + { + case 0: // No change + break; + case 1: // Processor cycles + PowerPC::ppcState.spr[SPR_PMC1] += cycles; + break; + default: + break; + } + + switch (MMCR0.PMC2SELECT) + { + case 0: // No change + break; + case 1: // Processor cycles + PowerPC::ppcState.spr[SPR_PMC2] += cycles; + break; + case 11: // Number of loads and stores completed + PowerPC::ppcState.spr[SPR_PMC2] += num_load_stores; + break; + default: + break; + } + + switch (MMCR1.PMC3SELECT) + { + case 0: // No change + break; + case 1: // Processor cycles + PowerPC::ppcState.spr[SPR_PMC3] += cycles; + break; + case 11: // Number of FPU instructions completed + PowerPC::ppcState.spr[SPR_PMC3] += num_fp_inst; + break; + default: + break; + } + + switch (MMCR1.PMC4SELECT) + { + case 0: // No change + break; + case 1: // Processor cycles + PowerPC::ppcState.spr[SPR_PMC4] += cycles; + break; + default: + break; + } + + if ((MMCR0.PMC1INTCONTROL && (PowerPC::ppcState.spr[SPR_PMC1] & 0x80000000) != 0) || + (MMCR0.PMCINTCONTROL && (PowerPC::ppcState.spr[SPR_PMC2] & 0x80000000) != 0) || + (MMCR0.PMCINTCONTROL && (PowerPC::ppcState.spr[SPR_PMC3] & 0x80000000) != 0) || + (MMCR0.PMCINTCONTROL && (PowerPC::ppcState.spr[SPR_PMC4] & 0x80000000) != 0)) + PowerPC::ppcState.Exceptions |= EXCEPTION_PERFORMANCE_MONITOR; +} + void CheckExceptions() { // Make sure we are checking against the latest EXI status. This is required @@ -298,9 +357,6 @@ void CheckExceptions() // Read volatile data once u32 exceptions = ppcState.Exceptions; - if (!exceptions) - return; - // Example procedure: // set SRR0 to either PC or NPC //SRR0 = NPC; @@ -311,7 +367,7 @@ void CheckExceptions() // clear MSR as specified //MSR &= ~0x04EF36; // 0x04FF36 also clears ME (only for machine check exception) // set to exception type entry point - //NPC = 0x80000x00; + //NPC = 0x00000x00; if (exceptions & EXCEPTION_ISI) { @@ -320,7 +376,7 @@ void CheckExceptions() SRR1 = (MSR & 0x87C0FFFF) | (1 << 30); MSR |= (MSR >> 16) & 1; MSR &= ~0x04EF36; - NPC = 0x80000400; + PC = NPC = 0x00000400; INFO_LOG(POWERPC, "EXCEPTION_ISI"); Common::AtomicAnd(ppcState.Exceptions, ~EXCEPTION_ISI); @@ -332,7 +388,7 @@ void CheckExceptions() SRR1 = (MSR & 0x87C0FFFF) | 0x20000; MSR |= (MSR >> 16) & 1; MSR &= ~0x04EF36; - NPC = 0x80000700; + PC = NPC = 0x00000700; INFO_LOG(POWERPC, "EXCEPTION_PROGRAM"); Common::AtomicAnd(ppcState.Exceptions, ~EXCEPTION_PROGRAM); @@ -343,7 +399,7 @@ void CheckExceptions() SRR1 = MSR & 0x87C0FFFF; MSR |= (MSR >> 16) & 1; MSR &= ~0x04EF36; - NPC = 0x80000C00; + PC = NPC = 0x00000C00; INFO_LOG(POWERPC, "EXCEPTION_SYSCALL (PC=%08x)", PC); Common::AtomicAnd(ppcState.Exceptions, ~EXCEPTION_SYSCALL); @@ -355,7 +411,7 @@ void CheckExceptions() SRR1 = MSR & 0x87C0FFFF; MSR |= (MSR >> 16) & 1; MSR &= ~0x04EF36; - NPC = 0x80000800; + PC = NPC = 0x00000800; INFO_LOG(POWERPC, "EXCEPTION_FPU_UNAVAILABLE"); Common::AtomicAnd(ppcState.Exceptions, ~EXCEPTION_FPU_UNAVAILABLE); @@ -366,7 +422,7 @@ void CheckExceptions() SRR1 = MSR & 0x87C0FFFF; MSR |= (MSR >> 16) & 1; MSR &= ~0x04EF36; - NPC = 0x80000300; + PC = NPC = 0x00000300; //DSISR and DAR regs are changed in GenerateDSIException() INFO_LOG(POWERPC, "EXCEPTION_DSI"); @@ -380,7 +436,7 @@ void CheckExceptions() SRR1 = MSR & 0x87C0FFFF; MSR |= (MSR >> 16) & 1; MSR &= ~0x04EF36; - NPC = 0x80000600; + PC = NPC = 0x00000600; //TODO crazy amount of DSISR options to check out @@ -398,20 +454,78 @@ void CheckExceptions() SRR1 = MSR & 0x87C0FFFF; MSR |= (MSR >> 16) & 1; MSR &= ~0x04EF36; - NPC = 0x80000500; + PC = NPC = 0x00000500; + + INFO_LOG(POWERPC, "EXCEPTION_EXTERNAL_INT"); + Common::AtomicAnd(ppcState.Exceptions, ~EXCEPTION_EXTERNAL_INT); + + _dbg_assert_msg_(POWERPC, (SRR1 & 0x02) != 0, "EXTERNAL_INT unrecoverable???"); + } + else if (exceptions & EXCEPTION_PERFORMANCE_MONITOR) + { + SRR0 = NPC; + SRR1 = MSR & 0x87C0FFFF; + MSR |= (MSR >> 16) & 1; + MSR &= ~0x04EF36; + PC = NPC = 0x00000F00; + + INFO_LOG(POWERPC, "EXCEPTION_PERFORMANCE_MONITOR"); + Common::AtomicAnd(ppcState.Exceptions, ~EXCEPTION_PERFORMANCE_MONITOR); + } + else if (exceptions & EXCEPTION_DECREMENTER) + { + SRR0 = NPC; + SRR1 = MSR & 0x87C0FFFF; + MSR |= (MSR >> 16) & 1; + MSR &= ~0x04EF36; + PC = NPC = 0x00000900; + + INFO_LOG(POWERPC, "EXCEPTION_DECREMENTER"); + Common::AtomicAnd(ppcState.Exceptions, ~EXCEPTION_DECREMENTER); + } + } +} + +void CheckExternalExceptions() +{ + // Read volatile data once + u32 exceptions = ppcState.Exceptions; + + // EXTERNAL INTERRUPT + if (MSR & 0x0008000) //hacky...the exception shouldn't be generated if EE isn't set... + { + if (exceptions & EXCEPTION_EXTERNAL_INT) + { + // Pokemon gets this "too early", it hasn't a handler yet + SRR0 = NPC; + SRR1 = MSR & 0x87C0FFFF; + MSR |= (MSR >> 16) & 1; + MSR &= ~0x04EF36; + PC = NPC = 0x00000500; INFO_LOG(POWERPC, "EXCEPTION_EXTERNAL_INT"); Common::AtomicAnd(ppcState.Exceptions, ~EXCEPTION_EXTERNAL_INT); _dbg_assert_msg_(POWERPC, (SRR1 & 0x02) != 0, "EXTERNAL_INT unrecoverable???"); } + else if (exceptions & EXCEPTION_PERFORMANCE_MONITOR) + { + SRR0 = NPC; + SRR1 = MSR & 0x87C0FFFF; + MSR |= (MSR >> 16) & 1; + MSR &= ~0x04EF36; + PC = NPC = 0x00000F00; + + INFO_LOG(POWERPC, "EXCEPTION_PERFORMANCE_MONITOR"); + Common::AtomicAnd(ppcState.Exceptions, ~EXCEPTION_PERFORMANCE_MONITOR); + } else if (exceptions & EXCEPTION_DECREMENTER) { SRR0 = NPC; SRR1 = MSR & 0x87C0FFFF; MSR |= (MSR >> 16) & 1; MSR &= ~0x04EF36; - NPC = 0x80000900; + PC = NPC = 0x00000900; INFO_LOG(POWERPC, "EXCEPTION_DECREMENTER"); Common::AtomicAnd(ppcState.Exceptions, ~EXCEPTION_DECREMENTER); diff --git a/Source/Core/Core/Src/PowerPC/PowerPC.h b/Source/Core/Core/Src/PowerPC/PowerPC.h index 54690ac6b5..e0b4bfaa16 100644 --- a/Source/Core/Core/Src/PowerPC/PowerPC.h +++ b/Source/Core/Core/Src/PowerPC/PowerPC.h @@ -102,6 +102,7 @@ void SetMode(CoreMode _coreType); void SingleStep(); void CheckExceptions(); +void CheckExternalExceptions(); void CheckBreakPoints(); void RunLoop(); void Start(); @@ -116,12 +117,16 @@ void ExpandCR(); void OnIdle(u32 _uThreadAddr); void OnIdleIL(); +void UpdatePerformanceMonitor(u32 cycles, u32 num_load_stores, u32 num_fp_inst); + // Easy register access macros. #define HID0 ((UReg_HID0&)PowerPC::ppcState.spr[SPR_HID0]) #define HID2 ((UReg_HID2&)PowerPC::ppcState.spr[SPR_HID2]) #define HID4 ((UReg_HID4&)PowerPC::ppcState.spr[SPR_HID4]) #define DMAU (*(UReg_DMAU*)&PowerPC::ppcState.spr[SPR_DMAU]) #define DMAL (*(UReg_DMAL*)&PowerPC::ppcState.spr[SPR_DMAL]) +#define MMCR0 ((UReg_MMCR0&)PowerPC::ppcState.spr[SPR_MMCR0]) +#define MMCR1 ((UReg_MMCR1&)PowerPC::ppcState.spr[SPR_MMCR1]) #define PC PowerPC::ppcState.pc #define NPC PowerPC::ppcState.npc #define FPSCR ((UReg_FPSCR&)PowerPC::ppcState.fpscr) diff --git a/Source/Core/Core/Src/PowerPC/Profiler.cpp b/Source/Core/Core/Src/PowerPC/Profiler.cpp index 2874705d4b..3636b00717 100644 --- a/Source/Core/Core/Src/PowerPC/Profiler.cpp +++ b/Source/Core/Core/Src/PowerPC/Profiler.cpp @@ -56,18 +56,21 @@ void WriteProfileResults(const char *filename) for (int i = 0; i < jit->GetBlockCache()->GetNumBlocks(); i++) { const JitBlock *block = jit->GetBlockCache()->GetBlock(i); - // Rough heuristic. Mem instructions should cost more. - u64 cost = block->originalSize * (block->runCount / 4); + if (block && !block->invalid) + { + // Rough heuristic. Mem instructions should cost more. + u64 cost = block->originalSize * (block->runCount / 4); #ifdef _WIN32 - u64 timecost = block->ticCounter; + u64 timecost = block->ticCounter; #endif - // Todo: tweak. - if (block->runCount >= 1) - stats.push_back(BlockStat(i, cost)); - cost_sum += cost; + // Todo: tweak. + if (block->runCount >= 1) + stats.push_back(BlockStat(i, cost)); + cost_sum += cost; #ifdef _WIN32 - timecost_sum += timecost; + timecost_sum += timecost; #endif + } } sort(stats.begin(), stats.end()); @@ -77,18 +80,18 @@ void WriteProfileResults(const char *filename) PanicAlert("failed to open %s", filename); return; } - fprintf(f.GetHandle(), "origAddr\tblkName\tcost\ttimeCost\tpercent\ttimePercent\tOvAllinBlkTime(ms)\tblkCodeSize\n"); + fprintf(f.GetHandle(), "origAddr\tblkName\tcost\trunCount\ttimeCost\tpercent\ttimePercent\tOvAllinBlkTime(ms)\tblkCodeSize\n"); for (unsigned int i = 0; i < stats.size(); i++) { const JitBlock *block = jit->GetBlockCache()->GetBlock(stats[i].blockNum); - if (block) + if (block && !block->invalid) { std::string name = g_symbolDB.GetDescription(block->originalAddress); double percent = 100.0 * (double)stats[i].cost / (double)cost_sum; #ifdef _WIN32 double timePercent = 100.0 * (double)block->ticCounter / (double)timecost_sum; - fprintf(f.GetHandle(), "%08x\t%s\t%llu\t%llu\t%.2lf\t%llf\t%lf\t%i\n", - block->originalAddress, name.c_str(), stats[i].cost, + fprintf(f.GetHandle(), "%08x\t%s\t%llu\t%llu\t%llu\t%.2lf\t%llf\t%lf\t%i\n", + block->originalAddress, name.c_str(), stats[i].cost, block->runCount, block->ticCounter, percent, timePercent, (double)block->ticCounter*1000.0/(double)countsPerSec, block->codeSize); #else diff --git a/Source/Core/DiscIO/CMakeLists.txt b/Source/Core/DiscIO/CMakeLists.txt index 7f6ff7e4cc..01e15a374f 100644 --- a/Source/Core/DiscIO/CMakeLists.txt +++ b/Source/Core/DiscIO/CMakeLists.txt @@ -3,6 +3,7 @@ set(SRCS Src/BannerLoader.cpp Src/BannerLoaderWii.cpp Src/Blob.cpp Src/CISOBlob.cpp + Src/WbfsBlob.cpp Src/CompressedBlob.cpp Src/DiscScrubber.cpp Src/DriveBlob.cpp diff --git a/Source/Core/DiscIO/DiscIO.vcxproj b/Source/Core/DiscIO/DiscIO.vcxproj index d94ac13212..6dd24ddd44 100644 --- a/Source/Core/DiscIO/DiscIO.vcxproj +++ b/Source/Core/DiscIO/DiscIO.vcxproj @@ -175,6 +175,7 @@ <ClInclude Include="Src\BannerLoaderWii.h" /> <ClInclude Include="Src\Blob.h" /> <ClInclude Include="Src\CISOBlob.h" /> + <ClInclude Include="Src\WbfsBlob.h" /> <ClInclude Include="Src\CompressedBlob.h" /> <ClInclude Include="Src\DiscScrubber.h" /> <ClInclude Include="Src\DriveBlob.h" /> @@ -199,6 +200,7 @@ <ClCompile Include="Src\BannerLoaderWii.cpp" /> <ClCompile Include="Src\Blob.cpp" /> <ClCompile Include="Src\CISOBlob.cpp" /> + <ClCompile Include="Src\WbfsBlob.cpp" /> <ClCompile Include="Src\CompressedBlob.cpp" /> <ClCompile Include="Src\DiscScrubber.cpp" /> <ClCompile Include="Src\DriveBlob.cpp" /> @@ -226,7 +228,6 @@ </ItemGroup> <ItemGroup> <None Include="CMakeLists.txt" /> - <None Include="Src\SConscript" /> </ItemGroup> <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" /> <ImportGroup Label="ExtensionTargets"> diff --git a/Source/Core/DiscIO/DiscIO.vcxproj.filters b/Source/Core/DiscIO/DiscIO.vcxproj.filters index 80ddbe57c6..105d3ffc47 100644 --- a/Source/Core/DiscIO/DiscIO.vcxproj.filters +++ b/Source/Core/DiscIO/DiscIO.vcxproj.filters @@ -8,6 +8,9 @@ <ClCompile Include="Src\CISOBlob.cpp"> <Filter>Volume\Blob</Filter> </ClCompile> + <ClCompile Include="Src\WbfsBlob.cpp"> + <Filter>Volume\Blob</Filter> + </ClCompile> <ClCompile Include="Src\CompressedBlob.cpp"> <Filter>Volume\Blob</Filter> </ClCompile> @@ -71,6 +74,9 @@ <ClInclude Include="Src\CISOBlob.h"> <Filter>Volume\Blob</Filter> </ClInclude> + <ClInclude Include="Src\WbfsBlob.h"> + <Filter>Volume\Blob</Filter> + </ClInclude> <ClInclude Include="Src\Blob.h"> <Filter>Volume\Blob</Filter> </ClInclude> @@ -133,7 +139,6 @@ </ClInclude> </ItemGroup> <ItemGroup> - <None Include="Src\SConscript" /> <None Include="CMakeLists.txt" /> </ItemGroup> <ItemGroup> diff --git a/Source/Core/DiscIO/SConscript b/Source/Core/DiscIO/SConscript deleted file mode 100644 index 3c563cf5e3..0000000000 --- a/Source/Core/DiscIO/SConscript +++ /dev/null @@ -1,29 +0,0 @@ -# -*- python -*- - -Import('env') - -files = [ - 'Src/BannerLoader.cpp', - 'Src/BannerLoaderGC.cpp', - 'Src/BannerLoaderWii.cpp', - 'Src/Blob.cpp', - 'Src/CISOBlob.cpp', - 'Src/CompressedBlob.cpp', - 'Src/DiscScrubber.cpp', - 'Src/DriveBlob.cpp', - 'Src/FileBlob.cpp', - 'Src/FileHandlerARC.cpp', - 'Src/FileMonitor.cpp', - 'Src/FileSystemGCWii.cpp', - 'Src/Filesystem.cpp', - 'Src/NANDContentLoader.cpp', - 'Src/VolumeCommon.cpp', - 'Src/VolumeCreator.cpp', - 'Src/VolumeDirectory.cpp', - 'Src/VolumeGC.cpp', - 'Src/VolumeWad.cpp', - 'Src/VolumeWiiCrypted.cpp', - 'Src/WiiWad.cpp', - ] - -env['LIBS'] += env.StaticLibrary('discio', files) diff --git a/Source/Core/DiscIO/Src/Blob.cpp b/Source/Core/DiscIO/Src/Blob.cpp index a728780f23..115145e290 100644 --- a/Source/Core/DiscIO/Src/Blob.cpp +++ b/Source/Core/DiscIO/Src/Blob.cpp @@ -23,6 +23,7 @@ #include "FileBlob.h" #include "CISOBlob.h" #include "DriveBlob.h" +#include "WbfsBlob.h" namespace DiscIO { @@ -128,6 +129,9 @@ IBlobReader* CreateBlobReader(const char* filename) if (!File::Exists(filename)) return 0; + if (IsWbfsBlob(filename)) + return WbfsFileReader::Create(filename); + if (IsCompressedBlob(filename)) return CompressedBlobReader::Create(filename); diff --git a/Source/Core/DiscIO/Src/NANDContentLoader.cpp b/Source/Core/DiscIO/Src/NANDContentLoader.cpp index f010b7ed98..dc1f44739b 100644 --- a/Source/Core/DiscIO/Src/NANDContentLoader.cpp +++ b/Source/Core/DiscIO/Src/NANDContentLoader.cpp @@ -462,7 +462,7 @@ void cUIDsys::AddTitle(u64 _TitleID) File::CreateFullPath(uidSys); File::IOFile pFile(uidSys, "ab"); - if (pFile.WriteArray(&Element, 1)) + if (!pFile.WriteArray(&Element, 1)) ERROR_LOG(DISCIO, "fwrite failed"); } diff --git a/Source/Core/DiscIO/Src/Volume.h b/Source/Core/DiscIO/Src/Volume.h index ec20e47b6c..f8a6f13ecb 100644 --- a/Source/Core/DiscIO/Src/Volume.h +++ b/Source/Core/DiscIO/Src/Volume.h @@ -38,9 +38,11 @@ public: virtual std::string GetUniqueID() const = 0; virtual std::string GetMakerID() const = 0; virtual std::string GetName() const = 0; - virtual bool GetWName(std::vector<std::wstring>& _rwNames) const {return false;}; + virtual bool GetWName(std::vector<std::wstring>& _rwNames) const { return false; } virtual u32 GetFSTSize() const = 0; virtual std::string GetApploaderDate() const = 0; + virtual bool SupportsIntegrityCheck() const { return false; } + virtual bool CheckIntegrity() const { return false; } enum ECountry { diff --git a/Source/Core/DiscIO/Src/VolumeDirectory.cpp b/Source/Core/DiscIO/Src/VolumeDirectory.cpp index 08188bac71..dc76e2e641 100644 --- a/Source/Core/DiscIO/Src/VolumeDirectory.cpp +++ b/Source/Core/DiscIO/Src/VolumeDirectory.cpp @@ -16,6 +16,7 @@ // http://code.google.com/p/dolphin-emu/ #include "Common.h" +#include "MathUtil.h" #include "CommonPaths.h" #include "VolumeDirectory.h" #include "FileBlob.h" @@ -23,17 +24,6 @@ namespace DiscIO { -static const u8 ENTRY_SIZE = 0x0c; -static const u8 FILE_ENTRY = 0; -static const u8 DIRECTORY_ENTRY = 1; -static const u64 DISKHEADER_ADDRESS = 0; -static const u64 DISKHEADERINFO_ADDRESS = 0x440; -static const u64 APPLOADER_ADDRESS = 0x2440; -static const u32 MAX_NAME_LENGTH = 0x3df; -// relocatable -static u64 FST_ADDRESS = 0x440; -static u64 DOL_ADDRESS = 0; - CVolumeDirectory::CVolumeDirectory(const std::string& _rDirectory, bool _bIsWii, const std::string& _rApploader, const std::string& _rDOL) : m_totalNameSize(0) @@ -44,6 +34,8 @@ CVolumeDirectory::CVolumeDirectory(const std::string& _rDirectory, bool _bIsWii, , m_apploader(NULL) , m_DOLSize(0) , m_DOL(NULL) + , FST_ADDRESS(0) + , DOL_ADDRESS(0) { m_rootDirectory = ExtractDirectoryName(_rDirectory); @@ -321,7 +313,7 @@ bool CVolumeDirectory::SetApploader(const std::string& _rApploader) copy(data.begin(), data.end(), m_apploader); // 32byte aligned (plus 0x20 padding) - DOL_ADDRESS = (APPLOADER_ADDRESS + m_apploaderSize + 0x20 + 31) & ~31ULL; + DOL_ADDRESS = ROUND_UP(APPLOADER_ADDRESS + m_apploaderSize + 0x20, 0x20ull); return true; } else @@ -347,7 +339,7 @@ void CVolumeDirectory::SetDOL(const std::string& _rDOL) Write32((u32)(DOL_ADDRESS >> m_addressShift), 0x0420, m_diskHeader); // 32byte aligned (plus 0x20 padding) - FST_ADDRESS = (DOL_ADDRESS + m_DOLSize + 0x20 + 31) & ~31ULL; + FST_ADDRESS = ROUND_UP(DOL_ADDRESS + m_DOLSize + 0x20, 0x20ull); } } @@ -367,8 +359,12 @@ void CVolumeDirectory::BuildFST() m_fstSize = m_fstNameOffset + m_totalNameSize; m_FSTData = new u8[(u32)m_fstSize]; + // if FST hasn't been assigned (ie no apploader/dol setup), set to default + if (FST_ADDRESS == 0) + FST_ADDRESS = APPLOADER_ADDRESS + 0x2000; + // 4 byte aligned start of data on disk - m_dataStartAddress = (FST_ADDRESS + m_fstSize + 3) & ~3; + m_dataStartAddress = ROUND_UP(FST_ADDRESS + m_fstSize, 0x8000ull); u64 curDataAddress = m_dataStartAddress; u32 fstOffset = 0; // offset within FST data @@ -389,8 +385,8 @@ void CVolumeDirectory::BuildFST() // write FST size and location _dbg_assert_(DVDINTERFACE, m_diskHeader); Write32((u32)(FST_ADDRESS >> m_addressShift), 0x0424, m_diskHeader); - Write32((u32)m_fstSize, 0x0428, m_diskHeader); - Write32((u32)m_fstSize, 0x042c, m_diskHeader); + Write32((u32)(m_fstSize >> m_addressShift), 0x0428, m_diskHeader); + Write32((u32)(m_fstSize >> m_addressShift), 0x042c, m_diskHeader); } void CVolumeDirectory::WriteToBuffer(u64 _SrcStartAddress, u64 _SrcLength, u8* _Src, @@ -490,7 +486,7 @@ void CVolumeDirectory::WriteEntry(const File::FSTEntry& entry, u32& fstOffset, u m_virtualDisk.insert(make_pair(dataOffset, entry.physicalName)); // 4 byte aligned - dataOffset = (dataOffset + entry.size + 3) & ~3ULL; + dataOffset = ROUND_UP(dataOffset + entry.size, 0x8000ull); } } diff --git a/Source/Core/DiscIO/Src/VolumeDirectory.h b/Source/Core/DiscIO/Src/VolumeDirectory.h index 727974a417..0547be3b8a 100644 --- a/Source/Core/DiscIO/Src/VolumeDirectory.h +++ b/Source/Core/DiscIO/Src/VolumeDirectory.h @@ -141,6 +141,16 @@ private: u64 m_DOLSize; u8* m_DOL; + + static const u8 ENTRY_SIZE = 0x0c; + static const u8 FILE_ENTRY = 0; + static const u8 DIRECTORY_ENTRY = 1; + static const u64 DISKHEADER_ADDRESS = 0; + static const u64 DISKHEADERINFO_ADDRESS = 0x440; + static const u64 APPLOADER_ADDRESS = 0x2440; + static const u32 MAX_NAME_LENGTH = 0x3df; + u64 FST_ADDRESS; + u64 DOL_ADDRESS; }; } // namespace diff --git a/Source/Core/DiscIO/Src/VolumeGC.cpp b/Source/Core/DiscIO/Src/VolumeGC.cpp index 0b0fabf7e9..51fac285fc 100644 --- a/Source/Core/DiscIO/Src/VolumeGC.cpp +++ b/Source/Core/DiscIO/Src/VolumeGC.cpp @@ -43,9 +43,9 @@ bool CVolumeGC::Read(u64 _Offset, u64 _Length, u8* _pBuffer) const return m_pReader->Read(_Offset, _Length, _pBuffer); } -bool CVolumeGC::RAWRead( u64 _Offset, u64 _Length, u8* _pBuffer ) const +bool CVolumeGC::RAWRead(u64 _Offset, u64 _Length, u8* _pBuffer) const { - return false; + return Read(_Offset, _Length, _pBuffer); } std::string CVolumeGC::GetUniqueID() const diff --git a/Source/Core/DiscIO/Src/VolumeWiiCrypted.cpp b/Source/Core/DiscIO/Src/VolumeWiiCrypted.cpp index 9e7865d9c6..ca010b5ae4 100644 --- a/Source/Core/DiscIO/Src/VolumeWiiCrypted.cpp +++ b/Source/Core/DiscIO/Src/VolumeWiiCrypted.cpp @@ -17,6 +17,7 @@ #include "VolumeWiiCrypted.h" #include "StringUtil.h" +#include "Crypto/sha1.h" namespace DiscIO { @@ -232,4 +233,68 @@ u64 CVolumeWiiCrypted::GetSize() const } } +bool CVolumeWiiCrypted::CheckIntegrity() const +{ + // Get partition data size + u32 partSizeDiv4; + RAWRead(m_VolumeOffset + 0x2BC, 4, (u8*)&partSizeDiv4); + u64 partDataSize = (u64)Common::swap32(partSizeDiv4) * 4; + + u32 nClusters = (u32)(partDataSize / 0x8000); + for (u32 clusterID = 0; clusterID < nClusters; ++clusterID) + { + u64 clusterOff = m_VolumeOffset + dataOffset + (u64)clusterID * 0x8000; + + // Read and decrypt the cluster metadata + u8 clusterMDCrypted[0x400]; + u8 clusterMD[0x400]; + u8 IV[16] = { 0 }; + if (!m_pReader->Read(clusterOff, 0x400, clusterMDCrypted)) + { + NOTICE_LOG(DISCIO, "Integrity Check: fail at cluster %d: could not read metadata", clusterID); + return false; + } + AES_cbc_encrypt(clusterMDCrypted, clusterMD, 0x400, &m_AES_KEY, IV, AES_DECRYPT); + + // Some clusters have invalid data and metadata because they aren't + // meant to be read by the game (for example, holes between files). To + // try to avoid reporting errors because of these clusters, we check + // the 0x00 paddings in the metadata. + // + // This may cause some false negatives though: some bad clusters may be + // skipped because they are *too* bad and are not even recognized as + // valid clusters. To be improved. + bool meaningless = false; + for (u32 idx = 0x26C; idx < 0x280; ++idx) + if (clusterMD[idx] != 0) + meaningless = true; + + if (meaningless) + continue; + + u8 clusterData[0x7C00]; + if (!Read((u64)clusterID * 0x7C00, 0x7C00, clusterData)) + { + NOTICE_LOG(DISCIO, "Integrity Check: fail at cluster %d: could not read data", clusterID); + return false; + } + + for (u32 hashID = 0; hashID < 31; ++hashID) + { + u8 hash[20]; + + sha1(clusterData + hashID * 0x400, 0x400, hash); + + // Note that we do not use strncmp here + if (memcmp(hash, clusterMD + hashID * 20, 20)) + { + NOTICE_LOG(DISCIO, "Integrity Check: fail at cluster %d: hash %d is invalid", clusterID, hashID); + return false; + } + } + } + + return true; +} + } // namespace diff --git a/Source/Core/DiscIO/Src/VolumeWiiCrypted.h b/Source/Core/DiscIO/Src/VolumeWiiCrypted.h index f69bcfb490..5010e46bbd 100644 --- a/Source/Core/DiscIO/Src/VolumeWiiCrypted.h +++ b/Source/Core/DiscIO/Src/VolumeWiiCrypted.h @@ -43,6 +43,9 @@ public: ECountry GetCountry() const; u64 GetSize() const; + bool SupportsIntegrityCheck() const { return true; } + bool CheckIntegrity() const; + private: IBlobReader* m_pReader; diff --git a/Source/Core/DiscIO/Src/WbfsBlob.cpp b/Source/Core/DiscIO/Src/WbfsBlob.cpp new file mode 100644 index 0000000000..1b7696cc58 --- /dev/null +++ b/Source/Core/DiscIO/Src/WbfsBlob.cpp @@ -0,0 +1,209 @@ +// 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 "WbfsBlob.h" +#include "FileUtil.h" + +namespace DiscIO +{ +const u64 wii_sector_size = 0x8000; +const u64 wii_sector_count = 143432 * 2; +const u64 wii_sector_log2 = 15; +const u64 wii_disc_header_size = 256; + +static inline u64 align(u64 value, u64 bounds) +{ + return (value + (bounds - 1)) & (~(bounds - 1)); +} + +WbfsFileReader::WbfsFileReader(const char* filename) + : m_total_files(0), m_size(0), m_wlba_table(0), m_good(true) +{ + if(!filename || (strlen(filename) < 4) || !OpenFiles(filename) || !ReadHeader()) + { + m_good = false; + return; + } + + // Grab disc info (assume slot 0, checked in ReadHeader()) + m_wlba_table = new u16[m_blocks_per_disc]; + m_files[0]->file.Seek(hd_sector_size + wii_disc_header_size /*+ i * m_disc_info_size*/, SEEK_SET); + m_files[0]->file.ReadBytes(m_wlba_table, m_blocks_per_disc * sizeof(u16)); +} + +WbfsFileReader::~WbfsFileReader() +{ + for(u32 i = 0; i != m_files.size(); ++ i) + { + delete m_files[i]; + } + + delete[] m_wlba_table; +} + +bool WbfsFileReader::OpenFiles(const char* filename) +{ + m_total_files = 0; + + while(true) + { + file_entry* new_entry = new file_entry; + + // Replace last character with index (e.g. wbfs = wbf1) + std::string path = filename; + if(0 != m_total_files) + { + path[path.length() - 1] = '0' + m_total_files; + } + + if(!new_entry->file.Open(path, "rb")) + { + delete new_entry; + return 0 != m_total_files; + } + + new_entry->base_address = m_size; + new_entry->size = new_entry->file.GetSize(); + m_size += new_entry->size; + + m_total_files ++; + m_files.push_back(new_entry); + } +} + +bool WbfsFileReader::ReadHeader() +{ + m_files[0]->file.Seek(4, SEEK_SET); + + // Read hd size info + m_files[0]->file.ReadBytes(&hd_sector_count, 4); + hd_sector_count = Common::swap32(hd_sector_count); + + m_files[0]->file.ReadBytes(&hd_sector_shift, 1); + hd_sector_size = 1 << hd_sector_shift; + + if(m_size != hd_sector_count * hd_sector_size) + { + //printf("File size doesn't match expected size\n"); + return false; + } + + // Read wbfs cluster info + m_files[0]->file.ReadBytes(&wbfs_sector_shift, 1); + wbfs_sector_size = 1 << wbfs_sector_shift; + wbfs_sector_count = m_size / wbfs_sector_size; + + if(wbfs_sector_size < wii_sector_size) + { + //Setting this too low would case a very large memory allocation + return false; + } + + m_blocks_per_disc = (wii_sector_count * wii_sector_size) / wbfs_sector_size; + m_disc_info_size = align(wii_disc_header_size + m_blocks_per_disc * 2, hd_sector_size); + + // Read disc table + m_files[0]->file.Seek(2, SEEK_CUR); + m_files[0]->file.ReadBytes(disc_table, 500); + + if(0 == disc_table[0]) + { + //printf("Game must be in 'slot 0'\n"); + return false; + } + + return true; +} + +bool WbfsFileReader::Read(u64 offset, u64 nbytes, u8* out_ptr) +{ + while(nbytes) + { + u64 read_size; + File::IOFile& data_file = SeekToCluster(offset, &read_size); + read_size = (read_size > nbytes) ? nbytes : read_size; + + data_file.ReadBytes(out_ptr, read_size); + + out_ptr += read_size; + nbytes -= read_size; + offset += read_size; + } + + return true; +} + +File::IOFile& WbfsFileReader::SeekToCluster(u64 offset, u64* available) +{ + u64 base_cluster = offset >> wbfs_sector_shift; + if(base_cluster < m_blocks_per_disc) + { + u64 cluster_address = wbfs_sector_size * Common::swap16(m_wlba_table[base_cluster]); + u64 cluster_offset = offset & (wbfs_sector_size - 1); + u64 final_address = cluster_address + cluster_offset; + + for(u32 i = 0; i != m_total_files; i ++) + { + if(final_address < (m_files[i]->base_address + m_files[i]->size)) + { + m_files[i]->file.Seek(final_address - m_files[i]->base_address, SEEK_SET); + if(available) + { + u64 till_end_of_file = m_files[i]->size - (final_address - m_files[i]->base_address); + u64 till_end_of_sector = wbfs_sector_size - cluster_offset; + *available = std::min(till_end_of_file, till_end_of_sector); + } + + return m_files[i]->file; + } + } + } + + PanicAlert("Read beyond end of disc"); + m_files[0]->file.Seek(0, SEEK_SET); + return m_files[0]->file; +} + +WbfsFileReader* WbfsFileReader::Create(const char* filename) +{ + WbfsFileReader* reader = new WbfsFileReader(filename); + + if(reader->IsGood()) + { + return reader; + } + else + { + delete reader; + return NULL; + } +} + +bool IsWbfsBlob(const char* filename) +{ + File::IOFile f(filename, "rb"); + + u8 magic[4] = {0, 0, 0, 0}; + f.ReadBytes(&magic, 4); + + return (magic[0] == 'W') && + (magic[1] == 'B') && + (magic[2] == 'F') && + (magic[3] == 'S'); +} + +} // namespace diff --git a/Source/Core/DiscIO/Src/WbfsBlob.h b/Source/Core/DiscIO/Src/WbfsBlob.h new file mode 100644 index 0000000000..78b3ae8b78 --- /dev/null +++ b/Source/Core/DiscIO/Src/WbfsBlob.h @@ -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/ + +#ifndef _WBFS_BLOB_H +#define _WBFS_BLOB_H + +#include "Blob.h" +#include "FileUtil.h" + +namespace DiscIO +{ + +struct wbfs_head_t; + +class WbfsFileReader : public IBlobReader +{ + WbfsFileReader(const char* filename); + ~WbfsFileReader(); + + bool OpenFiles(const char* filename); + bool ReadHeader(); + + File::IOFile& SeekToCluster(u64 offset, u64* available); + bool IsGood() {return m_good;} + + + struct file_entry + { + File::IOFile file; + u64 base_address; + u64 size; + }; + + std::vector<file_entry*> m_files; + + u32 m_total_files; + u64 m_size; + + u64 hd_sector_size; + u8 hd_sector_shift; + u32 hd_sector_count; + + u64 wbfs_sector_size; + u64 wbfs_sector_shift; + u64 wbfs_sector_count; + u64 m_disc_info_size; + + u8 disc_table[500]; + + u16* m_wlba_table; + u64 m_blocks_per_disc; + + bool m_good; + +public: + static WbfsFileReader* Create(const char* filename); + + u64 GetDataSize() const { return m_size; } + u64 GetRawSize() const { return m_size; } + bool Read(u64 offset, u64 nbytes, u8* out_ptr); +}; + +bool IsWbfsBlob(const char* filename); + + +} // namespace + +#endif // _FILE_BLOB_H diff --git a/Source/Core/DolphinWX/CMakeLists.txt b/Source/Core/DolphinWX/CMakeLists.txt index 2d7ed7e0ce..03f947b341 100644 --- a/Source/Core/DolphinWX/CMakeLists.txt +++ b/Source/Core/DolphinWX/CMakeLists.txt @@ -63,8 +63,7 @@ if(wxWidgets_FOUND) Src/WiimoteConfigDiag.cpp Src/WxUtils.cpp) - set(WXLIBS ${wxWidgets_LIBRARIES} - ${GTK2_LIBRARIES}) + set(WXLIBS ${wxWidgets_LIBRARIES}) else() set(SRCS Src/MainNoGUI.cpp) endif() diff --git a/Source/Core/DolphinWX/Dolphin.vcxproj b/Source/Core/DolphinWX/Dolphin.vcxproj index 942bd41f4e..72c40a3db4 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\wxWidgets\include;..\..\..\Externals\CLRun\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> + <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> </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\wxWidgets\include;..\..\..\Externals\CLRun\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> + <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> </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\wxWidgets\include;..\..\..\Externals\CLRun\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> + <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> <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\wxWidgets\include;..\..\..\Externals\CLRun\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> + <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> </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\wxWidgets\include;..\..\..\Externals\CLRun\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> + <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> <OpenMPSupport> </OpenMPSupport> </ClCompile> @@ -204,7 +204,7 @@ xcopy "$(SolutionDir)..\Externals\SDL\$(PlatformName)\*.dll" "$(TargetDir)" /e / </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\wxWidgets\include;..\..\..\Externals\CLRun\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> + <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> </ClCompile> <Link /> <PostBuildEvent> @@ -330,30 +330,23 @@ xcopy "$(SolutionDir)..\Externals\SDL\$(PlatformName)\*.dll" "$(TargetDir)" /e / <ItemGroup> <None Include="..\..\..\Installer\Dolphin.ico" /> <None Include="CMakeLists.txt" /> - <None Include="Src\SConscript" /> </ItemGroup> <ItemGroup> <ProjectReference Include="..\..\..\Externals\Bochs_disasm\Bochs_disasm.vcxproj"> <Project>{cd3d4c3c-1027-4d33-b047-aec7b56d0bf6}</Project> </ProjectReference> + <ProjectReference Include="..\..\..\Externals\libpng\png\png.vcxproj"> + <Project>{01573c36-ac6e-49f6-94ba-572517eb9740}</Project> + </ProjectReference> <ProjectReference Include="..\..\..\Externals\LZO\LZO.vcxproj"> <Project>{d8890b98-26f7-4cff-bbfb-b95f371b5f20}</Project> </ProjectReference> <ProjectReference Include="..\..\..\Externals\SFML\build\vc2010\SFML_Network.vcxproj"> <Project>{93d73454-2512-424e-9cda-4bb357fe13dd}</Project> </ProjectReference> - <ProjectReference Include="..\..\..\Externals\wxWidgets\build\msw\wx_adv.vcxproj"> - <Project>{0e231fb1-f3c9-4724-accb-de8bcb3c089e}</Project> - </ProjectReference> - <ProjectReference Include="..\..\..\Externals\wxWidgets\build\msw\wx_aui.vcxproj"> - <Project>{05c75041-d67d-4903-a362-8395a7b35c75}</Project> - </ProjectReference> - <ProjectReference Include="..\..\..\Externals\wxWidgets\build\msw\wx_base.vcxproj"> + <ProjectReference Include="..\..\..\Externals\wxWidgets3\build\msw\wx_base.vcxproj"> <Project>{1c8436c9-dbaf-42be-83bc-cf3ec9175abe}</Project> </ProjectReference> - <ProjectReference Include="..\..\..\Externals\wxWidgets\build\msw\wx_core.vcxproj"> - <Project>{11f55366-12ec-4c44-a8cb-1d4e315d61ed}</Project> - </ProjectReference> <ProjectReference Include="..\..\..\Externals\zlib\zlib.vcxproj"> <Project>{3e1339f5-9311-4122-9442-369702e8fcad}</Project> </ProjectReference> diff --git a/Source/Core/DolphinWX/Dolphin.vcxproj.filters b/Source/Core/DolphinWX/Dolphin.vcxproj.filters index ec7d68798b..61ae0826fc 100644 --- a/Source/Core/DolphinWX/Dolphin.vcxproj.filters +++ b/Source/Core/DolphinWX/Dolphin.vcxproj.filters @@ -266,7 +266,6 @@ </ClInclude> </ItemGroup> <ItemGroup> - <None Include="Src\SConscript" /> <None Include="CMakeLists.txt" /> <None Include="..\..\..\Installer\Dolphin.ico"> <Filter>Resources</Filter> diff --git a/Source/Core/DolphinWX/SConscript b/Source/Core/DolphinWX/SConscript deleted file mode 100644 index 92ca4f9f62..0000000000 --- a/Source/Core/DolphinWX/SConscript +++ /dev/null @@ -1,138 +0,0 @@ -# -*- python -*- - -Import('env') -import os -import sys - -if env['nowx']: - files = ['Src/MainNoGUI.cpp'] -else: - files = [ - 'Src/ARCodeAddEdit.cpp', - 'Src/AboutDolphin.cpp', - 'Src/CheatsWindow.cpp', - 'Src/ConfigMain.cpp', - 'Src/Debugger/BreakpointDlg.cpp', - 'Src/Debugger/BreakpointView.cpp', - 'Src/Debugger/BreakpointWindow.cpp', - 'Src/Debugger/CodeView.cpp', - 'Src/Debugger/CodeWindow.cpp', - 'Src/Debugger/CodeWindowFunctions.cpp', - 'Src/Debugger/DSPDebugWindow.cpp', - 'Src/Debugger/DSPRegisterView.cpp', - 'Src/Debugger/DebuggerPanel.cpp', - 'Src/Debugger/DebuggerUIUtil.cpp', - 'Src/Debugger/JitWindow.cpp', - 'Src/Debugger/MemoryCheckDlg.cpp', - 'Src/Debugger/MemoryView.cpp', - 'Src/Debugger/MemoryWindow.cpp', - 'Src/Debugger/RegisterView.cpp', - 'Src/Debugger/RegisterWindow.cpp', - 'Src/FifoPlayerDlg.cpp', - 'Src/Frame.cpp', - 'Src/FrameAui.cpp', - 'Src/FrameTools.cpp', - 'Src/GameListCtrl.cpp', - 'Src/GeckoCodeDiag.cpp', - 'Src/HotkeyDlg.cpp', - 'Src/ISOFile.cpp', - 'Src/ISOProperties.cpp', - 'Src/InputConfigDiag.cpp', - 'Src/InputConfigDiagBitmaps.cpp', - 'Src/LogConfigWindow.cpp', - 'Src/LogWindow.cpp', - 'Src/Main.cpp', - 'Src/MemcardManager.cpp', - 'Src/MemoryCards/WiiSaveCrypted.cpp', - 'Src/NetWindow.cpp', - 'Src/PHackSettings.cpp', - 'Src/PatchAddEdit.cpp', - 'Src/TASInputDlg.cpp', - 'Src/UDPConfigDiag.cpp', - 'Src/VideoConfigDiag.cpp', - 'Src/WXInputBase.cpp', - 'Src/WiimoteConfigDiag.cpp', - 'Src/WxUtils.cpp', - ] - -if sys.platform == 'win32': - files += ['Src/stdafx.cpp'] -elif sys.platform == 'darwin': - env['CPPPATH'] += ['#Externals'] - env['FRAMEWORKPATH'] += ['Externals/Cg'] - env['FRAMEWORKS'] += ['ApplicationServices', 'Carbon', 'Cocoa'] - env['FRAMEWORKS'] += ['AudioUnit', 'IOBluetooth', 'IOKit', 'OpenGL'] - env['FRAMEWORKSFLAGS'] = ['-Wl,-lazy_framework,Cg'] - env['FRAMEWORKSFLAGS'] += ['-Wl,-weak_framework,OpenCL'] - env['LIBS'] += ['iconv', 'z'] - - # XXX - env['FRAMEWORKSFLAGS'] += ['-Wl,-weak_framework,QuickTime'] - env['FRAMEWORKSFLAGS'] += ['-Wl,-no_arch_warnings'] - - exe = '#' + env['prefix'] + '/Dolphin.app/Contents/MacOS/Dolphin' - if env['nowx']: - exe += 'NoGUI' - - env.Install('#' + env['prefix'] + '/Dolphin.app/Contents/' + - 'Frameworks/Cg.framework', source = [ - '#Externals/Cg/Cg.framework/Cg', - '#Externals/Cg/Cg.framework/Resources' - ]) - - env.Install(env['data_dir'], '#Data/Sys') - env.Install(env['data_dir'], '#Data/User') - env.Install(env['data_dir'], - '#Source/Core/DolphinWX/resources/Dolphin.icns') - - languages = [] - msgfmt = env.WhereIs('msgfmt') - if not msgfmt == None: - po_files = Glob('#Languages/po/*.po', strings = True) - for po in po_files: - index_lo = po.find('Languages/po/') + len('Languages/po/') - index_hi = po.find('.po') - lang = po[index_lo:index_hi] - lproj = os.sep + lang + '.lproj' - mo_dir = env['build_dir'] + '/Languages' + lproj - mo_file = mo_dir + '/dolphin-emu.mo' - env.Command('#' + mo_file, po, 'mkdir -p ' + mo_dir + - ' && ' + msgfmt + ' -o ' + mo_file + ' ' + po) - env.Install(env['data_dir'] + lproj, '#' + mo_file) - languages += [lang] - - from plistlib import writePlist - def createPlist(target, source, env): - for srcNode in source: - writePlist(srcNode.value, str(target[0])) - env.Append(BUILDERS = {'Plist' : Builder(action = createPlist)}) - env.Plist('#' + env['prefix'] + '/Dolphin.app/Contents/Info.plist', - Value(dict( - CFBundleExecutable = 'Dolphin', - CFBundleIconFile = 'Dolphin.icns', - CFBundleIdentifier = 'com.dolphin-emulator.dolphin', - CFBundleLocalizations = languages, - CFBundlePackageType = 'APPL', - CFBundleShortVersionString = env['gitdesc'], - CFBundleVersion = '3.0', - LSMinimumSystemVersion = '10.5.4', - LSRequiresCarbon = True, - CFBundleDocumentTypes = [ - dict(CFBundleTypeExtensions = - ('ciso', 'dol', 'elf', 'gcm', 'gcz', 'iso', 'wad'), - CFBundleTypeIconFile = 'Dolphin.icns', - CFBundleTypeName = 'Nintendo GC/Wii file', - CFBundleTypeRole = 'Viewer')] - ))) - - env.Command('dummy', '#' + env['prefix'], - "find $SOURCES -name .svn -exec rm -rf {} +") -else: - files += ['Src/X11Utils.cpp'] - exe = env['binary_dir'] + '/dolphin-emu' - if env['nowx']: - exe += '-nogui' - env.InstallAs(env['data_dir'] + '/sys', '#Data/Sys') - env.InstallAs(env['data_dir'] + '/user', '#Data/User') - -env.Program(exe, files) diff --git a/Source/Core/DolphinWX/Src/ConfigMain.cpp b/Source/Core/DolphinWX/Src/ConfigMain.cpp index fdca309aee..2534c4a9db 100644 --- a/Source/Core/DolphinWX/Src/ConfigMain.cpp +++ b/Source/Core/DolphinWX/Src/ConfigMain.cpp @@ -90,7 +90,7 @@ static const wxLanguage langIds[] = #define EXIDEV_GECKO_STR "USBGecko" #define CSTR_TRANS(a) wxString(wxGetTranslation(wxT(a))).mb_str() - +#define WXSTR_TRANS(a) wxString(wxGetTranslation(wxT(a))) #ifdef WIN32 //only used with xgettext to be picked up as translatable string. //win32 does not have wx on its path, the provided wxALL_FILES @@ -116,7 +116,6 @@ EVT_CHECKBOX(ID_NTSCJ, CConfigMain::CoreSettingsChanged) EVT_RADIOBOX(ID_DSPENGINE, CConfigMain::AudioSettingsChanged) -EVT_CHECKBOX(ID_ENABLE_DTK_MUSIC, CConfigMain::AudioSettingsChanged) EVT_CHECKBOX(ID_DSPTHREAD, CConfigMain::AudioSettingsChanged) EVT_CHECKBOX(ID_ENABLE_THROTTLE, CConfigMain::AudioSettingsChanged) EVT_CHECKBOX(ID_DUMP_AUDIO, CConfigMain::AudioSettingsChanged) @@ -359,7 +358,6 @@ void CConfigMain::InitializeGUIValues() VolumeSlider->Enable(SupportsVolumeChanges(ac_Config.sBackend)); VolumeSlider->SetValue(ac_Config.m_Volume); VolumeText->SetLabel(wxString::Format(wxT("%d %%"), ac_Config.m_Volume)); - EnableDTKMusic->SetValue(ac_Config.m_EnableDTKMusic ? true : false); DSPThread->SetValue(startup_params.bDSPThread); DumpAudio->SetValue(ac_Config.m_DumpAudio ? true : false); FrequencySelection->SetSelection( @@ -502,7 +500,6 @@ void CConfigMain::InitializeGUITooltips() InterfaceLang->SetToolTip(_("Change the language of the user interface.\nRequires restart.")); // Audio tooltips - EnableDTKMusic->SetToolTip(_("This is used to play music tracks, like BGM.")); DSPThread->SetToolTip(_("Run DSP LLE on a dedicated thread (not recommended).")); FrequencySelection->SetToolTip(_("Changing this will have no effect while the emulator is running!")); BackendSelection->SetToolTip(_("Changing this will have no effect while the emulator is running!")); @@ -602,8 +599,6 @@ void CConfigMain::CreateGUIControls() // Audio page DSPEngine = new wxRadioBox(AudioPage, ID_DSPENGINE, _("DSP Emulator Engine"), wxDefaultPosition, wxDefaultSize, arrayStringFor_DSPEngine, 0, wxRA_SPECIFY_ROWS); - EnableDTKMusic = new wxCheckBox(AudioPage, ID_ENABLE_DTK_MUSIC, _("Enable DTK Music"), - wxDefaultPosition, wxDefaultSize, 0, wxDefaultValidator); DSPThread = new wxCheckBox(AudioPage, ID_DSPTHREAD, _("DSP LLE on Thread")); DumpAudio = new wxCheckBox(AudioPage, ID_DUMP_AUDIO, _("Dump Audio"), wxDefaultPosition, wxDefaultSize, 0, wxDefaultValidator); @@ -620,7 +615,6 @@ void CConfigMain::CreateGUIControls() // Create sizer and add items to dialog wxStaticBoxSizer *sbAudioSettings = new wxStaticBoxSizer(wxVERTICAL, AudioPage, _("Sound Settings")); sbAudioSettings->Add(DSPEngine, 0, wxALL | wxEXPAND, 5); - sbAudioSettings->Add(EnableDTKMusic, 0, wxALL, 5); sbAudioSettings->Add(DSPThread, 0, wxALL, 5); sbAudioSettings->Add(DumpAudio, 0, wxALL, 5); @@ -751,7 +745,7 @@ void CConfigMain::CreateGUIControls() RemoveISOPath->Enable(false); DefaultISO = new wxFilePickerCtrl(PathsPage, ID_DEFAULTISO, wxEmptyString, _("Choose a default ISO:"), - _("All GC/Wii images (gcm, iso, ciso, gcz)") + wxString::Format(wxT("|*.gcm;*.iso;*.ciso;*.gcz|%s"), wxGetTranslation(wxALL_FILES)), + _("All GC/Wii images (gcm, iso, wbfs, ciso, gcz)") + wxString::Format(wxT("|*.gcm;*.iso;*.wbfs;*.ciso;*.gcz|%s"), wxGetTranslation(wxALL_FILES)), wxDefaultPosition, wxDefaultSize, wxFLP_USE_TEXTCTRL|wxFLP_OPEN); DVDRoot = new wxDirPickerCtrl(PathsPage, ID_DVDROOT, wxEmptyString, _("Choose a DVD root directory:"), wxDefaultPosition, wxDefaultSize, wxDIRP_USE_TEXTCTRL); ApploaderPath = new wxFilePickerCtrl(PathsPage, ID_APPLOADERPATH, wxEmptyString, _("Choose file to use as apploader: (applies to discs constructed from directories only)"), @@ -918,7 +912,6 @@ void CConfigMain::AudioSettingsChanged(wxCommandEvent& event) break; default: - ac_Config.m_EnableDTKMusic = EnableDTKMusic->GetValue(); ac_Config.m_DumpAudio = DumpAudio->GetValue(); long int frequency; @@ -979,7 +972,7 @@ void CConfigMain::GCSettingsChanged(wxCommandEvent& event) case ID_GC_EXIDEVICE_SLOTB: exidevice++; case ID_GC_EXIDEVICE_SLOTA: - ChooseEXIDevice(std::string(event.GetString().mb_str()), exidevice); + ChooseEXIDevice(event.GetString(), exidevice); break; case ID_GC_EXIDEVICE_SLOTA_PATH: ChooseMemcardPath(SConfig::GetInstance().m_strMemoryCardA, true); @@ -994,7 +987,7 @@ void CConfigMain::GCSettingsChanged(wxCommandEvent& event) case ID_GC_SIDEVICE1: sidevice++; case ID_GC_SIDEVICE0: - ChooseSIDevice(std::string(event.GetString().mb_str()), sidevice); + ChooseSIDevice(event.GetString(), sidevice); break; } } @@ -1044,16 +1037,16 @@ void CConfigMain::ChooseMemcardPath(std::string& strMemcard, bool isSlotA) } } -void CConfigMain::ChooseSIDevice(std::string deviceName, int deviceNum) +void CConfigMain::ChooseSIDevice(wxString deviceName, int deviceNum) { SIDevices tempType; - if (!deviceName.compare(CSTR_TRANS(SIDEV_STDCONT_STR))) + if (!deviceName.compare(WXSTR_TRANS(SIDEV_STDCONT_STR))) tempType = SIDEVICE_GC_CONTROLLER; - else if (!deviceName.compare(CSTR_TRANS(SIDEV_BONGO_STR))) + else if (!deviceName.compare(WXSTR_TRANS(SIDEV_BONGO_STR))) tempType = SIDEVICE_GC_TARUKONGA; - else if (!deviceName.compare(SIDEV_GBA_STR)) + else if (!deviceName.compare(wxT(SIDEV_GBA_STR))) tempType = SIDEVICE_GC_GBA; - else if (!deviceName.compare(CSTR_TRANS(SIDEV_AM_BB_STR))) + else if (!deviceName.compare(WXSTR_TRANS(SIDEV_AM_BB_STR))) tempType = SIDEVICE_AM_BASEBOARD; else tempType = SIDEVICE_NONE; @@ -1067,21 +1060,21 @@ void CConfigMain::ChooseSIDevice(std::string deviceName, int deviceNum) } } -void CConfigMain::ChooseEXIDevice(std::string deviceName, int deviceNum) +void CConfigMain::ChooseEXIDevice(wxString deviceName, int deviceNum) { TEXIDevices tempType; - if (!deviceName.compare(CSTR_TRANS(EXIDEV_MEMCARD_STR))) + if (!deviceName.compare(WXSTR_TRANS(EXIDEV_MEMCARD_STR))) tempType = EXIDEVICE_MEMORYCARD; - else if (!deviceName.compare(CSTR_TRANS(EXIDEV_MIC_STR))) + else if (!deviceName.compare(WXSTR_TRANS(EXIDEV_MIC_STR))) tempType = EXIDEVICE_MIC; - else if (!deviceName.compare(EXIDEV_BBA_STR)) + else if (!deviceName.compare(wxT(EXIDEV_BBA_STR))) tempType = EXIDEVICE_ETH; - else if (!deviceName.compare(CSTR_TRANS(EXIDEV_AM_BB_STR))) + else if (!deviceName.compare(WXSTR_TRANS(EXIDEV_AM_BB_STR))) tempType = EXIDEVICE_AM_BASEBOARD; - else if (!deviceName.compare(EXIDEV_GECKO_STR)) + else if (!deviceName.compare(wxT(EXIDEV_GECKO_STR))) tempType = EXIDEVICE_GECKO; - else if (!deviceName.compare(CSTR_TRANS(DEV_NONE_STR))) + else if (!deviceName.compare(WXSTR_TRANS(DEV_NONE_STR))) tempType = EXIDEVICE_NONE; else tempType = EXIDEVICE_DUMMY; diff --git a/Source/Core/DolphinWX/Src/ConfigMain.h b/Source/Core/DolphinWX/Src/ConfigMain.h index 3ec798fb8e..eae9f8996d 100644 --- a/Source/Core/DolphinWX/Src/ConfigMain.h +++ b/Source/Core/DolphinWX/Src/ConfigMain.h @@ -77,7 +77,6 @@ private: // Audio Settings ID_DSPENGINE, ID_ENABLE_HLE_AUDIO, - ID_ENABLE_DTK_MUSIC, ID_ENABLE_THROTTLE, ID_DUMP_AUDIO, ID_FREQUENCY, @@ -156,7 +155,6 @@ private: wxRadioBox* DSPEngine; wxSlider* VolumeSlider; wxStaticText* VolumeText; - wxCheckBox* EnableDTKMusic; wxCheckBox* DumpAudio; wxArrayString wxArrayBackends; wxChoice* BackendSelection; @@ -253,8 +251,8 @@ private: void GCSettingsChanged(wxCommandEvent& event); void ChooseMemcardPath(std::string& strMemcard, bool isSlotA); - void ChooseSIDevice(std::string deviceName, int deviceNum); - void ChooseEXIDevice(std::string deviceName, int deviceNum); + void ChooseSIDevice(wxString deviceName, int deviceNum); + void ChooseEXIDevice(wxString deviceName, int deviceNum); void WiiSettingsChanged(wxCommandEvent& event); // Change from IPL.LNG value to country code diff --git a/Source/Core/DolphinWX/Src/Debugger/CodeWindow.cpp b/Source/Core/DolphinWX/Src/Debugger/CodeWindow.cpp index 37ff81772a..0b6b366c88 100644 --- a/Source/Core/DolphinWX/Src/Debugger/CodeWindow.cpp +++ b/Source/Core/DolphinWX/Src/Debugger/CodeWindow.cpp @@ -263,6 +263,8 @@ void CCodeWindow::SingleStep() { if (CCPU::IsStepping()) { + if (jit) + jit->GetBlockCache()->InvalidateICache(PC, 4); CCPU::StepOpcode(&sync_event); wxThread::Sleep(20); // need a short wait here diff --git a/Source/Core/DolphinWX/Src/Debugger/CodeWindowFunctions.cpp b/Source/Core/DolphinWX/Src/Debugger/CodeWindowFunctions.cpp index a3dd9a9ab8..05915ecd20 100644 --- a/Source/Core/DolphinWX/Src/Debugger/CodeWindowFunctions.cpp +++ b/Source/Core/DolphinWX/Src/Debugger/CodeWindowFunctions.cpp @@ -187,35 +187,40 @@ void CCodeWindow::CreateMenuSymbols(wxMenuBar *pMenuBar) void CCodeWindow::OnProfilerMenu(wxCommandEvent& event) { - if (Core::GetState() == Core::CORE_RUN) { - event.Skip(); - return; - } switch (event.GetId()) { case IDM_PROFILEBLOCKS: - if (jit != NULL) jit->ClearCache(); + Core::SetState(Core::CORE_PAUSE); + if (jit != NULL) + jit->ClearCache(); Profiler::g_ProfileBlocks = GetMenuBar()->IsChecked(IDM_PROFILEBLOCKS); + Core::SetState(Core::CORE_RUN); break; case IDM_WRITEPROFILE: - if (jit != NULL) - { - std::string filename = File::GetUserPath(D_DUMP_IDX) + "Debug/profiler.txt"; - File::CreateFullPath(filename); - Profiler::WriteProfileResults(filename.c_str()); + if (Core::GetState() == Core::CORE_RUN) + Core::SetState(Core::CORE_PAUSE); - wxFileType* filetype = NULL; - if (!(filetype = wxTheMimeTypesManager->GetFileTypeFromExtension(_T("txt")))) + if (Core::GetState() == Core::CORE_PAUSE && PowerPC::GetMode() == PowerPC::MODE_JIT) + { + if (jit != NULL) { - // From extension failed, trying with MIME type now - if (!(filetype = wxTheMimeTypesManager->GetFileTypeFromMimeType(_T("text/plain")))) - // MIME type failed, aborting mission - break; + std::string filename = File::GetUserPath(D_DUMP_IDX) + "Debug/profiler.txt"; + File::CreateFullPath(filename); + Profiler::WriteProfileResults(filename.c_str()); + + wxFileType* filetype = NULL; + if (!(filetype = wxTheMimeTypesManager->GetFileTypeFromExtension(_T("txt")))) + { + // From extension failed, trying with MIME type now + if (!(filetype = wxTheMimeTypesManager->GetFileTypeFromMimeType(_T("text/plain")))) + // MIME type failed, aborting mission + break; + } + wxString OpenCommand; + OpenCommand = filetype->GetOpenCommand(wxString::From8BitData(filename.c_str())); + if(!OpenCommand.IsEmpty()) + wxExecute(OpenCommand, wxEXEC_SYNC); } - wxString OpenCommand; - OpenCommand = filetype->GetOpenCommand(wxString::From8BitData(filename.c_str())); - if(!OpenCommand.IsEmpty()) - wxExecute(OpenCommand, wxEXEC_SYNC); } break; } diff --git a/Source/Core/DolphinWX/Src/FifoPlayerDlg.cpp b/Source/Core/DolphinWX/Src/FifoPlayerDlg.cpp index cd863095a1..cb467389ee 100644 --- a/Source/Core/DolphinWX/Src/FifoPlayerDlg.cpp +++ b/Source/Core/DolphinWX/Src/FifoPlayerDlg.cpp @@ -21,6 +21,7 @@ #include "Thread.h" #include "FifoPlayer/FifoPlayer.h" #include "FifoPlayer/FifoRecorder.h" +#include "OpcodeDecoding.h" #include <wx/spinctrl.h> DECLARE_EVENT_TYPE(RECORDING_FINISHED_EVENT, -1) @@ -36,7 +37,7 @@ wxEvtHandler *volatile FifoPlayerDlg::m_EvtHandler = NULL; FifoPlayerDlg::FifoPlayerDlg(wxWindow * const parent) : wxDialog(parent, wxID_ANY, _("FIFO Player"), wxDefaultPosition, wxDefaultSize), - m_FramesToRecord(1) + m_search_result_idx(0), m_FramesToRecord(1) { CreateGUIControls(); @@ -65,6 +66,10 @@ FifoPlayerDlg::~FifoPlayerDlg() m_FramesToRecordCtrl->Disconnect(wxEVT_COMMAND_SPINCTRL_UPDATED, wxSpinEventHandler(FifoPlayerDlg::OnNumFramesToRecord), NULL, this); m_Close->Disconnect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(FifoPlayerDlg::OnCloseClick), NULL, this); + m_framesList->Disconnect(wxEVT_COMMAND_LISTBOX_SELECTED, wxCommandEventHandler(FifoPlayerDlg::OnFrameListSelectionChanged), NULL, this); + m_objectsList->Disconnect(wxEVT_COMMAND_LISTBOX_SELECTED, wxCommandEventHandler(FifoPlayerDlg::OnObjectListSelectionChanged), NULL, this); + m_objectCmdList->Disconnect(wxEVT_COMMAND_LISTBOX_SELECTED, wxCommandEventHandler(FifoPlayerDlg::OnObjectCmdListSelectionChanged), NULL, this); + FifoPlayer::GetInstance().SetFrameWrittenCallback(NULL); sMutex.lock(); @@ -74,12 +79,12 @@ FifoPlayerDlg::~FifoPlayerDlg() void FifoPlayerDlg::CreateGUIControls() { - SetSizeHints(wxDefaultSize, wxDefaultSize); - wxBoxSizer* sMain; sMain = new wxBoxSizer(wxVERTICAL); m_Notebook = new wxNotebook(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, 0); + + { m_PlayPage = new wxPanel(m_Notebook, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL); wxBoxSizer* sPlayPage; sPlayPage = new wxBoxSizer(wxVERTICAL); @@ -146,11 +151,15 @@ void FifoPlayerDlg::CreateGUIControls() sPlayOptions->Add(m_EarlyMemoryUpdates, 0, wxALL, 5); sPlayPage->Add(sPlayOptions, 0, wxEXPAND, 5); - + sPlayPage->AddStretchSpacer(); + m_PlayPage->SetSizer(sPlayPage); m_PlayPage->Layout(); sPlayPage->Fit(m_PlayPage); m_Notebook->AddPage(m_PlayPage, _("Play"), true); + } + + { m_RecordPage = new wxPanel(m_Notebook, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL); wxBoxSizer* sRecordPage; sRecordPage = new wxBoxSizer(wxVERTICAL); @@ -194,33 +203,103 @@ void FifoPlayerDlg::CreateGUIControls() sRecordingOptions->Add(m_FramesToRecordCtrl, 0, wxALL, 5); sRecordPage->Add(sRecordingOptions, 0, wxEXPAND, 5); - + sRecordPage->AddStretchSpacer(); + m_RecordPage->SetSizer(sRecordPage); m_RecordPage->Layout(); sRecordPage->Fit(m_RecordPage); m_Notebook->AddPage(m_RecordPage, _("Record"), false); - + } + + // Analyze page + { + m_AnalyzePage = new wxPanel(m_Notebook, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL); + wxBoxSizer* sAnalyzePage; + sAnalyzePage = new wxBoxSizer(wxVERTICAL); + + wxStaticBoxSizer* sFrameInfoSizer; + sFrameInfoSizer = new wxStaticBoxSizer(new wxStaticBox(m_AnalyzePage, wxID_ANY, _("Frame Info")), wxVERTICAL); + + wxBoxSizer* sListsSizer = new wxBoxSizer(wxHORIZONTAL); + + m_framesList = new wxListBox(m_AnalyzePage, wxID_ANY); + m_framesList->SetMinSize(wxSize(100, 250)); + sListsSizer->Add(m_framesList, 0, wxALL, 5); + + m_objectsList = new wxListBox(m_AnalyzePage, wxID_ANY); + m_objectsList->SetMinSize(wxSize(110, 250)); + sListsSizer->Add(m_objectsList, 0, wxALL, 5); + + m_objectCmdList = new wxListBox(m_AnalyzePage, wxID_ANY); + m_objectCmdList->SetMinSize(wxSize(175, 250)); + sListsSizer->Add(m_objectCmdList, 0, wxALL, 5); + + sFrameInfoSizer->Add(sListsSizer, 0, wxALL, 5); + + m_objectCmdInfo = new wxStaticText(m_AnalyzePage, wxID_ANY, wxString()); + sFrameInfoSizer->Add(m_objectCmdInfo, 0, wxALL, 5); + + sAnalyzePage->Add(sFrameInfoSizer, 0, wxEXPAND, 5); + + wxStaticBoxSizer* sSearchSizer = new wxStaticBoxSizer(new wxStaticBox(m_AnalyzePage, wxID_ANY, _("Search current Object")), wxVERTICAL); + + wxBoxSizer* sSearchField = new wxBoxSizer(wxHORIZONTAL); + + sSearchField->Add(new wxStaticText(m_AnalyzePage, wxID_ANY, _("Search for hex Value:")), 0, wxALIGN_CENTER_VERTICAL, 5); + // TODO: ugh, wxValidator sucks - but we should use it anyway. + m_searchField = new wxTextCtrl(m_AnalyzePage, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, wxTE_PROCESS_ENTER); + m_numResultsText = new wxStaticText(m_AnalyzePage, wxID_ANY, wxEmptyString); + + sSearchField->Add(m_searchField, 0, wxALL, 5); + sSearchField->Add(m_numResultsText, 0, wxALIGN_CENTER_VERTICAL, 5); + + wxBoxSizer* sSearchButtons = new wxBoxSizer(wxHORIZONTAL); + + m_beginSearch = new wxButton(m_AnalyzePage, wxID_ANY, _("Search")); + m_findNext = new wxButton(m_AnalyzePage, wxID_ANY, _("Find next")); + m_findPrevious = new wxButton(m_AnalyzePage, wxID_ANY, _("Find previous")); + + m_beginSearch->Disable(); + m_findNext->Disable(); + m_findPrevious->Disable(); + + sSearchButtons->Add(m_beginSearch, 0, wxALL, 5); + sSearchButtons->Add(m_findNext, 0, wxALL, 5); + sSearchButtons->Add(m_findPrevious, 0, wxALL, 5); + + sSearchSizer->Add(sSearchField, 0, wxEXPAND, 5); + sSearchSizer->Add(sSearchButtons, 0, wxEXPAND, 5); + + sAnalyzePage->Add(sSearchSizer, 0, wxEXPAND, 5); + sAnalyzePage->AddStretchSpacer(); + + m_AnalyzePage->SetSizer(sAnalyzePage); + m_AnalyzePage->Layout(); + sAnalyzePage->Fit(m_AnalyzePage); + m_Notebook->AddPage(m_AnalyzePage, _("Analyze"), false); + } + sMain->Add(m_Notebook, 1, wxEXPAND | wxALL, 5); - + wxBoxSizer* sButtons; sButtons = new wxBoxSizer(wxHORIZONTAL); - + wxBoxSizer* sCloseButtonExpander; sCloseButtonExpander = new wxBoxSizer(wxHORIZONTAL); - + sButtons->Add(sCloseButtonExpander, 1, wxEXPAND, 5); - + m_Close = new wxButton(this, wxID_ANY, _("Close"), wxDefaultPosition, wxDefaultSize, 0); sButtons->Add(m_Close, 0, wxALL, 5); - + sMain->Add(sButtons, 0, wxEXPAND, 5); - + SetSizer(sMain); Layout(); sMain->Fit(this); - + Center(wxBOTH); - + // Connect Events Connect(wxEVT_PAINT, wxPaintEventHandler(FifoPlayerDlg::OnPaint)); m_FrameFromCtrl->Connect(wxEVT_COMMAND_SPINCTRL_UPDATED, wxSpinEventHandler(FifoPlayerDlg::OnFrameFrom), NULL, this); @@ -231,7 +310,18 @@ void FifoPlayerDlg::CreateGUIControls() m_RecordStop->Connect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(FifoPlayerDlg::OnRecordStop), NULL, this); m_Save->Connect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(FifoPlayerDlg::OnSaveFile), NULL, this); m_FramesToRecordCtrl->Connect(wxEVT_COMMAND_SPINCTRL_UPDATED, wxSpinEventHandler(FifoPlayerDlg::OnNumFramesToRecord), NULL, this); - m_Close->Connect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(FifoPlayerDlg::OnCloseClick), NULL, this); + Connect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(FifoPlayerDlg::OnCloseClick), NULL, this); + + m_framesList->Connect(wxEVT_COMMAND_LISTBOX_SELECTED, wxCommandEventHandler(FifoPlayerDlg::OnFrameListSelectionChanged), NULL, this); + m_objectsList->Connect(wxEVT_COMMAND_LISTBOX_SELECTED, wxCommandEventHandler(FifoPlayerDlg::OnObjectListSelectionChanged), NULL, this); + m_objectCmdList->Connect(wxEVT_COMMAND_LISTBOX_SELECTED, wxCommandEventHandler(FifoPlayerDlg::OnObjectCmdListSelectionChanged), NULL, this); + + m_beginSearch->Connect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(FifoPlayerDlg::OnBeginSearch), NULL, this); + m_findNext->Connect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(FifoPlayerDlg::OnFindNextClick), NULL, this); + m_findPrevious->Connect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(FifoPlayerDlg::OnFindPreviousClick), NULL, this); + + m_searchField->Connect(wxEVT_COMMAND_TEXT_ENTER, wxCommandEventHandler(FifoPlayerDlg::OnBeginSearch), NULL, this); + m_searchField->Connect(wxEVT_COMMAND_TEXT_UPDATED, wxCommandEventHandler(FifoPlayerDlg::OnSearchFieldTextChanged), NULL, this); Connect(RECORDING_FINISHED_EVENT, wxCommandEventHandler(FifoPlayerDlg::OnRecordingFinished), NULL, this); Connect(FRAME_WRITTEN_EVENT, wxCommandEventHandler(FifoPlayerDlg::OnFrameWritten), NULL, this); @@ -243,6 +333,7 @@ void FifoPlayerDlg::OnPaint(wxPaintEvent& event) { UpdatePlayGui(); UpdateRecorderGui(); + UpdateAnalyzerGui(); event.Skip(); } @@ -250,10 +341,11 @@ void FifoPlayerDlg::OnPaint(wxPaintEvent& event) void FifoPlayerDlg::OnFrameFrom(wxSpinEvent& event) { FifoPlayer &player = FifoPlayer::GetInstance(); + player.SetFrameRangeStart(event.GetPosition()); m_FrameFromCtrl->SetValue(player.GetFrameRangeStart()); - m_FrameToCtrl->SetValue(player.GetFrameRangeEnd()); + m_FrameToCtrl->SetValue(player.GetFrameRangeEnd()); } void FifoPlayerDlg::OnFrameTo(wxSpinEvent& event) @@ -326,6 +418,351 @@ void FifoPlayerDlg::OnNumFramesToRecord(wxSpinEvent& event) m_FramesToRecord = -1; } +void FifoPlayerDlg::OnBeginSearch(wxCommandEvent& event) +{ + wxString str_search_val = m_searchField->GetValue(); + + if (m_framesList->GetSelection() == -1) + return; + + // TODO: Limited to even str lengths... + if (str_search_val.Length() && str_search_val.Length() % 2) + { + m_numResultsText->SetLabel(_("Invalid search string (only even string lengths supported)")); + return; + } + + unsigned int val_length = str_search_val.Length() / 2; + u8* search_val = new u8[val_length]; + for (unsigned int i = 0; i < val_length; ++i) + { + wxString char_str = str_search_val.Mid(2*i, 2); + unsigned long val; + if (!char_str.ToULong(&val, 16)) + { + m_numResultsText->SetLabel(_("Invalid search string (couldn't convert to number)")); + delete[] search_val; + return; + } + search_val[i] = (u8)val; + } + search_results.clear(); + + u8* start_ptr; + u8* end_ptr; + + int frame_idx = m_framesList->GetSelection(); + FifoPlayer& player = FifoPlayer::GetInstance(); + const AnalyzedFrameInfo& frame = player.GetAnalyzedFrameInfo(frame_idx); + const FifoFrameInfo& fifo_frame = player.GetFile()->GetFrame(frame_idx); + + // TODO: Support searching through the last object... How do we know were the cmd data ends? + // TODO: Support searching for bit patterns + int obj_idx = m_objectsList->GetSelection(); + if (obj_idx == -1) + { + m_numResultsText->SetLabel(_("Invalid search parameters (no object selected)")); + return; + } + start_ptr = &fifo_frame.fifoData[frame.objectStarts[obj_idx]]; + end_ptr = &fifo_frame.fifoData[frame.objectStarts[obj_idx+1]]; + + for (u8* ptr = start_ptr; ptr < end_ptr-val_length+1; ++ptr) + { + if (memcmp(ptr, search_val, val_length) == 0) + { + SearchResult result; + result.frame_idx = frame_idx; + + int obj_idx = m_objectsList->GetSelection(); + result.obj_idx = obj_idx; + result.cmd_idx = 0; + for (unsigned int cmd_idx = 1; cmd_idx < m_objectCmdOffsets.size(); ++cmd_idx) + { + if (ptr < start_ptr + m_objectCmdOffsets[cmd_idx]) + { + result.cmd_idx = cmd_idx-1; + break; + } + } + search_results.push_back(result); + } + } + delete[] search_val; + + ChangeSearchResult(0); + m_beginSearch->Disable(); + m_findNext->Enable(); + m_findPrevious->Enable(); + m_numResultsText->SetLabel(wxString::Format(_("Found %d results for \'"), search_results.size()) + m_searchField->GetValue() + _("\'")); +} + +void FifoPlayerDlg::OnSearchFieldTextChanged(wxCommandEvent& event) +{ + m_beginSearch->Enable(m_searchField->GetLineLength(0) > 0); + m_findNext->Disable(); + m_findPrevious->Disable(); +} + +void FifoPlayerDlg::OnFindNextClick(wxCommandEvent& event) +{ + int cur_cmd_index = m_objectCmdList->GetSelection(); + if (cur_cmd_index == -1) + { + ChangeSearchResult(0); + return; + } + + for (std::vector<SearchResult>::iterator it = search_results.begin(); it != search_results.end(); ++it) + { + if (it->cmd_idx > cur_cmd_index) + { + ChangeSearchResult(it - search_results.begin()); + return; + } + } +} + +void FifoPlayerDlg::OnFindPreviousClick(wxCommandEvent& event) +{ + int cur_cmd_index = m_objectCmdList->GetSelection(); + if (cur_cmd_index == -1) + { + ChangeSearchResult(search_results.size() - 1); + return; + } + + for (std::vector<SearchResult>::reverse_iterator it = search_results.rbegin(); it != search_results.rend(); ++it) + { + if (it->cmd_idx < cur_cmd_index) + { + ChangeSearchResult(search_results.size()-1 - (it - search_results.rbegin())); + return; + } + } +} + +void FifoPlayerDlg::ChangeSearchResult(unsigned int result_idx) +{ + if (search_results.size() > result_idx) + { + m_search_result_idx = result_idx; + int prev_frame = m_framesList->GetSelection(); + int prev_obj = m_objectsList->GetSelection(); + int prev_cmd = m_objectCmdList->GetSelection(); + m_framesList->SetSelection(search_results[result_idx].frame_idx); + m_objectsList->SetSelection(search_results[result_idx].obj_idx); + m_objectCmdList->SetSelection(search_results[result_idx].cmd_idx); + + wxCommandEvent ev(wxEVT_COMMAND_LISTBOX_SELECTED); + if (prev_frame != m_framesList->GetSelection()) + { + ev.SetInt(m_framesList->GetSelection()); + OnFrameListSelectionChanged(ev); + } + if (prev_obj != m_objectsList->GetSelection()) + { + ev.SetInt(m_objectsList->GetSelection()); + OnObjectListSelectionChanged(ev); + } + if (prev_cmd != m_objectCmdList->GetSelection()) + { + ev.SetInt(m_objectCmdList->GetSelection()); + OnObjectCmdListSelectionChanged(ev); + } + } + else if (search_results.size()) + { + ChangeSearchResult(search_results.size() - 1); + } +} + +void FifoPlayerDlg::OnFrameListSelectionChanged(wxCommandEvent& event) +{ + FifoPlayer& player = FifoPlayer::GetInstance(); + + m_objectsList->Clear(); + if (event.GetInt() != -1) + { + int num_objects = player.GetAnalyzedFrameInfo(event.GetInt()).objectStarts.size(); + for (int i = 0; i < num_objects; ++i) + m_objectsList->Append(wxString::Format(wxT("Object %i"), i)); + } + + // Update object list + wxCommandEvent ev = wxCommandEvent(wxEVT_COMMAND_LISTBOX_SELECTED); + ev.SetInt(-1); + OnObjectListSelectionChanged(ev); +} + +void FifoPlayerDlg::OnObjectListSelectionChanged(wxCommandEvent& event) +{ + FifoPlayer& player = FifoPlayer::GetInstance(); + + int frame_idx = m_framesList->GetSelection(); + int object_idx = event.GetInt(); + + m_objectCmdList->Clear(); + m_objectCmdOffsets.clear(); + if (frame_idx != -1 && object_idx != -1) + { + const AnalyzedFrameInfo& frame = player.GetAnalyzedFrameInfo(frame_idx); + const FifoFrameInfo& fifo_frame = player.GetFile()->GetFrame(frame_idx); + const u8* objectdata_start = &fifo_frame.fifoData[frame.objectStarts[object_idx]]; + const u8* objectdata_end = &fifo_frame.fifoData[frame.objectEnds[object_idx]]; + u8* objectdata = (u8*)objectdata_start; + const int obj_offset = objectdata_start - &fifo_frame.fifoData[frame.objectStarts[0]]; + + 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) + { + newLabel += wxString::Format(wxT("%02X"), *objectdata++); + } + m_objectCmdList->Append(newLabel); + m_objectCmdOffsets.push_back(0); + + + // Between objectdata_end and next_objdata_start, there are register setting commands + if (object_idx + 1 < (int)frame.objectStarts.size()) + { + const u8* next_objdata_start = &fifo_frame.fifoData[frame.objectStarts[object_idx+1]]; + while (objectdata < next_objdata_start) + { + m_objectCmdOffsets.push_back(objectdata - objectdata_start); + int new_offset = objectdata - &fifo_frame.fifoData[frame.objectStarts[0]]; + int cmd = *objectdata++; + switch (cmd) + { + case GX_NOP: + newLabel = _("NOP"); + break; + + case 0x44: + newLabel = _("0x44"); + break; + + case GX_CMD_INVL_VC: + newLabel = _("GX_CMD_INVL_VC"); + break; + + case GX_LOAD_CP_REG: + { + u32 cmd2 = *objectdata++; + u32 value = Common::swap32(objectdata); + objectdata += 4; + + newLabel = wxString::Format(wxT("CP %02X %08X"), cmd2, value); + } + break; + + case GX_LOAD_XF_REG: + { + u32 cmd2 = Common::swap32(objectdata); + objectdata += 4; + + u8 streamSize = ((cmd2 >> 16) & 15) + 1; + + const u8* stream_start = objectdata; + const u8* stream_end = stream_start + streamSize * 4; + + newLabel = wxString::Format(wxT("XF %08X "), cmd2); + while (objectdata < stream_end) + { + newLabel += wxString::Format(wxT("%02X"), *objectdata++); + if (((objectdata - stream_start) % 4) == 0) newLabel += wxT(" "); + } + } + break; + + case GX_LOAD_INDX_A: + case GX_LOAD_INDX_B: + case GX_LOAD_INDX_C: + case GX_LOAD_INDX_D: + objectdata += 4; + newLabel = wxString::Format(wxT("LOAD INDX %s"), (cmd == GX_LOAD_INDX_A) ? _("A") : + (cmd == GX_LOAD_INDX_B) ? _("B") : + (cmd == GX_LOAD_INDX_C) ? _("C") : _("D")); + break; + + case GX_CMD_CALL_DL: + // The recorder should have expanded display lists into the fifo stream and skipped the call to start them + // That is done to make it easier to track where memory is updated + _assert_(false); + objectdata += 8; + newLabel = wxString::Format(wxT("CALL DL")); + break; + + case GX_LOAD_BP_REG: + { + u32 cmd2 = Common::swap32(objectdata); + objectdata += 4; + newLabel = wxString::Format(wxT("BP %02X %06X"), cmd2 >> 24, cmd2 & 0xFFFFFF); + } + break; + + default: + newLabel = _("Unexpected 0x80 call? Aborting..."); + objectdata = (u8*)next_objdata_start; + break; + } + newLabel = wxString::Format(_("%08X: "), new_offset) + newLabel; + m_objectCmdList->Append(newLabel); + } + } + } + // Update command list + wxCommandEvent ev = wxCommandEvent(wxEVT_COMMAND_LISTBOX_SELECTED); + ev.SetInt(-1); + OnObjectCmdListSelectionChanged(ev); +} + +void FifoPlayerDlg::OnObjectCmdListSelectionChanged(wxCommandEvent& event) +{ + const int frame_idx = m_framesList->GetSelection(); + const int object_idx = m_objectsList->GetSelection(); + + if (event.GetInt() == -1 || frame_idx == -1 || object_idx == -1) + { + m_objectCmdInfo->SetLabel(wxEmptyString); + return; + } + + FifoPlayer& player = FifoPlayer::GetInstance(); + const AnalyzedFrameInfo& frame = player.GetAnalyzedFrameInfo(frame_idx); + const FifoFrameInfo& fifo_frame = player.GetFile()->GetFrame(frame_idx); + const u8* cmddata = &fifo_frame.fifoData[frame.objectStarts[object_idx]] + m_objectCmdOffsets[event.GetInt()]; + + // TODO: Not sure whether we should bother translating the descriptions + wxString newLabel; + if (*cmddata == GX_LOAD_BP_REG) + { + char name[64]="\0", desc[512]="\0"; + GetBPRegInfo(cmddata+1, name, sizeof(name), desc, sizeof(desc)); + newLabel = _("BP register "); + newLabel += (name[0] != '\0') ? wxString(name, *wxConvCurrent) : wxString::Format(_("UNKNOWN_%02X"), *(cmddata+1)); + newLabel += wxT(":\n"); + if (desc[0] != '\0') + newLabel += wxString(desc, *wxConvCurrent); + else + newLabel += _("No description available"); + } + else if (*cmddata == GX_LOAD_CP_REG) + newLabel = _("CP reg"); + else if (*cmddata == GX_LOAD_XF_REG) + newLabel = _("XF reg"); + else + newLabel = _("No description available"); + + m_objectCmdInfo->SetLabel(newLabel); + Layout(); + Fit(); +} + void FifoPlayerDlg::OnCloseClick(wxCommandEvent& WXUNUSED(event)) { Hide(); @@ -375,6 +812,25 @@ void FifoPlayerDlg::UpdateRecorderGui() m_Save->Enable(GetSaveButtonEnabled()); } +void FifoPlayerDlg::UpdateAnalyzerGui() +{ + FifoPlayer &player = FifoPlayer::GetInstance(); + FifoDataFile* file = player.GetFile(); + + int num_frames = (file) ? player.GetFile()->GetFrameCount() : 0; + if ((int)m_framesList->GetCount() != num_frames) + { + m_framesList->Clear(); + for (int i = 0; i < num_frames; ++i) + { + m_framesList->Append(wxString::Format(wxT("Frame %i"), i)); + } + wxCommandEvent ev = wxCommandEvent(wxEVT_COMMAND_LISTBOX_SELECTED); + ev.SetInt(-1); + OnFrameListSelectionChanged(ev); + } +} + wxString FifoPlayerDlg::CreateFileFrameCountLabel() const { FifoDataFile *file = FifoPlayer::GetInstance().GetFile(); diff --git a/Source/Core/DolphinWX/Src/FifoPlayerDlg.h b/Source/Core/DolphinWX/Src/FifoPlayerDlg.h index 7ecbef8de3..4e2c24fdd6 100644 --- a/Source/Core/DolphinWX/Src/FifoPlayerDlg.h +++ b/Source/Core/DolphinWX/Src/FifoPlayerDlg.h @@ -18,6 +18,7 @@ #ifndef __FIFO_PLAYER_DLG_h__ #define __FIFO_PLAYER_DLG_h__ +#include <vector> #include <wx/wx.h> #include <wx/notebook.h> @@ -44,11 +45,22 @@ private: void OnNumFramesToRecord( wxSpinEvent& event ); void OnCloseClick( wxCommandEvent& event ); + void OnBeginSearch(wxCommandEvent& event); + void OnFindNextClick(wxCommandEvent& event); + void OnFindPreviousClick(wxCommandEvent& event); + void OnSearchFieldTextChanged(wxCommandEvent& event); + void ChangeSearchResult(unsigned int result_idx); + void OnRecordingFinished(wxCommandEvent& event); void OnFrameWritten(wxCommandEvent& event); + void OnFrameListSelectionChanged(wxCommandEvent& event); + void OnObjectListSelectionChanged(wxCommandEvent& event); + void OnObjectCmdListSelectionChanged(wxCommandEvent& event); + void UpdatePlayGui(); void UpdateRecorderGui(); + void UpdateAnalyzerGui(); wxString CreateFileFrameCountLabel() const; wxString CreateCurrentFrameLabel() const; @@ -89,6 +101,28 @@ private: wxButton* m_Save; wxStaticText* m_FramesToRecordLabel; wxSpinCtrl* m_FramesToRecordCtrl; + + wxPanel* m_AnalyzePage; + wxListBox* m_framesList; + wxListBox* m_objectsList; + wxListBox* m_objectCmdList; + std::vector<u32> m_objectCmdOffsets; + wxStaticText* m_objectCmdInfo; + + wxTextCtrl* m_searchField; + wxButton* m_beginSearch; + wxButton* m_findNext; + wxButton* m_findPrevious; + wxStaticText* m_numResultsText; + + struct SearchResult { + int frame_idx; + int obj_idx; + int cmd_idx; + }; + std::vector<SearchResult> search_results; + unsigned int m_search_result_idx; + wxButton* m_Close; s32 m_FramesToRecord; diff --git a/Source/Core/DolphinWX/Src/Frame.cpp b/Source/Core/DolphinWX/Src/Frame.cpp index e7c4fca067..93e0cf8f15 100644 --- a/Source/Core/DolphinWX/Src/Frame.cpp +++ b/Source/Core/DolphinWX/Src/Frame.cpp @@ -500,19 +500,34 @@ void CFrame::OnActive(wxActivateEvent& event) { if (event.GetActive() && event.GetEventObject() == m_RenderFrame) { -#ifdef _WIN32 + // 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 m_RenderParent->SetFocus(); #endif + if (SConfig::GetInstance().m_LocalCoreStartupParameter.bHideCursor && Core::GetState() == Core::CORE_RUN) - m_RenderParent->SetCursor(wxCURSOR_BLANK); + m_RenderParent->SetCursor(cursor_transparent); } else { if (SConfig::GetInstance().m_LocalCoreStartupParameter.bHideCursor) - m_RenderParent->SetCursor(wxCURSOR_ARROW); + m_RenderParent->SetCursor(wxNullCursor); } } event.Skip(); @@ -629,11 +644,6 @@ void CFrame::OnHostMessage(wxCommandEvent& event) m_RenderFrame->SetTitle(event.GetString()); break; - case WM_USER_CREATE: - if (SConfig::GetInstance().m_LocalCoreStartupParameter.bHideCursor) - m_RenderParent->SetCursor(wxCURSOR_BLANK); - break; - case IDM_WINDOWSIZEREQUEST: { std::pair<int, int> *win_size = (std::pair<int, int> *)(event.GetClientData()); @@ -643,6 +653,11 @@ void CFrame::OnHostMessage(wxCommandEvent& event) break; #ifdef __WXGTK__ + case WM_USER_CREATE: + if (SConfig::GetInstance().m_LocalCoreStartupParameter.bHideCursor) + m_RenderParent->SetCursor(wxCURSOR_BLANK); + break; + case IDM_PANIC: { wxString caption = event.GetString().BeforeFirst(':'); @@ -666,8 +681,11 @@ void CFrame::GetRenderWindowSize(int& x, int& y, int& width, int& height) if (!wxIsMainThread()) wxMutexGuiEnter(); #endif - m_RenderParent->GetClientSize(&width, &height); - m_RenderParent->GetPosition(&x, &y); + wxRect client_rect = m_RenderParent->GetClientRect(); + width = client_rect.width; + height = client_rect.height; + x = client_rect.x; + y = client_rect.y; #ifdef __WXGTK__ if (!wxIsMainThread()) wxMutexGuiLeave(); diff --git a/Source/Core/DolphinWX/Src/FrameTools.cpp b/Source/Core/DolphinWX/Src/FrameTools.cpp index 607c920906..a987ddebcd 100644 --- a/Source/Core/DolphinWX/Src/FrameTools.cpp +++ b/Source/Core/DolphinWX/Src/FrameTools.cpp @@ -632,12 +632,12 @@ void CFrame::BootGame(const std::string& filename) bootfile = m_GameListCtrl->GetSelectedISO()->GetFileName(); } else if (!StartUp.m_strDefaultGCM.empty() - && wxFileExists(wxString(StartUp.m_strDefaultGCM.c_str(), wxConvUTF8))) + && wxFileExists(wxSafeConvertMB2WX(StartUp.m_strDefaultGCM.c_str()))) bootfile = StartUp.m_strDefaultGCM; else { if (!SConfig::GetInstance().m_LastFilename.empty() - && wxFileExists(wxString(SConfig::GetInstance().m_LastFilename.c_str(), wxConvUTF8))) + && wxFileExists(wxSafeConvertMB2WX(SConfig::GetInstance().m_LastFilename.c_str()))) bootfile = SConfig::GetInstance().m_LastFilename; else { @@ -663,8 +663,8 @@ void CFrame::DoOpen(bool Boot) wxString path = wxFileSelector( _("Select the file to load"), wxEmptyString, wxEmptyString, wxEmptyString, - _("All GC/Wii files (elf, dol, gcm, iso, ciso, gcz, wad)") + - wxString::Format(wxT("|*.elf;*.dol;*.gcm;*.iso;*.ciso;*.gcz;*.wad;*.dff;*.tmd|%s"), + _("All GC/Wii files (elf, dol, gcm, iso, wbfs, ciso, gcz, wad)") + + wxString::Format(wxT("|*.elf;*.dol;*.gcm;*.iso;*.wbfs;*.ciso;*.gcz;*.wad;*.dff;*.tmd|%s"), wxGetTranslation(wxALL_FILES)), wxFD_OPEN | wxFD_FILE_MUST_EXIST, this); @@ -826,11 +826,9 @@ void CFrame::OnRenderParentResize(wxSizeEvent& event) SConfig::GetInstance().m_LocalCoreStartupParameter.iRenderWindowHeight = height; } #if defined(HAVE_X11) && HAVE_X11 - int x, y; - m_RenderParent->GetClientSize(&width, &height); - m_RenderParent->GetPosition(&x, &y); + wxRect client_rect = m_RenderParent->GetClientRect(); X11Utils::SendClientEvent(X11Utils::XDisplayFromHandle(GetHandle()), - "RESIZE", x, y, width, height); + "RESIZE", client_rect.x, client_rect.y, client_rect.width, client_rect.height); #endif m_LogWindow->Refresh(); m_LogWindow->Update(); @@ -892,7 +890,6 @@ void CFrame::ToggleDisplayMode(bool bFullscreen) if (w != x || h != y || d != 32) continue;; - CGDisplayCapture(CGMainDisplayID()); CGDisplaySwitchToMode(CGMainDisplayID(), mode); } @@ -916,6 +913,10 @@ void CFrame::StartGame(const std::string& filename) m_RenderParent = m_Panel; m_RenderFrame = this; + if (SConfig::GetInstance().m_LocalCoreStartupParameter.bKeepWindowOnTop) + m_RenderFrame->SetWindowStyle(m_RenderFrame->GetWindowStyle() | wxSTAY_ON_TOP); + else + m_RenderFrame->SetWindowStyle(m_RenderFrame->GetWindowStyle() & ~wxSTAY_ON_TOP); } else { @@ -930,6 +931,11 @@ void CFrame::StartGame(const std::string& filename) #endif m_RenderFrame = new CRenderFrame((wxFrame*)this, wxID_ANY, _("Dolphin"), position); + if (SConfig::GetInstance().m_LocalCoreStartupParameter.bKeepWindowOnTop) + m_RenderFrame->SetWindowStyle(m_RenderFrame->GetWindowStyle() | wxSTAY_ON_TOP); + else + m_RenderFrame->SetWindowStyle(m_RenderFrame->GetWindowStyle() & ~wxSTAY_ON_TOP); + wxSize size(SConfig::GetInstance().m_LocalCoreStartupParameter.iRenderWindowWidth, SConfig::GetInstance().m_LocalCoreStartupParameter.iRenderWindowHeight); m_RenderFrame->SetClientSize(size.GetWidth(), size.GetHeight()); @@ -1037,10 +1043,23 @@ void CFrame::DoPause() } 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(wxCURSOR_BLANK); + m_RenderParent->SetCursor(cursor_transparent); } UpdateGUI(); } @@ -1375,17 +1394,13 @@ void CFrame::OnInstallWAD(wxCommandEvent& event) wxProgressDialog dialog(_("Installing WAD..."), _("Working..."), - 1000, // range - this, // parent + 1000, + this, wxPD_APP_MODAL | - wxPD_ELAPSED_TIME | - wxPD_ESTIMATED_TIME | - wxPD_REMAINING_TIME | - wxPD_SMOOTH // - makes indeterminate mode bar on WinXP very small + wxPD_ELAPSED_TIME | wxPD_ESTIMATED_TIME | wxPD_REMAINING_TIME | + wxPD_SMOOTH ); - dialog.CenterOnParent(); - u64 titleID = DiscIO::CNANDContentManager::Access().Install_WiiWAD(fileName); if (titleID == TITLEID_SYSMENU) { @@ -1551,16 +1566,21 @@ void CFrame::UpdateGUI() bool Initialized = Core::IsRunning(); bool Running = Core::GetState() == Core::CORE_RUN; bool Paused = Core::GetState() == Core::CORE_PAUSE; + bool RunningWii = Initialized && SConfig::GetInstance().m_LocalCoreStartupParameter.bWii; + bool RunningGamecube = Initialized && !SConfig::GetInstance().m_LocalCoreStartupParameter.bWii; // Make sure that we have a toolbar if (m_ToolBar) { // Enable/disable the Config and Stop buttons m_ToolBar->EnableTool(wxID_OPEN, !Initialized); - m_ToolBar->EnableTool(wxID_REFRESH, !Initialized); // Don't allow refresh when we don't show the list + // Don't allow refresh when we don't show the list + m_ToolBar->EnableTool(wxID_REFRESH, !Initialized); m_ToolBar->EnableTool(IDM_STOP, Running || Paused); m_ToolBar->EnableTool(IDM_TOGGLE_FULLSCREEN, Running || Paused); m_ToolBar->EnableTool(IDM_SCREENSHOT, Running || Paused); + // Don't allow wiimote config while in Gamecube mode + m_ToolBar->EnableTool(IDM_CONFIG_WIIMOTE_PLUGIN, !RunningGamecube); } // File @@ -1590,15 +1610,12 @@ void CFrame::UpdateGUI() if (DiscIO::CNANDContentManager::Access().GetNANDLoader(TITLEID_SYSMENU).IsValid()) GetMenuBar()->FindItem(IDM_LOAD_WII_MENU)->Enable(!Initialized); - GetMenuBar()->FindItem(IDM_CONNECT_WIIMOTE1)-> - Enable(Initialized && SConfig::GetInstance().m_LocalCoreStartupParameter.bWii); - GetMenuBar()->FindItem(IDM_CONNECT_WIIMOTE2)-> - Enable(Initialized && SConfig::GetInstance().m_LocalCoreStartupParameter.bWii); - GetMenuBar()->FindItem(IDM_CONNECT_WIIMOTE3)-> - Enable(Initialized && SConfig::GetInstance().m_LocalCoreStartupParameter.bWii); - GetMenuBar()->FindItem(IDM_CONNECT_WIIMOTE4)-> - Enable(Initialized && SConfig::GetInstance().m_LocalCoreStartupParameter.bWii); - if (Initialized && SConfig::GetInstance().m_LocalCoreStartupParameter.bWii) + GetMenuBar()->FindItem(IDM_CONNECT_WIIMOTE1)->Enable(RunningWii); + GetMenuBar()->FindItem(IDM_CONNECT_WIIMOTE2)->Enable(RunningWii); + GetMenuBar()->FindItem(IDM_CONNECT_WIIMOTE3)->Enable(RunningWii); + GetMenuBar()->FindItem(IDM_CONNECT_WIIMOTE4)->Enable(RunningWii); + GetMenuBar()->FindItem(IDM_CONFIG_WIIMOTE_PLUGIN)->Enable(!RunningGamecube); + if (RunningWii) { GetMenuBar()->FindItem(IDM_CONNECT_WIIMOTE1)->Check(GetUsbPointer()-> AccessWiiMote(0x0100)->IsConnected()); @@ -1644,7 +1661,7 @@ void CFrame::UpdateGUI() } // Prepare to load last selected file, enable play button else if (!SConfig::GetInstance().m_LastFilename.empty() - && wxFileExists(wxString(SConfig::GetInstance().m_LastFilename.c_str(), wxConvUTF8))) + && wxFileExists(wxSafeConvertMB2WX(SConfig::GetInstance().m_LastFilename.c_str()))) { if (m_ToolBar) m_ToolBar->EnableTool(IDM_PLAY, true); diff --git a/Source/Core/DolphinWX/Src/GameListCtrl.cpp b/Source/Core/DolphinWX/Src/GameListCtrl.cpp index 8e0a498915..4a7d7d5dce 100644 --- a/Source/Core/DolphinWX/Src/GameListCtrl.cpp +++ b/Source/Core/DolphinWX/Src/GameListCtrl.cpp @@ -149,9 +149,6 @@ BEGIN_EVENT_TABLE(wxEmuStateTip, wxTipWindow) END_EVENT_TABLE() BEGIN_EVENT_TABLE(CGameListCtrl, wxListCtrl) -#ifdef _WIN32 - EVT_PAINT(CGameListCtrl::OnPaintDrawImages) -#endif EVT_SIZE(CGameListCtrl::OnSize) EVT_RIGHT_DOWN(CGameListCtrl::OnRightClick) EVT_LEFT_DOWN(CGameListCtrl::OnLeftClick) @@ -299,14 +296,19 @@ void CGameListCtrl::Update() InsertColumn(COLUMN_SIZE, _("Size")); InsertColumn(COLUMN_EMULATION_STATE, _("State")); - +#ifdef __WXMSW__ + const int platform_padding = 0; +#else + const int platform_padding = 8; +#endif + // set initial sizes for columns - SetColumnWidth(COLUMN_PLATFORM, 35); - SetColumnWidth(COLUMN_BANNER, 96); - SetColumnWidth(COLUMN_TITLE, 200); - SetColumnWidth(COLUMN_NOTES, 200); - SetColumnWidth(COLUMN_COUNTRY, 32); - SetColumnWidth(COLUMN_EMULATION_STATE, 50); + SetColumnWidth(COLUMN_PLATFORM, 35 + platform_padding); + SetColumnWidth(COLUMN_BANNER, 96 + platform_padding); + SetColumnWidth(COLUMN_TITLE, 200 + platform_padding); + SetColumnWidth(COLUMN_NOTES, 200 + platform_padding); + SetColumnWidth(COLUMN_COUNTRY, 32 + platform_padding); + SetColumnWidth(COLUMN_EMULATION_STATE, 50 + platform_padding); // add all items for (int i = 0; i < (int)m_ISOFiles.size(); i++) @@ -384,48 +386,6 @@ std::string CGameListCtrl::GetGameNames() const return m_gameList; } -#ifdef _WIN32 -// This draws our icons on top of the gamelist, it's only used on Windows -void CGameListCtrl::OnPaintDrawImages(wxPaintEvent& event) -{ - wxPaintDC dc(this); - - // Calls the default drawing code - wxControl::OnPaint(event); - - // Draw the flags, platform icons and emustate icons on top if there's games to show - if (m_ISOFiles.empty()) - return; - - // Retrieve the topmost shown item and get drawing offsets - const long - top_item = GetTopItem(), - bottom_item = std::min(top_item + GetCountPerPage() + 2, (long)GetItemCount()); - - int flagOffset = GetColumnWidth(0) + GetColumnWidth(1) + - GetColumnWidth(2) + GetColumnWidth(3); - int stateOffset = flagOffset + GetColumnWidth(4) + GetColumnWidth(5); - - // Only redraw shown lines - for (long i = top_item; i != bottom_item; ++i) - { - wxRect itemRect; - if (GetItemRect(i, itemRect)) - { - const int itemY = itemRect.GetTop(); - const GameListItem& rISOFile = *m_ISOFiles[GetItemData(i)]; - - m_imageListSmall->Draw(m_PlatformImageIndex[rISOFile.GetPlatform()], - dc, itemRect.GetX()+3, itemY); - m_imageListSmall->Draw(m_FlagImageIndex[rISOFile.GetCountry()], - dc, flagOffset, itemY); - m_imageListSmall->Draw(m_EmuStateImageIndex[rISOFile.GetEmuState()], - dc, stateOffset, itemY); - } - } -} -#endif - void CGameListCtrl::InsertItemInReportView(long _Index) { // When using wxListCtrl, there is no hope of per-column text colors. @@ -455,12 +415,8 @@ void CGameListCtrl::InsertItemInReportView(long _Index) m_gamePath.append(rISOFile.GetFileName() + '\n'); // Insert a first row with the platform image, that will be used as the Index -#ifndef _WIN32 long ItemIndex = InsertItem(_Index, wxEmptyString, m_PlatformImageIndex[rISOFile.GetPlatform()]); -#else - long ItemIndex = InsertItem(_Index, wxEmptyString, -1); -#endif if (rISOFile.GetImage().IsOk()) ImageIndex = m_imageListSmall->Add(rISOFile.GetImage()); @@ -516,13 +472,11 @@ void CGameListCtrl::InsertItemInReportView(long _Index) SetItem(_Index, COLUMN_TITLE, name, -1); SetItem(_Index, COLUMN_NOTES, description, -1); -#ifndef _WIN32 // Emulation state SetItemColumnImage(_Index, COLUMN_EMULATION_STATE, m_EmuStateImageIndex[rISOFile.GetEmuState()]); // Country SetItemColumnImage(_Index, COLUMN_COUNTRY, m_FlagImageIndex[rISOFile.GetCountry()]); -#endif // File size SetItem(_Index, COLUMN_SIZE, NiceSizeFormat(rISOFile.GetFileSize()), -1); @@ -599,6 +553,7 @@ void CGameListCtrl::ScanForISOs() Extensions.push_back("*.iso"); Extensions.push_back("*.ciso"); Extensions.push_back("*.gcz"); + Extensions.push_back("*.wbfs"); } if (SConfig::GetInstance().m_ListWad) Extensions.push_back("*.wad"); @@ -608,17 +563,17 @@ void CGameListCtrl::ScanForISOs() if (rFilenames.size() > 0) { - wxProgressDialog dialog(_("Scanning for ISOs"), - _("Scanning..."), - (int)rFilenames.size(), // range - this, // parent - wxPD_APP_MODAL | - wxPD_ELAPSED_TIME | - wxPD_ESTIMATED_TIME | - wxPD_REMAINING_TIME | - wxPD_SMOOTH // - makes indeterminate mode bar on WinXP very small - ); - dialog.CenterOnParent(); + wxProgressDialog dialog( + _("Scanning for ISOs"), + _("Scanning..."), + (int)rFilenames.size() - 1, + this, + wxPD_APP_MODAL | + wxPD_AUTO_HIDE | + wxPD_CAN_ABORT | + wxPD_ELAPSED_TIME | wxPD_ESTIMATED_TIME | wxPD_REMAINING_TIME | + wxPD_SMOOTH // - makes updates as small as possible (down to 1px) + ); for (u32 i = 0; i < rFilenames.size(); i++) { @@ -626,9 +581,9 @@ void CGameListCtrl::ScanForISOs() SplitPath(rFilenames[i], NULL, &FileName, NULL); // Update with the progress (i) and the message - bool Cont = dialog.Update(i, - wxString::Format(_("Scanning %s"), wxString(FileName.c_str(), *wxConvCurrent).c_str())); - if (!Cont) + dialog.Update(i, wxString::Format(_("Scanning %s"), + wxString(FileName.c_str(), *wxConvCurrent).c_str())); + if (dialog.WasCancelled()) break; std::auto_ptr<GameListItem> iso_file(new GameListItem(rFilenames[i])); @@ -723,8 +678,8 @@ const GameListItem *CGameListCtrl::GetISO(size_t index) const CGameListCtrl *caller; #if wxCHECK_VERSION(2, 9, 0) -int wxCALLBACK wxListCompare(long item1, long item2, wxIntPtr sortData) -#else +int wxCALLBACK wxListCompare(wxIntPtr item1, wxIntPtr item2, wxIntPtr sortData) +#else // 2.8.x int wxCALLBACK wxListCompare(long item1, long item2, long sortData) #endif { @@ -1140,20 +1095,15 @@ void CGameListCtrl::CompressSelection(bool _compress) if (browseDialog.ShowModal() != wxID_OK) return; - wxProgressDialog progressDialog(_compress ? - _("Compressing ISO") : _("Decompressing ISO"), - _("Working..."), - 1000, // range - this, // parent - wxPD_APP_MODAL | - wxPD_ELAPSED_TIME | - wxPD_ESTIMATED_TIME | - wxPD_REMAINING_TIME | - wxPD_SMOOTH // - makes indeterminate mode bar on WinXP very small - ); - - progressDialog.SetSize(wxSize(340, 180)); - progressDialog.CenterOnParent(); + wxProgressDialog progressDialog( + _compress ? _("Compressing ISO") : _("Decompressing ISO"), + _("Working..."), + 1000, + this, + wxPD_APP_MODAL | + wxPD_ELAPSED_TIME | wxPD_ESTIMATED_TIME | wxPD_REMAINING_TIME | + wxPD_SMOOTH + ); m_currentItem = 0; m_numberItem = GetSelectedItemCount(); @@ -1273,20 +1223,15 @@ void CGameListCtrl::OnCompressGCM(wxCommandEvent& WXUNUSED (event)) _("Confirm File Overwrite"), wxYES_NO) == wxNO); - wxProgressDialog dialog(iso->IsCompressed() ? - _("Decompressing ISO") : _("Compressing ISO"), - _("Working..."), - 1000, // range - this, // parent - wxPD_APP_MODAL | - wxPD_ELAPSED_TIME | - wxPD_ESTIMATED_TIME | - wxPD_REMAINING_TIME | - wxPD_SMOOTH // - makes indeterminate mode bar on WinXP very small - ); - - dialog.SetSize(wxSize(340, 180)); - dialog.CenterOnParent(); + wxProgressDialog dialog( + iso->IsCompressed() ? _("Decompressing ISO") : _("Compressing ISO"), + _("Working..."), + 1000, + this, + wxPD_APP_MODAL | + wxPD_ELAPSED_TIME | wxPD_ESTIMATED_TIME | wxPD_REMAINING_TIME | + wxPD_SMOOTH + ); if (iso->IsCompressed()) DiscIO::DecompressBlobToFile(iso->GetFileName().c_str(), diff --git a/Source/Core/DolphinWX/Src/GameListCtrl.h b/Source/Core/DolphinWX/Src/GameListCtrl.h index 8fca14f632..274cfdb7ee 100644 --- a/Source/Core/DolphinWX/Src/GameListCtrl.h +++ b/Source/Core/DolphinWX/Src/GameListCtrl.h @@ -99,7 +99,6 @@ private: DECLARE_EVENT_TABLE() // events - void OnPaintDrawImages(wxPaintEvent& event); void OnLeftClick(wxMouseEvent& event); void OnRightClick(wxMouseEvent& event); void OnMouseMotion(wxMouseEvent& event); diff --git a/Source/Core/DolphinWX/Src/ISOProperties.cpp b/Source/Core/DolphinWX/Src/ISOProperties.cpp index b5e5c82d1d..f004989055 100644 --- a/Source/Core/DolphinWX/Src/ISOProperties.cpp +++ b/Source/Core/DolphinWX/Src/ISOProperties.cpp @@ -75,6 +75,7 @@ BEGIN_EVENT_TABLE(CISOProperties, wxDialog) EVT_MENU(IDM_EXTRACTALL, CISOProperties::OnExtractDir) EVT_MENU(IDM_EXTRACTAPPLOADER, CISOProperties::OnExtractDataFromHeader) EVT_MENU(IDM_EXTRACTDOL, CISOProperties::OnExtractDataFromHeader) + EVT_MENU(IDM_CHECKINTEGRITY, CISOProperties::CheckPartitionIntegrity) EVT_CHOICE(ID_LANG, CISOProperties::OnChangeBannerLang) END_EVENT_TABLE() @@ -635,6 +636,13 @@ void CISOProperties::OnRightClickOnTree(wxTreeEvent& event) popupMenu->Append(IDM_EXTRACTAPPLOADER, _("Extract Apploader...")); popupMenu->Append(IDM_EXTRACTDOL, _("Extract DOL...")); + if (m_Treectrl->GetItemImage(m_Treectrl->GetSelection()) == 0 + && m_Treectrl->GetFirstVisibleItem() != m_Treectrl->GetSelection()) + { + popupMenu->AppendSeparator(); + popupMenu->Append(IDM_CHECKINTEGRITY, _("Check Partition Integrity")); + } + PopupMenu(popupMenu); event.Skip(); @@ -718,22 +726,26 @@ void CISOProperties::ExportDir(const char* _rFullPath, const char* _rExportFolde } wxString dialogTitle = index[0] ? _("Extracting Directory") : _("Extracting All Files"); - wxProgressDialog dialog(dialogTitle, - _("Extracting..."), - index[1], // range - this, // parent - wxPD_APP_MODAL | wxPD_AUTO_HIDE | wxPD_CAN_ABORT | - wxPD_ELAPSED_TIME | wxPD_ESTIMATED_TIME | wxPD_REMAINING_TIME | - wxPD_SMOOTH // - makes indeterminate mode bar on WinXP very small - ); - dialog.CenterOnParent(); + wxProgressDialog dialog( + dialogTitle, + _("Extracting..."), + index[1] - 1, + this, + wxPD_APP_MODAL | wxPD_AUTO_HIDE | wxPD_CAN_ABORT | + wxPD_ELAPSED_TIME | wxPD_ESTIMATED_TIME | wxPD_REMAINING_TIME | + wxPD_SMOOTH + ); // Extraction for (u32 i = index[0]; i < index[1]; i++) { dialog.SetTitle(wxString::Format(wxT("%s : %d%%"), dialogTitle.c_str(), (u32)(((float)(i - index[0]) / (float)(index[1] - index[0])) * 100))); - if (!dialog.Update(i, wxString::Format(_("Extracting %s"), wxString(fst[i]->m_FullPath, *wxConvCurrent).c_str()))) + + dialog.Update(i, wxString::Format(_("Extracting %s"), + wxString(fst[i]->m_FullPath, *wxConvCurrent).c_str())); + + if (dialog.WasCancelled()) break; if (fst[i]->IsDirectory()) @@ -836,6 +848,71 @@ void CISOProperties::OnExtractDataFromHeader(wxCommandEvent& event) PanicAlertT("Failed to extract to %s!", (const char *)Path.mb_str()); } +class IntegrityCheckThread : public wxThread +{ +public: + IntegrityCheckThread(const WiiPartition& Partition) + : wxThread(wxTHREAD_JOINABLE), m_Partition(Partition) + { + Create(); + } + + virtual ExitCode Entry() + { + return (ExitCode)m_Partition.Partition->CheckIntegrity(); + } + +private: + const WiiPartition& m_Partition; +}; + +void CISOProperties::CheckPartitionIntegrity(wxCommandEvent& event) +{ + // Normally we can't enter this function if we aren't analyzing a Wii disc + // anyway, but let's still check to be sure. + if (!DiscIO::IsVolumeWiiDisc(OpenISO)) + return; + + wxString PartitionName = m_Treectrl->GetItemText(m_Treectrl->GetSelection()); + if (!PartitionName) + return; + + // Get the partition number from the item text ("Partition N") + int PartitionNum = wxAtoi(PartitionName.SubString(10, 11)); + const WiiPartition& Partition = WiiDisc[PartitionNum]; + + wxProgressDialog* dialog = new wxProgressDialog( + _("Checking integrity..."), _("Working..."), 1000, this, + wxPD_APP_MODAL | wxPD_ELAPSED_TIME | wxPD_SMOOTH + ); + + IntegrityCheckThread thread(Partition); + thread.Run(); + + while (thread.IsAlive()) + { + dialog->Pulse(); + wxThread::Sleep(50); + } + + delete dialog; + + if (!thread.Wait()) + { + wxMessageBox( + wxString::Format(_("Integrity check for partition %d failed. " + "Your dump is most likely corrupted or has been " + "patched incorrectly."), PartitionNum), + _("Integrity Check Error"), wxOK | wxICON_ERROR, this + ); + } + else + { + wxMessageBox(_("Integrity check completed. No errors have been found."), + _("Integrity check completed"), wxOK | wxICON_INFORMATION, this); + } +} + void CISOProperties::SetRefresh(wxCommandEvent& event) { bRefreshList = true; diff --git a/Source/Core/DolphinWX/Src/ISOProperties.h b/Source/Core/DolphinWX/Src/ISOProperties.h index 6e72993b42..da275136fe 100644 --- a/Source/Core/DolphinWX/Src/ISOProperties.h +++ b/Source/Core/DolphinWX/Src/ISOProperties.h @@ -170,6 +170,7 @@ private: IDM_EXTRACTFILE, IDM_EXTRACTAPPLOADER, IDM_EXTRACTDOL, + IDM_CHECKINTEGRITY, IDM_BNRSAVEAS }; @@ -186,6 +187,7 @@ private: void OnExtractFile(wxCommandEvent& event); void OnExtractDir(wxCommandEvent& event); void OnExtractDataFromHeader(wxCommandEvent& event); + void CheckPartitionIntegrity(wxCommandEvent& event); void SetRefresh(wxCommandEvent& event); void OnChangeBannerLang(wxCommandEvent& event); void PHackButtonClicked(wxCommandEvent& event); diff --git a/Source/Core/DolphinWX/Src/InputConfigDiag.cpp b/Source/Core/DolphinWX/Src/InputConfigDiag.cpp index 87cecde27d..b3d57ae89c 100644 --- a/Source/Core/DolphinWX/Src/InputConfigDiag.cpp +++ b/Source/Core/DolphinWX/Src/InputConfigDiag.cpp @@ -887,7 +887,7 @@ ControlGroupsSizer::ControlGroupsSizer(ControllerEmu* const controller, wxWindow } GamepadPage::GamepadPage(wxWindow* parent, InputPlugin& plugin, const unsigned int pad_num, InputConfigDialog* const config_dialog) - : wxNotebookPage(parent, -1 , wxDefaultPosition, wxDefaultSize) + : wxPanel(parent, wxID_ANY, wxDefaultPosition, wxDefaultSize) ,controller(plugin.controllers[pad_num]) , m_config_dialog(config_dialog) , m_plugin(plugin) diff --git a/Source/Core/DolphinWX/Src/InputConfigDiag.h b/Source/Core/DolphinWX/Src/InputConfigDiag.h index 54f828b952..53f06a1144 100644 --- a/Source/Core/DolphinWX/Src/InputConfigDiag.h +++ b/Source/Core/DolphinWX/Src/InputConfigDiag.h @@ -177,7 +177,7 @@ public: class InputConfigDialog; -class GamepadPage : public wxNotebookPage +class GamepadPage : public wxPanel { friend class InputConfigDialog; friend class ControlDialog; diff --git a/Source/Core/DolphinWX/Src/LogWindow.cpp b/Source/Core/DolphinWX/Src/LogWindow.cpp index 0d11ef0142..4c9c495713 100644 --- a/Source/Core/DolphinWX/Src/LogWindow.cpp +++ b/Source/Core/DolphinWX/Src/LogWindow.cpp @@ -41,7 +41,7 @@ CLogWindow::CLogWindow(CFrame *parent, wxWindowID id, const wxPoint& pos, , x(0), y(0), winpos(0) , Parent(parent), m_ignoreLogTimer(false), m_LogAccess(true) , m_Log(NULL), m_cmdline(NULL), m_FontChoice(NULL) - , m_SJISConv(*(wxCSConv*)wxConvCurrent) + , m_SJISConv(wxT("")) { #ifdef _WIN32 static bool validCP932 = ::IsValidCodePage(932) != 0; @@ -52,6 +52,7 @@ CLogWindow::CLogWindow(CFrame *parent, wxWindowID id, const wxPoint& pos, else { WARN_LOG(COMMON, "Cannot Convert from Charset Windows Japanese cp 932"); + m_SJISConv = *(wxCSConv*)wxConvCurrent; } #else // on linux the wrong string is returned from wxFontMapper::GetEncodingName(wxFONTENCODING_SHIFT_JIS) diff --git a/Source/Core/DolphinWX/Src/Main.cpp b/Source/Core/DolphinWX/Src/Main.cpp index 709c2b4b53..d38c90e07f 100644 --- a/Source/Core/DolphinWX/Src/Main.cpp +++ b/Source/Core/DolphinWX/Src/Main.cpp @@ -115,37 +115,37 @@ bool DolphinApp::OnInit() wxCmdLineEntryDesc cmdLineDesc[] = { { - wxCMD_LINE_SWITCH, wxS("h"), wxS("help"), + wxCMD_LINE_SWITCH, "h", "help", _("Show this help message"), wxCMD_LINE_VAL_NONE, wxCMD_LINE_OPTION_HELP }, { - wxCMD_LINE_SWITCH, wxS("d"), wxS("debugger"), + wxCMD_LINE_SWITCH, "d", "debugger", _("Opens the debugger"), wxCMD_LINE_VAL_NONE, wxCMD_LINE_PARAM_OPTIONAL }, { - wxCMD_LINE_SWITCH, wxS("l"), wxS("logger"), + wxCMD_LINE_SWITCH, "l", "logger", _("Opens the logger"), wxCMD_LINE_VAL_NONE, wxCMD_LINE_PARAM_OPTIONAL }, { - wxCMD_LINE_OPTION, wxS("e"), wxS("exec"), + wxCMD_LINE_OPTION, "e", "exec", _("Loads the specified file (DOL,ELF,GCM,ISO,WAD)"), wxCMD_LINE_VAL_STRING, wxCMD_LINE_PARAM_OPTIONAL }, { - wxCMD_LINE_SWITCH, wxS("b"), wxS("batch"), + wxCMD_LINE_SWITCH, "b", "batch", _("Exit Dolphin with emulator"), wxCMD_LINE_VAL_NONE, wxCMD_LINE_PARAM_OPTIONAL }, { - wxCMD_LINE_OPTION, wxS("V"), wxS("video_backend"), + wxCMD_LINE_OPTION, "V", "video_backend", _("Specify a video backend"), wxCMD_LINE_VAL_STRING, wxCMD_LINE_PARAM_OPTIONAL }, { - wxCMD_LINE_OPTION, wxS("A"), wxS("audio_emulation"), + wxCMD_LINE_OPTION, "A", "audio_emulation", _("Low level (LLE) or high level (HLE) audio"), wxCMD_LINE_VAL_STRING, wxCMD_LINE_PARAM_OPTIONAL }, diff --git a/Source/Core/DolphinWX/Src/MemcardManager.cpp b/Source/Core/DolphinWX/Src/MemcardManager.cpp index 98390122e2..a6ed1513c6 100644 --- a/Source/Core/DolphinWX/Src/MemcardManager.cpp +++ b/Source/Core/DolphinWX/Src/MemcardManager.cpp @@ -101,6 +101,7 @@ CMemcardManager::CMemcardManager(wxWindow* parent, wxWindowID id, const wxString memoryCard[SLOT_A]=NULL; memoryCard[SLOT_B]=NULL; + mcmSettings.twoCardsLoaded = false; if (!LoadSettings()) { itemsPerPage = 16; @@ -283,7 +284,7 @@ void CMemcardManager::ChangePath(int slot) m_PrevPage[slot]->Disable(); m_MemcardList[slot]->prevPage = false; } - if (!strcasecmp(m_MemcardPath[slot2]->GetPath().mb_str(), m_MemcardPath[slot]->GetPath().mb_str())) + if (!m_MemcardPath[SLOT_A]->GetPath().CmpNoCase(m_MemcardPath[SLOT_B]->GetPath())) { if(m_MemcardPath[slot]->GetPath().length()) PanicAlertT("Memcard already opened"); @@ -292,7 +293,10 @@ void CMemcardManager::ChangePath(int slot) { if (m_MemcardPath[slot]->GetPath().length() && ReloadMemcard(m_MemcardPath[slot]->GetPath().mb_str(), slot)) { - mcmSettings.twoCardsLoaded = true; + if (memoryCard[slot2]) + { + mcmSettings.twoCardsLoaded = true; + } m_SaveImport[slot]->Enable(); m_SaveExport[slot]->Enable(); m_Delete[slot]->Enable(); @@ -318,16 +322,9 @@ void CMemcardManager::ChangePath(int slot) } } } - if (m_Delete[SLOT_A]->IsEnabled() && m_Delete[SLOT_B]->IsEnabled()) - { - m_CopyFrom[SLOT_A]->Enable(); - m_CopyFrom[SLOT_B]->Enable(); - } - else - { - m_CopyFrom[SLOT_A]->Disable(); - m_CopyFrom[SLOT_B]->Disable(); - } + + m_CopyFrom[SLOT_A]->Enable(mcmSettings.twoCardsLoaded); + m_CopyFrom[SLOT_B]->Enable(mcmSettings.twoCardsLoaded); } void CMemcardManager::OnPageChange(wxCommandEvent& event) @@ -496,6 +493,7 @@ void CMemcardManager::CopyDeleteClick(wxCommandEvent& event) slot2 = SLOT_B; case ID_COPYFROM_A: index = slot2 ? index_B : index_A; + index = memoryCard[slot2]->GetFileIndex(index); if ((index != wxNOT_FOUND)) { CopyDeleteSwitch(memoryCard[slot]->CopyFrom(*memoryCard[slot2], index), slot); @@ -545,17 +543,19 @@ void CMemcardManager::CopyDeleteClick(wxCommandEvent& event) slot=SLOT_A; index = index_A; case ID_SAVEEXPORT_B: + index = memoryCard[slot]->GetFileIndex(index); if (index != wxNOT_FOUND) { - char tempC[10 + DENTRY_STRLEN], - tempC2[DENTRY_STRLEN]; - memoryCard[slot]->DEntry_GameCode(index,tempC); - memoryCard[slot]->DEntry_FileName(index,tempC2); - sprintf(tempC, "%s_%s.gci", tempC, tempC2); + std::string gciFilename; + if (!memoryCard[slot]->GCI_FileName(index, gciFilename)) + { + PanicAlert("invalid index"); + return; + } wxString fileName = wxFileSelector( _("Export save as..."), wxString::From8BitData(DefaultIOPath.c_str()), - wxString::From8BitData(tempC), wxT(".gci"), + wxString::From8BitData(gciFilename.c_str()), wxT(".gci"), _("Native GCI files(*.gci)") + wxString(wxT("|*.gci|")) + _("MadCatz Gameshark files(*.gcs)") + wxString(wxT("|*.gcs|")) + _("Datel MaxDrive/Pro files(*.sav)") + wxString(wxT("|*.sav")), @@ -563,7 +563,7 @@ void CMemcardManager::CopyDeleteClick(wxCommandEvent& event) if (fileName.length() > 0) { - if (!CopyDeleteSwitch(memoryCard[slot]->ExportGci(index, fileName.mb_str(), NULL), -1)) + if (!CopyDeleteSwitch(memoryCard[slot]->ExportGci(index, fileName.mb_str(), ""), -1)) { File::Delete(std::string(fileName.mb_str())); } @@ -583,7 +583,7 @@ void CMemcardManager::CopyDeleteClick(wxCommandEvent& event) "%s\nand have the same name as a file on your memcard\nContinue?", path1.c_str())) for (int i = 0; i < DIRLEN; i++) { - CopyDeleteSwitch(memoryCard[slot]->ExportGci(i, ".", &path1), -1); + CopyDeleteSwitch(memoryCard[slot]->ExportGci(i, NULL, path1), -1); } break; } @@ -591,6 +591,7 @@ void CMemcardManager::CopyDeleteClick(wxCommandEvent& event) slot = SLOT_A; index = index_A; case ID_DELETE_B: + index = memoryCard[slot]->GetFileIndex(index); if (index != wxNOT_FOUND) { CopyDeleteSwitch(memoryCard[slot]->RemoveFile(index), slot); @@ -614,8 +615,7 @@ bool CMemcardManager::ReloadMemcard(const char *fileName, int card) wxComment, wxBlock, wxFirstBlock, - wxLabel, - tString; + wxLabel; m_MemcardList[card]->Hide(); @@ -631,18 +631,19 @@ bool CMemcardManager::ReloadMemcard(const char *fileName, int card) wxImageList *list = m_MemcardList[card]->GetImageList(wxIMAGE_LIST_SMALL); list->RemoveAll(); - int nFiles = memoryCard[card]->GetNumFiles(); + u8 nFiles = memoryCard[card]->GetNumFiles(); int *images = new int[nFiles*2]; - for (int i = 0;i < nFiles;i++) + for (u8 i = 0;i < nFiles;i++) { static u32 pxdata[96*32]; static u8 animDelay[8]; static u32 animData[32*32*8]; - int numFrames = memoryCard[card]->ReadAnimRGBA8(i,animData,animDelay); + u8 fileIndex = memoryCard[card]->GetFileIndex(i); + int numFrames = memoryCard[card]->ReadAnimRGBA8(fileIndex, animData, animDelay); - if (!memoryCard[card]->ReadBannerRGBA8(i,pxdata)) + if (!memoryCard[card]->ReadBannerRGBA8(fileIndex, pxdata)) { memset(pxdata,0,96*32*4); @@ -688,17 +689,17 @@ bool CMemcardManager::ReloadMemcard(const char *fileName, int card) for (j = page[card] * itemsPerPage; (j < nFiles) && (j < pagesMax); j++) { - char title[DENTRY_STRLEN]; - char comment[DENTRY_STRLEN]; u16 blocks; u16 firstblock; + u8 fileIndex = memoryCard[card]->GetFileIndex(j); + int index = m_MemcardList[card]->InsertItem(j, wxEmptyString); m_MemcardList[card]->SetItem(index, COLUMN_BANNER, wxEmptyString); - if (!memoryCard[card]->DEntry_Comment1(j, title)) title[0]=0; - if (!memoryCard[card]->DEntry_Comment2(j, comment)) comment[0]=0; + std::string title = memoryCard[card]->GetSaveComment1(fileIndex); + std::string comment = memoryCard[card]->GetSaveComment2(fileIndex); bool ascii = memoryCard[card]->IsAsciiEncoding(); @@ -718,20 +719,20 @@ bool CMemcardManager::ReloadMemcard(const char *fileName, int card) // it returns CP-932, in order to use iconv we need to use CP932 wxCSConv SJISConv(wxT("CP932")); #endif - wxTitle = wxString(title, ascii ? *wxConvCurrent : SJISConv); - wxComment = wxString(comment, ascii ? *wxConvCurrent : SJISConv); + wxTitle = wxString(title.c_str(), ascii ? *wxConvCurrent : SJISConv); + wxComment = wxString(comment.c_str(), ascii ? *wxConvCurrent : SJISConv); m_MemcardList[card]->SetItem(index, COLUMN_TITLE, wxTitle); m_MemcardList[card]->SetItem(index, COLUMN_COMMENT, wxComment); - blocks = memoryCard[card]->DEntry_BlockCount(j); + blocks = memoryCard[card]->DEntry_BlockCount(fileIndex); if (blocks == 0xFFFF) blocks = 0; wxBlock.Printf(wxT("%10d"), blocks); m_MemcardList[card]->SetItem(index,COLUMN_BLOCKS, wxBlock); - firstblock = memoryCard[card]->DEntry_FirstBlock(j); - if (firstblock == 0xFFFF) firstblock = 3; // to make firstblock -1 - wxFirstBlock.Printf(wxT("%15d"), firstblock-4); - m_MemcardList[card]->SetItem(index,COLUMN_FIRSTBLOCK, wxFirstBlock); + firstblock = memoryCard[card]->DEntry_FirstBlock(fileIndex); + //if (firstblock == 0xFFFF) firstblock = 3; // to make firstblock -1 + wxFirstBlock.Printf(wxT("%15d"), firstblock); + m_MemcardList[card]->SetItem(index, COLUMN_FIRSTBLOCK, wxFirstBlock); m_MemcardList[card]->SetItem(index, COLUMN_ICON, wxEmptyString); if (images[j] >= 0) diff --git a/Source/Core/DolphinWX/Src/NetWindow.cpp b/Source/Core/DolphinWX/Src/NetWindow.cpp index 0e17e70bae..0347385e73 100644 --- a/Source/Core/DolphinWX/Src/NetWindow.cpp +++ b/Source/Core/DolphinWX/Src/NetWindow.cpp @@ -29,7 +29,6 @@ #define NETPLAY_TITLEBAR "Dolphin NetPlay" -DEFINE_EVENT_TYPE(wxEVT_THREAD) BEGIN_EVENT_TABLE(NetPlayDiag, wxFrame) EVT_COMMAND(wxID_ANY, wxEVT_THREAD, NetPlayDiag::OnThread) END_EVENT_TABLE() diff --git a/Source/Core/DolphinWX/Src/NetWindow.h b/Source/Core/DolphinWX/Src/NetWindow.h index 0e70d352e8..ae27a75921 100644 --- a/Source/Core/DolphinWX/Src/NetWindow.h +++ b/Source/Core/DolphinWX/Src/NetWindow.h @@ -24,6 +24,7 @@ #include <string> #include <wx/wx.h> +#include <wx/event.h> #include <wx/sizer.h> #include <wx/dialog.h> #include <wx/notebook.h> @@ -114,8 +115,6 @@ private: static NetPlayDiag* npd; }; -DECLARE_EVENT_TYPE(wxEVT_THREAD, -1) - class ChangeGameDiag : public wxDialog { public: diff --git a/Source/Core/DolphinWX/Src/TASInputDlg.cpp b/Source/Core/DolphinWX/Src/TASInputDlg.cpp index 689681d199..65d17f6e03 100644 --- a/Source/Core/DolphinWX/Src/TASInputDlg.cpp +++ b/Source/Core/DolphinWX/Src/TASInputDlg.cpp @@ -371,5 +371,11 @@ void TASInputDlg::OnCloseWindow(wxCloseEvent& event) bool TASInputDlg::HasFocus() { - return (wxWindow::FindFocus() == this || wxWindow::FindFocus()->GetParent() == this); + if (wxWindow::FindFocus() == this) + return true; + else if (wxWindow::FindFocus() != NULL && + wxWindow::FindFocus()->GetParent() == this) + return true; + else + return false; } diff --git a/Source/Core/DolphinWX/Src/VideoConfigDiag.cpp b/Source/Core/DolphinWX/Src/VideoConfigDiag.cpp index 75252cdc67..b197109c33 100644 --- a/Source/Core/DolphinWX/Src/VideoConfigDiag.cpp +++ b/Source/Core/DolphinWX/Src/VideoConfigDiag.cpp @@ -75,6 +75,7 @@ wxString adapter_desc = wxTRANSLATE("Select a hardware adapter to use.\n\nIf uns wxString display_res_desc = wxTRANSLATE("Selects the display resolution used in fullscreen mode.\nThis should always be bigger than or equal to the internal resolution. Performance impact is negligible.\n\nIf unsure, use your desktop resolution.\nIf still unsure, use the highest resolution which works for you."); wxString use_fullscreen_desc = wxTRANSLATE("Enable this if you want the whole screen to be used for rendering.\nIf this is disabled, a render window will be created instead.\n\nIf unsure, leave this unchecked."); wxString auto_window_size_desc = wxTRANSLATE("Automatically adjusts the window size to your internal resolution.\n\nIf unsure, leave this unchecked."); +wxString keep_window_on_top_desc = wxTRANSLATE("Keep the game window on top of all other windows.\n\nIf unsure, leave this unchecked."); wxString hide_mouse_cursor_desc = wxTRANSLATE("Hides the mouse cursor if it's on top of the emulation window.\n\nIf unsure, leave this checked."); wxString render_to_main_win_desc = wxTRANSLATE("Enable this if you want to use the main Dolphin window for rendering rather than a separate render window.\n\nIf unsure, leave this unchecked."); wxString prog_scan_desc = wxTRANSLATE("Enables progressive scan if supported by the emulated software.\nMost games don't care about this.\n\nIf unsure, leave this unchecked."); @@ -301,6 +302,7 @@ VideoConfigDiag::VideoConfigDiag(wxWindow* parent, const std::string &title, con SettingCheckBox* render_to_main_cb; szr_other->Add(CreateCheckBox(page_general, _("Show FPS"), wxGetTranslation(show_fps_desc), vconfig.bShowFPS)); szr_other->Add(CreateCheckBox(page_general, _("Auto adjust Window Size"), wxGetTranslation(auto_window_size_desc), SConfig::GetInstance().m_LocalCoreStartupParameter.bRenderWindowAutoSize)); + szr_other->Add(CreateCheckBox(page_general, _("Keep window on top"), wxGetTranslation(keep_window_on_top_desc), SConfig::GetInstance().m_LocalCoreStartupParameter.bKeepWindowOnTop)); szr_other->Add(CreateCheckBox(page_general, _("Hide Mouse Cursor"), wxGetTranslation(hide_mouse_cursor_desc), SConfig::GetInstance().m_LocalCoreStartupParameter.bHideCursor)); szr_other->Add(render_to_main_cb = CreateCheckBox(page_general, _("Render to Main Window"), wxGetTranslation(render_to_main_win_desc), SConfig::GetInstance().m_LocalCoreStartupParameter.bRenderToMain)); diff --git a/Source/Core/DolphinWX/Src/WXInputBase.cpp b/Source/Core/DolphinWX/Src/WXInputBase.cpp index 3ed7f60ecd..467371ae9c 100644 --- a/Source/Core/DolphinWX/Src/WXInputBase.cpp +++ b/Source/Core/DolphinWX/Src/WXInputBase.cpp @@ -43,7 +43,10 @@ const wxString WXKeyToString(int keycode) case WXK_CLEAR: return _("Clear"); case WXK_SHIFT: return wxT("Shift"); case WXK_ALT: return wxT("Alt"); - case WXK_CONTROL: return _("Control"); + case WXK_RAW_CONTROL: return _("Control"); +#ifdef __WXOSX__ + case WXK_COMMAND: return _("Command"); +#endif case WXK_MENU: return _("Menu"); case WXK_PAUSE: return _("Pause"); case WXK_CAPITAL: return _("Caps Lock"); @@ -131,7 +134,6 @@ const wxString WXKeyToString(int keycode) case WXK_WINDOWS_LEFT: return _("Windows Left"); case WXK_WINDOWS_RIGHT: return _("Windows Right"); case WXK_WINDOWS_MENU: return _("Windows Menu"); - case WXK_COMMAND: return _("Command"); } if (keycode > WXK_SPACE && keycode < WXK_DELETE) { diff --git a/Source/Core/InputCommon/InputCommon.vcxproj b/Source/Core/InputCommon/InputCommon.vcxproj index 8eed835b2d..dc987d83a2 100644 --- a/Source/Core/InputCommon/InputCommon.vcxproj +++ b/Source/Core/InputCommon/InputCommon.vcxproj @@ -191,7 +191,6 @@ </ItemGroup> <ItemGroup> <None Include="CMakeLists.txt" /> - <None Include="Src\SConscript" /> </ItemGroup> <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" /> <ImportGroup Label="ExtensionTargets"> diff --git a/Source/Core/InputCommon/InputCommon.vcxproj.filters b/Source/Core/InputCommon/InputCommon.vcxproj.filters index c6acfdd6b3..311476bc72 100644 --- a/Source/Core/InputCommon/InputCommon.vcxproj.filters +++ b/Source/Core/InputCommon/InputCommon.vcxproj.filters @@ -54,7 +54,6 @@ </ItemGroup> <ItemGroup> <None Include="CMakeLists.txt" /> - <None Include="Src\SConscript" /> </ItemGroup> <ItemGroup> <Filter Include="ControllerInterface"> diff --git a/Source/Core/InputCommon/SConscript b/Source/Core/InputCommon/SConscript deleted file mode 100644 index 82e0de571c..0000000000 --- a/Source/Core/InputCommon/SConscript +++ /dev/null @@ -1,34 +0,0 @@ -# -*- python -*- - -import sys -Import('env') - -files = [ - 'Src/ControllerEmu.cpp', - 'Src/ControllerInterface/ControllerInterface.cpp', - 'Src/InputConfig.cpp', - 'Src/UDPWiimote.cpp', - 'Src/UDPWrapper.cpp', - ] - -if sys.platform == 'win32': - files += [ - 'Src/ControllerInterface/DInput/DInput.cpp', - 'Src/ControllerInterface/DInput/DInputJoystick.cpp', - 'Src/ControllerInterface/DInput/DInputKeyboardMouse.cpp' - 'Src/ControllerInterface/SDL/SDL.cpp', - 'Src/ControllerInterface/XInput/XInput.cpp', - ] -elif sys.platform == 'darwin': - files += [ - 'Src/ControllerInterface/OSX/OSX.mm', - 'Src/ControllerInterface/OSX/OSXKeyboard.mm', - 'Src/ControllerInterface/OSX/OSXJoystick.mm', - ] -elif env['HAVE_X11']: - files += [ - 'Src/ControllerInterface/SDL/SDL.cpp', - 'Src/ControllerInterface/Xlib/Xlib.cpp', - ] - -env['LIBS'] += env.StaticLibrary('inputcommon', files) diff --git a/Source/Core/InputCommon/Src/ControllerInterface/DInput/DInputJoystick.cpp b/Source/Core/InputCommon/Src/ControllerInterface/DInput/DInputJoystick.cpp index d37d1eb2ba..08d62bcfc1 100644 --- a/Source/Core/InputCommon/Src/ControllerInterface/DInput/DInputJoystick.cpp +++ b/Source/Core/InputCommon/Src/ControllerInterface/DInput/DInputJoystick.cpp @@ -241,7 +241,7 @@ Joystick::Joystick( /*const LPCDIDEVICEINSTANCE lpddi, */const LPDIRECTINPUTDEVI { // each hat gets 4 input instances associated with it, (up down left right) for (u8 d = 0; d != 4; ++d) - AddInput(new Hat(i, m_state_in.rgdwPOV[m_index], d)); + AddInput(new Hat(i, m_state_in.rgdwPOV[i], d)); } // get up to 6 axes and 2 sliders diff --git a/Source/Core/VideoCommon/SConscript b/Source/Core/VideoCommon/SConscript deleted file mode 100644 index 5499f422db..0000000000 --- a/Source/Core/VideoCommon/SConscript +++ /dev/null @@ -1,48 +0,0 @@ -# -*- python -*- - -Import('env') - -files = [ - 'Src/BPFunctions.cpp', - 'Src/BPMemory.cpp', - 'Src/BPStructs.cpp', - 'Src/CPMemory.cpp', - 'Src/CommandProcessor.cpp', - 'Src/DLCache.cpp', - 'Src/Debugger.cpp', - 'Src/Fifo.cpp', - 'Src/FramebufferManagerBase.cpp', - 'Src/HiresTextures.cpp', - 'Src/ImageWrite.cpp', - 'Src/IndexGenerator.cpp', - 'Src/LightingShaderGen.cpp', - 'Src/MainBase.cpp', - 'Src/OnScreenDisplay.cpp', - 'Src/OpcodeDecoding.cpp', - 'Src/OpenCL.cpp', - 'Src/OpenCL/OCLTextureDecoder.cpp', - 'Src/PixelEngine.cpp', - 'Src/PixelShaderGen.cpp', - 'Src/PixelShaderManager.cpp', - 'Src/RenderBase.cpp', - 'Src/Statistics.cpp', - 'Src/TextureCacheBase.cpp', - 'Src/TextureConversionShader.cpp', - 'Src/TextureDecoder.cpp', - 'Src/VertexLoader.cpp', - 'Src/VertexLoaderManager.cpp', - 'Src/VertexLoader_Color.cpp', - 'Src/VertexLoader_Normal.cpp', - 'Src/VertexLoader_Position.cpp', - 'Src/VertexLoader_TextCoord.cpp', - 'Src/VertexManagerBase.cpp', - 'Src/VertexShaderGen.cpp', - 'Src/VertexShaderManager.cpp', - 'Src/VideoConfig.cpp', - 'Src/VideoState.cpp', - 'Src/XFMemory.cpp', - 'Src/XFStructs.cpp', - 'Src/memcpy_amd.cpp', - ] - -env['LIBS'] += env.StaticLibrary('videocommon', files) diff --git a/Source/Core/VideoCommon/Src/AVIDump.cpp b/Source/Core/VideoCommon/Src/AVIDump.cpp index 670693690b..4c31798d9f 100644 --- a/Source/Core/VideoCommon/Src/AVIDump.cpp +++ b/Source/Core/VideoCommon/Src/AVIDump.cpp @@ -211,6 +211,7 @@ extern "C" { #include <libavcodec/avcodec.h> #include <libavformat/avformat.h> #include <libswscale/swscale.h> +#include <libavutil/mathematics.h> } AVFormatContext *s_FormatContext = NULL; diff --git a/Source/Core/VideoCommon/Src/BPMemory.cpp b/Source/Core/VideoCommon/Src/BPMemory.cpp index 5c4ed457e3..d5b762c1a4 100644 --- a/Source/Core/VideoCommon/Src/BPMemory.cpp +++ b/Source/Core/VideoCommon/Src/BPMemory.cpp @@ -66,3 +66,113 @@ void BPReload() } } } + + +void GetBPRegInfo(const u8* data, char* name, size_t name_size, char* desc, size_t desc_size) +{ + const char* no_yes[2] = { "No", "Yes" }; + + u32 cmddata = Common::swap32(*(u32*)data) & 0xFFFFFF; + switch (data[0]) + { + // Macro to set the register name and make sure it was written correctly via compile time assertion + #define SetRegName(reg) \ + snprintf(name, name_size, #reg); \ + (void)(reg); + + case BPMEM_DISPLAYCOPYFILER: // 0x01 + // TODO: This is actually the sample pattern used for copies from an antialiased EFB + SetRegName(BPMEM_DISPLAYCOPYFILER); + // TODO: Description + break; + + case 0x02: // 0x02 + case 0x03: // 0x03 + case 0x04: // 0x04 + // TODO: same as BPMEM_DISPLAYCOPYFILER + break; + + case BPMEM_EFB_TL: // 0x49 + { + SetRegName(BPMEM_EFB_TL); + X10Y10 left_top; left_top.hex = cmddata; + snprintf(desc, desc_size, "Left: %d\nTop: %d", left_top.x, left_top.y); + } + break; + + case BPMEM_EFB_BR: // 0x4A + { + // TODO: Misleading name, should be BPMEM_EFB_WH instead + SetRegName(BPMEM_EFB_BR); + X10Y10 width_height; width_height.hex = cmddata; + snprintf(desc, desc_size, "Width: %d\nHeight: %d", width_height.x+1, width_height.y+1); + } + break; + + case BPMEM_EFB_ADDR: // 0x4B + SetRegName(BPMEM_EFB_ADDR); + snprintf(desc, desc_size, "Target address (32 byte aligned): 0x%06X", cmddata << 5); + break; + + case BPMEM_COPYYSCALE: // 0x4E + SetRegName(BPMEM_COPYYSCALE); + snprintf(desc, desc_size, "Scaling factor (XFB copy only): 0x%X (%f or inverted %f)", cmddata, (float)cmddata/256.f, 256.f/(float)cmddata); + break; + + case BPMEM_CLEAR_AR: // 0x4F + SetRegName(BPMEM_CLEAR_AR); + snprintf(desc, desc_size, "Alpha: 0x%02X\nRed: 0x%02X", (cmddata&0xFF00)>>8, cmddata&0xFF); + break; + + case BPMEM_CLEAR_GB: // 0x50 + SetRegName(BPMEM_CLEAR_GB); + snprintf(desc, desc_size, "Green: 0x%02X\nBlue: 0x%02X", (cmddata&0xFF00)>>8, cmddata&0xFF); + break; + + case BPMEM_CLEAR_Z: // 0x51 + SetRegName(BPMEM_CLEAR_Z); + snprintf(desc, desc_size, "Z value: 0x%06X", cmddata); + break; + + case BPMEM_TRIGGER_EFB_COPY: // 0x52 + { + SetRegName(BPMEM_TRIGGER_EFB_COPY); + UPE_Copy copy; copy.Hex = cmddata; + snprintf(desc, desc_size, "Clamping: %s\n" + "Converting from RGB to YUV: %s\n" + "Target pixel format: 0x%X\n" + "Gamma correction: %s\n" + "Mipmap filter: %s\n" + "Vertical scaling: %s\n" + "Clear: %s\n" + "Frame to field: 0x%01X\n" + "Copy to XFB: %s\n" + "Intensity format: %s\n" + "Automatic color conversion: %s", + (copy.clamp0 && copy.clamp1) ? "Top and Bottom" : (copy.clamp0) ? "Top only" : (copy.clamp1) ? "Bottom only" : "None", + no_yes[copy.yuv], + copy.tp_realFormat(), + (copy.gamma==0)?"1.0":(copy.gamma==1)?"1.7":(copy.gamma==2)?"2.2":"Invalid value 0x3?", + no_yes[copy.half_scale], + no_yes[copy.scale_invert], + no_yes[copy.clear], + copy.frame_to_field, + no_yes[copy.copy_to_xfb], + no_yes[copy.intensity_fmt], + no_yes[copy.auto_conv]); + } + break; + + case BPMEM_COPYFILTER0: // 0x53 + SetRegName(BPMEM_COPYFILTER0); + // TODO: Description + break; + + case BPMEM_COPYFILTER1: // 0x54 + SetRegName(BPMEM_COPYFILTER1); + // TODO: Description + break; + +#undef SET_REG_NAME + } +} diff --git a/Source/Core/VideoCommon/Src/BPMemory.h b/Source/Core/VideoCommon/Src/BPMemory.h index 0bb2bf9013..9284674aa1 100644 --- a/Source/Core/VideoCommon/Src/BPMemory.h +++ b/Source/Core/VideoCommon/Src/BPMemory.h @@ -62,7 +62,7 @@ #define BPMEM_COPYFILTER1 0x54 #define BPMEM_CLEARBBOX1 0x55 #define BPMEM_CLEARBBOX2 0x56 -#define BPMEM_UNKOWN_57 0x57 +#define BPMEM_UNKNOWN_57 0x57 #define BPMEM_REVBITS 0x58 #define BPMEM_SCISSOROFFSET 0x59 #define BPMEM_PRELOAD_ADDR 0x60 @@ -995,4 +995,6 @@ extern BPMemory bpmem; void LoadBPReg(u32 value0); +void GetBPRegInfo(const u8* data, char* name, size_t name_size, char* desc, size_t desc_size); + #endif // _BPMEMORY_H diff --git a/Source/Core/VideoCommon/Src/BPStructs.cpp b/Source/Core/VideoCommon/Src/BPStructs.cpp index 6cb102555b..d59523e117 100644 --- a/Source/Core/VideoCommon/Src/BPStructs.cpp +++ b/Source/Core/VideoCommon/Src/BPStructs.cpp @@ -463,8 +463,8 @@ void BPWritten(const BPCmd& bp) case BPMEM_REVBITS: // Always set to 0x0F when GX_InitRevBits() is called. break; - case BPMEM_UNKOWN_57: // Sunshine alternates this register between values 0x000 and 0xAAA - DEBUG_LOG(VIDEO, "Uknown BP Reg 0x57: %08x", bp.newvalue); + case BPMEM_UNKNOWN_57: // Sunshine alternates this register between values 0x000 and 0xAAA + DEBUG_LOG(VIDEO, "Unknown BP Reg 0x57: %08x", bp.newvalue); break; case BPMEM_PRELOAD_ADDR: @@ -481,6 +481,13 @@ void BPWritten(const BPCmd& bp) u8* ram_ptr = Memory::GetPointer(tmem_cfg.preload_addr << 5); u32 tmem_addr = tmem_cfg.preload_tmem_even * TMEM_LINE_SIZE; u32 size = tmem_cfg.preload_tile_info.count * 32; + + // Check if the game has overflowed TMEM, and copy up to the limit. + // Paper Mario does this when entering the Great Boogly Tree (Chap 2) + // TODO: Does this wrap? + if ((tmem_addr + size) > TMEM_SIZE) + size = TMEM_SIZE - tmem_addr; + memcpy(texMem + tmem_addr, ram_ptr, size); } break; diff --git a/Source/Core/VideoCommon/Src/CommandProcessor.cpp b/Source/Core/VideoCommon/Src/CommandProcessor.cpp index fc85b8e39d..a4dddf537f 100644 --- a/Source/Core/VideoCommon/Src/CommandProcessor.cpp +++ b/Source/Core/VideoCommon/Src/CommandProcessor.cpp @@ -56,11 +56,12 @@ static bool bProcessFifoToLoWatermark = false; static bool bProcessFifoAllDistance = false; volatile bool isPossibleWaitingSetDrawDone = false; +volatile bool isHiWatermarkActive = false; volatile bool interruptSet= false; volatile bool interruptWaiting= false; volatile bool interruptTokenWaiting = false; volatile bool interruptFinishWaiting = false; -volatile bool OnOverflow = false; +volatile bool waitingForPEInterruptDisable = false; bool IsOnThread() { @@ -86,13 +87,12 @@ void DoState(PointerWrap &p) p.Do(bProcessFifoToLoWatermark); p.Do(bProcessFifoAllDistance); - + p.Do(isHiWatermarkActive); p.Do(isPossibleWaitingSetDrawDone); p.Do(interruptSet); p.Do(interruptWaiting); p.Do(interruptTokenWaiting); p.Do(interruptFinishWaiting); - p.Do(OnOverflow); } inline void WriteLow (volatile u32& _reg, u16 lowbits) {Common::AtomicStore(_reg,(_reg & 0xFFFF0000) | lowbits);} @@ -135,16 +135,14 @@ void Init() bProcessFifoToLoWatermark = false; bProcessFifoAllDistance = false; isPossibleWaitingSetDrawDone = false; - OnOverflow = false; + isHiWatermarkActive = false; et_UpdateInterrupts = CoreTiming::RegisterEvent("UpdateInterrupts", UpdateInterrupts_Wrapper); } void Read16(u16& _rReturnValue, const u32 _Address) { - INFO_LOG(COMMANDPROCESSOR, "(r): 0x%08x", _Address); - ProcessFifoEvents(); switch (_Address & 0xFFF) { case STATUS_REGISTER: @@ -173,11 +171,23 @@ void Read16(u16& _rReturnValue, const u32 _Address) case FIFO_LO_WATERMARK_HI: _rReturnValue = ReadHigh(fifo.CPLoWatermark); return; case FIFO_RW_DISTANCE_LO: - _rReturnValue = ReadLow (fifo.CPReadWriteDistance); + if (IsOnThread()) + if(fifo.CPWritePointer >= fifo.SafeCPReadPointer) + _rReturnValue = ReadLow (fifo.CPWritePointer - fifo.SafeCPReadPointer); + else + _rReturnValue = ReadLow (fifo.CPEnd - fifo.SafeCPReadPointer + fifo.CPWritePointer - fifo.CPBase + 32); + else + _rReturnValue = ReadLow (fifo.CPReadWriteDistance); DEBUG_LOG(COMMANDPROCESSOR, "read FIFO_RW_DISTANCE_LO : %04x", _rReturnValue); return; case FIFO_RW_DISTANCE_HI: - _rReturnValue = ReadHigh(fifo.CPReadWriteDistance); + if (IsOnThread()) + if(fifo.CPWritePointer >= fifo.SafeCPReadPointer) + _rReturnValue = ReadHigh (fifo.CPWritePointer - fifo.SafeCPReadPointer); + else + _rReturnValue = ReadHigh (fifo.CPEnd - fifo.SafeCPReadPointer + fifo.CPWritePointer - fifo.CPBase + 32); + else + _rReturnValue = ReadHigh(fifo.CPReadWriteDistance); DEBUG_LOG(COMMANDPROCESSOR, "read FIFO_RW_DISTANCE_HI : %04x", _rReturnValue); return; case FIFO_WRITE_POINTER_LO: @@ -358,6 +368,7 @@ void Write16(const u16 _Value, const u32 _Address) break; case FIFO_READ_POINTER_HI: WriteHigh((u32 &)fifo.CPReadPointer, _Value); + fifo.SafeCPReadPointer = fifo.CPReadPointer; DEBUG_LOG(COMMANDPROCESSOR,"\t write to FIFO_READ_POINTER_HI : %04x", _Value); break; @@ -390,10 +401,6 @@ void Write16(const u16 _Value, const u32 _Address) case FIFO_RW_DISTANCE_HI: WriteHigh((u32 &)fifo.CPReadWriteDistance, _Value); - DEBUG_LOG(COMMANDPROCESSOR,"try to write to FIFO_RW_DISTANCE_HI : %04x", _Value); - break; - case FIFO_RW_DISTANCE_LO: - WriteLow((u32 &)fifo.CPReadWriteDistance, _Value & 0xFFE0); if (fifo.CPReadWriteDistance == 0) { GPFifo::ResetGatherPipe(); @@ -403,6 +410,10 @@ void Write16(const u16 _Value, const u32 _Address) ResetVideoBuffer(); } IncrementCheckContextId(); + DEBUG_LOG(COMMANDPROCESSOR,"try to write to FIFO_RW_DISTANCE_HI : %04x", _Value); + break; + case FIFO_RW_DISTANCE_LO: + WriteLow((u32 &)fifo.CPReadWriteDistance, _Value & 0xFFE0); DEBUG_LOG(COMMANDPROCESSOR,"try to write to FIFO_RW_DISTANCE_LO : %04x", _Value); break; @@ -412,7 +423,6 @@ void Write16(const u16 _Value, const u32 _Address) if (!IsOnThread()) RunGpu(); - ProcessFifoEvents(); } void Read32(u32& _rReturnValue, const u32 _Address) @@ -434,6 +444,19 @@ void STACKALIGN GatherPipeBursted() { if (!IsOnThread()) RunGpu(); + else + { + // In multibuffer mode is not allowed write in the same fifo attached to the GPU. + // Fix Pokemon XD in DC mode. + if((ProcessorInterface::Fifo_CPUEnd == fifo.CPEnd) && (ProcessorInterface::Fifo_CPUBase == fifo.CPBase) + && fifo.CPReadWriteDistance > 0) + { + waitingForPEInterruptDisable = true; + ProcessFifoAllDistance(); + waitingForPEInterruptDisable = false; + } + + } return; } @@ -449,26 +472,7 @@ void STACKALIGN GatherPipeBursted() Common::AtomicAdd(fifo.CPReadWriteDistance, GATHER_PIPE_SIZE); if (!IsOnThread()) - { RunGpu(); - } - else - { - if(fifo.CPReadWriteDistance == fifo.CPEnd - fifo.CPBase - 32) - { - if(!OnOverflow) - NOTICE_LOG(COMMANDPROCESSOR,"FIFO is almost in overflown, BreakPoint: %i", fifo.bFF_Breakpoint); - OnOverflow = true; - while (!CommandProcessor::interruptWaiting && fifo.bFF_GPReadEnable && - fifo.CPReadWriteDistance > fifo.CPEnd - fifo.CPBase - 64) - Common::YieldCPU(); - } - else - { - OnOverflow = false; - } - } - _assert_msg_(COMMANDPROCESSOR, fifo.CPReadWriteDistance <= fifo.CPEnd - fifo.CPBase, "FIFO is overflown by GatherPipe !\nCPU thread is too fast!"); @@ -509,17 +513,15 @@ void AbortFrame() void SetOverflowStatusFromGatherPipe() { - if (!fifo.bFF_HiWatermarkInt) return; - fifo.bFF_HiWatermark = (fifo.CPReadWriteDistance > fifo.CPHiWatermark); - fifo.bFF_LoWatermark = (fifo.CPReadWriteDistance < fifo.CPLoWatermark); - - bool interrupt = fifo.bFF_HiWatermark && fifo.bFF_HiWatermarkInt && - m_CPCtrlReg.GPLinkEnable && m_CPCtrlReg.GPReadEnable; + isHiWatermarkActive = fifo.bFF_HiWatermark && fifo.bFF_HiWatermarkInt && m_CPCtrlReg.GPReadEnable; - if (interrupt != interruptSet && interrupt) - CommandProcessor::UpdateInterrupts(true); - + if (isHiWatermarkActive) + { + interruptSet = true; + INFO_LOG(COMMANDPROCESSOR,"Interrupt set"); + ProcessorInterface::SetInterrupt(INT_CAUSE_CP, true); + } } void SetCpStatus() @@ -527,14 +529,12 @@ void SetCpStatus() // overflow & underflow check fifo.bFF_HiWatermark = (fifo.CPReadWriteDistance > fifo.CPHiWatermark); fifo.bFF_LoWatermark = (fifo.CPReadWriteDistance < fifo.CPLoWatermark); - - // breakpoint + // breakpoint if (fifo.bFF_BPEnable) { if (fifo.CPBreakpoint == fifo.CPReadPointer) - { - + { if (!fifo.bFF_Breakpoint) { INFO_LOG(COMMANDPROCESSOR, "Hit breakpoint at %i", fifo.CPReadPointer); @@ -562,13 +562,18 @@ void SetCpStatus() bool interrupt = (bpInt || ovfInt || undfInt) && m_CPCtrlReg.GPReadEnable; + isHiWatermarkActive = ovfInt && m_CPCtrlReg.GPReadEnable; + if (interrupt != interruptSet && !interruptWaiting) { u64 userdata = interrupt?1:0; if (IsOnThread()) { - interruptWaiting = true; - CommandProcessor::UpdateInterruptsFromVideoBackend(userdata); + if(!interrupt || bpInt || undfInt) + { + interruptWaiting = true; + CommandProcessor::UpdateInterruptsFromVideoBackend(userdata); + } } else CommandProcessor::UpdateInterrupts(userdata); @@ -591,7 +596,7 @@ void ProcessFifoAllDistance() if (IsOnThread()) { while (!CommandProcessor::interruptWaiting && fifo.bFF_GPReadEnable && - fifo.CPReadWriteDistance && !AtBreakpoint()) + fifo.CPReadWriteDistance && !AtBreakpoint() && !PixelEngine::WaitingForPEInterrupt()) Common::YieldCPU(); } bProcessFifoAllDistance = false; @@ -611,13 +616,16 @@ void Shutdown() void SetCpStatusRegister() { // Here always there is one fifo attached to the GPU - m_CPStatusReg.Breakpoint = fifo.bFF_Breakpoint; - m_CPStatusReg.ReadIdle = (fifo.CPReadPointer == fifo.CPWritePointer) || (fifo.CPReadPointer == fifo.CPBreakpoint); + m_CPStatusReg.ReadIdle = !fifo.CPReadWriteDistance || (fifo.CPReadPointer == fifo.CPWritePointer) || (fifo.CPReadPointer == fifo.CPBreakpoint) ; m_CPStatusReg.CommandIdle = !fifo.CPReadWriteDistance; m_CPStatusReg.UnderflowLoWatermark = fifo.bFF_LoWatermark; m_CPStatusReg.OverflowHiWatermark = fifo.bFF_HiWatermark; + // HACK to compensate for slow response to PE interrupts in Time Splitters: Future Perfect + if (IsOnThread()) + PixelEngine::ResumeWaitingForPEInterrupt(); + INFO_LOG(COMMANDPROCESSOR,"\t Read from STATUS_REGISTER : %04x", m_CPStatusReg.Hex); DEBUG_LOG(COMMANDPROCESSOR, "(r) status: iBP %s | fReadIdle %s | fCmdIdle %s | iOvF %s | iUndF %s" , m_CPStatusReg.Breakpoint ? "ON" : "OFF" @@ -630,14 +638,14 @@ void SetCpStatusRegister() void SetCpControlRegister() { - // If the new fifo is being attached We make sure there wont be SetFinish event pending. // This protection fix eternal darkness booting, because the second SetFinish event when it is booting // seems invalid or has a bug and hang the game. if (!fifo.bFF_GPReadEnable && m_CPCtrlReg.GPReadEnable && !m_CPCtrlReg.BPEnable) { - PixelEngine::ResetSetFinish(); + ProcessFifoEvents(); + PixelEngine::ResetSetFinish(); } fifo.bFF_BPInt = m_CPCtrlReg.BPInt; @@ -652,9 +660,6 @@ void SetCpControlRegister() ProcessorInterface::Fifo_CPUBase = fifo.CPBase; ProcessorInterface::Fifo_CPUEnd = fifo.CPEnd; } - // If overflown happens process the fifo to LoWatemark - if (bProcessFifoToLoWatermark) - ProcessFifoToLoWatermark(); if(fifo.bFF_GPReadEnable && !m_CPCtrlReg.GPReadEnable) { @@ -666,7 +671,6 @@ void SetCpControlRegister() fifo.bFF_GPReadEnable = m_CPCtrlReg.GPReadEnable; } - DEBUG_LOG(COMMANDPROCESSOR, "\t GPREAD %s | BP %s | Int %s | OvF %s | UndF %s | LINK %s" , fifo.bFF_GPReadEnable ? "ON" : "OFF" , fifo.bFF_BPEnable ? "ON" : "OFF" diff --git a/Source/Core/VideoCommon/Src/CommandProcessor.h b/Source/Core/VideoCommon/Src/CommandProcessor.h index db6772d66d..5d31453537 100644 --- a/Source/Core/VideoCommon/Src/CommandProcessor.h +++ b/Source/Core/VideoCommon/Src/CommandProcessor.h @@ -25,18 +25,18 @@ class PointerWrap; extern bool MT; - namespace CommandProcessor { extern SCPFifoStruct fifo; //This one is shared between gfx thread and emulator thread. extern volatile bool isPossibleWaitingSetDrawDone; //This one is used for sync gfx thread and emulator thread. +extern volatile bool isHiWatermarkActive; extern volatile bool interruptSet; extern volatile bool interruptWaiting; extern volatile bool interruptTokenWaiting; extern volatile bool interruptFinishWaiting; -extern volatile bool OnOverflow; - +extern volatile bool waitingForPEInterruptDisable; + // internal hardware addresses enum { diff --git a/Source/Core/VideoCommon/Src/Fifo.cpp b/Source/Core/VideoCommon/Src/Fifo.cpp index 842ff49e78..2e60055c97 100644 --- a/Source/Core/VideoCommon/Src/Fifo.cpp +++ b/Source/Core/VideoCommon/Src/Fifo.cpp @@ -22,6 +22,7 @@ #include "Atomic.h" #include "OpcodeDecoding.h" #include "CommandProcessor.h" +#include "PixelEngine.h" #include "ChunkFile.h" #include "Fifo.h" #include "HW/Memmap.h" @@ -137,8 +138,7 @@ void RunGpuLoop() CommandProcessor::SetCpStatus(); // check if we are able to run this buffer - while (!CommandProcessor::interruptWaiting && fifo.bFF_GPReadEnable && - fifo.CPReadWriteDistance && (!AtBreakpoint() || CommandProcessor::OnOverflow)) + while (GpuRunningState && !CommandProcessor::interruptWaiting && fifo.bFF_GPReadEnable && fifo.CPReadWriteDistance && !AtBreakpoint() && !PixelEngine::WaitingForPEInterrupt()) { if (!GpuRunningState) break; diff --git a/Source/Core/VideoCommon/Src/MainBase.cpp b/Source/Core/VideoCommon/Src/MainBase.cpp index af21ebbb94..0b1258a662 100644 --- a/Source/Core/VideoCommon/Src/MainBase.cpp +++ b/Source/Core/VideoCommon/Src/MainBase.cpp @@ -250,6 +250,11 @@ bool VideoBackendHardware::Video_IsPossibleWaitingSetDrawDone() return CommandProcessor::isPossibleWaitingSetDrawDone; } +bool VideoBackendHardware::Video_IsHiWatermarkActive() +{ + return CommandProcessor::isHiWatermarkActive; +} + void VideoBackendHardware::Video_AbortFrame() { CommandProcessor::AbortFrame(); diff --git a/Source/Core/VideoCommon/Src/OpenCL/OCLTextureDecoder.cpp b/Source/Core/VideoCommon/Src/OpenCL/OCLTextureDecoder.cpp index 0f4809a6cc..440e69efd6 100644 --- a/Source/Core/VideoCommon/Src/OpenCL/OCLTextureDecoder.cpp +++ b/Source/Core/VideoCommon/Src/OpenCL/OCLTextureDecoder.cpp @@ -114,7 +114,7 @@ void TexDecoder_OpenCL_Initialize() else { binary_size = input.GetSize(); - header = new char[HEADER_SIZE]; // TODO: memleak possible + header = new char[HEADER_SIZE]; binary = new char[binary_size]; input.ReadBytes(header, HEADER_SIZE); input.ReadBytes(binary, binary_size); @@ -143,8 +143,8 @@ void TexDecoder_OpenCL_Initialize() } } } - delete header; - delete binary; + delete [] header; + delete [] binary; } // If an error occurred using the kernel binary, recompile the kernels diff --git a/Source/Core/VideoCommon/Src/PixelEngine.cpp b/Source/Core/VideoCommon/Src/PixelEngine.cpp index 456e0fb535..03a3a7547a 100644 --- a/Source/Core/VideoCommon/Src/PixelEngine.cpp +++ b/Source/Core/VideoCommon/Src/PixelEngine.cpp @@ -180,7 +180,6 @@ void Init() void Read16(u16& _uReturnValue, const u32 _iAddress) { DEBUG_LOG(PIXELENGINE, "(r16) 0x%08x", _iAddress); - CommandProcessor::ProcessFifoEvents(); switch (_iAddress & 0xFFF) { // CPU Direct Access EFB Raster State Config @@ -269,6 +268,10 @@ void Read16(u16& _uReturnValue, const u32 _iAddress) case PE_PERF_5L: case PE_PERF_5H: INFO_LOG(PIXELENGINE, "(r16) perf counter @ %08x", _iAddress); + // git r90a2096a24f4 (svn r3663) added the PE_PERF cases, without setting + // _uReturnValue to anything, this reverts to the previous behaviour which allows + // The timer in SMS:Scrubbing Serena Beach to countdown correctly + _uReturnValue = 1; break; default: @@ -323,7 +326,6 @@ void Write16(const u16 _iValue, const u32 _iAddress) break; case PE_TOKEN_REG: - //LOG(PIXELENGINE,"WEIRD: program wrote token: %i",_iValue); PanicAlert("(w16) WTF? PowerPC program wrote token: %i", _iValue); //only the gx pipeline is supposed to be able to write here //g_token = _iValue; @@ -334,7 +336,6 @@ void Write16(const u16 _iValue, const u32 _iAddress) break; } - CommandProcessor::ProcessFifoEvents(); } void Write32(const u32 _iValue, const u32 _iAddress) @@ -358,22 +359,16 @@ void UpdateInterrupts() void UpdateTokenInterrupt(bool active) { - if(interruptSetToken != active) - { ProcessorInterface::SetInterrupt(INT_CAUSE_PE_TOKEN, active); interruptSetToken = active; - } } void UpdateFinishInterrupt(bool active) { - if(interruptSetFinish != active) - { ProcessorInterface::SetInterrupt(INT_CAUSE_PE_FINISH, active); interruptSetFinish = active; if (active) State::ProcessRequestedStates(0); - } } // TODO(mb2): Refactor SetTokenINT_OnMainThread(u64 userdata, int cyclesLate). @@ -392,8 +387,6 @@ void SetToken_OnMainThread(u64 userdata, int cyclesLate) CommandProcessor::interruptTokenWaiting = false; IncrementCheckContextId(); //} - //else - // LOGV(PIXELENGINE, 1, "VIDEO Backend wrote token: %i", CommandProcessor::fifo.PEToken); } void SetFinish_OnMainThread(u64 userdata, int cyclesLate) @@ -470,4 +463,17 @@ void ResetSetToken() } CommandProcessor::interruptTokenWaiting = false; } + +bool WaitingForPEInterrupt() +{ + return !CommandProcessor::waitingForPEInterruptDisable && (CommandProcessor::interruptFinishWaiting || CommandProcessor::interruptTokenWaiting || interruptSetFinish || interruptSetToken); +} + +void ResumeWaitingForPEInterrupt() +{ + interruptSetFinish = false; + interruptSetToken = false; + CommandProcessor::interruptFinishWaiting = false; + CommandProcessor::interruptTokenWaiting = false; +} } // end of namespace PixelEngine diff --git a/Source/Core/VideoCommon/Src/PixelEngine.h b/Source/Core/VideoCommon/Src/PixelEngine.h index dd0304fbe1..64f959009f 100644 --- a/Source/Core/VideoCommon/Src/PixelEngine.h +++ b/Source/Core/VideoCommon/Src/PixelEngine.h @@ -80,7 +80,8 @@ void SetToken(const u16 _token, const int _bSetTokenAcknowledge); void SetFinish(void); void ResetSetFinish(void); void ResetSetToken(void); -bool AllowIdleSkipping(); +bool WaitingForPEInterrupt(); +void ResumeWaitingForPEInterrupt(); // Bounding box functionality. Paper Mario (both) are a couple of the few games that use it. extern u16 bbox[4]; diff --git a/Source/Core/VideoCommon/Src/PixelShaderGen.cpp b/Source/Core/VideoCommon/Src/PixelShaderGen.cpp index fe5827de05..7500997fef 100644 --- a/Source/Core/VideoCommon/Src/PixelShaderGen.cpp +++ b/Source/Core/VideoCommon/Src/PixelShaderGen.cpp @@ -158,7 +158,7 @@ void GetPixelShaderId(PIXELSHADERUID *uid, DSTALPHA_MODE dstAlphaMode, u32 compo } u32* ptr = &uid->values[2]; - for (int i = 0; i < bpmem.genMode.numtevstages+1; ++i) + for (unsigned int i = 0; i < bpmem.genMode.numtevstages+1; ++i) { StageHash(i, ptr); ptr += 4; // max: ptr = &uid->values[66] @@ -299,7 +299,7 @@ void ValidatePixelShaderIDs(API_TYPE api, PIXELSHADERUIDSAFE old_id, const std:: static void WriteStage(char *&p, int n, API_TYPE ApiType); static void SampleTexture(char *&p, const char *destination, const char *texcoords, const char *texswap, int texmap, API_TYPE ApiType); // static void WriteAlphaCompare(char *&p, int num, int comp); -static bool WriteAlphaTest(char *&p, API_TYPE ApiType,DSTALPHA_MODE dstAlphaMode); +static void WriteAlphaTest(char *&p, API_TYPE ApiType,DSTALPHA_MODE dstAlphaMode); static void WriteFog(char *&p); static const char *tevKSelTableC[] = // KCSEL @@ -556,26 +556,22 @@ const char *GeneratePixelShaderCode(DSTALPHA_MODE dstAlphaMode, API_TYPE ApiType WRITE(p, "\n"); - WRITE(p, "uniform float4 "I_COLORS"[4] : register(c%d);\n", C_COLORS); - WRITE(p, "uniform float4 "I_KCOLORS"[4] : register(c%d);\n", C_KCOLORS); - WRITE(p, "uniform float4 "I_ALPHA"[1] : register(c%d);\n", C_ALPHA); - WRITE(p, "uniform float4 "I_TEXDIMS"[8] : register(c%d);\n", C_TEXDIMS); - if (ApiType & API_D3D9) - { - WRITE(p, "uniform float4 "I_VTEXSCALE"[4] : register(c%d);\n", C_VTEXSCALE); - } - WRITE(p, "uniform float4 "I_ZBIAS"[2] : register(c%d);\n", C_ZBIAS); - WRITE(p, "uniform float4 "I_INDTEXSCALE"[2] : register(c%d);\n", C_INDTEXSCALE); - WRITE(p, "uniform float4 "I_INDTEXMTX"[6] : register(c%d);\n", C_INDTEXMTX); - WRITE(p, "uniform float4 "I_FOG"[3] : register(c%d);\n", C_FOG); + WRITE(p, "uniform float4 " I_COLORS"[4] : register(c%d);\n", C_COLORS); + WRITE(p, "uniform float4 " I_KCOLORS"[4] : register(c%d);\n", C_KCOLORS); + WRITE(p, "uniform float4 " I_ALPHA"[1] : register(c%d);\n", C_ALPHA); + WRITE(p, "uniform float4 " I_TEXDIMS"[8] : register(c%d);\n", C_TEXDIMS); + WRITE(p, "uniform float4 " I_ZBIAS"[2] : register(c%d);\n", C_ZBIAS); + WRITE(p, "uniform float4 " I_INDTEXSCALE"[2] : register(c%d);\n", C_INDTEXSCALE); + WRITE(p, "uniform float4 " I_INDTEXMTX"[6] : register(c%d);\n", C_INDTEXMTX); + WRITE(p, "uniform float4 " I_FOG"[3] : register(c%d);\n", C_FOG); if(g_ActiveConfig.bEnablePixelLighting && g_ActiveConfig.backend_info.bSupportsPixelLighting) { WRITE(p,"typedef struct { float4 col; float4 cosatt; float4 distatt; float4 pos; float4 dir; } Light;\n"); - WRITE(p,"typedef struct { Light lights[8]; } s_"I_PLIGHTS";\n"); - WRITE(p, "uniform s_"I_PLIGHTS" "I_PLIGHTS" : register(c%d);\n", C_PLIGHTS); - WRITE(p, "typedef struct { float4 C0, C1, C2, C3; } s_"I_PMATERIALS";\n"); - WRITE(p, "uniform s_"I_PMATERIALS" "I_PMATERIALS" : register(c%d);\n", C_PMATERIALS); + WRITE(p,"typedef struct { Light lights[8]; } s_" I_PLIGHTS";\n"); + WRITE(p, "uniform s_" I_PLIGHTS" " I_PLIGHTS" : register(c%d);\n", C_PLIGHTS); + WRITE(p, "typedef struct { float4 C0, C1, C2, C3; } s_" I_PMATERIALS";\n"); + WRITE(p, "uniform s_" I_PMATERIALS" " I_PMATERIALS" : register(c%d);\n", C_PMATERIALS); } WRITE(p, "void main(\n"); @@ -623,25 +619,32 @@ const char *GeneratePixelShaderCode(DSTALPHA_MODE dstAlphaMode, API_TYPE ApiType char* pmainstart = p; int Pretest = AlphaPreTest(); - if (dstAlphaMode == DSTALPHA_ALPHA_PASS && !DepthTextureEnable && Pretest >= 0) + if(Pretest >= 0 && !DepthTextureEnable) { if (!Pretest) { - // alpha test will always fail, so restart the shader and just make it an empty function + // alpha test will always fail, so restart the shader and just make it an empty function WRITE(p, "ocol0 = 0;\n"); + if(DepthTextureEnable) + WRITE(p, "depth = 1.f;\n"); + if(dstAlphaMode == DSTALPHA_DUAL_SOURCE_BLEND) + WRITE(p, "ocol1 = 0;\n"); WRITE(p, "discard;\n"); if(ApiType != API_D3D11) WRITE(p, "return;\n"); } - else + else if (dstAlphaMode == DSTALPHA_ALPHA_PASS) { - WRITE(p, " ocol0 = "I_ALPHA"[0].aaaa;\n"); + WRITE(p, " ocol0 = " I_ALPHA"[0].aaaa;\n"); + } + if(!Pretest || dstAlphaMode == DSTALPHA_ALPHA_PASS) + { + WRITE(p, "}\n"); + return text; } - WRITE(p, "}\n"); - return text; } - WRITE(p, " float4 c0 = "I_COLORS"[1], c1 = "I_COLORS"[2], c2 = "I_COLORS"[3], prev = float4(0.0f, 0.0f, 0.0f, 0.0f), textemp = float4(0.0f, 0.0f, 0.0f, 0.0f), rastemp = float4(0.0f, 0.0f, 0.0f, 0.0f), konsttemp = float4(0.0f, 0.0f, 0.0f, 0.0f);\n" + WRITE(p, " float4 c0 = " I_COLORS"[1], c1 = " I_COLORS"[2], c2 = " I_COLORS"[3], prev = float4(0.0f, 0.0f, 0.0f, 0.0f), textemp = float4(0.0f, 0.0f, 0.0f, 0.0f), rastemp = float4(0.0f, 0.0f, 0.0f, 0.0f), konsttemp = float4(0.0f, 0.0f, 0.0f, 0.0f);\n" " float3 comp16 = float3(1.0f, 255.0f, 0.0f), comp24 = float3(1.0f, 255.0f, 255.0f*255.0f);\n" " float4 alphabump=float4(0.0f,0.0f,0.0f,0.0f);\n" " float3 tevcoord=float3(0.0f, 0.0f, 0.0f);\n" @@ -692,7 +695,7 @@ const char *GeneratePixelShaderCode(DSTALPHA_MODE dstAlphaMode, API_TYPE ApiType WRITE(p, " uv%d.xy = uv%d.xy / uv%d.z;\n", i, i, i); } - WRITE(p, "uv%d.xy = uv%d.xy * "I_TEXDIMS"[%d].zw;\n", i, i, i); + WRITE(p, "uv%d.xy = uv%d.xy * " I_TEXDIMS"[%d].zw;\n", i, i, i); } } @@ -704,7 +707,7 @@ const char *GeneratePixelShaderCode(DSTALPHA_MODE dstAlphaMode, API_TYPE ApiType int texcoord = bpmem.tevindref.getTexCoord(i); if (texcoord < numTexgen) - WRITE(p, "tempcoord = uv%d.xy * "I_INDTEXSCALE"[%d].%s;\n", texcoord, i/2, (i&1)?"zw":"xy"); + WRITE(p, "tempcoord = uv%d.xy * " I_INDTEXSCALE"[%d].%s;\n", texcoord, i/2, (i&1)?"zw":"xy"); else WRITE(p, "tempcoord = float2(0.0f, 0.0f);\n"); @@ -727,65 +730,53 @@ const char *GeneratePixelShaderCode(DSTALPHA_MODE dstAlphaMode, API_TYPE ApiType // emulation of unsigned 8 overflow when casting WRITE(p, "prev = frac(4.0f + prev * (255.0f/256.0f)) * (256.0f/255.0f);\n"); - // TODO: Why are we doing a second alpha pretest here? - if (!WriteAlphaTest(p, ApiType, dstAlphaMode)) + if(Pretest == -1) { - // alpha test will always fail, so restart the shader and just make it an empty function - p = pmainstart; - WRITE(p, "ocol0 = 0;\n"); - if(DepthTextureEnable) - WRITE(p, "depth = 1.f;\n"); - if(dstAlphaMode == DSTALPHA_DUAL_SOURCE_BLEND) - WRITE(p, "ocol1 = 0;\n"); - WRITE(p, "discard;\n"); - if(ApiType != API_D3D11) - WRITE(p, "return;\n"); + WriteAlphaTest(p, ApiType, dstAlphaMode); } - else - { - if((bpmem.fog.c_proj_fsel.fsel != 0) || DepthTextureEnable) - { - // the screen space depth value = far z + (clip z / clip w) * z range - WRITE(p, "float zCoord = "I_ZBIAS"[1].x + (clipPos.z / clipPos.w) * "I_ZBIAS"[1].y;\n"); - } + if((bpmem.fog.c_proj_fsel.fsel != 0) || DepthTextureEnable) + { + // the screen space depth value = far z + (clip z / clip w) * z range + WRITE(p, "float zCoord = " I_ZBIAS"[1].x + (clipPos.z / clipPos.w) * " I_ZBIAS"[1].y;\n"); + } - if (DepthTextureEnable) + if (DepthTextureEnable) + { + // use the texture input of the last texture stage (textemp), hopefully this has been read and is in correct format... + if (bpmem.ztex2.op != ZTEXTURE_DISABLE && !bpmem.zcontrol.zcomploc && bpmem.zmode.testenable && bpmem.zmode.updateenable) { - // use the texture input of the last texture stage (textemp), hopefully this has been read and is in correct format... - if (bpmem.ztex2.op != ZTEXTURE_DISABLE && !bpmem.zcontrol.zcomploc && bpmem.zmode.testenable && bpmem.zmode.updateenable) - { - if (bpmem.ztex2.op == ZTEXTURE_ADD) - WRITE(p, "zCoord = dot("I_ZBIAS"[0].xyzw, textemp.xyzw) + "I_ZBIAS"[1].w + zCoord;\n"); - else - WRITE(p, "zCoord = dot("I_ZBIAS"[0].xyzw, textemp.xyzw) + "I_ZBIAS"[1].w;\n"); - - // scale to make result from frac correct - WRITE(p, "zCoord = zCoord * (16777215.0f/16777216.0f);\n"); - WRITE(p, "zCoord = frac(zCoord);\n"); - WRITE(p, "zCoord = zCoord * (16777216.0f/16777215.0f);\n"); - } - WRITE(p, "depth = zCoord;\n"); - } + if (bpmem.ztex2.op == ZTEXTURE_ADD) + WRITE(p, "zCoord = dot(" I_ZBIAS"[0].xyzw, textemp.xyzw) + " I_ZBIAS"[1].w + zCoord;\n"); + else + WRITE(p, "zCoord = dot(" I_ZBIAS"[0].xyzw, textemp.xyzw) + " I_ZBIAS"[1].w;\n"); - if (dstAlphaMode == DSTALPHA_ALPHA_PASS) - WRITE(p, " ocol0 = float4(prev.rgb, "I_ALPHA"[0].a);\n"); - else - { - WriteFog(p); - WRITE(p, " ocol0 = prev;\n"); + // scale to make result from frac correct + WRITE(p, "zCoord = zCoord * (16777215.0f/16777216.0f);\n"); + WRITE(p, "zCoord = frac(zCoord);\n"); + WRITE(p, "zCoord = zCoord * (16777216.0f/16777215.0f);\n"); } + WRITE(p, "depth = zCoord;\n"); + } - // On D3D11, use dual-source color blending to perform dst alpha in a - // single pass - if (dstAlphaMode == DSTALPHA_DUAL_SOURCE_BLEND) - { - // Colors will be blended against the alpha from ocol1... - WRITE(p, " ocol1 = ocol0;\n"); - // ...and the alpha from ocol0 will be written to the framebuffer. - WRITE(p, " ocol0.a = "I_ALPHA"[0].a;\n"); - } + if (dstAlphaMode == DSTALPHA_ALPHA_PASS) + WRITE(p, " ocol0 = float4(prev.rgb, " I_ALPHA"[0].a);\n"); + else + { + WriteFog(p); + WRITE(p, " ocol0 = prev;\n"); } + + // On D3D11, use dual-source color blending to perform dst alpha in a + // single pass + if (dstAlphaMode == DSTALPHA_DUAL_SOURCE_BLEND) + { + // Colors will be blended against the alpha from ocol1... + WRITE(p, " ocol1 = ocol0;\n"); + // ...and the alpha from ocol0 will be written to the framebuffer. + WRITE(p, " ocol0.a = " I_ALPHA"[0].a;\n"); + } + WRITE(p, "}\n"); if (text[sizeof(text) - 1] != 0x7C) PanicAlert("PixelShader generator - buffer too small, canary has been eaten!"); @@ -876,20 +867,20 @@ static void WriteStage(char *&p, int n, API_TYPE ApiType) if (bpmem.tevind[n].mid <= 3) { int mtxidx = 2*(bpmem.tevind[n].mid-1); - WRITE(p, "float2 indtevtrans%d = float2(dot("I_INDTEXMTX"[%d].xyz, indtevcrd%d), dot("I_INDTEXMTX"[%d].xyz, indtevcrd%d));\n", + WRITE(p, "float2 indtevtrans%d = float2(dot(" I_INDTEXMTX"[%d].xyz, indtevcrd%d), dot(" I_INDTEXMTX"[%d].xyz, indtevcrd%d));\n", n, mtxidx, n, mtxidx+1, n); } else if (bpmem.tevind[n].mid <= 7 && bHasTexCoord) { // s matrix _assert_(bpmem.tevind[n].mid >= 5); int mtxidx = 2*(bpmem.tevind[n].mid-5); - WRITE(p, "float2 indtevtrans%d = "I_INDTEXMTX"[%d].ww * uv%d.xy * indtevcrd%d.xx;\n", n, mtxidx, texcoord, n); + WRITE(p, "float2 indtevtrans%d = " I_INDTEXMTX"[%d].ww * uv%d.xy * indtevcrd%d.xx;\n", n, mtxidx, texcoord, n); } else if (bpmem.tevind[n].mid <= 11 && bHasTexCoord) { // t matrix _assert_(bpmem.tevind[n].mid >= 9); int mtxidx = 2*(bpmem.tevind[n].mid-9); - WRITE(p, "float2 indtevtrans%d = "I_INDTEXMTX"[%d].ww * uv%d.xy * indtevcrd%d.yy;\n", n, mtxidx, texcoord, n); + WRITE(p, "float2 indtevtrans%d = " I_INDTEXMTX"[%d].ww * uv%d.xy * indtevcrd%d.yy;\n", n, mtxidx, texcoord, n); } else WRITE(p, "float2 indtevtrans%d = 0;\n", n); @@ -1103,15 +1094,9 @@ static void WriteStage(char *&p, int n, API_TYPE ApiType) void SampleTexture(char *&p, const char *destination, const char *texcoords, const char *texswap, int texmap, API_TYPE ApiType) { if (ApiType == API_D3D11) - WRITE(p, "%s=Tex%d.Sample(samp%d, %s.xy * "I_TEXDIMS"[%d].xy).%s;\n", destination, texmap,texmap, texcoords, texmap, texswap); - else if (ApiType & API_D3D9) - { - // D3D9 uses different pixel to texel mapping, so we need to offset our sampling address by half a pixel (assuming native and virtual texture dimensions match each other, otherwise some math is involved). - // Read the MSDN article "Directly Mapping Texels to Pixels (Direct3D 9)" for further info. - WRITE(p, "%s=tex2D(samp%d, (%s.xy + 0.5f*"I_VTEXSCALE"[%d].%s) * "I_TEXDIMS"[%d].xy).%s;\n", destination, texmap, texcoords, texmap/2, (texmap&1)?"zw":"xy", texmap, texswap); - } + WRITE(p, "%s=Tex%d.Sample(samp%d,%s.xy * " I_TEXDIMS"[%d].xy).%s;\n", destination, texmap,texmap, texcoords, texmap, texswap); else - WRITE(p, "%s=tex2D(samp%d, %s.xy * "I_TEXDIMS"[%d].xy).%s;\n", destination, texmap, texcoords, texmap, texswap); + WRITE(p, "%s=tex2D(samp%d,%s.xy * " I_TEXDIMS"[%d].xy).%s;\n", destination, texmap, texcoords, texmap, texswap); } static const char *tevAlphaFuncsTable[] = @@ -1167,19 +1152,13 @@ static int AlphaPreTest() } -static bool WriteAlphaTest(char *&p, API_TYPE ApiType,DSTALPHA_MODE dstAlphaMode) +static void WriteAlphaTest(char *&p, API_TYPE ApiType,DSTALPHA_MODE dstAlphaMode) { static const char *alphaRef[2] = { I_ALPHA"[0].r", I_ALPHA"[0].g" - }; - - int Pretest = AlphaPreTest(); - if(Pretest >= 0) - { - return Pretest != 0; - } + }; // using discard then return works the same in cg and dx9 but not in dx11 WRITE(p, "if(!( "); @@ -1191,11 +1170,35 @@ static bool WriteAlphaTest(char *&p, API_TYPE ApiType,DSTALPHA_MODE dstAlphaMode compindex = bpmem.alphaFunc.comp1 % 8; WRITE(p, tevAlphaFuncsTable[compindex],alphaRef[1]);//lookup the second component from the alpha function table - WRITE(p, ")){ocol0 = 0;%s%s discard;%s}\n", - dstAlphaMode == DSTALPHA_DUAL_SOURCE_BLEND ? "ocol1 = 0;" : "", - DepthTextureEnable ? "depth = 1.f;" : "", - (ApiType != API_D3D11) ? "return;" : ""); - return true; + WRITE(p, ")) {\n"); + + WRITE(p, "ocol0 = 0;\n"); + if (dstAlphaMode == DSTALPHA_DUAL_SOURCE_BLEND) + WRITE(p, "ocol1 = 0;\n"); + if (DepthTextureEnable) + WRITE(p, "depth = 1.f;\n"); + + // HAXX: zcomploc is a way to control whether depth test is done before + // or after texturing and alpha test. PC GPU does depth test before texturing ONLY if depth value is + // not updated during shader execution. + // We implement "depth test before texturing" by discarding the fragment + // when the alpha test fail. This is not a correct implementation because + // even if the depth test fails the fragment could be alpha blended. + // this implemnetation is a trick to keep speed. + // the correct, but slow, way to implement a correct zComploc is : + // 1 - if zcomplock is enebled make a first pass, with color channel write disabled updating only + // depth channel. + // 2 - in the next pass disable depth chanel update, but proccess the color data normally + // this way is the only CORRECT way to emulate perfectly the zcomplock behaviour + if (!(bpmem.zcontrol.zcomploc && bpmem.zmode.updateenable)) + { + WRITE(p, "discard;\n"); + if (ApiType != API_D3D11) + WRITE(p, "return;\n"); + } + + WRITE(p, "}\n"); + } static const char *tevFogFuncsTable[] = @@ -1218,13 +1221,13 @@ static void WriteFog(char *&p) { // perspective // ze = A/(B - (Zs >> B_SHF) - WRITE (p, " float ze = "I_FOG"[1].x / ("I_FOG"[1].y - (zCoord / "I_FOG"[1].w));\n"); + WRITE (p, " float ze = " I_FOG"[1].x / (" I_FOG"[1].y - (zCoord / " I_FOG"[1].w));\n"); } else { // orthographic // ze = a*Zs (here, no B_SHF) - WRITE (p, " float ze = "I_FOG"[1].x * zCoord;\n"); + WRITE (p, " float ze = " I_FOG"[1].x * zCoord;\n"); } // x_adjust = sqrt((x-center)^2 + k^2)/k @@ -1232,12 +1235,12 @@ static void WriteFog(char *&p) //this is complitly teorical as the real hard seems to use a table intead of calculate the values. if(bpmem.fogRange.Base.Enabled) { - WRITE (p, " float x_adjust = (2.0f * (clipPos.x / "I_FOG"[2].y)) - 1.0f - "I_FOG"[2].x;\n"); - WRITE (p, " x_adjust = sqrt(x_adjust * x_adjust + "I_FOG"[2].z * "I_FOG"[2].z) / "I_FOG"[2].z;\n"); + WRITE (p, " float x_adjust = (2.0f * (clipPos.x / " I_FOG"[2].y)) - 1.0f - " I_FOG"[2].x;\n"); + WRITE (p, " x_adjust = sqrt(x_adjust * x_adjust + " I_FOG"[2].z * " I_FOG"[2].z) / " I_FOG"[2].z;\n"); WRITE (p, " ze *= x_adjust;\n"); } - WRITE (p, " float fog = saturate(ze - "I_FOG"[1].z);\n"); + WRITE (p, " float fog = saturate(ze - " I_FOG"[1].z);\n"); if(bpmem.fog.c_proj_fsel.fsel > 3) { @@ -1249,7 +1252,7 @@ static void WriteFog(char *&p) WARN_LOG(VIDEO, "Unknown Fog Type! %08x", bpmem.fog.c_proj_fsel.fsel); } - WRITE(p, " prev.rgb = lerp(prev.rgb,"I_FOG"[0].rgb,fog);\n"); + WRITE(p, " prev.rgb = lerp(prev.rgb," I_FOG"[0].rgb,fog);\n"); -}
\ No newline at end of file +} diff --git a/Source/Core/VideoCommon/Src/PixelShaderGen.h b/Source/Core/VideoCommon/Src/PixelShaderGen.h index 7374251c96..31242a916e 100644 --- a/Source/Core/VideoCommon/Src/PixelShaderGen.h +++ b/Source/Core/VideoCommon/Src/PixelShaderGen.h @@ -24,27 +24,26 @@ #define I_KCOLORS "k" #define I_ALPHA "alphaRef" #define I_TEXDIMS "texdim" -#define I_VTEXSCALE "vtexscale" #define I_ZBIAS "czbias" #define I_INDTEXSCALE "cindscale" #define I_INDTEXMTX "cindmtx" #define I_FOG "cfog" #define I_PLIGHTS "cLights" -#define I_PMATERIALS "cmtrl" +#define I_PMATERIALS "cmtrl" #define C_COLORMATRIX 0 // 0 #define C_COLORS 0 // 0 #define C_KCOLORS (C_COLORS + 4) // 4 #define C_ALPHA (C_KCOLORS + 4) // 8 #define C_TEXDIMS (C_ALPHA + 1) // 9 -#define C_VTEXSCALE (C_TEXDIMS + 8) //17 - virtual texture scaling factor (e.g. custom textures, scaled EFB copies) -#define C_ZBIAS (C_VTEXSCALE + 4) //21 -#define C_INDTEXSCALE (C_ZBIAS + 2) //23 -#define C_INDTEXMTX (C_INDTEXSCALE + 2) //25 -#define C_FOG (C_INDTEXMTX + 6) //31 -#define C_PLIGHTS (C_FOG + 3) //34 -#define C_PMATERIALS (C_PLIGHTS + 40) //74 -#define C_PENVCONST_END (C_PMATERIALS + 4) //78 +#define C_ZBIAS (C_TEXDIMS + 8) //17 +#define C_INDTEXSCALE (C_ZBIAS + 2) //19 +#define C_INDTEXMTX (C_INDTEXSCALE + 2) //21 +#define C_FOG (C_INDTEXMTX + 6) //27 + +#define C_PLIGHTS (C_FOG + 3) +#define C_PMATERIALS (C_PLIGHTS + 40) +#define C_PENVCONST_END (C_PMATERIALS + 4) #define PIXELSHADERUID_MAX_VALUES 70 #define PIXELSHADERUID_MAX_VALUES_SAFE 120 diff --git a/Source/Core/VideoCommon/Src/PixelShaderManager.cpp b/Source/Core/VideoCommon/Src/PixelShaderManager.cpp index 3e0f6d73c4..2521f80500 100644 --- a/Source/Core/VideoCommon/Src/PixelShaderManager.cpp +++ b/Source/Core/VideoCommon/Src/PixelShaderManager.cpp @@ -36,11 +36,9 @@ static bool s_bFogRangeAdjustChanged; static int nLightsChanged[2]; // min,max static float lastRGBAfull[2][4][4]; static u8 s_nTexDimsChanged; -static u8 s_nVirtualTexScalesChanged; static u8 s_nIndTexScaleChanged; static u32 lastAlpha; static u32 lastTexDims[8]; // width | height << 16 | wrap_s << 28 | wrap_t << 30 -static float lastVirtualTexScales[16]; // even fields: width ratio; odd fields: height ratio static u32 lastZBias; static int nMaterialsChanged; @@ -63,7 +61,6 @@ void PixelShaderManager::Init() { lastAlpha = 0; memset(lastTexDims, 0, sizeof(lastTexDims)); - memset(lastVirtualTexScales, 0, sizeof(lastVirtualTexScales)); lastZBias = 0; memset(lastRGBAfull, 0, sizeof(lastRGBAfull)); Dirty(); @@ -73,7 +70,6 @@ void PixelShaderManager::Dirty() { s_nColorsChanged[0] = s_nColorsChanged[1] = 15; s_nTexDimsChanged = 0xFF; - s_nVirtualTexScalesChanged = 0xFF; s_nIndTexScaleChanged = 0xFF; s_nIndTexMtxChanged = 15; s_bAlphaChanged = s_bZBiasChanged = s_bZTextureTypeChanged = s_bDepthRangeChanged = true; @@ -87,7 +83,7 @@ void PixelShaderManager::Shutdown() } -void PixelShaderManager::SetConstants(API_TYPE api_type) +void PixelShaderManager::SetConstants() { for (int i = 0; i < 2; ++i) { @@ -113,16 +109,6 @@ void PixelShaderManager::SetConstants(API_TYPE api_type) s_nTexDimsChanged = 0; } - if ((api_type & API_D3D9) && s_nVirtualTexScalesChanged) - { - for (int i = 0; i < 8; i += 2) - { - if (s_nVirtualTexScalesChanged & (3<<i)) - SetPSVirtualTexScalePair(i/2); - } - s_nVirtualTexScalesChanged = 0; - } - if (s_bAlphaChanged) { SetPSConstant4f(C_ALPHA, (lastAlpha&0xff)/255.0f, ((lastAlpha>>8)&0xff)/255.0f, 0, ((lastAlpha>>16)&0xff)/255.0f); @@ -352,13 +338,6 @@ void PixelShaderManager::SetPSTextureDims(int texid) SetPSConstant4fv(C_TEXDIMS + texid, fdims); } -void PixelShaderManager::SetPSVirtualTexScalePair(int texpairid) -{ - PRIM_LOG("vtexscale%d: %f %f %f %f\n", texpairid, lastVirtualTexScales[texpairid*4], lastVirtualTexScales[texpairid*4+1], - lastVirtualTexScales[texpairid*4+2], lastVirtualTexScales[texpairid*4+3]); - SetPSConstant4fv(C_VTEXSCALE + texpairid, &lastVirtualTexScales[texpairid*4]); -} - // This one is high in profiles (0.5%). TODO: Move conversion out, only store the raw color value // and update it when the shader constant is set, only. void PixelShaderManager::SetColorChanged(int type, int num, bool high) @@ -397,25 +376,14 @@ void PixelShaderManager::SetDestAlpha(const ConstantAlpha& alpha) } } -void PixelShaderManager::SetTexDims(int texmapid, u32 width, u32 height, u32 virtual_width, u32 virtual_height, u32 wraps, u32 wrapt, API_TYPE api_type) +void PixelShaderManager::SetTexDims(int texmapid, u32 width, u32 height, u32 wraps, u32 wrapt) { u32 wh = width | (height << 16) | (wraps << 28) | (wrapt << 30); - - bool refresh = lastTexDims[texmapid] != wh; - if (api_type & API_D3D9) + if (lastTexDims[texmapid] != wh) { - refresh |= (lastVirtualTexScales[texmapid*2] != (float)width / (float)virtual_width); - refresh |= (lastVirtualTexScales[texmapid*2+1] != (float)height / (float)virtual_height); - } - - if (refresh) - { - lastTexDims[texmapid] = wh; - lastVirtualTexScales[texmapid*2] = (float)width / (float)virtual_width; - lastVirtualTexScales[texmapid*2+1] = (float)height / (float)virtual_height; + lastTexDims[texmapid] = wh; s_nTexDimsChanged |= 1 << texmapid; - s_nVirtualTexScalesChanged |= 1 << texmapid; - } + } } void PixelShaderManager::SetZTextureBias(u32 bias) diff --git a/Source/Core/VideoCommon/Src/PixelShaderManager.h b/Source/Core/VideoCommon/Src/PixelShaderManager.h index 5cbe86cae4..2d1c01cad6 100644 --- a/Source/Core/VideoCommon/Src/PixelShaderManager.h +++ b/Source/Core/VideoCommon/Src/PixelShaderManager.h @@ -26,20 +26,18 @@ class PixelShaderManager { static void SetPSTextureDims(int texid); - static void SetPSVirtualTexScalePair(int texpairid); - public: static void Init(); static void Dirty(); static void Shutdown(); - static void SetConstants(API_TYPE api_type); // sets pixel shader constants + static void SetConstants(); // sets pixel shader constants // constant management, should be called after memory is committed static void SetColorChanged(int type, int index, bool high); static void SetAlpha(const AlphaFunc& alpha); static void SetDestAlpha(const ConstantAlpha& alpha); - static void SetTexDims(int texmapid, u32 width, u32 height, u32 virtual_width, u32 virtual_height, u32 wraps, u32 wrapt, API_TYPE api_type); + static void SetTexDims(int texmapid, u32 width, u32 height, u32 wraps, u32 wrapt); static void SetZTextureBias(u32 bias); static void SetViewportChanged(); static void SetIndMatrixChanged(int matrixidx); diff --git a/Source/Core/VideoCommon/Src/RenderBase.cpp b/Source/Core/VideoCommon/Src/RenderBase.cpp index 3b06bbb1c0..ef0fff57f7 100644 --- a/Source/Core/VideoCommon/Src/RenderBase.cpp +++ b/Source/Core/VideoCommon/Src/RenderBase.cpp @@ -43,6 +43,7 @@ #include "XFMemory.h" #include "FifoPlayer/FifoRecorder.h" #include "AVIDump.h" +#include "VertexShaderManager.h" #include <cmath> #include <string> @@ -193,6 +194,7 @@ bool Renderer::CalculateTargetSize(int multiplier) { s_target_width = newEFBWidth; s_target_height = newEFBHeight; + VertexShaderManager::SetViewportChanged(); return true; } return false; diff --git a/Source/Core/VideoCommon/Src/TextureCacheBase.cpp b/Source/Core/VideoCommon/Src/TextureCacheBase.cpp index cc14499330..00ff9610be 100644 --- a/Source/Core/VideoCommon/Src/TextureCacheBase.cpp +++ b/Source/Core/VideoCommon/Src/TextureCacheBase.cpp @@ -172,8 +172,10 @@ void TextureCache::ClearRenderTargets() TexCache::iterator iter = textures.begin(), tcend = textures.end(); + for (; iter!=tcend; ++iter) - iter->second->type = TCET_NORMAL; + if (iter->second->type != TCET_EC_DYNAMIC) + iter->second->type = TCET_NORMAL; } TextureCache::TCacheEntryBase* TextureCache::Load(unsigned int stage, @@ -238,6 +240,9 @@ TextureCache::TCacheEntryBase* TextureCache::Load(unsigned int stage, // 2. a) For EFB copies, only the hash and the texture address need to match if (entry->IsEfbCopy() && tex_hash == entry->hash && address == entry->addr) { + if (entry->type != TCET_EC_VRAM) + entry->type = TCET_NORMAL; + // TODO: Print a warning if the format changes! In this case, we could reinterpret the internal texture object data to the new pixel format (similiar to what is already being done in Renderer::ReinterpretPixelFormat()) goto return_entry; } @@ -318,8 +323,8 @@ TextureCache::TCacheEntryBase* TextureCache::Load(unsigned int stage, entry->SetGeneralParameters(address, texture_size, full_format, entry->num_mipmaps); entry->SetDimensions(nativeW, nativeH, width, height); entry->hash = tex_hash; - if (g_ActiveConfig.bCopyEFBToTexture) entry->type = TCET_NORMAL; - else if (entry->IsEfbCopy()) entry->type = TCET_EC_DYNAMIC; + if (entry->IsEfbCopy() && !g_ActiveConfig.bCopyEFBToTexture) entry->type = TCET_EC_DYNAMIC; + else entry->type = TCET_NORMAL; // load texture entry->Load(width, height, expandedWidth, 0, (texLevels == 0)); @@ -647,8 +652,11 @@ void TextureCache::CopyRenderTargetToTexture(u32 dstAddr, unsigned int dstFormat if ((entry->type == TCET_EC_VRAM && entry->virtual_width == scaled_tex_w && entry->virtual_height == scaled_tex_h) || (entry->type == TCET_EC_DYNAMIC && entry->native_width == tex_w && entry->native_height == tex_h)) { - scaled_tex_w = tex_w; - scaled_tex_h = tex_h; + if (entry->type == TCET_EC_DYNAMIC) + { + scaled_tex_w = tex_w; + scaled_tex_h = tex_h; + } } else { diff --git a/Source/Core/VideoCommon/Src/TextureConversionShader.cpp b/Source/Core/VideoCommon/Src/TextureConversionShader.cpp index c921a1a9fd..2132a25258 100644 --- a/Source/Core/VideoCommon/Src/TextureConversionShader.cpp +++ b/Source/Core/VideoCommon/Src/TextureConversionShader.cpp @@ -259,7 +259,7 @@ void WriteIncrementSampleX(char*& p,API_TYPE ApiType) void WriteToBitDepth(char*& p, u8 depth, const char* src, const char* dest) { - float result = pow(2.0f, depth) - 1.0f; + float result = 255 / pow(2.0f, (8 - depth)); WRITE(p, " %s = floor(%s * %ff);\n", dest, src, result); } diff --git a/Source/Core/VideoCommon/Src/VertexShaderGen.cpp b/Source/Core/VideoCommon/Src/VertexShaderGen.cpp index 5076f9f044..07ace04b97 100644 --- a/Source/Core/VideoCommon/Src/VertexShaderGen.cpp +++ b/Source/Core/VideoCommon/Src/VertexShaderGen.cpp @@ -178,31 +178,31 @@ const char *GenerateVertexShaderCode(u32 components, API_TYPE api_type) char *p = text; WRITE(p, "//Vertex Shader: comp:%x, \n", components); - WRITE(p, "typedef struct { float4 T0, T1, T2; float4 N0, N1, N2; } s_"I_POSNORMALMATRIX";\n" + WRITE(p, "typedef struct { float4 T0, T1, T2; float4 N0, N1, N2; } s_" I_POSNORMALMATRIX";\n" "typedef struct { float4 t; } FLT4;\n" - "typedef struct { FLT4 T[24]; } s_"I_TEXMATRICES";\n" - "typedef struct { FLT4 T[64]; } s_"I_TRANSFORMMATRICES";\n" - "typedef struct { FLT4 T[32]; } s_"I_NORMALMATRICES";\n" - "typedef struct { FLT4 T[64]; } s_"I_POSTTRANSFORMMATRICES";\n" + "typedef struct { FLT4 T[24]; } s_" I_TEXMATRICES";\n" + "typedef struct { FLT4 T[64]; } s_" I_TRANSFORMMATRICES";\n" + "typedef struct { FLT4 T[32]; } s_" I_NORMALMATRICES";\n" + "typedef struct { FLT4 T[64]; } s_" I_POSTTRANSFORMMATRICES";\n" "typedef struct { float4 col; float4 cosatt; float4 distatt; float4 pos; float4 dir; } Light;\n" - "typedef struct { Light lights[8]; } s_"I_LIGHTS";\n" - "typedef struct { float4 C0, C1, C2, C3; } s_"I_MATERIALS";\n" - "typedef struct { float4 T0, T1, T2, T3; } s_"I_PROJECTION";\n" + "typedef struct { Light lights[8]; } s_" I_LIGHTS";\n" + "typedef struct { float4 C0, C1, C2, C3; } s_" I_MATERIALS";\n" + "typedef struct { float4 T0, T1, T2, T3; } s_" I_PROJECTION";\n" ); p = GenerateVSOutputStruct(p, components, api_type); // uniforms - WRITE(p, "uniform s_"I_TRANSFORMMATRICES" "I_TRANSFORMMATRICES" : register(c%d);\n", C_TRANSFORMMATRICES); - WRITE(p, "uniform s_"I_TEXMATRICES" "I_TEXMATRICES" : register(c%d);\n", C_TEXMATRICES); // also using tex matrices - WRITE(p, "uniform s_"I_NORMALMATRICES" "I_NORMALMATRICES" : register(c%d);\n", C_NORMALMATRICES); - WRITE(p, "uniform s_"I_POSNORMALMATRIX" "I_POSNORMALMATRIX" : register(c%d);\n", C_POSNORMALMATRIX); - WRITE(p, "uniform s_"I_POSTTRANSFORMMATRICES" "I_POSTTRANSFORMMATRICES" : register(c%d);\n", C_POSTTRANSFORMMATRICES); - WRITE(p, "uniform s_"I_LIGHTS" "I_LIGHTS" : register(c%d);\n", C_LIGHTS); - WRITE(p, "uniform s_"I_MATERIALS" "I_MATERIALS" : register(c%d);\n", C_MATERIALS); - WRITE(p, "uniform s_"I_PROJECTION" "I_PROJECTION" : register(c%d);\n", C_PROJECTION); - WRITE(p, "uniform float4 "I_DEPTHPARAMS" : register(c%d);\n", C_DEPTHPARAMS); + WRITE(p, "uniform s_" I_TRANSFORMMATRICES" " I_TRANSFORMMATRICES" : register(c%d);\n", C_TRANSFORMMATRICES); + WRITE(p, "uniform s_" I_TEXMATRICES" " I_TEXMATRICES" : register(c%d);\n", C_TEXMATRICES); // also using tex matrices + WRITE(p, "uniform s_" I_NORMALMATRICES" " I_NORMALMATRICES" : register(c%d);\n", C_NORMALMATRICES); + WRITE(p, "uniform s_" I_POSNORMALMATRIX" " I_POSNORMALMATRIX" : register(c%d);\n", C_POSNORMALMATRIX); + WRITE(p, "uniform s_" I_POSTTRANSFORMMATRICES" " I_POSTTRANSFORMMATRICES" : register(c%d);\n", C_POSTTRANSFORMMATRICES); + WRITE(p, "uniform s_" I_LIGHTS" " I_LIGHTS" : register(c%d);\n", C_LIGHTS); + WRITE(p, "uniform s_" I_MATERIALS" " I_MATERIALS" : register(c%d);\n", C_MATERIALS); + WRITE(p, "uniform s_" I_PROJECTION" " I_PROJECTION" : register(c%d);\n", C_PROJECTION); + WRITE(p, "uniform float4 " I_DEPTHPARAMS" : register(c%d);\n", C_DEPTHPARAMS); WRITE(p, "VS_OUTPUT main(\n"); @@ -258,11 +258,11 @@ const char *GenerateVertexShaderCode(u32 components, API_TYPE api_type) WRITE(p, "int posmtx = fposmtx;\n"); } - WRITE(p, "float4 pos = float4(dot("I_TRANSFORMMATRICES".T[posmtx].t, rawpos), dot("I_TRANSFORMMATRICES".T[posmtx+1].t, rawpos), dot("I_TRANSFORMMATRICES".T[posmtx+2].t, rawpos), 1);\n"); + WRITE(p, "float4 pos = float4(dot(" I_TRANSFORMMATRICES".T[posmtx].t, rawpos), dot(" I_TRANSFORMMATRICES".T[posmtx+1].t, rawpos), dot(" I_TRANSFORMMATRICES".T[posmtx+2].t, rawpos), 1);\n"); if (components & VB_HAS_NRMALL) { WRITE(p, "int normidx = posmtx >= 32 ? (posmtx-32) : posmtx;\n"); - WRITE(p, "float3 N0 = "I_NORMALMATRICES".T[normidx].t.xyz, N1 = "I_NORMALMATRICES".T[normidx+1].t.xyz, N2 = "I_NORMALMATRICES".T[normidx+2].t.xyz;\n"); + WRITE(p, "float3 N0 = " I_NORMALMATRICES".T[normidx].t.xyz, N1 = " I_NORMALMATRICES".T[normidx+1].t.xyz, N2 = " I_NORMALMATRICES".T[normidx+2].t.xyz;\n"); } if (components & VB_HAS_NRM0) @@ -274,13 +274,13 @@ const char *GenerateVertexShaderCode(u32 components, API_TYPE api_type) } else { - WRITE(p, "float4 pos = float4(dot("I_POSNORMALMATRIX".T0, rawpos), dot("I_POSNORMALMATRIX".T1, rawpos), dot("I_POSNORMALMATRIX".T2, rawpos), 1.0f);\n"); + WRITE(p, "float4 pos = float4(dot(" I_POSNORMALMATRIX".T0, rawpos), dot(" I_POSNORMALMATRIX".T1, rawpos), dot(" I_POSNORMALMATRIX".T2, rawpos), 1.0f);\n"); if (components & VB_HAS_NRM0) - WRITE(p, "float3 _norm0 = normalize(float3(dot("I_POSNORMALMATRIX".N0.xyz, rawnorm0), dot("I_POSNORMALMATRIX".N1.xyz, rawnorm0), dot("I_POSNORMALMATRIX".N2.xyz, rawnorm0)));\n"); + WRITE(p, "float3 _norm0 = normalize(float3(dot(" I_POSNORMALMATRIX".N0.xyz, rawnorm0), dot(" I_POSNORMALMATRIX".N1.xyz, rawnorm0), dot(" I_POSNORMALMATRIX".N2.xyz, rawnorm0)));\n"); if (components & VB_HAS_NRM1) - WRITE(p, "float3 _norm1 = float3(dot("I_POSNORMALMATRIX".N0.xyz, rawnorm1), dot("I_POSNORMALMATRIX".N1.xyz, rawnorm1), dot("I_POSNORMALMATRIX".N2.xyz, rawnorm1));\n"); + WRITE(p, "float3 _norm1 = float3(dot(" I_POSNORMALMATRIX".N0.xyz, rawnorm1), dot(" I_POSNORMALMATRIX".N1.xyz, rawnorm1), dot(" I_POSNORMALMATRIX".N2.xyz, rawnorm1));\n"); if (components & VB_HAS_NRM2) - WRITE(p, "float3 _norm2 = float3(dot("I_POSNORMALMATRIX".N0.xyz, rawnorm2), dot("I_POSNORMALMATRIX".N1.xyz, rawnorm2), dot("I_POSNORMALMATRIX".N2.xyz, rawnorm2));\n"); + WRITE(p, "float3 _norm2 = float3(dot(" I_POSNORMALMATRIX".N0.xyz, rawnorm2), dot(" I_POSNORMALMATRIX".N1.xyz, rawnorm2), dot(" I_POSNORMALMATRIX".N2.xyz, rawnorm2));\n"); } if (!(components & VB_HAS_NRM0)) @@ -288,7 +288,7 @@ const char *GenerateVertexShaderCode(u32 components, API_TYPE api_type) - WRITE(p, "o.pos = float4(dot("I_PROJECTION".T0, pos), dot("I_PROJECTION".T1, pos), dot("I_PROJECTION".T2, pos), dot("I_PROJECTION".T3, pos));\n"); + WRITE(p, "o.pos = float4(dot(" I_PROJECTION".T0, pos), dot(" I_PROJECTION".T1, pos), dot(" I_PROJECTION".T2, pos), dot(" I_PROJECTION".T3, pos));\n"); WRITE(p, "float4 mat, lacc;\n" "float3 ldir, h;\n" @@ -367,7 +367,7 @@ const char *GenerateVertexShaderCode(u32 components, API_TYPE api_type) if (components & (VB_HAS_NRM1|VB_HAS_NRM2)) { // transform the light dir into tangent space - WRITE(p, "ldir = normalize("I_LIGHTS".lights[%d].pos.xyz - pos.xyz);\n", texinfo.embosslightshift); + WRITE(p, "ldir = normalize(" I_LIGHTS".lights[%d].pos.xyz - pos.xyz);\n", texinfo.embosslightshift); WRITE(p, "o.tex%d.xyz = o.tex%d.xyz + float3(dot(ldir, _norm1), dot(ldir, _norm2), 0.0f);\n", i, texinfo.embosssourceshift); } else @@ -389,16 +389,16 @@ const char *GenerateVertexShaderCode(u32 components, API_TYPE api_type) default: if (components & (VB_HAS_TEXMTXIDX0<<i)) { if (texinfo.projection == XF_TEXPROJ_STQ) - WRITE(p, "o.tex%d.xyz = float3(dot(coord, "I_TRANSFORMMATRICES".T[tex%d.z].t), dot(coord, "I_TRANSFORMMATRICES".T[tex%d.z+1].t), dot(coord, "I_TRANSFORMMATRICES".T[tex%d.z+2].t));\n", i, i, i, i); + WRITE(p, "o.tex%d.xyz = float3(dot(coord, " I_TRANSFORMMATRICES".T[tex%d.z].t), dot(coord, " I_TRANSFORMMATRICES".T[tex%d.z+1].t), dot(coord, " I_TRANSFORMMATRICES".T[tex%d.z+2].t));\n", i, i, i, i); else { - WRITE(p, "o.tex%d.xyz = float3(dot(coord, "I_TRANSFORMMATRICES".T[tex%d.z].t), dot(coord, "I_TRANSFORMMATRICES".T[tex%d.z+1].t), 1);\n", i, i, i); + WRITE(p, "o.tex%d.xyz = float3(dot(coord, " I_TRANSFORMMATRICES".T[tex%d.z].t), dot(coord, " I_TRANSFORMMATRICES".T[tex%d.z+1].t), 1);\n", i, i, i); } } else { if (texinfo.projection == XF_TEXPROJ_STQ) - WRITE(p, "o.tex%d.xyz = float3(dot(coord, "I_TEXMATRICES".T[%d].t), dot(coord, "I_TEXMATRICES".T[%d].t), dot(coord, "I_TEXMATRICES".T[%d].t));\n", i, 3*i, 3*i+1, 3*i+2); + WRITE(p, "o.tex%d.xyz = float3(dot(coord, " I_TEXMATRICES".T[%d].t), dot(coord, " I_TEXMATRICES".T[%d].t), dot(coord, " I_TEXMATRICES".T[%d].t));\n", i, 3*i, 3*i+1, 3*i+2); else - WRITE(p, "o.tex%d.xyz = float3(dot(coord, "I_TEXMATRICES".T[%d].t), dot(coord, "I_TEXMATRICES".T[%d].t), 1);\n", i, 3*i, 3*i+1); + WRITE(p, "o.tex%d.xyz = float3(dot(coord, " I_TEXMATRICES".T[%d].t), dot(coord, " I_TEXMATRICES".T[%d].t), 1);\n", i, 3*i, 3*i+1); } break; } @@ -407,9 +407,9 @@ const char *GenerateVertexShaderCode(u32 components, API_TYPE api_type) const PostMtxInfo& postInfo = xfregs.postMtxInfo[i]; int postidx = postInfo.index; - WRITE(p, "float4 P0 = "I_POSTTRANSFORMMATRICES".T[%d].t;\n" - "float4 P1 = "I_POSTTRANSFORMMATRICES".T[%d].t;\n" - "float4 P2 = "I_POSTTRANSFORMMATRICES".T[%d].t;\n", + WRITE(p, "float4 P0 = " I_POSTTRANSFORMMATRICES".T[%d].t;\n" + "float4 P1 = " I_POSTTRANSFORMMATRICES".T[%d].t;\n" + "float4 P2 = " I_POSTTRANSFORMMATRICES".T[%d].t;\n", postidx&0x3f, (postidx+1)&0x3f, (postidx+2)&0x3f); if (texGenSpecialCase) { @@ -467,7 +467,7 @@ const char *GenerateVertexShaderCode(u32 components, API_TYPE api_type) //if not early z culling will improve speed if (is_d3d) { - WRITE(p, "o.pos.z = "I_DEPTHPARAMS".x * o.pos.w + o.pos.z * "I_DEPTHPARAMS".y;\n"); + WRITE(p, "o.pos.z = " I_DEPTHPARAMS".x * o.pos.w + o.pos.z * " I_DEPTHPARAMS".y;\n"); } else { @@ -493,6 +493,13 @@ const char *GenerateVertexShaderCode(u32 components, API_TYPE api_type) //seems to get rather complicated } + if (api_type & API_D3D9) + { + // D3D9 is addressing pixel centers instead of pixel boundaries in clip space. + // Thus we need to offset the final position by half a pixel + WRITE(p, "o.pos = o.pos + float4(" I_DEPTHPARAMS".z, " I_DEPTHPARAMS".w, 0.f, 0.f);\n"); + } + WRITE(p, "return o;\n}\n"); diff --git a/Source/Core/VideoCommon/Src/VertexShaderGen.h b/Source/Core/VideoCommon/Src/VertexShaderGen.h index 0c522286b1..cb253a9b6c 100644 --- a/Source/Core/VideoCommon/Src/VertexShaderGen.h +++ b/Source/Core/VideoCommon/Src/VertexShaderGen.h @@ -35,7 +35,7 @@ #define I_TRANSFORMMATRICES "ctrmtx" #define I_NORMALMATRICES "cnmtx" #define I_POSTTRANSFORMMATRICES "cpostmtx" -#define I_DEPTHPARAMS "cDepth" +#define I_DEPTHPARAMS "cDepth" // farZ, zRange, scaled viewport width, scaled viewport height #define C_POSNORMALMATRIX 0 #define C_PROJECTION (C_POSNORMALMATRIX + 6) diff --git a/Source/Core/VideoCommon/Src/VertexShaderManager.cpp b/Source/Core/VideoCommon/Src/VertexShaderManager.cpp index d7d25c5c85..b6afbc61c6 100644 --- a/Source/Core/VideoCommon/Src/VertexShaderManager.cpp +++ b/Source/Core/VideoCommon/Src/VertexShaderManager.cpp @@ -306,7 +306,11 @@ void VertexShaderManager::SetConstants() if (bViewportChanged) { bViewportChanged = false; - SetVSConstant4f(C_DEPTHPARAMS,xfregs.viewport.farZ / 16777216.0f,xfregs.viewport.zRange / 16777216.0f,0.0f,0.0f); + SetVSConstant4f(C_DEPTHPARAMS, + xfregs.viewport.farZ / 16777216.0f, + xfregs.viewport.zRange / 16777216.0f, + -1.f / (float)g_renderer->EFBToScaledX((int)ceil(2.0f * xfregs.viewport.wd)), + 1.f / (float)g_renderer->EFBToScaledY((int)ceil(-2.0f * xfregs.viewport.ht))); // This is so implementation-dependent that we can't have it here. UpdateViewport(s_viewportCorrection); bProjectionChanged = true; diff --git a/Source/Core/VideoCommon/VideoCommon.vcxproj b/Source/Core/VideoCommon/VideoCommon.vcxproj index dd29d29ccb..f53c18cb37 100644 --- a/Source/Core/VideoCommon/VideoCommon.vcxproj +++ b/Source/Core/VideoCommon/VideoCommon.vcxproj @@ -266,7 +266,6 @@ <ItemGroup> <None Include="..\..\..\Data\User\OpenCL\TextureDecoder.cl" /> <None Include="CMakeLists.txt" /> - <None Include="Src\SConscript" /> </ItemGroup> <ItemGroup> <ProjectReference Include="..\..\..\Externals\CLRun\clrun\CLRun.vcxproj"> diff --git a/Source/Core/VideoCommon/VideoCommon.vcxproj.filters b/Source/Core/VideoCommon/VideoCommon.vcxproj.filters index 5ce157a78e..c933fbc939 100644 --- a/Source/Core/VideoCommon/VideoCommon.vcxproj.filters +++ b/Source/Core/VideoCommon/VideoCommon.vcxproj.filters @@ -248,7 +248,6 @@ </ClInclude> </ItemGroup> <ItemGroup> - <None Include="Src\SConscript" /> <None Include="CMakeLists.txt" /> <None Include="..\..\..\Data\User\OpenCL\TextureDecoder.cl"> <Filter>Decoding\OpenCL</Filter> |
