Merge branch 'master' into GLSL-master

Conflicts:
	CMakeLists.txt
	Source/Core/DolphinWX/CMakeLists.txt
	Source/Core/DolphinWX/Src/GLInterface.h
	Source/Core/VideoCommon/Src/PixelShaderGen.cpp
	Source/Core/VideoCommon/Src/TextureCacheBase.cpp
	Source/Core/VideoCommon/Src/VertexManagerBase.cpp
	Source/Plugins/Plugin_VideoDX11/Src/VertexManager.cpp
	Source/Plugins/Plugin_VideoDX9/Src/VertexManager.cpp
	Source/Plugins/Plugin_VideoOGL/Plugin_VideoOGL.vcxproj
	Source/Plugins/Plugin_VideoOGL/Plugin_VideoOGL.vcxproj.filters
	Source/Plugins/Plugin_VideoOGL/Src/GLUtil.h
	Source/Plugins/Plugin_VideoOGL/Src/PixelShaderCache.cpp
	Source/Plugins/Plugin_VideoOGL/Src/TextureCache.cpp
	Source/Plugins/Plugin_VideoOGL/Src/VertexManager.cpp
	Source/Plugins/Plugin_VideoOGL/Src/VertexShaderCache.cpp
	Source/Plugins/Plugin_VideoOGL/Src/main.cpp
This commit is contained in:
degasus
2013-03-06 15:59:29 +01:00
443 changed files with 16217 additions and 6374 deletions
+5
View File
@@ -6,6 +6,11 @@ set(SRCS Src/AudioCommon.cpp
set(LIBS "")
if(ANDROID)
set(SRCS ${SRCS} Src/OpenSLESStream.cpp)
set(LIBS ${LIBS} OpenSLES)
endif(ANDROID)
if(ALSA_FOUND)
set(SRCS ${SRCS} Src/AlsaSoundStream.cpp)
set(LIBS ${LIBS} ${ALSA_LIBRARIES})
+5 -2
View File
@@ -26,6 +26,7 @@
#include "CoreAudioSoundStream.h"
#include "OpenALStream.h"
#include "PulseAudioStream.h"
#include "OpenSLESStream.h"
#include "../../Core/Src/Movie.h"
#include "../../Core/Src/ConfigManager.h"
@@ -55,7 +56,8 @@ namespace AudioCommon
soundStream = new CoreAudioSound(mixer);
else if (backend == BACKEND_PULSEAUDIO && PulseAudio::isValid())
soundStream = new PulseAudio(mixer);
else if (backend == BACKEND_OPENSLES && OpenSLESStream::isValid())
soundStream = new OpenSLESStream(mixer);
if (soundStream != NULL)
{
UpdateSoundStream();
@@ -116,7 +118,8 @@ namespace AudioCommon
backends.push_back(BACKEND_PULSEAUDIO);
if (OpenALStream::isValid())
backends.push_back(BACKEND_OPENAL);
if (OpenSLESStream::isValid())
backends.push_back(BACKEND_OPENSLES);
return backends;
}
+9 -2
View File
@@ -200,6 +200,7 @@ void OpenALStream::SoundLoop()
u64 num_samples_to_render = (audio_dma_period * ais_samples_per_second) / SystemTimers::GetTicksPerSecond();
unsigned int numSamples = (unsigned int)num_samples_to_render;
unsigned int minSamples = surround_capable ? 240 : 0; // DPL2 accepts 240 samples minimum (FWRDURATION)
numSamples = (numSamples > OAL_MAX_SAMPLES) ? OAL_MAX_SAMPLES : numSamples;
numSamples = m_mixer->Mix(realtimeBuffer, numSamples);
@@ -236,9 +237,15 @@ void OpenALStream::SoundLoop()
// Adjust SETTING_SEQUENCE_MS to balance between lag vs hollow audio
soundTouch.setSetting(SETTING_SEQUENCE_MS, (int)(1 / (rate * rate)));
soundTouch.setTempo(rate);
if (rate > 10)
{
soundTouch.clear();
}
}
unsigned int nSamples = soundTouch.receiveSamples(sampleBuffer, OAL_MAX_SAMPLES * SIZE_FLOAT * SURROUND_CHANNELS * OAL_MAX_BUFFERS);
if (nSamples > 0)
unsigned int nSamples = soundTouch.receiveSamples(sampleBuffer, OAL_MAX_SAMPLES * SIZE_FLOAT * OAL_MAX_BUFFERS);
if (nSamples > minSamples)
{
// Remove the Buffer from the Queue. (uiBuffer contains the Buffer ID for the unqueued Buffer)
if (iBuffersFilled == 0)
@@ -0,0 +1,145 @@
// 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/
#ifdef ANDROID
#include "Common.h"
#include <assert.h>
#include "OpenSLESStream.h"
#include <SLES/OpenSLES.h>
#include <SLES/OpenSLES_Android.h>
// engine interfaces
static SLObjectItf engineObject;
static SLEngineItf engineEngine;
static SLObjectItf outputMixObject;
// buffer queue player interfaces
static SLObjectItf bqPlayerObject = NULL;
static SLPlayItf bqPlayerPlay;
static SLAndroidSimpleBufferQueueItf bqPlayerBufferQueue;
static SLMuteSoloItf bqPlayerMuteSolo;
static SLVolumeItf bqPlayerVolume;
static CMixer *g_mixer;
#define BUFFER_SIZE 512
#define BUFFER_SIZE_IN_SAMPLES (BUFFER_SIZE / 2)
// Double buffering.
static short buffer[2][BUFFER_SIZE];
static int curBuffer = 0;
static void bqPlayerCallback(SLAndroidSimpleBufferQueueItf bq, void *context) {
assert(bq == bqPlayerBufferQueue);
assert(NULL == context);
short *nextBuffer = buffer[curBuffer];
int nextSize = sizeof(buffer[0]);
SLresult result = (*bqPlayerBufferQueue)->Enqueue(bqPlayerBufferQueue, nextBuffer, nextSize);
// Comment from sample code:
// the most likely other result is SL_RESULT_BUFFER_INSUFFICIENT,
// which for this code example would indicate a programming error
assert(SL_RESULT_SUCCESS == result);
curBuffer ^= 1; // Switch buffer
// Render to the fresh buffer
g_mixer->Mix(reinterpret_cast<short *>(buffer[curBuffer]), BUFFER_SIZE_IN_SAMPLES);
}
bool OpenSLESStream::Start()
{
SLresult result;
// create engine
result = slCreateEngine(&engineObject, 0, NULL, 0, NULL, NULL);
assert(SL_RESULT_SUCCESS == result);
result = (*engineObject)->Realize(engineObject, SL_BOOLEAN_FALSE);
assert(SL_RESULT_SUCCESS == result);
result = (*engineObject)->GetInterface(engineObject, SL_IID_ENGINE, &engineEngine);
assert(SL_RESULT_SUCCESS == result);
result = (*engineEngine)->CreateOutputMix(engineEngine, &outputMixObject, 0, 0, 0);
assert(SL_RESULT_SUCCESS == result);
result = (*outputMixObject)->Realize(outputMixObject, SL_BOOLEAN_FALSE);
assert(SL_RESULT_SUCCESS == result);
SLDataLocator_AndroidSimpleBufferQueue loc_bufq = {SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE, 2};
SLDataFormat_PCM format_pcm = {
SL_DATAFORMAT_PCM,
2,
SL_SAMPLINGRATE_44_1,
SL_PCMSAMPLEFORMAT_FIXED_16,
SL_PCMSAMPLEFORMAT_FIXED_16,
SL_SPEAKER_FRONT_LEFT | SL_SPEAKER_FRONT_RIGHT,
SL_BYTEORDER_LITTLEENDIAN
};
SLDataSource audioSrc = {&loc_bufq, &format_pcm};
// configure audio sink
SLDataLocator_OutputMix loc_outmix = {SL_DATALOCATOR_OUTPUTMIX, outputMixObject};
SLDataSink audioSnk = {&loc_outmix, NULL};
// create audio player
const SLInterfaceID ids[2] = {SL_IID_BUFFERQUEUE, SL_IID_VOLUME};
const SLboolean req[2] = {SL_BOOLEAN_TRUE, SL_BOOLEAN_TRUE};
result = (*engineEngine)->CreateAudioPlayer(engineEngine, &bqPlayerObject, &audioSrc, &audioSnk, 2, ids, req);
assert(SL_RESULT_SUCCESS == result);
result = (*bqPlayerObject)->Realize(bqPlayerObject, SL_BOOLEAN_FALSE);
assert(SL_RESULT_SUCCESS == result);
result = (*bqPlayerObject)->GetInterface(bqPlayerObject, SL_IID_PLAY, &bqPlayerPlay);
assert(SL_RESULT_SUCCESS == result);
result = (*bqPlayerObject)->GetInterface(bqPlayerObject, SL_IID_BUFFERQUEUE,
&bqPlayerBufferQueue);
assert(SL_RESULT_SUCCESS == result);
result = (*bqPlayerBufferQueue)->RegisterCallback(bqPlayerBufferQueue, bqPlayerCallback, NULL);
assert(SL_RESULT_SUCCESS == result);
result = (*bqPlayerPlay)->SetPlayState(bqPlayerPlay, SL_PLAYSTATE_PLAYING);
assert(SL_RESULT_SUCCESS == result);
// Render and enqueue a first buffer. (or should we just play the buffer empty?)
curBuffer = 0;
result = (*bqPlayerBufferQueue)->Enqueue(bqPlayerBufferQueue, buffer[curBuffer], sizeof(buffer[curBuffer]));
if (SL_RESULT_SUCCESS != result) {
return false;
}
curBuffer ^= 1;
g_mixer = m_mixer;
return true;
}
void OpenSLESStream::Stop()
{
if (bqPlayerObject != NULL) {
(*bqPlayerObject)->Destroy(bqPlayerObject);
bqPlayerObject = NULL;
bqPlayerPlay = NULL;
bqPlayerBufferQueue = NULL;
bqPlayerMuteSolo = NULL;
bqPlayerVolume = NULL;
}
if (outputMixObject != NULL) {
(*outputMixObject)->Destroy(outputMixObject);
outputMixObject = NULL;
}
if (engineObject != NULL) {
(*engineObject)->Destroy(engineObject);
engineObject = NULL;
engineEngine = NULL;
}
}
#endif
@@ -0,0 +1,48 @@
// 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 _OPENSLSTREAM_H_
#define _OPENSLSTREAM_H_
#include "Thread.h"
#include "SoundStream.h"
class OpenSLESStream : public SoundStream
{
#ifdef ANDROID
public:
OpenSLESStream(CMixer *mixer, void *hWnd = NULL)
: SoundStream(mixer)
{};
virtual ~OpenSLESStream() {};
virtual bool Start();
virtual void Stop();
static bool isValid() { return true; }
virtual bool usesMixer() const { return true; }
private:
std::thread thread;
Common::Event soundSyncEvent;
#else
public:
OpenSLESStream(CMixer *mixer, void *hWnd = NULL): SoundStream(mixer) {}
#endif // HAVE_OPENSL
};
#endif
+19 -4
View File
@@ -1,9 +1,7 @@
set(SRCS Src/ABI.cpp
Src/BreakPoints.cpp
set(SRCS Src/BreakPoints.cpp
Src/CDUtils.cpp
Src/ColorUtil.cpp
Src/ConsoleListener.cpp
Src/CPUDetect.cpp
Src/FileSearch.cpp
Src/FileUtil.cpp
Src/Hash.cpp
@@ -20,10 +18,10 @@ set(SRCS Src/ABI.cpp
Src/SymbolDB.cpp
Src/SysConf.cpp
Src/Thread.cpp
Src/Thunk.cpp
Src/Timer.cpp
Src/Version.cpp
Src/VideoBackendBase.cpp
Src/x64ABI.cpp
Src/x64Analyzer.cpp
Src/x64Emitter.cpp
Src/Crypto/aes_cbc.cpp
@@ -33,6 +31,23 @@ set(SRCS Src/ABI.cpp
Src/Crypto/md5.cpp
Src/Crypto/sha1.cpp)
if(_M_ARM) #ARM
set(SRCS ${SRCS}
Src/ArmCPUDetect.cpp
Src/ArmEmitter.cpp)
else()
if(NOT _M_GENERIC) #X86
set(SRCS ${SRCS}
Src/x64FPURoundMode.cpp
Src/x64Thunk.cpp
)
endif()
set(SRCS ${SRCS} Src/x64CPUDetect.cpp)
endif()
if(_M_GENERIC) #Generic
set(SRCS ${SRCS}
Src/GenericFPURoundMode.cpp)
endif()
if(WIN32)
set(SRCS ${SRCS} Src/ExtendedTrace.cpp)
endif(WIN32)
+7 -6
View File
@@ -44,7 +44,7 @@
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<UseDebugLibraries>false</UseDebugLibraries>
<ConfigurationType>StaticLibrary</ConfigurationType>
<CharacterSet>MultiByte</CharacterSet>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='DebugFast|Win32'" Label="Configuration">
<ConfigurationType>StaticLibrary</ConfigurationType>
@@ -54,7 +54,7 @@
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<UseDebugLibraries>false</UseDebugLibraries>
<ConfigurationType>StaticLibrary</ConfigurationType>
<CharacterSet>MultiByte</CharacterSet>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='DebugFast|x64'" Label="Configuration">
<ConfigurationType>StaticLibrary</ConfigurationType>
@@ -158,12 +158,10 @@
<Lib />
</ItemDefinitionGroup>
<ItemGroup>
<ClCompile Include="Src\ABI.cpp" />
<ClCompile Include="Src\BreakPoints.cpp" />
<ClCompile Include="Src\CDUtils.cpp" />
<ClCompile Include="Src\ColorUtil.cpp" />
<ClCompile Include="Src\ConsoleListener.cpp" />
<ClCompile Include="Src\CPUDetect.cpp" />
<ClCompile Include="Src\Crypto\aes_cbc.cpp" />
<ClCompile Include="Src\Crypto\aes_core.cpp" />
<ClCompile Include="Src\Crypto\bn.cpp" />
@@ -195,15 +193,17 @@
<ClCompile Include="Src\SymbolDB.cpp" />
<ClCompile Include="Src\SysConf.cpp" />
<ClCompile Include="Src\Thread.cpp" />
<ClCompile Include="Src\Thunk.cpp" />
<ClCompile Include="Src\Timer.cpp" />
<ClCompile Include="Src\Version.cpp" />
<ClCompile Include="Src\VideoBackendBase.cpp" />
<ClCompile Include="Src\x64ABI.cpp" />
<ClCompile Include="Src\x64Analyzer.cpp" />
<ClCompile Include="Src\x64CPUDetect.cpp" />
<ClCompile Include="Src\x64Emitter.cpp" />
<ClCompile Include="Src\x64FPURoundMode.cpp" />
<ClCompile Include="Src\x64Thunk.cpp" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="Src\ABI.h" />
<ClInclude Include="Src\Atomic.h" />
<ClInclude Include="Src\Atomic_GCC.h" />
<ClInclude Include="Src\Atomic_Win32.h" />
@@ -251,6 +251,7 @@
<ClInclude Include="Src\Thunk.h" />
<ClInclude Include="Src\Timer.h" />
<ClInclude Include="Src\VideoBackendBase.h" />
<ClInclude Include="Src\x64ABI.h" />
<ClInclude Include="Src\x64Analyzer.h" />
<ClInclude Include="Src\x64Emitter.h" />
</ItemGroup>
+5 -4
View File
@@ -1,11 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<ClCompile Include="Src\ABI.cpp" />
<ClCompile Include="Src\BreakPoints.cpp" />
<ClCompile Include="Src\CDUtils.cpp" />
<ClCompile Include="Src\ColorUtil.cpp" />
<ClCompile Include="Src\CPUDetect.cpp" />
<ClCompile Include="Src\ExtendedTrace.cpp" />
<ClCompile Include="Src\FileSearch.cpp" />
<ClCompile Include="Src\FileUtil.cpp" />
@@ -23,7 +21,6 @@
<ClCompile Include="Src\SymbolDB.cpp" />
<ClCompile Include="Src\SysConf.cpp" />
<ClCompile Include="Src\Thread.cpp" />
<ClCompile Include="Src\Thunk.cpp" />
<ClCompile Include="Src\Timer.cpp" />
<ClCompile Include="Src\Version.cpp" />
<ClCompile Include="Src\VideoBackendBase.cpp" />
@@ -53,9 +50,12 @@
<ClCompile Include="Src\Crypto\sha1.cpp">
<Filter>Crypto</Filter>
</ClCompile>
<ClCompile Include="Src\x64ABI.cpp" />
<ClCompile Include="Src\x64CPUDetect.cpp" />
<ClCompile Include="Src\x64FPURoundMode.cpp" />
<ClCompile Include="Src\x64Thunk.cpp" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="Src\ABI.h" />
<ClInclude Include="Src\Atomic.h" />
<ClInclude Include="Src\Atomic_GCC.h" />
<ClInclude Include="Src\Atomic_Win32.h" />
@@ -121,6 +121,7 @@
</ClInclude>
<ClInclude Include="Src\StdMutex.h" />
<ClInclude Include="Src\StdConditionVariable.h" />
<ClInclude Include="Src\x64ABI.h" />
</ItemGroup>
<ItemGroup>
<None Include="CMakeLists.txt" />
+161
View File
@@ -0,0 +1,161 @@
// 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 "CPUDetect.h"
#include "StringUtil.h"
#include "FileUtil.h"
const char procfile[] = "/proc/cpuinfo";
char *GetCPUString()
{
const char marker[] = "Hardware\t: ";
char *cpu_string = 0;
// Count the number of processor lines in /proc/cpuinfo
char buf[1024];
File::IOFile file(procfile, "r");
auto const fp = file.GetHandle();
if (!fp)
return 0;
while (fgets(buf, sizeof(buf), fp))
{
if (strncmp(buf, marker, sizeof(marker) - 1))
continue;
cpu_string = buf + sizeof(marker) - 1;
cpu_string = strndup(cpu_string, strlen(cpu_string) - 1); // Strip the newline
break;
}
return cpu_string;
}
bool CheckCPUFeature(const char *feature)
{
const char marker[] = "Features\t: ";
char buf[1024];
File::IOFile file(procfile, "r");
auto const fp = file.GetHandle();
if (!fp)
return 0;
while (fgets(buf, sizeof(buf), fp))
{
if (strncmp(buf, marker, sizeof(marker) - 1))
continue;
char *featurestring = buf + sizeof(marker) - 1;
char *token = strtok(featurestring, " ");
while (token != NULL)
{
if (strstr(token, feature))
return true;
token = strtok(NULL, " ");
}
}
return false;
}
int GetCoreCount()
{
const char marker[] = "processor\t: ";
int cores = 0;
char buf[1024];
File::IOFile file(procfile, "r");
auto const fp = file.GetHandle();
if (!fp)
return 0;
while (fgets(buf, sizeof(buf), fp))
{
if (strncmp(buf, marker, sizeof(marker) - 1))
continue;
++cores;
}
return cores;
}
CPUInfo cpu_info;
CPUInfo::CPUInfo() {
Detect();
}
// Detects the various cpu features
void CPUInfo::Detect()
{
// Set some defaults here
// When ARMv8 cpus come out, these need to be updated.
HTT = false;
OS64bit = false;
CPU64bit = false;
Mode64bit = false;
vendor = VENDOR_ARM;
// Get the information about the CPU
strncpy(cpu_string, GetCPUString(), sizeof(cpu_string));
num_cores = GetCoreCount();
bSwp = CheckCPUFeature("swp");
bHalf = CheckCPUFeature("half");
bThumb = CheckCPUFeature("thumb");
bFastMult = CheckCPUFeature("fastmult");
bVFP = CheckCPUFeature("vfp");
bEDSP = CheckCPUFeature("edsp");
bThumbEE = CheckCPUFeature("thumbee");
bNEON = CheckCPUFeature("neon");
bVFPv3 = CheckCPUFeature("vfpv3");
bTLS = CheckCPUFeature("tls");
bVFPv4 = CheckCPUFeature("vfpv4");
bIDIVa = CheckCPUFeature("idiva");
bIDIVt = CheckCPUFeature("idivt");
// These two are ARMv8 specific.
bFP = CheckCPUFeature("fp");
bASIMD = CheckCPUFeature("asimd");
#if defined(__ARM_ARCH_7A__)
bArmV7 = true;
#else
bArmV7 = false;
#endif
}
// Turn the cpu info into a string we can show
std::string CPUInfo::Summarize()
{
std::string sum;
if (num_cores == 1)
sum = StringFromFormat("%s, %i core", cpu_string, num_cores);
else
sum = StringFromFormat("%s, %i cores", cpu_string, num_cores);
if (bSwp) sum += ", SWP";
if (bHalf) sum += ", Half";
if (bThumb) sum += ", Thumb";
if (bFastMult) sum += ", FastMult";
if (bVFP) sum += ", VFP";
if (bEDSP) sum += ", EDSP";
if (bThumbEE) sum += ", ThumbEE";
if (bNEON) sum += ", NEON";
if (bVFPv3) sum += ", VFPv3";
if (bTLS) sum += ", TLS";
if (bVFPv4) sum += ", VFPv4";
if (bIDIVa) sum += ", IDIVa";
if (bIDIVt) sum += ", IDIVt";
return sum;
}
File diff suppressed because it is too large Load Diff
+589
View File
@@ -0,0 +1,589 @@
// 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/
// WARNING - THIS LIBRARY IS NOT THREAD SAFE!!!
#ifndef _DOLPHIN_ARM_CODEGEN_
#define _DOLPHIN_ARM_CODEGEN_
#include "Common.h"
#include "MemoryUtil.h"
#if defined(__SYMBIAN32__) || defined(PANDORA)
#include <signal.h>
#endif
#undef _IP
#undef R0
#undef _SP
#undef _LR
#undef _PC
namespace ArmGen
{
enum ARMReg
{
// GPRs
R0 = 0, R1, R2, R3, R4, R5,
R6, R7, R8, R9, R10, R11,
// SPRs
// R13 - R15 are SP, LR, and PC.
// Almost always referred to by name instead of register number
R12 = 12, R13 = 13, R14 = 14, R15 = 15,
_IP = 12, _SP = 13, _LR = 14, _PC = 15,
// VFP single precision registers
S0, S1, S2, S3, S4, S5, S6,
S7, S8, S9, S10, S11, S12, S13,
S14, S15, S16, S17, S18, S19, S20,
S21, S22, S23, S24, S25, S26, S27,
S28, S29, S30, S31,
// VFP Double Precision registers
D0, D1, D2, D3, D4, D5, D6, D7,
D8, D9, D10, D11, D12, D13, D14, D15,
D16, D17, D18, D19, D20, D21, D22, D23,
D24, D25, D26, D27, D28, D29, D30, D31,
// ASIMD Quad-Word registers
Q0, Q1, Q2, Q3, Q4, Q5, Q6, Q7,
Q8, Q9, Q10, Q11, Q12, Q13, Q14, Q15,
INVALID_REG = 0xFFFFFFFF
};
enum CCFlags
{
CC_EQ = 0, // Equal
CC_NEQ, // Not equal
CC_CS, // Carry Set
CC_CC, // Carry Clear
CC_MI, // Minus (Negative)
CC_PL, // Plus
CC_VS, // Overflow
CC_VC, // No Overflow
CC_HI, // Unsigned higher
CC_LS, // Unsigned lower or same
CC_GE, // Signed greater than or equal
CC_LT, // Signed less than
CC_GT, // Signed greater than
CC_LE, // Signed less than or equal
CC_AL, // Always (unconditional) 14
CC_HS = CC_CS, // Alias of CC_CS Unsigned higher or same
CC_LO = CC_CC, // Alias of CC_CC Unsigned lower
};
const u32 NO_COND = 0xE0000000;
enum ShiftType
{
ST_LSL = 0,
ST_ASL = 0,
ST_LSR = 1,
ST_ASR = 2,
ST_ROR = 3,
ST_RRX = 4
};
enum IntegerSize
{
I_I8 = 0,
I_I16,
I_I32,
I_I64
};
enum
{
NUMGPRs = 13,
};
class ARMXEmitter;
enum OpType
{
TYPE_IMM = 0,
TYPE_REG,
TYPE_IMMSREG,
TYPE_RSR,
TYPE_MEM
};
// This is no longer a proper operand2 class. Need to split up.
class Operand2
{
friend class ARMXEmitter;
protected:
u32 Value;
private:
OpType Type;
// IMM types
u8 Rotation; // Only for u8 values
// Register types
u8 IndexOrShift;
ShiftType Shift;
public:
OpType GetType()
{
return Type;
}
Operand2() {}
Operand2(u32 imm, OpType type = TYPE_IMM)
{
Type = type;
Value = imm;
Rotation = 0;
}
Operand2(ARMReg Reg)
{
Type = TYPE_REG;
Value = Reg;
Rotation = 0;
}
Operand2(u8 imm, u8 rotation)
{
Type = TYPE_IMM;
Value = imm;
Rotation = rotation;
}
Operand2(ARMReg base, ShiftType type, ARMReg shift) // RSR
{
Type = TYPE_RSR;
_assert_msg_(DYNA_REC, type != ST_RRX, "Invalid Operand2: RRX does not take a register shift amount");
IndexOrShift = shift;
Shift = type;
Value = base;
}
Operand2(u8 shift, ShiftType type, ARMReg base)// For IMM shifted register
{
if(shift == 32) shift = 0;
switch (type)
{
case ST_LSL:
_assert_msg_(DYNA_REC, shift < 32, "Invalid Operand2: LSL %u", shift);
break;
case ST_LSR:
_assert_msg_(DYNA_REC, shift <= 32, "Invalid Operand2: LSR %u", shift);
if (!shift)
type = ST_LSL;
if (shift == 32)
shift = 0;
break;
case ST_ASR:
_assert_msg_(DYNA_REC, shift < 32, "Invalid Operand2: LSR %u", shift);
if (!shift)
type = ST_LSL;
if (shift == 32)
shift = 0;
break;
case ST_ROR:
_assert_msg_(DYNA_REC, shift < 32, "Invalid Operand2: ROR %u", shift);
if (!shift)
type = ST_LSL;
break;
case ST_RRX:
_assert_msg_(DYNA_REC, shift == 0, "Invalid Operand2: RRX does not take an immediate shift amount");
type = ST_ROR;
break;
}
IndexOrShift = shift;
Shift = type;
Value = base;
Type = TYPE_IMMSREG;
}
u32 GetData()
{
switch(Type)
{
case TYPE_IMM:
return Imm12Mod(); // This'll need to be changed later
case TYPE_REG:
return Rm();
case TYPE_IMMSREG:
return IMMSR();
case TYPE_RSR:
return RSR();
default:
_assert_msg_(DYNA_REC, false, "GetData with Invalid Type");
return 0;
}
}
u32 IMMSR() // IMM shifted register
{
_assert_msg_(DYNA_REC, Type == TYPE_IMMSREG, "IMMSR must be imm shifted register");
return ((IndexOrShift & 0x1f) << 7 | (Shift << 5) | Value);
}
u32 RSR() // Register shifted register
{
_assert_msg_(DYNA_REC, Type == TYPE_RSR, "RSR must be RSR Of Course");
return (IndexOrShift << 8) | (Shift << 5) | 0x10 | Value;
}
u32 Rm()
{
_assert_msg_(DYNA_REC, Type == TYPE_REG, "Rm must be with Reg");
return Value;
}
u32 Imm5()
{
_assert_msg_(DYNA_REC, (Type == TYPE_IMM), "Imm5 not IMM value");
return ((Value & 0x0000001F) << 7);
}
u32 Imm8()
{
_assert_msg_(DYNA_REC, (Type == TYPE_IMM), "Imm8Rot not IMM value");
return Value & 0xFF;
}
u32 Imm8Rot() // IMM8 with Rotation
{
_assert_msg_(DYNA_REC, (Type == TYPE_IMM), "Imm8Rot not IMM value");
_assert_msg_(DYNA_REC, (Rotation & 0xE1) != 0, "Invalid Operand2: immediate rotation %u", Rotation);
return (1 << 25) | (Rotation << 7) | (Value & 0x000000FF);
}
u32 Imm12()
{
_assert_msg_(DYNA_REC, (Type == TYPE_IMM), "Imm12 not IMM");
return (Value & 0x00000FFF);
}
u32 Imm12Mod()
{
// This is a IMM12 with the top four bits being rotation and the
// bottom eight being a IMM. This is for instructions that need to
// expand a 8bit IMM to a 32bit value and gives you some rotation as
// well.
// Each rotation rotates to the right by 2 bits
_assert_msg_(DYNA_REC, (Type == TYPE_IMM), "Imm12Mod not IMM");
return ((Rotation & 0xF) << 8) | (Value & 0xFF);
}
u32 Imm16()
{
_assert_msg_(DYNA_REC, (Type == TYPE_IMM), "Imm16 not IMM");
return ( (Value & 0xF000) << 4) | (Value & 0x0FFF);
}
u32 Imm16Low()
{
return Imm16();
}
u32 Imm16High() // Returns high 16bits
{
_assert_msg_(DYNA_REC, (Type == TYPE_IMM), "Imm16 not IMM");
return ( ((Value >> 16) & 0xF000) << 4) | ((Value >> 16) & 0x0FFF);
}
u32 Imm24()
{
_assert_msg_(DYNA_REC, (Type == TYPE_IMM), "Imm16 not IMM");
return (Value & 0x0FFFFFFF);
}
// NEON and ASIMD specific
u32 Imm8ASIMD()
{
_assert_msg_(DYNA_REC, (Type == TYPE_IMM), "Imm8ASIMD not IMM");
return ((Value & 0x80) << 17) | ((Value & 0x70) << 12) | (Value & 0xF);
}
u32 Imm8VFP()
{
_assert_msg_(DYNA_REC, (Type == TYPE_IMM), "Imm8VFP not IMM");
return ((Value & 0xF0) << 12) | (Value & 0xF);
}
};
// Use these when you don't know if an imm can be represented as an operand2.
// This lets you generate both an optimal and a fallback solution by checking
// the return value, which will be false if these fail to find a Operand2 that
// represents your 32-bit imm value.
bool TryMakeOperand2(u32 imm, Operand2 &op2);
bool TryMakeOperand2_AllowInverse(u32 imm, Operand2 &op2, bool *inverse);
bool TryMakeOperand2_AllowNegation(s32 imm, Operand2 &op2, bool *negated);
inline Operand2 R(ARMReg Reg) { return Operand2(Reg, TYPE_REG); }
inline Operand2 IMM(u32 Imm) { return Operand2(Imm, TYPE_IMM); }
inline Operand2 Mem(void *ptr) { return Operand2((u32)ptr, TYPE_IMM); }
//usage: struct {int e;} s; STRUCT_OFFSET(s,e)
#define STRUCT_OFF(str,elem) ((u32)((u32)&(str).elem-(u32)&(str)))
struct FixupBranch
{
u8 *ptr;
u32 condition; // Remembers our codition at the time
int type; //0 = B 1 = BL
};
typedef const u8* JumpTarget;
class ARMXEmitter
{
friend struct OpArg; // for Write8 etc
private:
u8 *code, *startcode;
u8 *lastCacheFlushEnd;
u32 condition;
void WriteStoreOp(u32 op, ARMReg dest, ARMReg src, s16 op2);
void WriteRegStoreOp(u32 op, ARMReg dest, bool WriteBack, u16 RegList);
void WriteShiftedDataOp(u32 op, bool SetFlags, ARMReg dest, ARMReg src, ARMReg op2);
void WriteShiftedDataOp(u32 op, bool SetFlags, ARMReg dest, ARMReg src, Operand2 op2);
void WriteSignedMultiply(u32 Op, u32 Op2, u32 Op3, ARMReg dest, ARMReg r1, ARMReg r2);
void Write4OpMultiply(u32 op, ARMReg destLo, ARMReg destHi, ARMReg rn, ARMReg rm);
// New Ops
void WriteInstruction(u32 op, ARMReg Rd, ARMReg Rn, Operand2 Rm, bool SetFlags = false);
protected:
inline void Write32(u32 value) {*(u32*)code = value; code+=4;}
public:
ARMXEmitter() : code(0), startcode(0), lastCacheFlushEnd(0) {
condition = CC_AL << 28;
}
ARMXEmitter(u8 *code_ptr) {
code = code_ptr;
lastCacheFlushEnd = code_ptr;
startcode = code_ptr;
condition = CC_AL << 28;
}
virtual ~ARMXEmitter() {}
void SetCodePtr(u8 *ptr);
void ReserveCodeSpace(u32 bytes);
const u8 *AlignCode16();
const u8 *AlignCodePage();
const u8 *GetCodePtr() const;
void FlushIcache();
void FlushIcacheSection(u8 *start, u8 *end);
u8 *GetWritableCodePtr();
void SetCC(CCFlags cond = CC_AL);
// Special purpose instructions
// Dynamic Endian Switching
void SETEND(bool BE);
// Debug Breakpoint
void BKPT(u16 arg);
// Hint instruction
void YIELD();
// Do nothing
void NOP(int count = 1); //nop padding - TODO: fast nop slides, for amd and intel (check their manuals)
#ifdef CALL
#undef CALL
#endif
// Branching
FixupBranch B();
FixupBranch B_CC(CCFlags Cond);
void B_CC(CCFlags Cond, const void *fnptr);
FixupBranch BL();
FixupBranch BL_CC(CCFlags Cond);
void SetJumpTarget(FixupBranch const &branch);
void B (const void *fnptr);
void B (ARMReg src);
void BL(const void *fnptr);
void BL(ARMReg src);
void PUSH(const int num, ...);
void POP(const int num, ...);
// New Data Ops
void AND (ARMReg Rd, ARMReg Rn, Operand2 Rm);
void ANDS(ARMReg Rd, ARMReg Rn, Operand2 Rm);
void EOR (ARMReg dest, ARMReg src, Operand2 op2);
void EORS(ARMReg dest, ARMReg src, Operand2 op2);
void SUB (ARMReg dest, ARMReg src, Operand2 op2);
void SUBS(ARMReg dest, ARMReg src, Operand2 op2);
void RSB (ARMReg dest, ARMReg src, Operand2 op2);
void RSBS(ARMReg dest, ARMReg src, Operand2 op2);
void ADD (ARMReg dest, ARMReg src, Operand2 op2);
void ADDS(ARMReg dest, ARMReg src, Operand2 op2);
void ADC (ARMReg dest, ARMReg src, Operand2 op2);
void ADCS(ARMReg dest, ARMReg src, Operand2 op2);
void LSL (ARMReg dest, ARMReg src, Operand2 op2);
void LSL (ARMReg dest, ARMReg src, ARMReg op2);
void LSLS(ARMReg dest, ARMReg src, Operand2 op2);
void LSLS(ARMReg dest, ARMReg src, ARMReg op2);
void SBC (ARMReg dest, ARMReg src, Operand2 op2);
void SBCS(ARMReg dest, ARMReg src, Operand2 op2);
void REV (ARMReg dest, ARMReg src);
void REV16 (ARMReg dest, ARMReg src);
void RSC (ARMReg dest, ARMReg src, Operand2 op2);
void RSCS(ARMReg dest, ARMReg src, Operand2 op2);
void TST ( ARMReg src, Operand2 op2);
void TEQ ( ARMReg src, Operand2 op2);
void CMP ( ARMReg src, Operand2 op2);
void CMN ( ARMReg src, Operand2 op2);
void ORR (ARMReg dest, ARMReg src, Operand2 op2);
void ORRS(ARMReg dest, ARMReg src, Operand2 op2);
void MOV (ARMReg dest, Operand2 op2);
void MOVS(ARMReg dest, Operand2 op2);
void BIC (ARMReg dest, ARMReg src, Operand2 op2); // BIC = ANDN
void BICS(ARMReg dest, ARMReg src, Operand2 op2);
void MVN (ARMReg dest, Operand2 op2);
void MVNS(ARMReg dest, Operand2 op2);
void MOVW(ARMReg dest, Operand2 op2);
void MOVT(ARMReg dest, Operand2 op2, bool TopBits = false);
// UDIV and SDIV are only available on CPUs that have
// the idiva hardare capacity
void UDIV(ARMReg dest, ARMReg dividend, ARMReg divisor);
void SDIV(ARMReg dest, ARMReg dividend, ARMReg divisor);
void MUL (ARMReg dest, ARMReg src, ARMReg op2);
void MULS(ARMReg dest, ARMReg src, ARMReg op2);
void UMULL(ARMReg destLo, ARMReg destHi, ARMReg rn, ARMReg rm);
void SMULL(ARMReg destLo, ARMReg destHi, ARMReg rn, ARMReg rm);
void SXTB(ARMReg dest, ARMReg op2);
void SXTH(ARMReg dest, ARMReg op2, u8 rotation = 0);
void SXTAH(ARMReg dest, ARMReg src, ARMReg op2, u8 rotation = 0);
// Using just MSR here messes with our defines on the PPC side of stuff (when this code was in dolphin...)
// Just need to put an underscore here, bit annoying.
void _MSR (bool nzcvq, bool g, Operand2 op2);
void _MSR (bool nzcvq, bool g, ARMReg src );
void MRS (ARMReg dest);
// Memory load/store operations
void LDR (ARMReg dest, ARMReg src, s16 op2 = 0);
// Offset adds to the base register in LDR
void LDR (ARMReg dest, ARMReg base, ARMReg offset, bool Index, bool Add);
void LDRH(ARMReg dest, ARMReg src, Operand2 op = 0);
void LDRB(ARMReg dest, ARMReg src, s16 op2 = 0);
void STR (ARMReg dest, ARMReg src, s16 op2 = 0);
// Offset adds on to the destination register in STR
void STR (ARMReg dest, ARMReg base, ARMReg offset, bool Index, bool Add);
void STRB(ARMReg dest, ARMReg src, s16 op2 = 0);
void STMFD(ARMReg dest, bool WriteBack, const int Regnum, ...);
void LDMFD(ARMReg dest, bool WriteBack, const int Regnum, ...);
// Exclusive Access operations
void LDREX(ARMReg dest, ARMReg base);
// dest contains the result if the instruction managed to store the value
void STREX(ARMReg dest, ARMReg base, ARMReg op);
void DMB ();
void SVC(Operand2 op);
// NEON and ASIMD instructions
// None of these will be created with conditional since ARM
// is deprecating conditional execution of ASIMD instructions.
// ASIMD instructions don't even have a conditional encoding.
// Subtracts the base from the register to give us the real one
ARMReg SubBase(ARMReg Reg);
// NEON Only
void VADD(IntegerSize Size, ARMReg Vd, ARMReg Vn, ARMReg Vm);
void VSUB(IntegerSize Size, ARMReg Vd, ARMReg Vn, ARMReg Vm);
// VFP Only
void VLDR(ARMReg Dest, ARMReg Base, s16 offset);
void VSTR(ARMReg Src, ARMReg Base, s16 offset);
void VCMP(ARMReg Vd, ARMReg Vm);
// Compares against zero
void VCMP(ARMReg Vd);
void VDIV(ARMReg Vd, ARMReg Vn, ARMReg Vm);
void VSQRT(ARMReg Vd, ARMReg Vm);
// NEON and VFP
void VADD(ARMReg Vd, ARMReg Vn, ARMReg Vm);
void VSUB(ARMReg Vd, ARMReg Vn, ARMReg Vm);
void VABS(ARMReg Vd, ARMReg Vm);
void VNEG(ARMReg Vd, ARMReg Vm);
void VMUL(ARMReg Vd, ARMReg Vn, ARMReg Vm);
void VMOV(ARMReg Dest, ARMReg Src, bool high);
void VMOV(ARMReg Dest, ARMReg Src);
void QuickCallFunction(ARMReg scratchreg, void *func);
// Utility functions
void MOVI2R(ARMReg reg, u32 val, bool optimize = true);
void ARMABI_MOVI2M(Operand2 op, Operand2 val);
}; // class ARMXEmitter
// Everything that needs to generate X86 code should inherit from this.
// You get memory management for free, plus, you can use all the MOV etc functions without
// having to prefix them with gen-> or something similar.
class ARMXCodeBlock : public ARMXEmitter
{
protected:
u8 *region;
size_t region_size;
public:
ARMXCodeBlock() : region(NULL), region_size(0) {}
virtual ~ARMXCodeBlock() { if (region) FreeCodeSpace(); }
// Call this before you generate any code.
void AllocCodeSpace(int size)
{
region_size = size;
region = (u8*)AllocateExecutableMemory(region_size);
SetCodePtr(region);
}
// Always clear code space with breakpoints, so that if someone accidentally executes
// uninitialized, it just breaks into the debugger.
void ClearCodeSpace()
{
// x86/64: 0xCC = breakpoint
memset(region, 0xCC, region_size);
ResetCodePtr();
}
// Call this when shutting down. Don't rely on the destructor, even though it'll do the job.
void FreeCodeSpace()
{
FreeMemoryPages(region, region_size);
region = NULL;
region_size = 0;
}
bool IsInSpace(u8 *ptr)
{
return ptr >= region && ptr < region + region_size;
}
// Cannot currently be undone. Will write protect the entire code region.
// Start over if you need to change the code (call FreeCodeSpace(), AllocCodeSpace()).
void WriteProtect()
{
WriteProtectMemory(region, region_size, true);
}
void ResetCodePtr()
{
SetCodePtr(region);
}
size_t GetSpaceLeft() const
{
return region_size - (GetCodePtr() - region);
}
};
} // namespace
#endif // _DOLPHIN_INTEL_CODEGEN_
+6 -5
View File
@@ -6,6 +6,7 @@
#include <memory> // for std::unique_ptr
#ifdef _WIN32
#include <windows.h>
#include "StringUtil.h"
#elif __APPLE__
#include <CoreFoundation/CoreFoundation.h>
#include <IOKit/IOBSD.h>
@@ -25,7 +26,7 @@
#ifdef _WIN32
// takes a root drive path, returns true if it is a cdrom drive
bool is_cdrom(const char drive[])
bool is_cdrom(const TCHAR* drive)
{
return (DRIVE_CDROM == GetDriveType(drive));
}
@@ -36,15 +37,15 @@ std::vector<std::string> cdio_get_devices()
std::vector<std::string> drives;
const DWORD buffsize = GetLogicalDriveStrings(0, NULL);
std::unique_ptr<char[]> buff(new char[buffsize]);
if (GetLogicalDriveStrings(buffsize, buff.get()) == buffsize - 1)
std::vector<TCHAR> buff(buffsize);
if (GetLogicalDriveStrings(buffsize, buff.data()) == buffsize - 1)
{
const char* drive = buff.get();
auto drive = buff.data();
while (*drive)
{
if (is_cdrom(drive))
{
std::string str(drive);
std::string str(TStrToUTF8(drive));
str.pop_back(); // we don't want the final backslash
drives.push_back(std::move(str));
}
+22 -1
View File
@@ -25,7 +25,8 @@ enum CPUVendor
{
VENDOR_INTEL = 0,
VENDOR_AMD = 1,
VENDOR_OTHER = 2,
VENDOR_ARM = 2,
VENDOR_OTHER = 3,
};
struct CPUInfo
@@ -55,6 +56,26 @@ struct CPUInfo
bool bAES;
bool bLAHFSAHF64;
bool bLongMode;
// ARM specific CPUInfo
bool bSwp;
bool bHalf;
bool bThumb;
bool bFastMult;
bool bVFP;
bool bEDSP;
bool bThumbEE;
bool bNEON;
bool bVFPv3;
bool bTLS;
bool bVFPv4;
bool bIDIVa;
bool bIDIVt;
bool bArmV7; // enable MOVT, MOVW etc
// ARMv8 specific
bool bFP;
bool bASIMD;
// Call Detect()
explicit CPUInfo();
+118 -112
View File
@@ -29,6 +29,7 @@
#include <map>
#include <vector>
#include <list>
#include <deque>
#include <string>
@@ -45,7 +46,8 @@ struct LinkedListItem : public T
class PointerWrap
{
public:
enum Mode {
enum Mode
{
MODE_READ = 1, // load
MODE_WRITE, // save
MODE_MEASURE, // calculate size
@@ -57,124 +59,95 @@ public:
public:
PointerWrap(u8 **ptr_, Mode mode_) : ptr(ptr_), mode(mode_) {}
PointerWrap(unsigned char **ptr_, int mode_) : ptr((u8**)ptr_), mode((Mode)mode_) {}
void SetMode(Mode mode_) {mode = mode_;}
Mode GetMode() const {return mode;}
u8 **GetPPtr() {return ptr;}
void SetMode(Mode mode_) { mode = mode_; }
Mode GetMode() const { return mode; }
u8** GetPPtr() { return ptr; }
void DoVoid(void *data, int size)
template <typename K, class V>
void Do(std::map<K, V>& x)
{
switch (mode) {
case MODE_READ: memcpy(data, *ptr, size); break;
case MODE_WRITE: memcpy(*ptr, data, size); break;
case MODE_MEASURE: break; // MODE_MEASURE - don't need to do anything
case MODE_VERIFY: for(int i = 0; i < size; i++) _dbg_assert_msg_(COMMON, ((u8*)data)[i] == (*ptr)[i], "Savestate verification failure: %d (0x%X) (at %p) != %d (0x%X) (at %p).\n", ((u8*)data)[i], ((u8*)data)[i], &((u8*)data)[i], (*ptr)[i], (*ptr)[i], &(*ptr)[i]); break;
default: break; // throw an error?
}
(*ptr) += size;
}
template<class T>
void Do(std::map<unsigned int, T> &x)
{
unsigned int number = (unsigned int)x.size();
Do(number);
switch (mode) {
u32 count = (u32)x.size();
Do(count);
switch (mode)
{
case MODE_READ:
for (x.clear(); count != 0; --count)
{
x.clear();
while (number > 0)
{
unsigned int first = 0;
Do(first);
T second;
Do(second);
x[first] = second;
--number;
}
std::pair<K, V> pair;
Do(pair.first);
Do(pair.second);
x.insert(pair);
}
break;
case MODE_WRITE:
case MODE_MEASURE:
case MODE_VERIFY:
for (auto itr = x.begin(); itr != x.end(); ++itr)
{
typename std::map<unsigned int, T>::iterator itr = x.begin();
while (number > 0)
{
Do(itr->first);
Do(itr->second);
--number;
++itr;
}
Do(itr->first);
Do(itr->second);
}
break;
}
}
// Store vectors.
template<class T>
void Do(std::vector<T> &x)
{
u32 vec_size = (u32)x.size();
Do(vec_size);
x.resize(vec_size);
DoArray(&x[0], vec_size);
}
// Store deques.
template<class T>
void Do(std::deque<T> &x)
template <typename T>
void DoContainer(T& x)
{
u32 deq_size = (u32)x.size();
Do(deq_size);
x.resize(deq_size);
u32 i;
for(i = 0; i < deq_size; i++)
DoVoid(&x[i],sizeof(T));
}
// Store strings.
void Do(std::string &x)
{
int stringLen = (int)x.length() + 1;
Do(stringLen);
u32 size = (u32)x.size();
Do(size);
x.resize(size);
switch (mode) {
case MODE_READ: x = (char*)*ptr; break;
case MODE_WRITE: memcpy(*ptr, x.c_str(), stringLen); break;
case MODE_MEASURE: break;
case MODE_VERIFY: _dbg_assert_msg_(COMMON, !strcmp(x.c_str(), (char*)*ptr), "Savestate verification failure: \"%s\" != \"%s\" (at %p).\n", x.c_str(), (char*)*ptr, ptr); break;
}
(*ptr) += stringLen;
for (auto itr = x.begin(); itr != x.end(); ++itr)
Do(*itr);
}
void Do(std::wstring &x)
template <typename T>
void Do(std::vector<T>& x)
{
int stringLen = sizeof(wchar_t)*((int)x.length() + 1);
Do(stringLen);
switch (mode) {
case MODE_READ: x.assign((wchar_t*)*ptr, (stringLen / sizeof(wchar_t)) - 1); break;
case MODE_WRITE: memcpy(*ptr, x.c_str(), stringLen); break;
case MODE_MEASURE: break;
case MODE_VERIFY: _dbg_assert_msg_(COMMON, x == (wchar_t*)*ptr, "Savestate verification failure: \"%ls\" != \"%ls\" (at %p).\n", x.c_str(), (wchar_t*)*ptr, ptr); break;
}
(*ptr) += stringLen;
DoContainer(x);
}
template <typename T>
void Do(std::list<T>& x)
{
DoContainer(x);
}
template <typename T>
void Do(std::deque<T>& x)
{
DoContainer(x);
}
template <typename T>
void Do(std::basic_string<T>& x)
{
DoContainer(x);
}
template<class T>
void DoArray(T *x, int count) {
DoVoid((void *)x, sizeof(T) * count);
template <typename T>
void DoArray(T* x, u32 count)
{
for (u32 i = 0; i != count; ++i)
Do(x[i]);
}
template<class T>
void Do(T &x) {
DoVoid((void *)&x, sizeof(x));
template <typename T>
void Do(T& x)
{
// TODO: Bad, Do(some_non_POD) will compile and fail at runtime
// type_traits are not fully supported everywhere yet
DoVoid((void*)&x, sizeof(x));
}
template<class T>
void DoPointer(T* &x, T*const base) {
template <typename T>
void DoPointer(T*& x, T* const base)
{
// pointers can be more than 2^31 apart, but you're using this function wrong if you need that much range
s32 offset = x - base;
Do(offset);
@@ -182,7 +155,8 @@ public:
x = base + offset;
}
template<class T, LinkedListItem<T>* (*TNew)(), void (*TFree)(LinkedListItem<T>*), void (*TDo)(PointerWrap&, T*)>
// Let's pretend std::list doesn't exist!
template <class T, LinkedListItem<T>* (*TNew)(), void (*TFree)(LinkedListItem<T>*), void (*TDo)(PointerWrap&, T*)>
void DoLinkedList(LinkedListItem<T>*& list_start, LinkedListItem<T>** list_end=0)
{
LinkedListItem<T>* list_cur = list_start;
@@ -242,25 +216,61 @@ public:
}
}
void DoMarker(const char* prevName, u32 arbitraryNumber=0x42)
void DoMarker(const char* prevName, u32 arbitraryNumber = 0x42)
{
u32 cookie = arbitraryNumber;
Do(cookie);
if(mode == PointerWrap::MODE_READ && cookie != arbitraryNumber)
if (mode == PointerWrap::MODE_READ && cookie != arbitraryNumber)
{
PanicAlertT("Error: After \"%s\", found %d (0x%X) instead of save marker %d (0x%X). Aborting savestate load...", prevName, cookie, cookie, arbitraryNumber, arbitraryNumber);
PanicAlertT("Error: After \"%s\", found %d (0x%X) instead of save marker %d (0x%X). Aborting savestate load...",
prevName, cookie, cookie, arbitraryNumber, arbitraryNumber);
mode = PointerWrap::MODE_MEASURE;
}
}
private:
__forceinline void DoByte(u8& x)
{
switch (mode)
{
case MODE_READ:
x = **ptr;
break;
case MODE_WRITE:
**ptr = x;
break;
case MODE_MEASURE:
break;
case MODE_VERIFY:
_dbg_assert_msg_(COMMON, (x == *ptr),
"Savestate verification failure: %d (0x%X) (at %p) != %d (0x%X) (at %p).\n",
x, x, &x, *ptr, *ptr, &*ptr);
break;
default:
break;
}
++(*ptr);
}
void DoVoid(void *data, u32 size)
{
for(u32 i = 0; i != size; ++i)
DoByte(reinterpret_cast<u8*>(data)[i]);
}
};
class CChunkFileReader
{
public:
// Load file template
template<class T>
static bool Load(const std::string& _rFilename, int _Revision, T& _class)
static bool Load(const std::string& _rFilename, u32 _Revision, T& _class)
{
INFO_LOG(COMMON, "ChunkReader: Loading %s" , _rFilename.c_str());
@@ -300,7 +310,7 @@ public:
}
// get size
const int sz = (int)(fileSize - headerSize);
const u32 sz = (u32)(fileSize - headerSize);
if (header.ExpectedSize != sz)
{
ERROR_LOG(COMMON,"ChunkReader: Bad file size, got %d expected %d",
@@ -309,17 +319,16 @@ public:
}
// read the state
u8* buffer = new u8[sz];
if (!pFile.ReadBytes(buffer, sz))
std::vector<u8> buffer(sz);
if (!pFile.ReadArray(&buffer[0], sz))
{
ERROR_LOG(COMMON,"ChunkReader: Error reading file");
return false;
}
u8 *ptr = buffer;
u8* ptr = &buffer[0];
PointerWrap p(&ptr, PointerWrap::MODE_READ);
_class.DoState(p);
delete[] buffer;
INFO_LOG(COMMON, "ChunkReader: Done loading %s" , _rFilename.c_str());
return true;
@@ -327,7 +336,7 @@ public:
// Save file template
template<class T>
static bool Save(const std::string& _rFilename, int _Revision, T& _class)
static bool Save(const std::string& _rFilename, u32 _Revision, T& _class)
{
INFO_LOG(COMMON, "ChunkReader: Writing %s" , _rFilename.c_str());
File::IOFile pFile(_rFilename, "wb");
@@ -349,9 +358,8 @@ public:
// Create header
SChunkHeader header;
header.Compress = 0;
header.Revision = _Revision;
header.ExpectedSize = (int)sz;
header.ExpectedSize = (u32)sz;
// Write to file
if (!pFile.WriteArray(&header, 1))
@@ -360,23 +368,21 @@ public:
return false;
}
if (!pFile.WriteBytes(&buffer[0], sz))
if (!pFile.WriteArray(&buffer[0], sz))
{
ERROR_LOG(COMMON,"ChunkReader: Failed writing data");
return false;
}
INFO_LOG(COMMON,"ChunkReader: Done writing %s",
_rFilename.c_str());
INFO_LOG(COMMON,"ChunkReader: Done writing %s", _rFilename.c_str());
return true;
}
private:
struct SChunkHeader
{
int Revision;
int Compress;
int ExpectedSize;
u32 Revision;
u32 ExpectedSize;
};
};
+4 -3
View File
@@ -133,7 +133,9 @@ private:
// wxWidgets does not have a true dummy macro for this.
#define _trans(a) a
#if defined __GNUC__
#if defined _M_GENERIC
# define _M_SSE 0x0
#elif defined __GNUC__
# if defined __SSE4_2__
# define _M_SSE 0x402
# elif defined __SSE4_1__
@@ -144,7 +146,7 @@ private:
# define _M_SSE 0x300
# endif
#elif (_MSC_VER >= 1500) || __INTEL_COMPILER // Visual Studio 2008
# define _M_SSE 0x402
# define _M_SSE 0x402
#endif
// Host communication.
@@ -155,7 +157,6 @@ enum HOST_COMM
WM_USER_CREATE,
WM_USER_SETCURSOR,
WM_USER_KEYDOWN,
WIIMOTE_DISCONNECT // Disconnect Wiimote
};
// Used for notification on emulation state
+46 -1
View File
@@ -35,7 +35,7 @@ template<> struct CompileTimeAssert<true> {};
#define b32(x) (b16(x) | (b16(x) >>16) )
#define ROUND_UP_POW2(x) (b32(x - 1) + 1)
#if defined __GNUC__ && !defined __SSSE3__
#if defined __GNUC__ && !defined __SSSE3__ && !defined _M_GENERIC
#include <emmintrin.h>
static __inline __m128i __attribute__((__always_inline__))
_mm_shuffle_epi8(__m128i a, __m128i mask)
@@ -60,6 +60,8 @@ _mm_shuffle_epi8(__m128i a, __m128i mask)
// go to debugger mode
#ifdef GEKKO
#define Crash()
#elif defined _M_GENERIC
#define Crash() { exit(1); }
#else
#define Crash() {asm ("int $3");}
#endif
@@ -136,6 +138,15 @@ inline u8 swap8(u8 _data) {return _data;}
inline u16 swap16(u16 _data) {return _byteswap_ushort(_data);}
inline u32 swap32(u32 _data) {return _byteswap_ulong (_data);}
inline u64 swap64(u64 _data) {return _byteswap_uint64(_data);}
#elif _M_ARM
#ifdef ANDROID
#undef swap16
#undef swap32
#undef swap64
#endif
inline u16 swap16 (u16 _data) { u32 data = _data; __asm__ ("rev16 %0, %1\n" : "=l" (data) : "l" (data)); return (u16)data;}
inline u32 swap32 (u32 _data) {__asm__ ("rev %0, %1\n" : "=l" (_data) : "l" (_data)); return _data;}
inline u64 swap64(u64 _data) {return ((u64)swap32(_data) << 32) | swap32(_data >> 32);}
#elif __linux__
inline u16 swap16(u16 _data) {return bswap_16(_data);}
inline u32 swap32(u32 _data) {return bswap_32(_data);}
@@ -162,6 +173,40 @@ inline u16 swap16(const u8* _pData) {return swap16(*(const u16*)_pData);}
inline u32 swap32(const u8* _pData) {return swap32(*(const u32*)_pData);}
inline u64 swap64(const u8* _pData) {return swap64(*(const u64*)_pData);}
template <int count>
void swap(u8*);
template <>
inline void swap<1>(u8* data)
{}
template <>
inline void swap<2>(u8* data)
{
*reinterpret_cast<u16*>(data) = swap16(data);
}
template <>
inline void swap<4>(u8* data)
{
*reinterpret_cast<u32*>(data) = swap32(data);
}
template <>
inline void swap<8>(u8* data)
{
*reinterpret_cast<u64*>(data) = swap64(data);
}
template <typename T>
inline T FromBigEndian(T data)
{
//static_assert(std::is_arithmetic<T>::value, "function only makes sense with arithmetic types");
swap<sizeof(data)>(reinterpret_cast<u8*>(&data));
return data;
}
} // Namespace Common
#endif // _COMMONFUNCS_H_
+5
View File
@@ -36,6 +36,9 @@
// You can use the File::GetUserPath() util for this
#define USERDATA_DIR "Contents/Resources/User"
#define DOLPHIN_DATA_DIR "Library/Application Support/Dolphin"
#elif defined ANDROID
#define USERDATA_DIR "user"
#define DOLPHIN_DATA_DIR "/sdcard/dolphin-emu"
#else
#define USERDATA_DIR "user"
#ifdef USER_DIR
@@ -52,6 +55,8 @@
#define SYSDATA_DIR "Contents/Resources/Sys"
#define SHARED_USER_DIR File::GetBundleDirectory() + \
DIR_SEP USERDATA_DIR DIR_SEP
#elif defined ANDROID
#define SYSDATA_DIR "/sdcard/dolphin-emu"
#else
#ifdef DATA_DIR
#define SYSDATA_DIR DATA_DIR "sys"
+2 -2
View File
@@ -61,7 +61,7 @@ void ConsoleListener::Open(bool Hidden, int Width, int Height, const char *Title
// Save the window handle that AllocConsole() created
hConsole = GetStdHandle(STD_OUTPUT_HANDLE);
// Set the console window title
SetConsoleTitle(Title);
SetConsoleTitle(UTF8ToTStr(Title).c_str());
// Set letter space
LetterSpace(80, 4000);
//MoveWindow(GetConsoleWindow(), 200,200, 800,800, true);
@@ -195,7 +195,7 @@ void ConsoleListener::PixelSpace(int Left, int Top, int Width, int Height, bool
static const int MAX_BYTES = 1024 * 16;
std::vector<std::array<CHAR, MAX_BYTES>> Str;
std::vector<std::array<TCHAR, MAX_BYTES>> Str;
std::vector<std::array<WORD, MAX_BYTES>> Attr;
// ReadConsoleOutputAttribute seems to have a limit at this level
+6 -3
View File
@@ -37,6 +37,8 @@
#include <string.h>
#include <stdio.h>
#include "../FileUtil.h"
/*
* 32-bit integer manipulation macros (little endian)
*/
@@ -301,7 +303,10 @@ int md5_file( char *path, unsigned char output[16] )
md5_context ctx;
unsigned char buf[1024];
if( ( f = fopen( path, "rb" ) ) == NULL )
File::IOFile file(path, "rb");
f = file.GetHandle();
if (f == NULL)
return( 1 );
md5_starts( &ctx );
@@ -315,11 +320,9 @@ int md5_file( char *path, unsigned char output[16] )
if( ferror( f ) != 0 )
{
fclose( f );
return( 2 );
}
fclose( f );
return( 0 );
}
+6 -3
View File
@@ -36,6 +36,8 @@
#include <string.h>
#include <stdio.h>
#include "../FileUtil.h"
/*
* 32-bit integer manipulation macros (big endian)
*/
@@ -335,7 +337,10 @@ int sha1_file( char *path, unsigned char output[20] )
sha1_context ctx;
unsigned char buf[1024];
if( ( f = fopen( path, "rb" ) ) == NULL )
File::IOFile file(path, "rb");
f = file.GetHandle();
if (f == NULL)
return( 1 );
sha1_starts( &ctx );
@@ -349,11 +354,9 @@ int sha1_file( char *path, unsigned char output[20] )
if( ferror( f ) != 0 )
{
fclose( f );
return( 2 );
}
fclose( f );
return( 0 );
}
+21 -31
View File
@@ -17,6 +17,7 @@
#include <windows.h>
#include <stdio.h>
#include "ExtendedTrace.h"
#include "StringUtil.h"
using namespace std;
#include <tchar.h>
@@ -274,13 +275,21 @@ static BOOL GetSourceInfoFromAddress( UINT address, LPTSTR lpszSourceInfo )
return ret;
}
void StackTrace( HANDLE hThread, LPCTSTR lpszMessage, FILE *file )
void PrintFunctionAndSourceInfo(FILE* file, const STACKFRAME& callstack)
{
TCHAR symInfo[BUFFERSIZE] = _T("?");
TCHAR srcInfo[BUFFERSIZE] = _T("?");
GetFunctionInfoFromAddresses((ULONG)callstack.AddrPC.Offset, (ULONG)callstack.AddrFrame.Offset, symInfo);
GetSourceInfoFromAddress((ULONG)callstack.AddrPC.Offset, srcInfo);
etfprint(file, " " + TStrToUTF8(srcInfo) + " : " + TStrToUTF8(symInfo) + "\n");
}
void StackTrace( HANDLE hThread, const char* lpszMessage, FILE *file )
{
STACKFRAME callStack;
BOOL bResult;
CONTEXT context;
TCHAR symInfo[BUFFERSIZE] = _T("?");
TCHAR srcInfo[BUFFERSIZE] = _T("?");
HANDLE hProcess = GetCurrentProcess();
// If it's not this thread, let's suspend it, and resume it at the end
@@ -318,9 +327,7 @@ void StackTrace( HANDLE hThread, LPCTSTR lpszMessage, FILE *file )
etfprint(file, "Call stack info: \n");
etfprint(file, lpszMessage);
GetFunctionInfoFromAddresses( (ULONG)callStack.AddrPC.Offset, (ULONG)callStack.AddrFrame.Offset, symInfo );
GetSourceInfoFromAddress( (ULONG)callStack.AddrPC.Offset, srcInfo );
etfprint(file, string(" ") + srcInfo + string(" : ") + symInfo + string("\n"));
PrintFunctionAndSourceInfo(file, callStack);
for( ULONG index = 0; ; index++ )
{
@@ -341,9 +348,7 @@ void StackTrace( HANDLE hThread, LPCTSTR lpszMessage, FILE *file )
if( !bResult || callStack.AddrFrame.Offset == 0 )
break;
GetFunctionInfoFromAddresses( (ULONG)callStack.AddrPC.Offset, (ULONG)callStack.AddrFrame.Offset, symInfo );
GetSourceInfoFromAddress( (UINT)callStack.AddrPC.Offset, srcInfo );
etfprint(file, string(" ") + srcInfo + string(" : ") + symInfo + string("\n"));
PrintFunctionAndSourceInfo(file, callStack);
}
@@ -351,19 +356,7 @@ void StackTrace( HANDLE hThread, LPCTSTR lpszMessage, FILE *file )
ResumeThread( hThread );
}
void StackTrace( HANDLE hThread, wchar_t const*lpszMessage, FILE *file, DWORD eip, DWORD esp, DWORD ebp )
{
// TODO: remove when Common builds as unicode
size_t origsize = wcslen(lpszMessage) + 1;
const size_t newsize = 100;
size_t convertedChars = 0;
char nstring[newsize];
wcstombs_s(&convertedChars, nstring, origsize, lpszMessage, _TRUNCATE);
StackTrace(hThread, nstring, file, eip, esp, ebp );
}
void StackTrace( HANDLE hThread, LPCTSTR lpszMessage, FILE *file, DWORD eip, DWORD esp, DWORD ebp )
void StackTrace(HANDLE hThread, const char* lpszMessage, FILE *file, DWORD eip, DWORD esp, DWORD ebp )
{
STACKFRAME callStack;
BOOL bResult;
@@ -391,9 +384,7 @@ void StackTrace( HANDLE hThread, LPCTSTR lpszMessage, FILE *file, DWORD eip, DWO
etfprint(file, "Call stack info: \n");
etfprint(file, lpszMessage);
GetFunctionInfoFromAddresses( (ULONG)callStack.AddrPC.Offset, (ULONG)callStack.AddrFrame.Offset, symInfo );
GetSourceInfoFromAddress( (UINT)callStack.AddrPC.Offset, srcInfo );
etfprint(file, string(" ") + srcInfo + string(" : ") + symInfo + string("\n"));
PrintFunctionAndSourceInfo(file, callStack);
for( ULONG index = 0; ; index++ )
{
@@ -414,10 +405,7 @@ void StackTrace( HANDLE hThread, LPCTSTR lpszMessage, FILE *file, DWORD eip, DWO
if( !bResult || callStack.AddrFrame.Offset == 0 )
break;
GetFunctionInfoFromAddresses( (ULONG)callStack.AddrPC.Offset, (ULONG)callStack.AddrFrame.Offset, symInfo );
GetSourceInfoFromAddress( (UINT)callStack.AddrPC.Offset, srcInfo );
etfprint(file, string(" ") + srcInfo + string(" : ") + symInfo + string("\n"));
PrintFunctionAndSourceInfo(file, callStack);
}
if ( hThread != GetCurrentThread() )
@@ -426,7 +414,8 @@ void StackTrace( HANDLE hThread, LPCTSTR lpszMessage, FILE *file, DWORD eip, DWO
char g_uefbuf[2048];
void etfprintf(FILE *file, const char *format, ...) {
void etfprintf(FILE *file, const char *format, ...)
{
va_list ap;
va_start(ap, format);
int len = vsprintf(g_uefbuf, format, ap);
@@ -434,7 +423,8 @@ void etfprintf(FILE *file, const char *format, ...) {
va_end(ap);
}
void etfprint(FILE *file, const std::string &text) {
void etfprint(FILE *file, const std::string &text)
{
size_t len = text.length();
fwrite(text.data(), 1, len, file);
}
+4 -5
View File
@@ -26,15 +26,14 @@
#define EXTENDEDTRACEINITIALIZE( IniSymbolPath ) InitSymInfo( IniSymbolPath )
#define EXTENDEDTRACEUNINITIALIZE() UninitSymInfo()
#define STACKTRACE(file) StackTrace( GetCurrentThread(), _T(""), file)
#define STACKTRACE2(file, eip, esp, ebp) StackTrace(GetCurrentThread(), _T(""), file, eip, esp, ebp)
#define STACKTRACE(file) StackTrace( GetCurrentThread(), "", file)
#define STACKTRACE2(file, eip, esp, ebp) StackTrace(GetCurrentThread(), "", file, eip, esp, ebp)
// class File;
BOOL InitSymInfo( PCSTR );
BOOL UninitSymInfo();
void StackTrace( HANDLE, LPCTSTR, FILE *file);
void StackTrace( HANDLE, LPCTSTR, FILE *file, DWORD eip, DWORD esp, DWORD ebp);
void StackTrace( HANDLE hThread, wchar_t const* lpszMessage, FILE *file, DWORD eip, DWORD esp, DWORD ebp);
void StackTrace(HANDLE, char const* msg, FILE *file);
void StackTrace(HANDLE, char const* msg, FILE *file, DWORD eip, DWORD esp, DWORD ebp);
// functions by Masken
void etfprintf(FILE *file, const char *format, ...);
+51
View File
@@ -0,0 +1,51 @@
// 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 FPU_ROUND_MODE_H_
#define FPU_ROUND_MODE_H_
#include "Common.h"
namespace FPURoundMode
{
enum RoundModes
{
ROUND_NEAR = 0,
ROUND_CHOP,
ROUND_UP,
ROUND_DOWN
};
enum PrecisionModes {
PREC_24 = 0,
PREC_53,
PREC_64
};
void SetRoundMode(u32 mode);
void SetPrecisionMode(u32 mode);
void SetSIMDMode(u32 mode);
/*
There are two different flavors of float to int conversion:
_mm_cvtps_epi32() and _mm_cvttps_epi32(). The first rounds
according to the MXCSR rounding bits. The second one always
uses round towards zero.
*/
void SaveSIMDState();
void LoadSIMDState();
void LoadDefaultSIMDState();
}
#endif
+2 -3
View File
@@ -51,7 +51,7 @@ void CFileSearch::FindFiles(const std::string& _searchString, const std::string&
BuildCompleteFilename(GCMSearchPath, _strPath, _searchString);
#ifdef _WIN32
WIN32_FIND_DATA findData;
HANDLE FindFirst = FindFirstFile(GCMSearchPath.c_str(), &findData);
HANDLE FindFirst = FindFirstFile(UTF8ToTStr(GCMSearchPath).c_str(), &findData);
if (FindFirst != INVALID_HANDLE_VALUE)
{
@@ -62,7 +62,7 @@ void CFileSearch::FindFiles(const std::string& _searchString, const std::string&
if (findData.cFileName[0] != '.')
{
std::string strFilename;
BuildCompleteFilename(strFilename, _strPath, findData.cFileName);
BuildCompleteFilename(strFilename, _strPath, TStrToUTF8(findData.cFileName));
m_FileNames.push_back(strFilename);
}
@@ -112,7 +112,6 @@ void CFileSearch::FindFiles(const std::string& _searchString, const std::string&
#endif
}
const CFileSearch::XStringVector& CFileSearch::GetFileNames() const
{
return m_FileNames;
+43 -40
View File
@@ -41,10 +41,11 @@
#include <CoreFoundation/CFBundle.h>
#endif
#include <fstream>
#include <algorithm>
#include <sys/stat.h>
#include "StringUtil.h"
#ifndef S_ISDIR
#define S_ISDIR(m) (((m)&S_IFMT) == S_IFDIR)
#endif
@@ -81,7 +82,11 @@ bool Exists(const std::string &filename)
std::string copy(filename);
StripTailDirSlashes(copy);
#ifdef _WIN32
int result = _tstat64(UTF8ToTStr(copy).c_str(), &file_info);
#else
int result = stat64(copy.c_str(), &file_info);
#endif
return (result == 0);
}
@@ -94,7 +99,11 @@ bool IsDirectory(const std::string &filename)
std::string copy(filename);
StripTailDirSlashes(copy);
#ifdef _WIN32
int result = _tstat64(UTF8ToTStr(copy).c_str(), &file_info);
#else
int result = stat64(copy.c_str(), &file_info);
#endif
if (result < 0) {
WARN_LOG(COMMON, "IsDirectory: stat failed on %s: %s",
@@ -127,7 +136,7 @@ bool Delete(const std::string &filename)
}
#ifdef _WIN32
if (!DeleteFile(filename.c_str()))
if (!DeleteFile(UTF8ToTStr(filename).c_str()))
{
WARN_LOG(COMMON, "Delete: DeleteFile failed on %s: %s",
filename.c_str(), GetLastErrorMsg());
@@ -149,7 +158,7 @@ bool CreateDir(const std::string &path)
{
INFO_LOG(COMMON, "CreateDir: directory %s", path.c_str());
#ifdef _WIN32
if (::CreateDirectory(path.c_str(), NULL))
if (::CreateDirectory(UTF8ToTStr(path).c_str(), NULL))
return true;
DWORD error = GetLastError();
if (error == ERROR_ALREADY_EXISTS)
@@ -228,7 +237,7 @@ bool DeleteDir(const std::string &filename)
}
#ifdef _WIN32
if (::RemoveDirectory(filename.c_str()))
if (::RemoveDirectory(UTF8ToTStr(filename).c_str()))
return true;
#else
if (rmdir(filename.c_str()) == 0)
@@ -257,7 +266,7 @@ bool Copy(const std::string &srcFilename, const std::string &destFilename)
INFO_LOG(COMMON, "Copy: %s --> %s",
srcFilename.c_str(), destFilename.c_str());
#ifdef _WIN32
if (CopyFile(srcFilename.c_str(), destFilename.c_str(), FALSE))
if (CopyFile(UTF8ToTStr(srcFilename).c_str(), UTF8ToTStr(destFilename).c_str(), FALSE))
return true;
ERROR_LOG(COMMON, "Copy: failed %s --> %s: %s",
@@ -342,8 +351,13 @@ u64 GetSize(const std::string &filename)
WARN_LOG(COMMON, "GetSize: failed %s: is a directory", filename.c_str());
return 0;
}
struct stat64 buf;
#ifdef _WIN32
if (_tstat64(UTF8ToTStr(filename).c_str(), &buf) == 0)
#else
if (stat64(filename.c_str(), &buf) == 0)
#endif
{
DEBUG_LOG(COMMON, "GetSize: %s: %lld",
filename.c_str(), (long long)buf.st_size);
@@ -391,13 +405,13 @@ bool CreateEmptyFile(const std::string &filename)
{
INFO_LOG(COMMON, "CreateEmptyFile: %s", filename.c_str());
FILE *pFile = fopen(filename.c_str(), "wb");
if (!pFile) {
if (!File::IOFile(filename, "wb"))
{
ERROR_LOG(COMMON, "CreateEmptyFile: failed %s: %s",
filename.c_str(), GetLastErrorMsg());
return false;
}
fclose(pFile);
return true;
}
@@ -413,7 +427,7 @@ u32 ScanDirectoryTree(const std::string &directory, FSTEntry& parentEntry)
// Find the first file in the directory.
WIN32_FIND_DATA ffd;
HANDLE hFind = FindFirstFile((directory + "\\*").c_str(), &ffd);
HANDLE hFind = FindFirstFile(UTF8ToTStr(directory + "\\*").c_str(), &ffd);
if (hFind == INVALID_HANDLE_VALUE)
{
FindClose(hFind);
@@ -423,7 +437,7 @@ u32 ScanDirectoryTree(const std::string &directory, FSTEntry& parentEntry)
do
{
FSTEntry entry;
const std::string virtualName(ffd.cFileName);
const std::string virtualName(TStrToUTF8(ffd.cFileName));
#else
struct dirent dirent, *result = NULL;
@@ -480,7 +494,7 @@ bool DeleteDirRecursively(const std::string &directory)
#ifdef _WIN32
// Find the first file in the directory.
WIN32_FIND_DATA ffd;
HANDLE hFind = FindFirstFile((directory + "\\*").c_str(), &ffd);
HANDLE hFind = FindFirstFile(UTF8ToTStr(directory + "\\*").c_str(), &ffd);
if (hFind == INVALID_HANDLE_VALUE)
{
@@ -491,7 +505,7 @@ bool DeleteDirRecursively(const std::string &directory)
// windows loop
do
{
const std::string virtualName = ffd.cFileName;
const std::string virtualName(TStrToUTF8(ffd.cFileName));
#else
struct dirent dirent, *result = NULL;
DIR *dirp = opendir(directory.c_str());
@@ -622,14 +636,14 @@ std::string GetBundleDirectory()
#endif
#ifdef _WIN32
std::string &GetExeDirectory()
std::string& GetExeDirectory()
{
static std::string DolphinPath;
if (DolphinPath.empty())
{
char Dolphin_exe_Path[2048];
GetModuleFileNameA(NULL, Dolphin_exe_Path, 2048);
DolphinPath = Dolphin_exe_Path;
TCHAR Dolphin_exe_Path[2048];
GetModuleFileName(NULL, Dolphin_exe_Path, 2048);
DolphinPath = TStrToUTF8(Dolphin_exe_Path);
DolphinPath = DolphinPath.substr(0, DolphinPath.find_last_of('\\'));
}
return DolphinPath;
@@ -668,9 +682,10 @@ std::string &GetUserPath(const unsigned int DirIDX, const std::string &newPath)
if (File::Exists(ROOT_DIR DIR_SEP USERDATA_DIR))
paths[D_USER_IDX] = ROOT_DIR DIR_SEP USERDATA_DIR DIR_SEP;
else
paths[D_USER_IDX] = std::string(getenv("HOME") ? getenv("HOME") : getenv("PWD")) + DIR_SEP DOLPHIN_DATA_DIR DIR_SEP;
paths[D_USER_IDX] = std::string(getenv("HOME") ?
getenv("HOME") : getenv("PWD") ?
getenv("PWD") : "") + DIR_SEP DOLPHIN_DATA_DIR DIR_SEP;
#endif
INFO_LOG(COMMON, "GetUserPath: Setting user directory to %s:", paths[D_USER_IDX].c_str());
paths[D_GCUSER_IDX] = paths[D_USER_IDX] + GC_USER_DIR DIR_SEP;
paths[D_WIIROOT_IDX] = paths[D_USER_IDX] + WII_USER_DIR;
@@ -729,31 +744,19 @@ std::string &GetUserPath(const unsigned int DirIDX, const std::string &newPath)
bool WriteStringToFile(bool text_file, const std::string &str, const char *filename)
{
FILE *f = fopen(filename, text_file ? "w" : "wb");
if (!f)
return false;
size_t len = str.size();
if (len != fwrite(str.data(), 1, str.size(), f)) // TODO: string::data() may not be contiguous
{
fclose(f);
return false;
}
fclose(f);
return true;
return File::IOFile(filename, text_file ? "w" : "wb").WriteBytes(str.data(), str.size());
}
bool ReadFileToString(bool text_file, const char *filename, std::string &str)
{
FILE *f = fopen(filename, text_file ? "r" : "rb");
File::IOFile file(filename, text_file ? "r" : "rb");
auto const f = file.GetHandle();
if (!f)
return false;
size_t len = (size_t)GetSize(f);
char *buf = new char[len + 1];
buf[fread(buf, 1, len, f)] = 0;
str = std::string(buf, len);
fclose(f);
delete [] buf;
return true;
str.resize(GetSize(f));
return file.ReadArray(&str[0], str.size());
}
IOFile::IOFile()
@@ -781,9 +784,9 @@ IOFile::IOFile(IOFile&& other)
Swap(other);
}
IOFile& IOFile::operator=(IOFile other)
IOFile& IOFile::operator=(IOFile&& other)
{
Swap(other);
IOFile((IOFile&&)other).Swap(*this);
return *this;
}
@@ -797,7 +800,7 @@ bool IOFile::Open(const std::string& filename, const char openmode[])
{
Close();
#ifdef _WIN32
fopen_s(&m_file, filename.c_str(), openmode);
_tfopen_s(&m_file, UTF8ToTStr(filename).c_str(), UTF8ToTStr(openmode).c_str());
#else
m_file = fopen(filename.c_str(), openmode);
#endif
+13 -1
View File
@@ -25,6 +25,7 @@
#include <string.h>
#include "Common.h"
#include "StringUtil.h"
// User directory indices for GetUserPath
enum {
@@ -160,7 +161,7 @@ public:
~IOFile();
IOFile(IOFile&& other);
IOFile& operator=(IOFile other);
IOFile& operator=(IOFile&& other);
void Swap(IOFile& other);
@@ -226,4 +227,15 @@ private:
} // namespace
// To deal with Windows being dumb at unicode:
template <typename T>
void OpenFStream(T& fstream, const std::string& filename, std::ios_base::openmode openmode)
{
#ifdef _WIN32
fstream.open(UTF8ToTStr(filename).c_str(), openmode);
#else
fstream.open(filename.c_str(), openmode);
#endif
}
#endif
@@ -0,0 +1,41 @@
// Copyright (C) 2003 Dolphin Project.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, version 2.0.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/
// Official SVN repository and contact information can be found at
// http://code.google.com/p/dolphin-emu/
#include "FPURoundMode.h"
// Generic, do nothing
namespace FPURoundMode
{
void SetRoundMode(u32 mode)
{
}
void SetPrecisionMode(u32 mode)
{
}
void SetSIMDMode(u32 mode)
{
}
void SaveSIMDState()
{
}
void LoadSIMDState()
{
}
void LoadDefaultSIMDState()
{
}
}
+3 -2
View File
@@ -25,6 +25,7 @@
#include <fstream>
#include <algorithm>
#include "FileUtil.h"
#include "StringUtil.h"
#include "IniFile.h"
@@ -400,7 +401,7 @@ bool IniFile::Load(const char* filename)
// Open file
std::ifstream in;
in.open(filename, std::ios::in);
OpenFStream(in, filename, std::ios::in);
if (in.fail()) return false;
@@ -452,7 +453,7 @@ bool IniFile::Load(const char* filename)
bool IniFile::Save(const char* filename)
{
std::ofstream out;
out.open(filename, std::ios::out);
OpenFStream(out, filename, std::ios::out);
if (out.fail())
{
+1 -1
View File
@@ -71,7 +71,7 @@ public:
m_num_entries = 0;
// try opening for reading/writing
m_file.open(filename, ios_base::in | ios_base::out | ios_base::binary);
OpenFStream(m_file, filename, ios_base::in | ios_base::out | ios_base::binary);
m_file.seekg(0, std::ios::end);
std::fstream::pos_type end_pos = m_file.tellg();
+7 -2
View File
@@ -17,6 +17,9 @@
#include <algorithm>
#ifdef ANDROID
#include "Host.h"
#endif
#include "LogManager.h"
#include "ConsoleListener.h"
#include "Timer.h"
@@ -132,7 +135,9 @@ void LogManager::Log(LogTypes::LOG_LEVELS level, LogTypes::LOG_TYPE type,
Common::Timer::GetTimeFormatted().c_str(),
file, line, level_to_char[(int)level],
log->GetShortName(), temp);
#ifdef ANDROID
Host_SysMessage(msg);
#endif
log->Trigger(level, msg);
}
@@ -181,7 +186,7 @@ void LogContainer::Trigger(LogTypes::LOG_LEVELS level, const char *msg)
FileLogListener::FileLogListener(const char *filename)
{
m_logfile.open(filename, std::ios::app);
OpenFStream(m_logfile, filename, std::ios::app);
SetEnable(true);
}
-24
View File
@@ -21,13 +21,6 @@
#include <cmath>
#include <numeric>
namespace {
static u32 saved_sse_state = _mm_getcsr();
static const u32 default_sse_state = _mm_getcsr();
}
namespace MathUtil
{
@@ -114,23 +107,6 @@ u32 ClassifyFloat(float fvalue)
} // namespace
void LoadDefaultSSEState()
{
_mm_setcsr(default_sse_state);
}
void LoadSSEState()
{
_mm_setcsr(saved_sse_state);
}
void SaveSSEState()
{
saved_sse_state = _mm_getcsr();
}
inline void MatrixMul(int n, const float *a, const float *b, float *result)
{
for (int i = 0; i < n; ++i)
+22 -12
View File
@@ -20,8 +20,8 @@
#include "Common.h"
#include <xmmintrin.h>
#include <vector>
#include "FPURoundMode.h"
namespace MathUtil
{
@@ -149,22 +149,32 @@ struct Rectangle
inline float pow2f(float x) {return x * x;}
inline double pow2(double x) {return x * x;}
/*
There are two different flavors of float to int conversion:
_mm_cvtps_epi32() and _mm_cvttps_epi32(). The first rounds
according to the MXCSR rounding bits. The second one always
uses round towards zero.
*/
void SaveSSEState();
void LoadSSEState();
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))
// Rounds down. 0 -> undefined
inline u64 Log2(u64 val)
{
#if defined(__GNUC__)
return 63 - __builtin_clzll(val);
#elif defined(_MSC_VER) && defined(_M_X64)
unsigned long result = -1;
_BitScanReverse64(&result, val);
return result;
#else
u64 result = -1;
while (val != 0)
{
val >>= 1;
++result;
}
return result;
#endif
}
// Tiny matrix/vector library.
// Used for things like Free-Look in the gfx backend.
+34
View File
@@ -27,6 +27,10 @@
#include <unistd.h>
#include <cerrno>
#include <cstring>
#ifdef ANDROID
#include <sys/ioctl.h>
#include <linux/ashmem.h>
#endif
#endif
#if defined(__APPLE__)
@@ -34,11 +38,41 @@ static const char* ram_temp_file = "/tmp/gc_mem.tmp";
#elif !defined(_WIN32) // non OSX unixes
static const char* ram_temp_file = "/dev/shm/gc_mem.tmp";
#endif
#ifdef ANDROID
#define ASHMEM_DEVICE "/dev/ashmem"
int AshmemCreateFileMapping(const char *name, size_t size)
{
int fd, ret;
fd = open(ASHMEM_DEVICE, O_RDWR);
if (fd < 0)
return fd;
// We don't really care if we can't set the name, it is optional
ret = ioctl(fd, ASHMEM_SET_NAME, name);
ret = ioctl(fd, ASHMEM_SET_SIZE, size);
if (ret < 0)
{
close(fd);
NOTICE_LOG(MEMMAP, "Ashmem returned error: 0x%08x", ret);
return ret;
}
return fd;
}
#endif
void MemArena::GrabLowMemSpace(size_t size)
{
#ifdef _WIN32
hMemoryMapping = CreateFileMapping(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0, (DWORD)(size), NULL);
#elif defined(ANDROID)
fd = AshmemCreateFileMapping("Dolphin-emu", size);
if (fd < 0)
{
NOTICE_LOG(MEMMAP, "Ashmem allocation failed");
return;
}
#else
mode_t mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH;
fd = open(ram_temp_file, O_RDWR | O_CREAT, mode);
+4 -1
View File
@@ -117,9 +117,12 @@ void* AllocateAlignedMemory(size_t size,size_t alignment)
void* ptr = _aligned_malloc(size,alignment);
#else
void* ptr = NULL;
#ifdef ANDROID
ptr = memalign(alignment, size);
#else
if (posix_memalign(&ptr, alignment, size) != 0)
ERROR_LOG(MEMMAP, "Failed to allocate aligned memory");
;
#endif
#endif
// printf("Mapped memory at %p (size %ld)\n", ptr,
+1 -1
View File
@@ -31,7 +31,7 @@ const char* GetLastErrorMsg()
#ifdef _WIN32
static __declspec(thread) char err_str[buff_size] = {};
FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, NULL, GetLastError(),
FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM, NULL, GetLastError(),
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
err_str, buff_size, NULL);
#else
+1 -1
View File
@@ -106,7 +106,7 @@ bool DefaultMsgHandler(const char* caption, const char* text, bool yes_no, int S
if (Style == QUESTION) STYLE = MB_ICONQUESTION;
if (Style == WARNING) STYLE = MB_ICONWARNING;
return IDYES == MessageBox(0, text, caption, STYLE | (yes_no ? MB_YESNO : MB_OK));
return IDYES == MessageBox(0, UTF8ToTStr(text).c_str(), UTF8ToTStr(caption).c_str(), STYLE | (yes_no ? MB_YESNO : MB_OK));
#else
printf("%s\n", text);
+4 -2
View File
@@ -86,7 +86,8 @@ bool CheckTitleTIK(u64 _titleID)
static void CreateReplacementFile(std::string &filename)
{
std::ofstream replace(filename.c_str());
std::ofstream replace;
OpenFStream(replace, filename, std::ios_base::out);
replace <<"\" __22__\n";
replace << "* __2a__\n";
//replace << "/ __2f__\n";
@@ -108,7 +109,8 @@ void ReadReplacements(replace_v& replacements)
if (!File::Exists(filename))
CreateReplacementFile(filename);
std::ifstream f(filename.c_str());
std::ifstream f;
OpenFStream(f, filename, std::ios_base::in);
char letter;
std::string replacement;
+3 -4
View File
@@ -29,6 +29,7 @@
// Modified for Dolphin.
#include "SDCardUtil.h"
#include "FileUtil.h"
#include <time.h>
#include <stdio.h>
@@ -190,7 +191,6 @@ bool SDCardCreate(u64 disk_size /*in MB*/, const char* filename)
{
u32 sectors_per_fat;
u32 sectors_per_disk;
FILE* f;
// Convert MB to bytes
disk_size *= 1024 * 1024;
@@ -207,7 +207,8 @@ bool SDCardCreate(u64 disk_size /*in MB*/, const char* filename)
boot_sector_init(s_boot_sector, s_fsinfo_sector, disk_size, nullptr);
fat_init(s_fat_head);
f = fopen(filename, "wb");
File::IOFile file(filename, "wb");
FILE* const f = file.GetHandle();
if (!f)
{
ERROR_LOG(COMMON, "Could not create file '%s', aborting...\n", filename);
@@ -247,13 +248,11 @@ bool SDCardCreate(u64 disk_size /*in MB*/, const char* filename)
if (write_empty(f, sectors_per_disk - RESERVED_SECTORS - 2*sectors_per_fat)) goto FailWrite;
fclose(f);
return true;
FailWrite:
ERROR_LOG(COMMON, "Could not write to '%s', aborting...\n", filename);
if (unlink(filename) < 0)
ERROR_LOG(COMMON, "unlink(%s) failed\n%s", filename, GetLastErrorMsg());
fclose(f);
return false;
}
@@ -5,7 +5,7 @@
#define GCC_VER(x,y,z) ((x) * 10000 + (y) * 100 + (z))
#define GCC_VERSION GCC_VER(__GNUC__, __GNUC_MINOR__, __GNUC_PATCHLEVEL__)
#if GCC_VERSION >= GCC_VER(4,4,0) && __GXX_EXPERIMENTAL_CXX0X__
#if GCC_VERSION >= GCC_VER(4,4,0) && __GXX_EXPERIMENTAL_CXX0X__ && !ANDROID
// GCC 4.4 provides <condition_variable>
#include <condition_variable>
#else
+1 -1
View File
@@ -5,7 +5,7 @@
#define GCC_VER(x,y,z) ((x) * 10000 + (y) * 100 + (z))
#define GCC_VERSION GCC_VER(__GNUC__, __GNUC_MINOR__, __GNUC_PATCHLEVEL__)
#if GCC_VERSION >= GCC_VER(4,4,0) && __GXX_EXPERIMENTAL_CXX0X__
#if GCC_VERSION >= GCC_VER(4,4,0) && __GXX_EXPERIMENTAL_CXX0X__ && !ANDROID
// GCC 4.4 provides <mutex>
#include <mutex>
#else
+1 -1
View File
@@ -5,7 +5,7 @@
#define GCC_VER(x,y,z) ((x) * 10000 + (y) * 100 + (z))
#define GCC_VERSION GCC_VER(__GNUC__, __GNUC_MINOR__, __GNUC_PATCHLEVEL__)
#if GCC_VERSION >= GCC_VER(4,4,0) && __GXX_EXPERIMENTAL_CXX0X__
#if GCC_VERSION >= GCC_VER(4,4,0) && __GXX_EXPERIMENTAL_CXX0X__ && !ANDROID
// GCC 4.4 provides <thread>
#ifndef _GLIBCXX_USE_SCHED_YIELD
#define _GLIBCXX_USE_SCHED_YIELD
+162 -18
View File
@@ -17,11 +17,21 @@
#include <stdlib.h>
#include <stdio.h>
#include <algorithm>
#include "Common.h"
#include "CommonPaths.h"
#include "StringUtil.h"
#ifdef _WIN32
#include <Windows.h>
#elif defined(ANDROID)
#else
#include <iconv.h>
#include <errno.h>
#endif
// faster than sscanf
bool AsciiToHex(const char* _szValue, u32& result)
{
@@ -263,25 +273,25 @@ std::string ReplaceAll(std::string result, const std::string& src, const std::st
const char HEX2DEC[256] =
{
/* 0 1 2 3 4 5 6 7 8 9 A B C D E F */
/* 0 */ -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1,
/* 1 */ -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1,
/* 2 */ -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1,
/* 3 */ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,-1,-1, -1,-1,-1,-1,
/* 0 */ 16,16,16,16, 16,16,16,16, 16,16,16,16, 16,16,16,16,
/* 1 */ 16,16,16,16, 16,16,16,16, 16,16,16,16, 16,16,16,16,
/* 2 */ 16,16,16,16, 16,16,16,16, 16,16,16,16, 16,16,16,16,
/* 3 */ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,16,16, 16,16,16,16,
/* 4 */ -1,10,11,12, 13,14,15,-1, -1,-1,-1,-1, -1,-1,-1,-1,
/* 5 */ -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1,
/* 6 */ -1,10,11,12, 13,14,15,-1, -1,-1,-1,-1, -1,-1,-1,-1,
/* 7 */ -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1,
/* 4 */ 16,10,11,12, 13,14,15,16, 16,16,16,16, 16,16,16,16,
/* 5 */ 16,16,16,16, 16,16,16,16, 16,16,16,16, 16,16,16,16,
/* 6 */ 16,10,11,12, 13,14,15,16, 16,16,16,16, 16,16,16,16,
/* 7 */ 16,16,16,16, 16,16,16,16, 16,16,16,16, 16,16,16,16,
/* 8 */ -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1,
/* 9 */ -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1,
/* A */ -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1,
/* B */ -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1,
/* 8 */ 16,16,16,16, 16,16,16,16, 16,16,16,16, 16,16,16,16,
/* 9 */ 16,16,16,16, 16,16,16,16, 16,16,16,16, 16,16,16,16,
/* A */ 16,16,16,16, 16,16,16,16, 16,16,16,16, 16,16,16,16,
/* B */ 16,16,16,16, 16,16,16,16, 16,16,16,16, 16,16,16,16,
/* C */ -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1,
/* D */ -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1,
/* E */ -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1,
/* F */ -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1
/* C */ 16,16,16,16, 16,16,16,16, 16,16,16,16, 16,16,16,16,
/* D */ 16,16,16,16, 16,16,16,16, 16,16,16,16, 16,16,16,16,
/* E */ 16,16,16,16, 16,16,16,16, 16,16,16,16, 16,16,16,16,
/* F */ 16,16,16,16, 16,16,16,16, 16,16,16,16, 16,16,16,16
};
std::string UriDecode(const std::string & sSrc)
@@ -303,8 +313,8 @@ std::string UriDecode(const std::string & sSrc)
if (*pSrc == '%')
{
char dec1, dec2;
if (-1 != (dec1 = HEX2DEC[*(pSrc + 1)])
&& -1 != (dec2 = HEX2DEC[*(pSrc + 2)]))
if (16 != (dec1 = HEX2DEC[*(pSrc + 1)])
&& 16 != (dec2 = HEX2DEC[*(pSrc + 2)]))
{
*pEnd++ = (dec1 << 4) + dec2;
pSrc += 3;
@@ -375,3 +385,137 @@ std::string UriEncode(const std::string & sSrc)
delete [] pStart;
return sResult;
}
#ifdef _WIN32
std::string UTF16ToUTF8(const std::wstring& input)
{
auto const size = WideCharToMultiByte(CP_UTF8, 0, input.data(), input.size(), nullptr, 0, nullptr, nullptr);
std::string output;
output.resize(size);
if (size != WideCharToMultiByte(CP_UTF8, 0, input.data(), input.size(), &output[0], output.size(), nullptr, nullptr))
output.clear();
return output;
}
std::wstring CPToUTF16(u32 code_page, const std::string& input)
{
auto const size = MultiByteToWideChar(code_page, 0, input.data(), input.size(), nullptr, 0);
std::wstring output;
output.resize(size);
if (size != MultiByteToWideChar(code_page, 0, input.data(), input.size(), &output[0], output.size()))
output.clear();
return output;
}
std::wstring UTF8ToUTF16(const std::string& input)
{
return CPToUTF16(CP_UTF8, input);
}
std::string SHIFTJISToUTF8(const std::string& input)
{
return UTF16ToUTF8(CPToUTF16(932, input));
}
std::string CP1252ToUTF8(const std::string& input)
{
return UTF16ToUTF8(CPToUTF16(1252, input));
}
#else
template <typename T>
std::string CodeToUTF8(const char* fromcode, const std::basic_string<T>& input)
{
std::string result;
#if defined(ANDROID)
result = "Not implemented on Android!";
#else
iconv_t const conv_desc = iconv_open("UTF-8", fromcode);
if ((iconv_t)-1 == conv_desc)
{
ERROR_LOG(COMMON, "Iconv initialization failure [%s]: %s", fromcode, strerror(errno));
}
else
{
size_t const in_bytes = sizeof(T) * input.size();
size_t const out_buffer_size = 4 * in_bytes;
std::string out_buffer;
out_buffer.resize(out_buffer_size);
auto src_buffer = &input[0];
size_t src_bytes = in_bytes;
auto dst_buffer = &out_buffer[0];
size_t dst_bytes = out_buffer.size();
while (src_bytes != 0)
{
size_t const iconv_result = iconv(conv_desc, (char**)(&src_buffer), &src_bytes,
&dst_buffer, &dst_bytes);
if ((size_t)-1 == iconv_result)
{
if (EILSEQ == errno || EINVAL == errno)
{
// Try to skip the bad character
if (src_bytes != 0)
{
--src_bytes;
++src_buffer;
}
}
else
{
ERROR_LOG(COMMON, "iconv failure [%s]: %s", fromcode, strerror(errno));
break;
}
}
}
out_buffer.resize(out_buffer_size - dst_bytes);
out_buffer.swap(result);
iconv_close(conv_desc);
}
#endif
return result;
}
std::string CP1252ToUTF8(const std::string& input)
{
//return CodeToUTF8("CP1252//TRANSLIT", input);
//return CodeToUTF8("CP1252//IGNORE", input);
return CodeToUTF8("CP1252", input);
}
std::string SHIFTJISToUTF8(const std::string& input)
{
//return CodeToUTF8("CP932", input);
return CodeToUTF8("SJIS", input);
}
std::string UTF16ToUTF8(const std::wstring& input)
{
std::string result =
// CodeToUTF8("UCS-2", input);
// CodeToUTF8("UCS-2LE", input);
// CodeToUTF8("UTF-16", input);
CodeToUTF8("UTF-16LE", input);
// TODO: why is this needed?
result.erase(std::remove(result.begin(), result.end(), 0x00), result.end());
return result;
}
#endif
+24
View File
@@ -97,4 +97,28 @@ std::string ReplaceAll(std::string result, const std::string& src, const std::st
std::string UriDecode(const std::string & sSrc);
std::string UriEncode(const std::string & sSrc);
std::string CP1252ToUTF8(const std::string& str);
std::string SHIFTJISToUTF8(const std::string& str);
std::string UTF16ToUTF8(const std::wstring& str);
#ifdef _WIN32
std::wstring UTF8ToUTF16(const std::string& str);
#ifdef _UNICODE
inline std::string TStrToUTF8(const std::wstring& str)
{ return UTF16ToUTF8(str); }
inline std::wstring UTF8ToTStr(const std::string& str)
{ return UTF8ToUTF16(str); }
#else
inline std::string TStrToUTF8(const std::string& str)
{ return str; }
inline std::string UTF8ToTStr(const std::string& str)
{ return str; }
#endif
#endif
#endif // _STRINGUTIL_H_
+1 -1
View File
@@ -105,7 +105,7 @@ void SetThreadAffinity(std::thread::native_handle_type thread, u32 mask)
#ifdef __APPLE__
thread_policy_set(pthread_mach_thread_np(thread),
THREAD_AFFINITY_POLICY, (integer_t *)&mask, 1);
#elif defined __linux__ || defined BSD4_4
#elif (defined __linux__ || defined BSD4_4) && !(defined ANDROID)
cpu_set_t cpu_set;
CPU_ZERO(&cpu_set);
-2
View File
@@ -33,8 +33,6 @@
#define INFINITE 0xffffffff
#endif
#include <xmmintrin.h>
//for gettimeofday and struct time(spec|val)
#include <time.h>
#include <sys/time.h>
+5 -1
View File
@@ -22,6 +22,7 @@
#include <vector>
#include "ChunkFile.h"
#include "../../VideoCommon/Src/PerfQueryBase.h"
typedef void (*writeFn16)(const u16,const u32);
typedef void (*writeFn32)(const u32,const u32);
@@ -108,6 +109,7 @@ public:
virtual void Video_EndField() = 0;
virtual u32 Video_AccessEFB(EFBAccessType, u32, u32, u32) = 0;
virtual u32 Video_GetQueryResult(PerfQueryType type) = 0;
virtual void Video_AddMessage(const char* pstr, unsigned int milliseconds) = 0;
virtual void Video_ClearMessages() = 0;
@@ -157,8 +159,10 @@ class VideoBackendHardware : public VideoBackend
void Video_ExitLoop();
void Video_BeginField(u32, FieldType, u32, u32);
void Video_EndField();
u32 Video_AccessEFB(EFBAccessType, u32, u32, u32);
u32 Video_AccessEFB(EFBAccessType, u32, u32, u32);
u32 Video_GetQueryResult(PerfQueryType type);
void Video_AddMessage(const char* pstr, unsigned int milliseconds);
void Video_ClearMessages();
bool Video_Screenshot(const char* filename);
@@ -17,7 +17,7 @@
#include "Common.h"
#include "x64Emitter.h"
#include "ABI.h"
#include "x64ABI.h"
using namespace Gen;
@@ -30,7 +30,9 @@
#else
//#include <config/i386/cpuid.h>
#ifndef _M_GENERIC
#include <xmmintrin.h>
#endif
#if defined __FreeBSD__
#include <sys/types.h>
@@ -39,7 +41,9 @@
static inline void do_cpuid(unsigned int *eax, unsigned int *ebx,
unsigned int *ecx, unsigned int *edx)
{
#ifdef _LP64
#if defined _M_GENERIC
(*eax) = (*ebx) = (*ecx) = (*edx) = 0;
#elif defined _LP64
// Note: EBX is reserved on Mac OS X and in PIC on Linux, so it has to
// restored at the end of the asm block.
__asm__ (
+1 -1
View File
@@ -17,7 +17,7 @@
#include "Common.h"
#include "x64Emitter.h"
#include "ABI.h"
#include "x64ABI.h"
#include "CPUDetect.h"
namespace Gen
+1 -1
View File
@@ -757,7 +757,7 @@ public:
region_size = 0;
}
bool IsInCodeSpace(u8 *ptr)
bool IsInSpace(u8 *ptr)
{
return ptr >= region && ptr < region + region_size;
}
+120
View File
@@ -0,0 +1,120 @@
// 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 "FPURoundMode.h"
#ifndef _WIN32
static const unsigned short FPU_ROUND_NEAR = 0 << 10;
static const unsigned short FPU_ROUND_DOWN = 1 << 10;
static const unsigned short FPU_ROUND_UP = 2 << 10;
static const unsigned short FPU_ROUND_CHOP = 3 << 10;
static const unsigned short FPU_ROUND_MASK = 3 << 10;
#include <xmmintrin.h>
#endif
const u32 MASKS = 0x1F80; // mask away the interrupts.
const u32 DAZ = 0x40;
const u32 FTZ = 0x8000;
namespace FPURoundMode
{
// Get the default SSE states here.
static u32 saved_sse_state = _mm_getcsr();
static const u32 default_sse_state = _mm_getcsr();
void SetRoundMode(u32 mode)
{
// Set FPU rounding mode to mimic the PowerPC's
#ifdef _M_IX86
// This shouldn't really be needed anymore since we use SSE
#ifdef _WIN32
const int table[4] =
{
_RC_NEAR,
_RC_CHOP,
_RC_UP,
_RC_DOWN
};
_set_controlfp(_MCW_RC, table[mode]);
#else
const unsigned short table[4] =
{
FPU_ROUND_NEAR,
FPU_ROUND_CHOP,
FPU_ROUND_UP,
FPU_ROUND_DOWN
};
unsigned short _mode;
asm ("fstcw %0" : "=m" (_mode) : );
_mode = (_mode & ~FPU_ROUND_MASK) | table[mode];
asm ("fldcw %0" : : "m" (_mode));
#endif
#endif
}
void SetPrecisionMode(u32 mode)
{
#ifdef _M_IX86
// sets the floating-point lib to 53-bit
// PowerPC has a 53bit floating pipeline only
// eg: sscanf is very sensitive
#ifdef _WIN32
_control87(_PC_53, MCW_PC);
#else
const unsigned short table[4] = {
0 << 8, // FPU_PREC_24
2 << 8, // FPU_PREC_53
3 << 8, // FPU_PREC_64
3 << 8, // FPU_PREC_MASK
};
unsigned short _mode;
asm ("fstcw %0" : : "m" (_mode));
_mode = (_mode & ~table[4]) | table[mode];
asm ("fldcw %0" : : "m" (_mode));
#endif
#else
//x64 doesn't need this - fpu is done with SSE
//but still - set any useful sse options here
#endif
}
void SetSIMDMode(u32 mode)
{
static const u32 ssetable[4] =
{
(0 << 13) | MASKS,
(3 << 13) | MASKS,
(2 << 13) | MASKS,
(1 << 13) | MASKS,
};
u32 csr = ssetable[mode];
_mm_setcsr(csr);
}
void SaveSIMDState()
{
saved_sse_state = _mm_getcsr();
}
void LoadSIMDState()
{
_mm_setcsr(saved_sse_state);
}
void LoadDefaultSIMDState()
{
_mm_setcsr(default_sse_state);
}
}
@@ -18,9 +18,8 @@
#include <map>
#include "Common.h"
#include "x64Emitter.h"
#include "MemoryUtil.h"
#include "ABI.h"
#include "x64ABI.h"
#include "Thunk.h"
#define THUNK_ARENA_SIZE 1024*1024*1
+29 -7
View File
@@ -9,7 +9,6 @@ set(SRCS Src/ActionReplay.cpp
Src/DSPEmulator.cpp
Src/GeckoCodeConfig.cpp
Src/GeckoCode.cpp
Src/MemTools.cpp
Src/Movie.cpp
Src/NetPlay.cpp
Src/NetPlayClient.cpp
@@ -153,6 +152,7 @@ set(SRCS Src/ActionReplay.cpp
Src/PowerPC/PPCTables.cpp
Src/PowerPC/Profiler.cpp
Src/PowerPC/SignatureDB.cpp
Src/PowerPC/JitInterface.cpp
Src/PowerPC/Interpreter/Interpreter_Branch.cpp
Src/PowerPC/Interpreter/Interpreter.cpp
Src/PowerPC/Interpreter/Interpreter_FloatingPoint.cpp
@@ -162,6 +162,15 @@ set(SRCS Src/ActionReplay.cpp
Src/PowerPC/Interpreter/Interpreter_Paired.cpp
Src/PowerPC/Interpreter/Interpreter_SystemRegisters.cpp
Src/PowerPC/Interpreter/Interpreter_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)
if(NOT _M_GENERIC)
set(SRCS ${SRCS}
Src/x64MemTools.cpp
Src/PowerPC/Jit64IL/IR.cpp
Src/PowerPC/Jit64IL/IR_X86.cpp
Src/PowerPC/Jit64IL/JitILAsm.cpp
@@ -186,12 +195,25 @@ set(SRCS Src/ActionReplay.cpp
Src/PowerPC/Jit64/Jit_LoadStorePaired.cpp
Src/PowerPC/Jit64/Jit_Paired.cpp
Src/PowerPC/Jit64/JitRegCache.cpp
Src/PowerPC/Jit64/Jit_SystemRegisters.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/Jit64/Jit_SystemRegisters.cpp)
endif()
if(_M_ARM)
set(SRCS ${SRCS}
Src/ArmMemTools.cpp
Src/PowerPC/JitArm32/Jit.cpp
Src/PowerPC/JitArm32/JitAsm.cpp
Src/PowerPC/JitArm32/JitArm_BackPatch.cpp
Src/PowerPC/JitArm32/JitArm_Tables.cpp
Src/PowerPC/JitArm32/JitArmCache.cpp
Src/PowerPC/JitArm32/JitRegCache.cpp
Src/PowerPC/JitArm32/JitFPRCache.cpp
Src/PowerPC/JitArm32/JitArm_Branch.cpp
Src/PowerPC/JitArm32/JitArm_Integer.cpp
Src/PowerPC/JitArm32/JitArm_LoadStore.cpp
Src/PowerPC/JitArm32/JitArm_FloatingPoint.cpp
Src/PowerPC/JitArm32/JitArm_SystemRegisters.cpp
Src/PowerPC/JitArm32/JitArm_LoadStoreFloating.cpp)
endif()
set(LIBS bdisasm inputcommon videosoftware sfml-network)
+10 -8
View File
@@ -44,7 +44,7 @@
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<UseDebugLibraries>false</UseDebugLibraries>
<ConfigurationType>StaticLibrary</ConfigurationType>
<CharacterSet>MultiByte</CharacterSet>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='DebugFast|Win32'" Label="Configuration">
<ConfigurationType>StaticLibrary</ConfigurationType>
@@ -54,7 +54,7 @@
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<UseDebugLibraries>false</UseDebugLibraries>
<ConfigurationType>StaticLibrary</ConfigurationType>
<CharacterSet>MultiByte</CharacterSet>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='DebugFast|x64'" Label="Configuration">
<ConfigurationType>StaticLibrary</ConfigurationType>
@@ -332,7 +332,7 @@
<ClCompile Include="Src\IPC_HLE\WII_IPC_HLE_Device_usb.cpp" />
<ClCompile Include="Src\IPC_HLE\WII_IPC_HLE_Device_usb_kbd.cpp" />
<ClCompile Include="Src\IPC_HLE\WII_IPC_HLE_WiiMote.cpp" />
<ClCompile Include="Src\MemTools.cpp" />
<ClCompile Include="Src\x64MemTools.cpp" />
<ClCompile Include="Src\Movie.cpp" />
<ClCompile Include="Src\NetPlay.cpp" />
<ClCompile Include="Src\NetPlayClient.cpp" />
@@ -378,6 +378,7 @@
<ClCompile Include="Src\PowerPC\JitCommon\JitBase.cpp" />
<ClCompile Include="Src\PowerPC\JitCommon\JitCache.cpp" />
<ClCompile Include="Src\PowerPC\JitCommon\Jit_Util.cpp" />
<ClCompile Include="Src\PowerPC\JitInterface.cpp" />
<ClCompile Include="Src\PowerPC\LUT_frsqrtex.cpp" />
<ClCompile Include="Src\PowerPC\PowerPC.cpp" />
<ClCompile Include="Src\PowerPC\PPCAnalyst.cpp" />
@@ -387,10 +388,10 @@
<ClCompile Include="Src\PowerPC\Profiler.cpp" />
<ClCompile Include="Src\PowerPC\SignatureDB.cpp" />
<ClCompile Include="Src\State.cpp">
<OpenMPSupport Condition="'$(Configuration)|$(Platform)'=='DebugFast|Win32'">false</OpenMPSupport>
<OpenMPSupport Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">false</OpenMPSupport>
<OpenMPSupport Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">false</OpenMPSupport>
</ClCompile>
<OpenMPSupport Condition="'$(Configuration)|$(Platform)'=='DebugFast|Win32'">false</OpenMPSupport>
<OpenMPSupport Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">false</OpenMPSupport>
<OpenMPSupport Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">false</OpenMPSupport>
</ClCompile>
<ClCompile Include="Src\stdafx.cpp">
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Create</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Create</PrecompiledHeader>
@@ -563,6 +564,7 @@
<ClInclude Include="Src\PowerPC\JitCommon\JitBase.h" />
<ClInclude Include="Src\PowerPC\JitCommon\JitCache.h" />
<ClInclude Include="Src\PowerPC\JitCommon\Jit_Util.h" />
<ClInclude Include="Src\PowerPC\JitInterface.h" />
<ClInclude Include="Src\PowerPC\LUT_frsqrtex.h" />
<ClInclude Include="Src\PowerPC\PowerPC.h" />
<ClInclude Include="Src\PowerPC\PPCAnalyst.h" />
@@ -600,4 +602,4 @@
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>
</Project>
+7 -2
View File
@@ -5,9 +5,8 @@
<ClCompile Include="Src\Console.cpp" />
<ClCompile Include="Src\Core.cpp" />
<ClCompile Include="Src\CoreParameter.cpp" />
<ClCompile Include="Src\CoreRerecording.cpp" />
<ClCompile Include="Src\CoreTiming.cpp" />
<ClCompile Include="Src\MemTools.cpp" />
<ClCompile Include="Src\x64MemTools.cpp" />
<ClCompile Include="Src\PatchEngine.cpp" />
<ClCompile Include="Src\DSPEmulator.cpp" />
<ClCompile Include="Src\State.cpp" />
@@ -562,6 +561,9 @@
<ClCompile Include="Src\HW\GCMemcard.cpp">
<Filter>HW %28Flipper/Hollywood%29\GCMemcard</Filter>
</ClCompile>
<ClCompile Include="Src\PowerPC\JitInterface.cpp">
<Filter>PowerPC</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="Src\ConfigManager.h" />
@@ -1048,6 +1050,9 @@
<ClInclude Include="Src\HW\GCMemcard.h">
<Filter>HW %28Flipper/Hollywood%29\GCMemcard</Filter>
</ClInclude>
<ClInclude Include="Src\PowerPC\JitInterface.h">
<Filter>PowerPC</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<None Include="CMakeLists.txt" />
+103
View File
@@ -0,0 +1,103 @@
// 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 <stdio.h>
#include <signal.h>
#ifdef ANDROID
#include <asm/sigcontext.h>
#else
#include <sys/ucontext.h> // Look in here for the context definition.
#include <execinfo.h>
#endif
#include "Common.h"
#include "MemTools.h"
#include "HW/Memmap.h"
#include "PowerPC/PowerPC.h"
#include "PowerPC/JitInterface.h"
#include "PowerPC/JitCommon/JitBase.h"
namespace EMM
{
#ifdef ANDROID
typedef struct sigcontext mcontext_t;
typedef struct ucontext {
uint32_t uc_flags;
struct ucontext* uc_link;
stack_t uc_stack;
mcontext_t uc_mcontext;
// Other fields are not used by Google Breakpad. Don't define them.
} ucontext_t;
#endif
void sigsegv_handler(int signal, siginfo_t *info, void *raw_context)
{
if (signal != SIGSEGV)
{
// We are not interested in other signals - handle it as usual.
return;
}
ucontext_t *context = (ucontext_t *)raw_context;
int sicode = info->si_code;
if (sicode != SEGV_MAPERR && sicode != SEGV_ACCERR)
{
// Huh? Return.
return;
}
// Get all the information we can out of the context.
mcontext_t *ctx = &context->uc_mcontext;
void *fault_memory_ptr = (void*)ctx->arm_r10;
u8 *fault_instruction_ptr = (u8 *)ctx->arm_pc;
if (!JitInterface::IsInCodeSpace(fault_instruction_ptr)) {
// Let's not prevent debugging.
return;
}
u64 bad_address = (u64)fault_memory_ptr;
u64 memspace_bottom = (u64)Memory::base;
if (bad_address < memspace_bottom) {
PanicAlertT("Exception handler - access below memory space. %08llx%08llx",
bad_address >> 32, bad_address);
}
u32 em_address = (u32)(bad_address - memspace_bottom);
int access_type = 0;
CONTEXT fake_ctx;
fake_ctx.reg_pc = ctx->arm_pc;
const u8 *new_rip = jit->BackPatch(fault_instruction_ptr, access_type, em_address, &fake_ctx);
if (new_rip) {
ctx->arm_pc = fake_ctx.reg_pc;
}
}
void InstallExceptionHandler()
{
struct sigaction sa;
sa.sa_handler = 0;
sa.sa_sigaction = &sigsegv_handler;
sa.sa_flags = SA_SIGINFO;
sigemptyset(&sa.sa_mask);
sigaction(SIGSEGV, &sa, NULL);
}
} // namespace
+1 -3
View File
@@ -90,9 +90,7 @@ bool CBoot::Boot_WiiWAD(const char* _pFilename)
u64 titleID = ContentLoader.GetTitleID();
// create data directory
File::CreateFullPath(Common::GetTitleDataPath(titleID));
if (titleID == TITLEID_SYSMENU)
HLE_IPC_CreateVirtualFATFilesystem();
// setup wii mem
if (!SetupWiiMemory(ContentLoader.GetCountry()))
return false;
+12 -22
View File
@@ -100,9 +100,6 @@ SConfig::SConfig()
{
// Make sure we have log manager
LoadSettings();
//Make sure we load any extra settings
LoadSettingsWii();
}
void SConfig::Init()
@@ -140,7 +137,7 @@ void SConfig::SaveSettings()
ini.Get("General", "GCMPathes", &oldPaths, 0);
for (int i = numPaths; i < oldPaths; i++)
{
TCHAR tmp[16];
char tmp[16];
sprintf(tmp, "GCMPath%i", i);
ini.DeleteKey("General", tmp);
}
@@ -149,7 +146,7 @@ void SConfig::SaveSettings()
for (int i = 0; i < numPaths; i++)
{
TCHAR tmp[16];
char tmp[16];
sprintf(tmp, "GCMPath%i", i);
ini.Set("General", tmp, m_ISOFolder[i]);
}
@@ -244,6 +241,8 @@ void SConfig::SaveSettings()
ini.Set("Core", "WiiSDCard", m_WiiSDCard);
ini.Set("Core", "WiiKeyboard", m_WiiKeyboard);
ini.Set("Core", "WiimoteReconnectOnLoad", m_WiimoteReconnectOnLoad);
ini.Set("Core", "WiimoteContinuousScanning", m_WiimoteContinuousScanning);
ini.Set("Core", "WiimoteEnableSpeaker", m_WiimoteEnableSpeaker);
ini.Set("Core", "RunCompareServer", m_LocalCoreStartupParameter.bRunCompareServer);
ini.Set("Core", "RunCompareClient", m_LocalCoreStartupParameter.bRunCompareClient);
ini.Set("Core", "FrameLimit", m_Framelimit);
@@ -285,7 +284,7 @@ void SConfig::LoadSettings()
{
for (int i = 0; i < numGCMPaths; i++)
{
TCHAR tmp[16];
char tmp[16];
sprintf(tmp, "GCMPath%i", i);
std::string tmpPath;
ini.Get("General", tmp, &tmpPath, "");
@@ -363,7 +362,11 @@ void SConfig::LoadSettings()
// Core
ini.Get("Core", "HLE_BS2", &m_LocalCoreStartupParameter.bHLE_BS2, false);
#ifdef _M_ARM
ini.Get("Core", "CPUCore", &m_LocalCoreStartupParameter.iCPUCore, 3);
#else
ini.Get("Core", "CPUCore", &m_LocalCoreStartupParameter.iCPUCore, 1);
#endif
ini.Get("Core", "DSPThread", &m_LocalCoreStartupParameter.bDSPThread, false);
ini.Get("Core", "DSPHLE", &m_LocalCoreStartupParameter.bDSPHLE, true);
ini.Get("Core", "CPUThread", &m_LocalCoreStartupParameter.bCPUThread, true);
@@ -393,7 +396,9 @@ void SConfig::LoadSettings()
ini.Get("Core", "WiiSDCard", &m_WiiSDCard, false);
ini.Get("Core", "WiiKeyboard", &m_WiiKeyboard, false);
ini.Get("Core", "WiimoteReconnectOnLoad", &m_WiimoteReconnectOnLoad, true);
ini.Get("Core", "WiimoteReconnectOnLoad", &m_WiimoteReconnectOnLoad, true);
ini.Get("Core", "WiimoteContinuousScanning", &m_WiimoteContinuousScanning, false);
ini.Get("Core", "WiimoteEnableSpeaker", &m_WiimoteEnableSpeaker, true);
ini.Get("Core", "RunCompareServer", &m_LocalCoreStartupParameter.bRunCompareServer, false);
ini.Get("Core", "RunCompareClient", &m_LocalCoreStartupParameter.bRunCompareClient, false);
ini.Get("Core", "MMU", &m_LocalCoreStartupParameter.bMMU, false);
@@ -428,18 +433,3 @@ void SConfig::LoadSettings()
m_SYSCONF = new SysConf();
}
void SConfig::LoadSettingsWii()
{
IniFile ini;
//Wiimote configs
ini.Load((File::GetUserPath(D_CONFIG_IDX) + "Dolphin.ini"));
for (int i = 0; i < 4; i++)
{
char SectionName[32];
sprintf(SectionName, "Wiimote%i", i + 1);
ini.Get(SectionName, "AutoReconnectRealWiimote", &m_WiiAutoReconnect[i], false);
}
ini.Load((File::GetUserPath(D_CONFIG_IDX) + "wiimote.ini"));
ini.Get("Real", "Unpair", &m_WiiAutoUnpair, false);
}
+3 -6
View File
@@ -35,15 +35,15 @@
#define BACKEND_OPENAL "OpenAL"
#define BACKEND_PULSEAUDIO "Pulse"
#define BACKEND_XAUDIO2 "XAudio2"
#define BACKEND_OPENSLES "OpenSLES"
struct SConfig : NonCopyable
{
// Wii Devices
bool m_WiiSDCard;
bool m_WiiKeyboard;
bool m_WiiAutoReconnect[4];
bool m_WiiAutoUnpair;
bool m_WiimoteReconnectOnLoad;
bool m_WiimoteContinuousScanning;
bool m_WiimoteEnableSpeaker;
// name of the last used filename
std::string m_LastFilename;
@@ -107,9 +107,6 @@ struct SConfig : NonCopyable
// load settings
void LoadSettings();
//Special load settings
void LoadSettingsWii();
// Return the permanent and somewhat globally used instance of this struct
static SConfig& GetInstance() {return(*m_Instance);}
+2 -2
View File
@@ -98,8 +98,8 @@ void Console_Submit(const char *cmd)
}
CASE("dump")
{
TCHAR temp[256];
TCHAR filename[256];
char temp[256];
char filename[256];
u32 start;
u32 end;
sscanf(cmd, "%s %08x %08x %s", temp, &start, &end, filename);
+3 -4
View File
@@ -54,7 +54,6 @@
#include "IPC_HLE/WII_IPC_HLE_Device_usb.h"
#include "PowerPC/PowerPC.h"
#include "PowerPC/JitCommon/JitBase.h"
#include "DSPEmulator.h"
#include "ConfigManager.h"
@@ -140,7 +139,7 @@ void DisplayMessage(const char *message, int time_in_ms)
if (_CoreParameter.bRenderToMain &&
SConfig::GetInstance().m_InterfaceStatusbar)
{
Host_UpdateStatusBar(message);
Host_UpdateStatusBar(message);
}
else
Host_UpdateTitle(message);
@@ -189,7 +188,7 @@ bool IsGPUThread()
return IsCPUThread();
}
}
// This is called from the GUI thread. See the booting call schedule in
// BootManager.cpp
bool Init()
@@ -310,7 +309,7 @@ void CpuThread()
g_video_backend->Video_Prepare();
}
#if defined(_M_X64)
#if defined(_M_X64) || _M_ARM
EMM::InstallExceptionHandler(); // Let's run under memory watch
#endif
+1 -1
View File
@@ -25,7 +25,7 @@
#include "DSPAnalyzer.h"
#include "Jit/DSPJitUtil.h"
#include "x64Emitter.h"
#include "ABI.h"
#include "x64ABI.h"
#define MAX_BLOCK_SIZE 250
#define DSP_IDLE_SKIP_CYCLES 0x1000
@@ -252,7 +252,9 @@ static void gdsp_idma_out(u16 dsp_addr, u32 addr, u32 size)
ERROR_LOG(DSPLLE, "*** idma_out IRAM_DSP (0x%04x) -> RAM (0x%08x) : size (0x%08x)", dsp_addr / 2, addr, size);
}
#if _M_SSE >= 0x301
static const __m128i s_mask = _mm_set_epi32(0x0E0F0C0DL, 0x0A0B0809L, 0x06070405L, 0x02030001L);
#endif
// TODO: These should eat clock cycles.
static void gdsp_ddma_in(u16 dsp_addr, u32 addr, u32 size)
@@ -25,7 +25,7 @@
#include "DSPJitUtil.h"
#endif
#include "x64Emitter.h"
#include "ABI.h"
#include "x64ABI.h"
using namespace Gen;
// CLR $acR
@@ -21,7 +21,7 @@
#include "../DSPAnalyzer.h"
#include "DSPJitUtil.h"
#include "x64Emitter.h"
#include "ABI.h"
#include "x64ABI.h"
using namespace Gen;
@@ -24,7 +24,7 @@
#include "../DSPEmitter.h"
#include "DSPJitUtil.h"
#include "x64Emitter.h"
#include "ABI.h"
#include "x64ABI.h"
using namespace Gen;
// In: RAX: s64 _Value
@@ -18,7 +18,7 @@
#include "../DSPEmitter.h"
#include "DSPJitUtil.h"
#include "x64Emitter.h"
#include "ABI.h"
#include "x64ABI.h"
using namespace Gen;
@@ -22,7 +22,7 @@
#include "../DSPEmitter.h"
#include "DSPJitUtil.h"
#include "x64Emitter.h"
#include "ABI.h"
#include "x64ABI.h"
using namespace Gen;
// SRS @M, $(0x18+S)
+1 -1
View File
@@ -20,7 +20,7 @@
#include "../DSPEmitter.h"
#include "DSPJitUtil.h"
#include "x64Emitter.h"
#include "ABI.h"
#include "x64ABI.h"
using namespace Gen;
//clobbers:
@@ -27,7 +27,7 @@
#include "DSPJitUtil.h"
#endif
#include "x64Emitter.h"
#include "ABI.h"
#include "x64ABI.h"
using namespace Gen;
// Returns s64 in RAX
+1 -1
View File
@@ -20,7 +20,7 @@
#include "../DSPEmitter.h"
#include "DSPJitUtil.h"
#include "x64Emitter.h"
#include "ABI.h"
#include "x64ABI.h"
using namespace Gen;
+2 -1
View File
@@ -754,7 +754,8 @@ bool DSPAssembler::AssembleFile(const char *fname, int pass)
{
int disable_text = 0; // modified by Hermes
std::ifstream fsrc(fname);
std::ifstream fsrc;
OpenFStream(fsrc, fname, std::ios_base::in);
if (fsrc.fail())
{
+21 -25
View File
@@ -25,7 +25,7 @@
namespace Win32TAPHelper
{
bool IsTAPDevice(const char *guid)
bool IsTAPDevice(const TCHAR *guid)
{
HKEY netcard_key;
LONG status;
@@ -39,13 +39,13 @@ bool IsTAPDevice(const char *guid)
for (;;)
{
char enum_name[256];
char unit_string[256];
TCHAR enum_name[256];
TCHAR unit_string[256];
HKEY unit_key;
char component_id_string[] = "ComponentId";
char component_id[256];
char net_cfg_instance_id_string[] = "NetCfgInstanceId";
char net_cfg_instance_id[256];
TCHAR component_id_string[] = _T("ComponentId");
TCHAR component_id[256];
TCHAR net_cfg_instance_id_string[] = _T("NetCfgInstanceId");
TCHAR net_cfg_instance_id[256];
DWORD data_type;
len = sizeof(enum_name);
@@ -56,7 +56,7 @@ bool IsTAPDevice(const char *guid)
else if (status != ERROR_SUCCESS)
return false;
snprintf(unit_string, sizeof(unit_string), "%s\\%s", ADAPTER_KEY, enum_name);
_sntprintf(unit_string, sizeof(unit_string), _T("%s\\%s"), ADAPTER_KEY, enum_name);
status = RegOpenKeyEx(HKEY_LOCAL_MACHINE, unit_string, 0, KEY_READ, &unit_key);
@@ -78,8 +78,8 @@ bool IsTAPDevice(const char *guid)
if (status == ERROR_SUCCESS && data_type == REG_SZ)
{
if (!strcmp(component_id, TAP_COMPONENT_ID) &&
!strcmp(net_cfg_instance_id, guid))
if (!_tcscmp(component_id, TAP_COMPONENT_ID) &&
!_tcscmp(net_cfg_instance_id, guid))
{
RegCloseKey(unit_key);
RegCloseKey(netcard_key);
@@ -96,7 +96,7 @@ bool IsTAPDevice(const char *guid)
return false;
}
bool GetGUIDs(std::vector<std::string>& guids)
bool GetGUIDs(std::vector<std::basic_string<TCHAR>>& guids)
{
LONG status;
HKEY control_net_key;
@@ -111,12 +111,12 @@ bool GetGUIDs(std::vector<std::string>& guids)
while (!found_all)
{
char enum_name[256];
char connection_string[256];
TCHAR enum_name[256];
TCHAR connection_string[256];
HKEY connection_key;
char name_data[256];
TCHAR name_data[256];
DWORD name_type;
const char name_string[] = "Name";
const TCHAR name_string[] = _T("Name");
len = sizeof(enum_name);
status = RegEnumKeyEx(control_net_key, i, enum_name,
@@ -127,8 +127,8 @@ bool GetGUIDs(std::vector<std::string>& guids)
else if (status != ERROR_SUCCESS)
return false;
snprintf(connection_string, sizeof(connection_string),
"%s\\%s\\Connection", NETWORK_CONNECTIONS_KEY, enum_name);
_sntprintf(connection_string, sizeof(connection_string),
_T("%s\\%s\\Connection"), NETWORK_CONNECTIONS_KEY, enum_name);
status = RegOpenKeyEx(HKEY_LOCAL_MACHINE, connection_string,
0, KEY_READ, &connection_key);
@@ -165,15 +165,11 @@ bool GetGUIDs(std::vector<std::string>& guids)
return true;
}
bool OpenTAP(HANDLE& adapter, const std::string device_guid)
bool OpenTAP(HANDLE& adapter, const std::basic_string<TCHAR>& device_guid)
{
char device_path[256];
auto const device_path = USERMODEDEVICEDIR + device_guid + TAPSUFFIX;
/* Open Windows TAP-Win32 adapter */
snprintf(device_path, sizeof(device_path), "%s%s%s",
USERMODEDEVICEDIR, device_guid.c_str(), TAPSUFFIX);
adapter = CreateFile(device_path, GENERIC_READ | GENERIC_WRITE, 0, 0,
adapter = CreateFile(device_path.c_str(), GENERIC_READ | GENERIC_WRITE, 0, 0,
OPEN_EXISTING, FILE_ATTRIBUTE_SYSTEM | FILE_FLAG_OVERLAPPED, 0);
if (adapter == INVALID_HANDLE_VALUE)
@@ -192,7 +188,7 @@ bool CEXIETHERNET::Activate()
return true;
DWORD len;
std::vector<std::string> device_guids;
std::vector<std::basic_string<TCHAR>> device_guids;
if (!Win32TAPHelper::GetGUIDs(device_guids))
{
+7 -7
View File
@@ -65,18 +65,18 @@
// Registry keys
//=================
#define ADAPTER_KEY "SYSTEM\\CurrentControlSet\\Control\\Class\\{4D36E972-E325-11CE-BFC1-08002BE10318}"
#define ADAPTER_KEY _T("SYSTEM\\CurrentControlSet\\Control\\Class\\{4D36E972-E325-11CE-BFC1-08002BE10318}")
#define NETWORK_CONNECTIONS_KEY "SYSTEM\\CurrentControlSet\\Control\\Network\\{4D36E972-E325-11CE-BFC1-08002BE10318}"
#define NETWORK_CONNECTIONS_KEY _T("SYSTEM\\CurrentControlSet\\Control\\Network\\{4D36E972-E325-11CE-BFC1-08002BE10318}")
//======================
// Filesystem prefixes
//======================
#define USERMODEDEVICEDIR "\\\\.\\Global\\"
#define SYSDEVICEDIR "\\Device\\"
#define USERDEVICEDIR "\\DosDevices\\Global\\"
#define TAPSUFFIX ".tap"
#define USERMODEDEVICEDIR _T("\\\\.\\Global\\")
#define SYSDEVICEDIR _T("\\Device\\")
#define USERDEVICEDIR _T("\\DosDevices\\Global\\")
#define TAPSUFFIX _T(".tap")
//=========================================================
// TAP_COMPONENT_ID -- This string defines the TAP driver
@@ -84,4 +84,4 @@
// simultaneously.
//=========================================================
#define TAP_COMPONENT_ID "tap0901"
#define TAP_COMPONENT_ID _T("tap0901")
@@ -27,6 +27,7 @@
#include "UCodes/UCodes.h"
#include "../AudioInterface.h"
#include "ConfigManager.h"
#include "Core.h"
DSPHLE::DSPHLE() {
m_InitMixer = false;
@@ -130,6 +131,14 @@ void DSPHLE::SwapUCode(u32 _crc)
void DSPHLE::DoState(PointerWrap &p)
{
bool isHLE = true;
p.Do(isHLE);
if (isHLE != true && p.GetMode() == PointerWrap::MODE_READ)
{
Core::DisplayMessage("State is incompatible with current DSP engine. Aborting load state.", 3000);
p.SetMode(PointerWrap::MODE_VERIFY);
return;
}
bool prevInitMixer = m_InitMixer;
p.Do(m_InitMixer);
if (prevInitMixer != m_InitMixer && p.GetMode() == PointerWrap::MODE_READ)
@@ -26,6 +26,7 @@
#include "IniFile.h"
#include "ConfigManager.h"
#include "CPUDetect.h"
#include "Core.h"
#include "DSPLLEGlobals.h" // Local
#include "DSP/DSPInterpreter.h"
@@ -56,6 +57,14 @@ Common::Event ppcEvent;
void DSPLLE::DoState(PointerWrap &p)
{
bool isHLE = false;
p.Do(isHLE);
if (isHLE != false && p.GetMode() == PointerWrap::MODE_READ)
{
Core::DisplayMessage("State is incompatible with current DSP engine. Aborting load state.", 3000);
p.SetMode(PointerWrap::MODE_VERIFY);
return;
}
p.Do(g_dsp.r);
p.Do(g_dsp.pc);
#if PROFILE
-4
View File
@@ -432,7 +432,6 @@ std::string GCMemcard::DEntry_BIFlags(u8 index) const
flags.push_back((x & 0x80) ? '1' : '0');
x = x << 1;
}
flags.push_back(0);
return flags;
}
@@ -469,7 +468,6 @@ std::string GCMemcard::DEntry_IconFmt(u8 index) const
format.push_back((x & 0x80) ? '1' : '0');
x = x << 1;
}
format.push_back(0);
return format;
}
@@ -485,7 +483,6 @@ std::string GCMemcard::DEntry_AnimSpeed(u8 index) const
speed.push_back((x & 0x80) ? '1' : '0');
x = x << 1;
}
speed.push_back(0);
return speed;
}
@@ -498,7 +495,6 @@ std::string GCMemcard::DEntry_Permissions(u8 index) const
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;
}
-126
View File
@@ -419,132 +419,6 @@ u32 Read_Instruction(const u32 em_address)
return inst.hex;
}
u32 Read_Opcode_JIT_Uncached(const u32 _Address)
{
u8* iCache;
u32 addr;
if (_Address & JIT_ICACHE_VMEM_BIT)
{
iCache = jit->GetBlockCache()->GetICacheVMEM();
addr = _Address & JIT_ICACHE_MASK;
}
else if (_Address & JIT_ICACHE_EXRAM_BIT)
{
iCache = jit->GetBlockCache()->GetICacheEx();
addr = _Address & JIT_ICACHEEX_MASK;
}
else
{
iCache = jit->GetBlockCache()->GetICache();
addr = _Address & JIT_ICACHE_MASK;
}
u32 inst = *(u32*)(iCache + addr);
if (inst == JIT_ICACHE_INVALID_WORD)
{
u32 cache_block_start = addr & ~0x1f;
u32 mem_block_start = _Address & ~0x1f;
u8 *pMem = Memory::GetPointer(mem_block_start);
memcpy(iCache + cache_block_start, pMem, 32);
inst = *(u32*)(iCache + addr);
}
inst = Common::swap32(inst);
if ((inst & 0xfc000000) == 0)
{
inst = jit->GetBlockCache()->GetOriginalFirstOp(inst);
}
return inst;
}
u32 Read_Opcode_JIT(u32 _Address)
{
#ifdef FAST_ICACHE
if (bMMU && !bFakeVMEM && (_Address & ADDR_MASK_MEM1))
{
_Address = Memory::TranslateAddress(_Address, FLAG_OPCODE);
if (_Address == 0)
{
return 0;
}
}
u32 inst = 0;
// Bypass the icache for the external interrupt exception handler
if ( (_Address & 0x0FFFFF00) == 0x00000500 )
inst = Read_Opcode_JIT_Uncached(_Address);
else
inst = PowerPC::ppcState.iCache.ReadInstruction(_Address);
#else
u32 inst = Memory::ReadUnchecked_U32(_Address);
#endif
return inst;
}
// The following function is deprecated in favour of FAST_ICACHE
u32 Read_Opcode_JIT_LC(const u32 _Address)
{
#ifdef JIT_UNLIMITED_ICACHE
if ((_Address & ~JIT_ICACHE_MASK) != 0x80000000 && (_Address & ~JIT_ICACHE_MASK) != 0x00000000 &&
(_Address & ~JIT_ICACHE_MASK) != 0x7e000000 && // TLB area
(_Address & ~JIT_ICACHEEX_MASK) != 0x90000000 && (_Address & ~JIT_ICACHEEX_MASK) != 0x10000000)
{
PanicAlertT("iCacheJIT: Reading Opcode from %x. Please report.", _Address);
ERROR_LOG(MEMMAP, "iCacheJIT: Reading Opcode from %x. Please report.", _Address);
return 0;
}
u8* iCache;
u32 addr;
if (_Address & JIT_ICACHE_VMEM_BIT)
{
iCache = jit->GetBlockCache()->GetICacheVMEM();
addr = _Address & JIT_ICACHE_MASK;
}
else if (_Address & JIT_ICACHE_EXRAM_BIT)
{
iCache = jit->GetBlockCache()->GetICacheEx();
addr = _Address & JIT_ICACHEEX_MASK;
}
else
{
iCache = jit->GetBlockCache()->GetICache();
addr = _Address & JIT_ICACHE_MASK;
}
u32 inst = *(u32*)(iCache + addr);
if (inst == JIT_ICACHE_INVALID_WORD)
inst = Memory::ReadUnchecked_U32(_Address);
else
inst = Common::swap32(inst);
#else
u32 inst = Memory::ReadUnchecked_U32(_Address);
#endif
if ((inst & 0xfc000000) == 0)
{
inst = jit->GetBlockCache()->GetOriginalFirstOp(inst);
}
return inst;
}
// WARNING! No checks!
// We assume that _Address is cached
void Write_Opcode_JIT(const u32 _Address, const u32 _Value)
{
#ifdef JIT_UNLIMITED_ICACHE
if (_Address & JIT_ICACHE_VMEM_BIT)
{
*(u32*)(jit->GetBlockCache()->GetICacheVMEM() + (_Address & JIT_ICACHE_MASK)) = Common::swap32(_Value);
}
else if (_Address & JIT_ICACHE_EXRAM_BIT)
{
*(u32*)(jit->GetBlockCache()->GetICacheEx() + (_Address & JIT_ICACHEEX_MASK)) = Common::swap32(_Value);
}
else
*(u32*)(jit->GetBlockCache()->GetICache() + (_Address & JIT_ICACHE_MASK)) = Common::swap32(_Value);
#else
Memory::WriteUnchecked_U32(_Value, _Address);
#endif
}
void WriteBigEData(const u8 *_pData, const u32 _Address, const u32 _iSize)
{
memcpy(GetPointer(_Address), _pData, _iSize);
-5
View File
@@ -119,11 +119,6 @@ inline u32 ReadFast32(const u32 _Address)
// used by interpreter to read instructions, uses iCache
u32 Read_Opcode(const u32 _Address);
// used by JIT to read instructions
u32 Read_Opcode_JIT(const u32 _Address);
// used by JIT. uses iCacheJIT. Reads in the "Locked cache" mode
u32 Read_Opcode_JIT_LC(const u32 _Address);
void Write_Opcode_JIT(const u32 _Address, const u32 _Value);
// this is used by Debugger a lot.
// For now, just reads from memory!
u32 Read_Instruction(const u32 _Address);
+1 -1
View File
@@ -133,7 +133,7 @@ unsigned int GetAttached()
// input/output: ptr
// input: mode
//
void DoState(unsigned char **ptr, int mode)
void DoState(u8 **ptr, PointerWrap::Mode mode)
{
// TODO:
+3 -7
View File
@@ -3,6 +3,7 @@
#define _WIIMOTE_H_
#include "../../InputCommon/Src/InputConfig.h"
#include "ChunkFile.h"
#define MAX_WIIMOTES 4
@@ -25,7 +26,7 @@ void Shutdown();
void Initialize(void* const hwnd);
unsigned int GetAttached();
void DoState(unsigned char **ptr, int mode);
void DoState(u8 **ptr, PointerWrap::Mode mode);
void EmuStateChange(EMUSTATE_CHANGE newState);
InputPlugin *GetPlugin();
@@ -38,17 +39,12 @@ void Update(int _number);
namespace WiimoteReal
{
unsigned int Initialize();
void Initialize();
void Shutdown();
void Refresh();
void LoadSettings();
#ifdef _WIN32
int PairUp(bool unpair = false);
int UnPair();
#endif
}
#endif
@@ -248,13 +248,12 @@ void Wiimote::RequestStatus(const wm_request_status* const rs)
{
using namespace WiimoteReal;
std::lock_guard<std::mutex> lk(g_refresh_lock);
std::lock_guard<std::recursive_mutex> lk(g_refresh_lock);
if (g_wiimotes[m_index])
{
wm_request_status rpt;
rpt.rumble = 0;
g_wiimotes[m_index]->SendPacket(WM_REQUEST_STATUS, &rpt, sizeof(rpt));
wm_request_status rpt = {};
g_wiimotes[m_index]->QueueReport(WM_REQUEST_STATUS, &rpt, sizeof(rpt));
}
return;
@@ -298,7 +297,7 @@ void Wiimote::WriteData(const wm_write_data* const wd)
{
// writing the whole mii block each write :/
std::ofstream file;
file.open((File::GetUserPath(D_WIIUSER_IDX) + "mii.bin").c_str(), std::ios::binary | std::ios::out);
OpenFStream(file, File::GetUserPath(D_WIIUSER_IDX) + "mii.bin", std::ios::binary | std::ios::out);
file.write((char*)m_eeprom + 0x0FCA, 0x02f0);
file.close();
}
@@ -106,7 +106,7 @@ void Wiimote::SpeakerData(wm_speaker_data* sd)
File::Delete("rmtdump.wav");
File::Delete("rmtdump.bin");
atexit(stopdamnwav);
ofile.open("rmtdump.bin", ofile.binary | ofile.out);
OpenFStream(ofile, "rmtdump.bin", ofile.binary | ofile.out);
wav.Start("rmtdump.wav", 6000/*Common::swap16(m_reg_speaker.sample_rate)*/);
}
wav.AddMonoSamples(samples, sd->length*2);
@@ -704,7 +704,7 @@ void Wiimote::Update()
{
using namespace WiimoteReal;
std::lock_guard<std::mutex> lk(g_refresh_lock);
std::lock_guard<std::recursive_mutex> lk(g_refresh_lock);
if (g_wiimotes[m_index])
{
Report rpt = g_wiimotes[m_index]->ProcessReadQueue();
@@ -201,6 +201,7 @@ struct wm_report
#define WM_LEDS 0x11
struct wm_leds {
u8 rumble : 1;
// real wii also sets bit 0x2 (unknown purpose)
u8 : 3;
u8 leds : 4;
};
@@ -208,8 +209,9 @@ struct wm_leds {
#define WM_REPORT_MODE 0x12
struct wm_report_mode {
u8 rumble : 1;
u8 continuous : 1; // these 2 seem to be named wrong
// unsure what "all_the_time" actually is, the real wii does set it (bit 0x2)
u8 all_the_time : 1;
u8 continuous : 1;
u8 : 5;
u8 mode;
};
@@ -21,9 +21,25 @@
namespace WiimoteReal
{
int FindWiimotes(Wiimote **wm, int max_wiimotes)
WiimoteScanner::WiimoteScanner()
{
return 0;
return;
}
WiimoteScanner::~WiimoteScanner()
{}
void WiimoteScanner::Update()
{}
std::vector<Wiimote*> WiimoteScanner::FindWiimotes()
{
return std::vector<Wiimote*>();
}
bool WiimoteScanner::IsReady() const
{
return false;
}
bool Wiimote::Connect()
@@ -31,22 +47,22 @@ bool Wiimote::Connect()
return 0;
}
void Wiimote::RealDisconnect()
void Wiimote::Disconnect()
{
return;
}
bool Wiimote::IsOpen() const
bool Wiimote::IsConnected() const
{
return IsConnected();
return false;
}
int Wiimote::IORead(unsigned char* buf)
int Wiimote::IORead(u8* buf)
{
return 0;
}
int Wiimote::IOWrite(unsigned char* buf, int len)
int Wiimote::IOWrite(const u8* buf, int len)
{
return 0;
}
+94 -138
View File
@@ -15,16 +15,6 @@
// Official SVN repository and contact information can be found at
// http://code.google.com/p/dolphin-emu/
#include <sys/time.h>
#include <errno.h>
#include <sys/types.h>
#include <stdlib.h>
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <bluetooth/bluetooth.h>
#include <bluetooth/hci.h>
#include <bluetooth/hci_lib.h>
@@ -32,114 +22,116 @@
#include "Common.h"
#include "WiimoteReal.h"
#include "Host.h"
namespace WiimoteReal
{
// Find wiimotes.
// Does not replace already found wiimotes even if they are disconnected.
// wm is an array of max_wiimotes wiimotes
// Returns the total number of found wiimotes.
int FindWiimotes(Wiimote** wm, int max_wiimotes)
WiimoteScanner::WiimoteScanner()
: m_run_thread()
, m_want_wiimotes()
, device_id(-1)
, device_sock(-1)
{
int device_id;
int device_sock;
int found_devices;
int found_wiimotes = 0;
int i;
// Count the number of already found wiimotes
for (i = 0; i < MAX_WIIMOTES; ++i)
{
if (wm[i])
found_wiimotes++;
}
// Get the id of the first bluetooth device.
if ((device_id = hci_get_route(NULL)) < 0)
device_id = hci_get_route(NULL);
if (device_id < 0)
{
NOTICE_LOG(WIIMOTE, "Bluetooth not found.");
return found_wiimotes;
return;
}
// Create a socket to the device
if ((device_sock = hci_open_dev(device_id)) < 0)
device_sock = hci_open_dev(device_id);
if (device_sock < 0)
{
ERROR_LOG(WIIMOTE, "Unable to open bluetooth.");
return;
}
}
bool WiimoteScanner::IsReady() const
{
return device_sock > 0;
}
WiimoteScanner::~WiimoteScanner()
{
if (IsReady())
close(device_sock);
}
void WiimoteScanner::Update()
{}
std::vector<Wiimote*> WiimoteScanner::FindWiimotes()
{
std::vector<Wiimote*> found_wiimotes;
// supposedly 1.28 seconds
int const wait_len = 1;
int const max_infos = 255;
inquiry_info scan_infos[max_infos] = {};
auto* scan_infos_ptr = scan_infos;
// Scan for bluetooth devices
int const found_devices = hci_inquiry(device_id, wait_len, max_infos, NULL, &scan_infos_ptr, IREQ_CACHE_FLUSH);
if (found_devices < 0)
{
ERROR_LOG(WIIMOTE, "Error searching for bluetooth devices.");
return found_wiimotes;
}
int try_num = 0;
while ((try_num < 5) && (found_wiimotes < max_wiimotes))
DEBUG_LOG(WIIMOTE, "Found %i bluetooth device(s).", found_devices);
// Display discovered devices
for (int i = 0; i < found_devices; ++i)
{
inquiry_info scan_info_arr[128];
inquiry_info* scan_info = scan_info_arr;
memset(&scan_info_arr, 0, sizeof(scan_info_arr));
// Scan for bluetooth devices for approximately one second
found_devices = hci_inquiry(device_id, 1, 128, NULL, &scan_info, IREQ_CACHE_FLUSH);
if (found_devices < 0)
ERROR_LOG(WIIMOTE, "found a device...");
// BT names are a maximum of 248 bytes apparently
char name[255] = {};
if (hci_read_remote_name(device_sock, &scan_infos[i].bdaddr, sizeof(name), name, 0) < 0)
{
ERROR_LOG(WIIMOTE, "Error searching for bluetooth devices.");
return found_wiimotes;
ERROR_LOG(WIIMOTE, "name request failed");
continue;
}
DEBUG_LOG(WIIMOTE, "Found %i bluetooth device(s).", found_devices);
// Display discovered devices
for (i = 0; (i < found_devices) && (found_wiimotes < max_wiimotes); ++i)
ERROR_LOG(WIIMOTE, "device name %s", name);
if (IsValidBluetoothName(name))
{
char name[1000];
memset(name, 0, sizeof(name));
ERROR_LOG(WIIMOTE, "found a device...");
if (hci_read_remote_name(device_sock, &scan_info[i].bdaddr, sizeof(name), name, 0) < 0) {
ERROR_LOG(WIIMOTE, "name request failed");
continue;
}
ERROR_LOG(WIIMOTE, "device name %s", name);
if (IsValidBluetoothName(name))
bool new_wiimote = true;
// TODO: do this
// Determine if this wiimote has already been found.
//for (int j = 0; j < MAX_WIIMOTES && new_wiimote; ++j)
//{
// if (wm[j] && bacmp(&scan_infos[i].bdaddr,&wm[j]->bdaddr) == 0)
// new_wiimote = false;
//}
if (new_wiimote)
{
bool new_wiimote = true;
// Determine if this wiimote has already been found.
for (int j = 0; j < MAX_WIIMOTES && new_wiimote; ++j)
{
if (wm[j] && bacmp(&scan_info[i].bdaddr,&wm[j]->bdaddr) == 0)
new_wiimote = false;
}
// Found a new device
char bdaddr_str[18] = {};
ba2str(&scan_infos[i].bdaddr, bdaddr_str);
if (new_wiimote)
{
// Find an unused slot
unsigned int k = 0;
for (; k < MAX_WIIMOTES && !(WIIMOTE_SRC_REAL & g_wiimote_sources[k] && !wm[k]); ++k);
wm[k] = new Wiimote(k);
// Found a new device
char bdaddr_str[18];
ba2str(&scan_info[i].bdaddr, bdaddr_str);
NOTICE_LOG(WIIMOTE, "Found wiimote %i, (%s).",
wm[k]->index + 1, bdaddr_str);
wm[k]->bdaddr = scan_info[i].bdaddr;
++found_wiimotes;
}
auto* const wm = new Wiimote;
wm->bdaddr = scan_infos[i].bdaddr;
found_wiimotes.push_back(wm);
NOTICE_LOG(WIIMOTE, "Found wiimote (%s).", bdaddr_str);
}
}
try_num++;
}
close(device_sock);
return found_wiimotes;
}
// Connect to a wiimote with a known address.
bool Wiimote::Connect()
{
if (IsConnected())
return false;
sockaddr_l2 addr;
addr.l2_family = AF_BLUETOOTH;
addr.l2_bdaddr = bdaddr;
@@ -148,7 +140,7 @@ bool Wiimote::Connect()
// Output channel
addr.l2_psm = htobs(WM_OUTPUT_CHANNEL);
if ((cmd_sock = socket(AF_BLUETOOTH, SOCK_SEQPACKET, BTPROTO_L2CAP)) == -1 ||
connect(cmd_sock, (struct sockaddr*)&addr, sizeof(addr)) < 0)
connect(cmd_sock, (sockaddr*)&addr, sizeof(addr)) < 0)
{
DEBUG_LOG(WIIMOTE, "Unable to open output socket to wiimote.");
close(cmd_sock);
@@ -159,7 +151,7 @@ bool Wiimote::Connect()
// Input channel
addr.l2_psm = htobs(WM_INPUT_CHANNEL);
if ((int_sock = socket(AF_BLUETOOTH, SOCK_SEQPACKET, BTPROTO_L2CAP)) == -1 ||
connect(int_sock, (struct sockaddr*)&addr, sizeof(addr)) < 0)
connect(int_sock, (sockaddr*)&addr, sizeof(addr)) < 0)
{
DEBUG_LOG(WIIMOTE, "Unable to open input socket from wiimote.");
close(int_sock);
@@ -168,57 +160,27 @@ bool Wiimote::Connect()
return false;
}
NOTICE_LOG(WIIMOTE, "Connected to wiimote %i.", index + 1);
m_connected = true;
// Do the handshake
Handshake();
// Set LEDs
SetLEDs(WIIMOTE_LED_1 << index);
m_wiimote_thread = std::thread(std::mem_fun(&Wiimote::ThreadFunc), this);
return true;
}
// Disconnect a wiimote.
void Wiimote::RealDisconnect()
void Wiimote::Disconnect()
{
if (!IsConnected())
return;
close(cmd_sock);
close(int_sock);
NOTICE_LOG(WIIMOTE, "Disconnecting wiimote %i.", index + 1);
m_connected = false;
if (m_wiimote_thread.joinable())
m_wiimote_thread.join();
Close();
cmd_sock = -1;
int_sock = -1;
}
void Wiimote::Close()
bool Wiimote::IsConnected() const
{
if (IsOpen())
{
Host_ConnectWiimote(index, false);
close(cmd_sock);
close(int_sock);
cmd_sock = -1;
int_sock = -1;
}
return cmd_sock != -1;// && int_sock != -1;
}
bool Wiimote::IsOpen() const
{
return IsConnected() && cmd_sock != -1 && int_sock != -1;
}
int Wiimote::IORead(unsigned char *buf)
// positive = read packet
// negative = didn't read packet
// zero = error
int Wiimote::IORead(u8* buf)
{
// Block select for 1/2000th of a second
timeval tv;
@@ -232,11 +194,11 @@ int Wiimote::IORead(unsigned char *buf)
if (select(int_sock + 1, &fds, NULL, NULL, &tv) == -1)
{
ERROR_LOG(WIIMOTE, "Unable to select wiimote %i input socket.", index + 1);
return 0;
return -1;
}
if (!FD_ISSET(int_sock, &fds))
return 0;
return -1;
// Read the pending message into the buffer
int r = read(int_sock, buf, MAX_PAYLOAD);
@@ -250,21 +212,15 @@ int Wiimote::IORead(unsigned char *buf)
// This can happen if the bluetooth dongle is disconnected
ERROR_LOG(WIIMOTE, "Bluetooth appears to be disconnected. "
"Wiimote %i will be disconnected.", index + 1);
Close();
}
return 0;
}
else if (!r)
{
// Disconnect
Close();
r = 0;
}
return r;
}
int Wiimote::IOWrite(unsigned char* buf, int len)
int Wiimote::IOWrite(u8 const* buf, int len)
{
return write(int_sock, buf, len);
}
+378 -274
View File
@@ -17,7 +17,10 @@
#include <stdio.h>
#include <stdlib.h>
#include <regex>
#include <algorithm>
#include <unordered_map>
#include <ctime>
#include <unordered_set>
#include <windows.h>
#include <dbt.h>
@@ -32,6 +35,9 @@
#include <bthdef.h>
#include <BluetoothAPIs.h>
//#define AUTHENTICATE_WIIMOTES
#define SHARE_WRITE_WIIMOTES
typedef struct _HIDD_ATTRIBUTES
{
ULONG Size;
@@ -53,6 +59,8 @@ typedef BOOL (__stdcall *PBth_BluetoothFindRadioClose)(HBLUETOOTH_RADIO_FIND);
typedef DWORD (__stdcall *PBth_BluetoothGetRadioInfo)(HANDLE, PBLUETOOTH_RADIO_INFO);
typedef DWORD (__stdcall *PBth_BluetoothRemoveDevice)(const BLUETOOTH_ADDRESS*);
typedef DWORD (__stdcall *PBth_BluetoothSetServiceState)(HANDLE, const BLUETOOTH_DEVICE_INFO*, const GUID*, DWORD);
typedef DWORD (__stdcall *PBth_BluetoothAuthenticateDevice)(HWND, HANDLE, BLUETOOTH_DEVICE_INFO*, PWCHAR, ULONG);
typedef DWORD (__stdcall *PBth_BluetoothEnumerateInstalledServices)(HANDLE, BLUETOOTH_DEVICE_INFO*, DWORD*, GUID*);
PHidD_GetHidGuid HidD_GetHidGuid = NULL;
PHidD_GetAttributes HidD_GetAttributes = NULL;
@@ -67,12 +75,21 @@ PBth_BluetoothFindRadioClose Bth_BluetoothFindRadioClose = NULL;
PBth_BluetoothGetRadioInfo Bth_BluetoothGetRadioInfo = NULL;
PBth_BluetoothRemoveDevice Bth_BluetoothRemoveDevice = NULL;
PBth_BluetoothSetServiceState Bth_BluetoothSetServiceState = NULL;
PBth_BluetoothAuthenticateDevice Bth_BluetoothAuthenticateDevice = NULL;
PBth_BluetoothEnumerateInstalledServices Bth_BluetoothEnumerateInstalledServices = NULL;
HINSTANCE hid_lib = NULL;
HINSTANCE bthprops_lib = NULL;
static int initialized = 0;
std::unordered_map<BTH_ADDR, std::time_t> g_connect_times;
#ifdef SHARE_WRITE_WIIMOTES
std::unordered_set<std::basic_string<TCHAR>> g_connected_wiimotes;
std::mutex g_connected_wiimotes_lock;
#endif
inline void init_lib()
{
if (!initialized)
@@ -109,12 +126,15 @@ inline void init_lib()
Bth_BluetoothGetRadioInfo = (PBth_BluetoothGetRadioInfo)GetProcAddress(bthprops_lib, "BluetoothGetRadioInfo");
Bth_BluetoothRemoveDevice = (PBth_BluetoothRemoveDevice)GetProcAddress(bthprops_lib, "BluetoothRemoveDevice");
Bth_BluetoothSetServiceState = (PBth_BluetoothSetServiceState)GetProcAddress(bthprops_lib, "BluetoothSetServiceState");
Bth_BluetoothAuthenticateDevice = (PBth_BluetoothAuthenticateDevice)GetProcAddress(bthprops_lib, "BluetoothAuthenticateDevice");
Bth_BluetoothEnumerateInstalledServices = (PBth_BluetoothEnumerateInstalledServices)GetProcAddress(bthprops_lib, "BluetoothEnumerateInstalledServices");
if (!Bth_BluetoothFindDeviceClose || !Bth_BluetoothFindFirstDevice ||
!Bth_BluetoothFindFirstRadio || !Bth_BluetoothFindNextDevice ||
!Bth_BluetoothFindNextRadio || !Bth_BluetoothFindRadioClose ||
!Bth_BluetoothGetRadioInfo || !Bth_BluetoothRemoveDevice ||
!Bth_BluetoothSetServiceState)
!Bth_BluetoothSetServiceState || !Bth_BluetoothAuthenticateDevice ||
!Bth_BluetoothEnumerateInstalledServices)
{
PanicAlertT("Failed to load bthprops.cpl");
exit(EXIT_FAILURE);
@@ -127,312 +147,353 @@ inline void init_lib()
namespace WiimoteReal
{
template <typename T>
void ProcessWiimotes(bool new_scan, T& callback);
bool AttachWiimote(HANDLE hRadio, const BLUETOOTH_RADIO_INFO&, BLUETOOTH_DEVICE_INFO_STRUCT&);
void RemoveWiimote(BLUETOOTH_DEVICE_INFO_STRUCT&);
bool ForgetWiimote(BLUETOOTH_DEVICE_INFO_STRUCT&);
WiimoteScanner::WiimoteScanner()
: m_run_thread()
, m_want_wiimotes()
{
init_lib();
}
WiimoteScanner::~WiimoteScanner()
{
// TODO: what do we want here?
ProcessWiimotes(false, [](HANDLE, BLUETOOTH_RADIO_INFO&, BLUETOOTH_DEVICE_INFO_STRUCT& btdi)
{
RemoveWiimote(btdi);
});
}
void WiimoteScanner::Update()
{
bool forgot_some = false;
ProcessWiimotes(false, [&](HANDLE, BLUETOOTH_RADIO_INFO&, BLUETOOTH_DEVICE_INFO_STRUCT& btdi)
{
forgot_some |= ForgetWiimote(btdi);
});
// Some hacks that allows disconnects to be detected before connections are handled
// workaround for wiimote 1 moving to slot 2 on temporary disconnect
if (forgot_some)
SLEEP(100);
}
// Find and connect wiimotes.
// Does not replace already found wiimotes even if they are disconnected.
// wm is an array of max_wiimotes wiimotes
// Returns the total number of found and connected wiimotes.
int FindWiimotes(Wiimote** wm, int max_wiimotes)
std::vector<Wiimote*> WiimoteScanner::FindWiimotes()
{
GUID device_id;
HANDLE dev;
HDEVINFO device_info;
int found_wiimotes = 0;
DWORD len;
SP_DEVICE_INTERFACE_DATA device_data;
PSP_DEVICE_INTERFACE_DETAIL_DATA detail_data = NULL;
HIDD_ATTRIBUTES attr;
init_lib();
// Count the number of already found wiimotes
for (int i = 0; i < MAX_WIIMOTES; ++i)
ProcessWiimotes(true, [](HANDLE hRadio, const BLUETOOTH_RADIO_INFO& rinfo, BLUETOOTH_DEVICE_INFO_STRUCT& btdi)
{
if (wm[i])
found_wiimotes++;
}
device_data.cbSize = sizeof(device_data);
ForgetWiimote(btdi);
AttachWiimote(hRadio, rinfo, btdi);
});
// Get the device id
GUID device_id;
HidD_GetHidGuid(&device_id);
// Get all hid devices connected
device_info = SetupDiGetClassDevs(&device_id, NULL, NULL, (DIGCF_DEVICEINTERFACE | DIGCF_PRESENT));
HDEVINFO const device_info = SetupDiGetClassDevs(&device_id, NULL, NULL, (DIGCF_DEVICEINTERFACE | DIGCF_PRESENT));
for (int index = 0; found_wiimotes < max_wiimotes; ++index)
std::vector<Wiimote*> wiimotes;
SP_DEVICE_INTERFACE_DATA device_data;
device_data.cbSize = sizeof(device_data);
PSP_DEVICE_INTERFACE_DETAIL_DATA detail_data = NULL;
for (int index = 0; SetupDiEnumDeviceInterfaces(device_info, NULL, &device_id, index, &device_data); ++index)
{
if (detail_data)
{
free(detail_data);
detail_data = NULL;
}
// Query the next hid device info
if (!SetupDiEnumDeviceInterfaces(device_info, NULL, &device_id, index, &device_data))
break;
// Get the size of the data block required
DWORD len;
SetupDiGetDeviceInterfaceDetail(device_info, &device_data, NULL, 0, &len, NULL);
detail_data = (PSP_DEVICE_INTERFACE_DETAIL_DATA)malloc(len);
detail_data->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA);
// Query the data for this device
if (!SetupDiGetDeviceInterfaceDetail(device_info, &device_data, detail_data, len, NULL, NULL))
continue;
// Determine if this wiimote has already been found.
bool found = false;
for(int i = 0; i < MAX_WIIMOTES; i++)
if (SetupDiGetDeviceInterfaceDetail(device_info, &device_data, detail_data, len, NULL, NULL))
{
if(wm[i] && (wm[i]->devicepath == detail_data->DevicePath))
{
found = true;
break;
}
auto const wm = new Wiimote;
wm->devicepath = detail_data->DevicePath;
wiimotes.push_back(wm);
}
if (found)
continue;
// Open new device
dev = CreateFile(detail_data->DevicePath,
(GENERIC_READ | GENERIC_WRITE),
(FILE_SHARE_READ | FILE_SHARE_WRITE),
NULL, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL);
if (dev == INVALID_HANDLE_VALUE)
continue;
// Get device attributes
attr.Size = sizeof(attr);
HidD_GetAttributes(dev, &attr);
// Find an unused slot
unsigned int k = 0;
for (; k < MAX_WIIMOTES && !(WIIMOTE_SRC_REAL & g_wiimote_sources[k] && !wm[k]); ++k);
wm[k] = new Wiimote(k);
wm[k]->dev_handle = dev;
wm[k]->devicepath = detail_data->DevicePath;
if (!wm[k]->Connect())
{
ERROR_LOG(WIIMOTE, "Unable to connect to wiimote %i.", wm[k]->index + 1);
delete wm[k];
wm[k] = NULL;
CloseHandle(dev);
}
else
{
++found_wiimotes;
}
}
if (detail_data)
free(detail_data);
}
SetupDiDestroyDeviceInfoList(device_info);
return found_wiimotes;
// Don't mind me, just a random sleep to fix stuff on Windows
//if (!wiimotes.empty())
// SLEEP(2000);
return wiimotes;
}
bool WiimoteScanner::IsReady() const
{
// TODO: don't search for a radio each time
BLUETOOTH_FIND_RADIO_PARAMS radioParam;
radioParam.dwSize = sizeof(radioParam);
HANDLE hRadio;
HBLUETOOTH_RADIO_FIND hFindRadio = Bth_BluetoothFindFirstRadio(&radioParam, &hRadio);
if (NULL != hFindRadio)
{
Bth_BluetoothFindRadioClose(hFindRadio);
return true;
}
else
{
return false;
}
}
// Connect to a wiimote with a known device path.
bool Wiimote::Connect()
{
if (IsConnected()) return false;
if (IsConnected())
return false;
if (!dev_handle)
#ifdef SHARE_WRITE_WIIMOTES
std::lock_guard<std::mutex> lk(g_connected_wiimotes_lock);
if (g_connected_wiimotes.count(devicepath) != 0)
return false;
auto const open_flags = FILE_SHARE_READ | FILE_SHARE_WRITE;
#else
// Having no FILE_SHARE_WRITE disallows us from connecting to the same wiimote twice.
// (And disallows using wiimotes in use by other programs)
// This is what "WiiYourself" does.
// Apparently this doesn't work for everyone. It might be their fault.
auto const open_flags = FILE_SHARE_READ;
#endif
dev_handle = CreateFile(devicepath.c_str(),
GENERIC_READ | GENERIC_WRITE, open_flags,
NULL, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL);
if (dev_handle == INVALID_HANDLE_VALUE)
{
dev_handle = CreateFile(devicepath.c_str(),
(GENERIC_READ | GENERIC_WRITE),
(FILE_SHARE_READ | FILE_SHARE_WRITE),
NULL, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL);
if (dev_handle == INVALID_HANDLE_VALUE)
return false;
}
hid_overlap.hEvent = CreateEvent(NULL, 1, 1, _T(""));
hid_overlap.Offset = 0;
hid_overlap.OffsetHigh = 0;
m_connected = true;
// Try a handshake to see if the device is actually connected
if (!Handshake())
{
m_connected = false;
dev_handle = 0;
return false;
}
// Set LEDs
SetLEDs(WIIMOTE_LED_1 << index);
#if 0
HIDD_ATTRIBUTES attr;
attr.Size = sizeof(attr);
if (!HidD_GetAttributes(dev_handle, &attr))
{
CloseHandle(dev_handle);
dev_handle = 0;
return false;
}
#endif
m_wiimote_thread = std::thread(std::mem_fun(&Wiimote::ThreadFunc), this);
hid_overlap_read = OVERLAPPED();
hid_overlap_read.hEvent = CreateEvent(NULL, true, false, NULL);
hid_overlap_write = OVERLAPPED();
hid_overlap_write.hEvent = CreateEvent(NULL, true, false, NULL);
// TODO: thread isn't started here now, do this elsewhere
// This isn't as drastic as it sounds, since the process in which the threads
// reside is normal priority. Needed for keeping audio reports at a decent rate
/*
if (!SetThreadPriority(m_wiimote_thread.native_handle(), THREAD_PRIORITY_TIME_CRITICAL))
{
ERROR_LOG(WIIMOTE, "Failed to set wiimote thread priority");
}
NOTICE_LOG(WIIMOTE, "Connected to wiimote %i.", index + 1);
*/
#ifdef SHARE_WRITE_WIIMOTES
g_connected_wiimotes.insert(devicepath);
#endif
return true;
}
void Wiimote::RealDisconnect()
void Wiimote::Disconnect()
{
if (!IsConnected())
return;
m_connected = false;
if (m_wiimote_thread.joinable())
m_wiimote_thread.join();
CloseHandle(dev_handle);
dev_handle = 0;
ResetEvent(&hid_overlap);
CloseHandle(hid_overlap_read.hEvent);
CloseHandle(hid_overlap_write.hEvent);
#ifdef SHARE_WRITE_WIIMOTES
std::lock_guard<std::mutex> lk(g_connected_wiimotes_lock);
g_connected_wiimotes.erase(devicepath);
#endif
}
bool Wiimote::IsOpen() const
bool Wiimote::IsConnected() const
{
return IsConnected();
return dev_handle != 0;
}
int Wiimote::IORead(unsigned char* buf)
// positive = read packet
// negative = didn't read packet
// zero = error
int Wiimote::IORead(u8* buf)
{
DWORD b, r;
init_lib();
if (!IsConnected())
return 0;
// used below for a warning
*buf = 0;
if (!ReadFile(dev_handle, buf, MAX_PAYLOAD, &b, &hid_overlap))
DWORD bytes;
ResetEvent(hid_overlap_read.hEvent);
if (!ReadFile(dev_handle, buf, MAX_PAYLOAD - 1, &bytes, &hid_overlap_read))
{
// Partial read
b = GetLastError();
auto const err = GetLastError();
if ((b == ERROR_HANDLE_EOF) || (b == ERROR_DEVICE_NOT_CONNECTED))
if (ERROR_IO_PENDING == err)
{
auto const r = WaitForSingleObject(hid_overlap_read.hEvent, WIIMOTE_DEFAULT_TIMEOUT);
if (WAIT_TIMEOUT == r)
{
// Timeout - cancel and continue
if (*buf)
WARN_LOG(WIIMOTE, "Packet ignored. This may indicate a problem (timeout is %i ms).",
WIIMOTE_DEFAULT_TIMEOUT);
CancelIo(dev_handle);
bytes = -1;
}
else if (WAIT_FAILED == r)
{
WARN_LOG(WIIMOTE, "A wait error occured on reading from wiimote %i.", index + 1);
bytes = 0;
}
else if (WAIT_OBJECT_0 == r)
{
if (!GetOverlappedResult(dev_handle, &hid_overlap_read, &bytes, TRUE))
{
WARN_LOG(WIIMOTE, "GetOverlappedResult failed on wiimote %i.", index + 1);
bytes = 0;
}
}
else
{
bytes = 0;
}
}
else if (ERROR_HANDLE_EOF == err)
{
// Remote disconnect
RealDisconnect();
return 0;
bytes = 0;
}
r = WaitForSingleObject(hid_overlap.hEvent, WIIMOTE_DEFAULT_TIMEOUT);
if (r == WAIT_TIMEOUT)
else if (ERROR_DEVICE_NOT_CONNECTED == err)
{
// Timeout - cancel and continue
if (*buf)
WARN_LOG(WIIMOTE, "Packet ignored. This may indicate a problem (timeout is %i ms).",
WIIMOTE_DEFAULT_TIMEOUT);
CancelIo(dev_handle);
ResetEvent(hid_overlap.hEvent);
return 0;
// Remote disconnect
bytes = 0;
}
else if (r == WAIT_FAILED)
else
{
WARN_LOG(WIIMOTE, "A wait error occured on reading from wiimote %i.", index + 1);
return 0;
}
if (!GetOverlappedResult(dev_handle, &hid_overlap, &b, 0))
{
return 0;
bytes = 0;
}
}
// This needs to be done even if ReadFile fails, essential during init
// Move the data over one, so we can add back in data report indicator byte (here, 0xa1)
memmove(buf + 1, buf, MAX_PAYLOAD - 1);
buf[0] = 0xa1;
if (bytes > 0)
{
// Move the data over one, so we can add back in data report indicator byte (here, 0xa1)
std::copy_n(buf, MAX_PAYLOAD - 1, buf + 1);
buf[0] = 0xa1;
ResetEvent(hid_overlap.hEvent);
return MAX_PAYLOAD; // XXX
// TODO: is this really needed?
bytes = MAX_PAYLOAD;
}
return bytes;
}
int Wiimote::IOWrite(unsigned char* buf, int len)
int Wiimote::IOWrite(const u8* buf, int len)
{
DWORD bytes, dw;
int i;
init_lib();
if (!IsConnected())
return 0;
switch (stack)
{
case MSBT_STACK_UNKNOWN:
{
// Try to auto-detect the stack type
if (i = WriteFile(dev_handle, buf + 1, 22, &bytes, &hid_overlap))
{
// Bluesoleil will always return 1 here, even if it's not connected
stack = MSBT_STACK_BLUESOLEIL;
return i;
}
case MSBT_STACK_UNKNOWN:
{
// Try to auto-detect the stack type
stack = MSBT_STACK_BLUESOLEIL;
if (IOWrite(buf, len))
return 1;
if (i = HidD_SetOutputReport(dev_handle, buf + 1, len - 1))
{
stack = MSBT_STACK_MS;
return i;
}
stack = MSBT_STACK_MS;
if (IOWrite(buf, len))
return 1;
dw = GetLastError();
// Checking for 121 = timeout on semaphore/device off/disconnected to
// avoid trouble with other stacks toshiba/widcomm
if (dw == 121)
{
NOTICE_LOG(WIIMOTE, "IOWrite[MSBT_STACK_UNKNOWN]: Timeout");
RealDisconnect();
}
else ERROR_LOG(WIIMOTE,
"IOWrite[MSBT_STACK_UNKNOWN]: ERROR: %08x", dw);
return 0;
}
stack = MSBT_STACK_UNKNOWN;
break;
}
case MSBT_STACK_MS:
{
auto result = HidD_SetOutputReport(dev_handle, const_cast<u8*>(buf) + 1, len - 1);
//FlushFileBuffers(dev_handle);
case MSBT_STACK_MS:
i = HidD_SetOutputReport(dev_handle, buf + 1, len - 1);
dw = GetLastError();
if (dw == 121)
if (!result)
{
auto err = GetLastError();
if (err == 121)
{
// Semaphore timeout
NOTICE_LOG(WIIMOTE, "WiimoteIOWrite[MSBT_STACK_MS]: Unable to send data to wiimote");
RealDisconnect();
return 0;
}
return i;
else
{
WARN_LOG(WIIMOTE, "IOWrite[MSBT_STACK_MS]: ERROR: %08x", err);
}
}
case MSBT_STACK_BLUESOLEIL:
return WriteFile(dev_handle, buf + 1, 22, &bytes, &hid_overlap);
return result;
break;
}
case MSBT_STACK_BLUESOLEIL:
{
u8 big_buf[MAX_PAYLOAD];
if (len < MAX_PAYLOAD)
{
std::copy(buf, buf + len, big_buf);
std::fill(big_buf + len, big_buf + MAX_PAYLOAD, 0);
buf = big_buf;
}
ResetEvent(hid_overlap_write.hEvent);
DWORD bytes = 0;
if (WriteFile(dev_handle, buf + 1, MAX_PAYLOAD - 1, &bytes, &hid_overlap_write))
{
// WriteFile always returns true with bluesoleil.
return 1;
}
else
{
auto const err = GetLastError();
if (ERROR_IO_PENDING == err)
{
CancelIo(dev_handle);
}
}
break;
}
}
return 0;
}
int UnPair()
// invokes callback for each found wiimote bluetooth device
template <typename T>
void ProcessWiimotes(bool new_scan, T& callback)
{
// TODO:
return 0;
}
// WiiMote Pair-Up, function will return amount of either new paired or unpaired devices
// negative number on failure
int PairUp(bool unpair)
{
init_lib();
// match strings like "Nintendo RVL-WBC-01", "Nintendo RVL-CNT-01", "Nintendo RVL-CNT-01-TR"
const std::wregex wiimote_device_name(L"Nintendo RVL-\\w{3}-\\d{2}(-\\w{2})?");
int nPaired = 0;
BLUETOOTH_DEVICE_SEARCH_PARAMS srch;
srch.dwSize = sizeof(srch);
srch.fReturnAuthenticated = true;
@@ -441,83 +502,50 @@ int PairUp(bool unpair)
// fConnected BT Devices
srch.fReturnConnected = true;
srch.fReturnUnknown = true;
srch.fIssueInquiry = true;
srch.cTimeoutMultiplier = 2; // == (2 * 1.28) seconds
srch.fIssueInquiry = new_scan;
// multiple of 1.28 seconds
srch.cTimeoutMultiplier = 2;
BLUETOOTH_FIND_RADIO_PARAMS radioParam;
radioParam.dwSize = sizeof(radioParam);
HANDLE hRadio;
// TODO: save radio(s) in the WiimoteScanner constructor?
// Enumerate BT radios
HBLUETOOTH_RADIO_FIND hFindRadio = Bth_BluetoothFindFirstRadio(&radioParam, &hRadio);
if (NULL == hFindRadio)
return -1;
while (hFindRadio)
{
BLUETOOTH_RADIO_INFO radioInfo;
radioInfo.dwSize = sizeof(radioInfo);
// TODO: check for SUCCEEDED()
Bth_BluetoothGetRadioInfo(hRadio, &radioInfo);
srch.hRadio = hRadio;
BLUETOOTH_DEVICE_INFO btdi;
btdi.dwSize = sizeof(btdi);
// Enumerate BT devices
HBLUETOOTH_DEVICE_FIND hFindDevice = Bth_BluetoothFindFirstDevice(&srch, &btdi);
while (hFindDevice)
auto const rinfo_result = Bth_BluetoothGetRadioInfo(hRadio, &radioInfo);
if (ERROR_SUCCESS == rinfo_result)
{
// btdi.szName is sometimes missings it's content - it's a bt feature..
DEBUG_LOG(WIIMOTE, "authed %i connected %i remembered %i ",
btdi.fAuthenticated, btdi.fConnected, btdi.fRemembered);
srch.hRadio = hRadio;
if (std::regex_match(btdi.szName, wiimote_device_name))
BLUETOOTH_DEVICE_INFO btdi;
btdi.dwSize = sizeof(btdi);
// Enumerate BT devices
HBLUETOOTH_DEVICE_FIND hFindDevice = Bth_BluetoothFindFirstDevice(&srch, &btdi);
while (hFindDevice)
{
if (unpair)
{
if (SUCCEEDED(Bth_BluetoothRemoveDevice(&btdi.Address)))
{
NOTICE_LOG(WIIMOTE,
"Pair-Up: Automatically removed BT Device on shutdown: %08x",
GetLastError());
++nPaired;
}
}
else
{
if (false == btdi.fConnected)
{
// TODO: improve the read of the BT driver, esp. when batteries
// of the wiimote are removed while being fConnected
if (btdi.fRemembered)
{
// Make Windows forget old expired pairing. We can pretty
// much ignore the return value here. It either worked
// (ERROR_SUCCESS), or the device did not exist
// (ERROR_NOT_FOUND). In both cases, there is nothing left.
Bth_BluetoothRemoveDevice(&btdi.Address);
}
// btdi.szName is sometimes missings it's content - it's a bt feature..
DEBUG_LOG(WIIMOTE, "authed %i connected %i remembered %i ",
btdi.fAuthenticated, btdi.fConnected, btdi.fRemembered);
// Activate service
const DWORD hr = Bth_BluetoothSetServiceState(hRadio, &btdi,
&HumanInterfaceDeviceServiceClass_UUID, BLUETOOTH_SERVICE_ENABLE);
if (SUCCEEDED(hr))
++nPaired;
else
ERROR_LOG(WIIMOTE, "Pair-Up: BluetoothSetServiceState() returned %08x", hr);
}
if (IsValidBluetoothName(UTF16ToUTF8(btdi.szName)))
{
callback(hRadio, radioInfo, btdi);
}
}
if (false == Bth_BluetoothFindNextDevice(hFindDevice, &btdi))
{
Bth_BluetoothFindDeviceClose(hFindDevice);
hFindDevice = NULL;
if (false == Bth_BluetoothFindNextDevice(hFindDevice, &btdi))
{
Bth_BluetoothFindDeviceClose(hFindDevice);
hFindDevice = NULL;
}
}
}
@@ -527,8 +555,84 @@ int PairUp(bool unpair)
hFindRadio = NULL;
}
}
}
return nPaired;
void RemoveWiimote(BLUETOOTH_DEVICE_INFO_STRUCT& btdi)
{
//if (btdi.fConnected)
{
if (SUCCEEDED(Bth_BluetoothRemoveDevice(&btdi.Address)))
{
NOTICE_LOG(WIIMOTE, "Removed BT Device", GetLastError());
}
}
}
bool AttachWiimote(HANDLE hRadio, const BLUETOOTH_RADIO_INFO& radio_info, BLUETOOTH_DEVICE_INFO_STRUCT& btdi)
{
// We don't want "remembered" devices.
// SetServiceState will just fail with them..
if (!btdi.fConnected && !btdi.fRemembered)
{
auto const& wm_addr = btdi.Address.rgBytes;
NOTICE_LOG(WIIMOTE, "Found wiimote (%02x:%02x:%02x:%02x:%02x:%02x). Enabling HID service.",
wm_addr[0], wm_addr[1], wm_addr[2], wm_addr[3], wm_addr[4], wm_addr[5]);
#if defined(AUTHENTICATE_WIIMOTES)
// Authenticate
auto const& radio_addr = radio_info.address.rgBytes;
const DWORD auth_result = Bth_BluetoothAuthenticateDevice(NULL, hRadio, &btdi,
std::vector<WCHAR>(radio_addr, radio_addr + 6).data(), 6);
if (ERROR_SUCCESS != auth_result)
ERROR_LOG(WIIMOTE, "AttachWiimote: BluetoothAuthenticateDevice returned %08x", auth_result);
DWORD pcServices = 16;
GUID guids[16];
// If this is not done, the Wii device will not remember the pairing
const DWORD srv_result = Bth_BluetoothEnumerateInstalledServices(hRadio, &btdi, &pcServices, guids);
if (ERROR_SUCCESS != srv_result)
ERROR_LOG(WIIMOTE, "AttachWiimote: BluetoothEnumerateInstalledServices returned %08x", srv_result);
#endif
// Activate service
const DWORD hr = Bth_BluetoothSetServiceState(hRadio, &btdi,
&HumanInterfaceDeviceServiceClass_UUID, BLUETOOTH_SERVICE_ENABLE);
g_connect_times[btdi.Address.ullLong] = std::time(nullptr);
if (FAILED(hr))
ERROR_LOG(WIIMOTE, "AttachWiimote: BluetoothSetServiceState returned %08x", hr);
else
return true;
}
return false;
}
// Removes remembered non-connected devices
bool ForgetWiimote(BLUETOOTH_DEVICE_INFO_STRUCT& btdi)
{
if (!btdi.fConnected && btdi.fRemembered)
{
// Time to avoid RemoveDevice after SetServiceState.
// Sometimes SetServiceState takes a while..
auto const avoid_forget_seconds = 5.0;
auto pair_time = g_connect_times.find(btdi.Address.ullLong);
if (pair_time == g_connect_times.end()
|| std::difftime(time(nullptr), pair_time->second) >= avoid_forget_seconds)
{
// Make Windows forget about device so it will re-find it if visible.
// This is also required to detect a disconnect for some reason..
NOTICE_LOG(WIIMOTE, "Removing remembered wiimote.");
Bth_BluetoothRemoveDevice(&btdi.Address);
return true;
}
}
return false;
}
};
+67 -56
View File
@@ -40,8 +40,11 @@
{
IOBluetoothDevice *device = [l2capChannel getDevice];
WiimoteReal::Wiimote *wm = NULL;
std::lock_guard<std::recursive_mutex> lk(WiimoteReal::g_refresh_lock);
for (int i = 0; i < MAX_WIIMOTES; i++) {
for (int i = 0; i < MAX_WIIMOTES; i++)
{
if (WiimoteReal::g_wiimotes[i] == NULL)
continue;
if ([device isEqual: WiimoteReal::g_wiimotes[i]->btd] == TRUE)
@@ -77,8 +80,11 @@
{
IOBluetoothDevice *device = [l2capChannel getDevice];
WiimoteReal::Wiimote *wm = NULL;
std::lock_guard<std::recursive_mutex> lk(WiimoteReal::g_refresh_lock);
for (int i = 0; i < MAX_WIIMOTES; i++) {
for (int i = 0; i < MAX_WIIMOTES; i++)
{
if (WiimoteReal::g_wiimotes[i] == NULL)
continue;
if ([device isEqual: WiimoteReal::g_wiimotes[i]->btd] == TRUE)
@@ -92,41 +98,47 @@
WARN_LOG(WIIMOTE, "Lost channel to wiimote %i", wm->index + 1);
wm->RealDisconnect();
wm->Disconnect();
}
@end
namespace WiimoteReal
{
// Find wiimotes.
// wm is an array of max_wiimotes wiimotes
// Returns the total number of found wiimotes.
int FindWiimotes(Wiimote **wm, int max_wiimotes)
WiimoteScanner::WiimoteScanner()
: m_run_thread()
, m_want_wiimotes()
{}
WiimoteScanner::~WiimoteScanner()
{}
void WiimoteScanner::Update()
{}
std::vector<Wiimote*> WiimoteScanner::FindWiimotes()
{
// TODO: find the device in the constructor and save it for later
std::vector<Wiimote*> wiimotes;
IOBluetoothHostController *bth;
IOBluetoothDeviceInquiry *bti;
SearchBT *sbt;
NSEnumerator *en;
int found_devices = 0, found_wiimotes = 0;
// Count the number of already found wiimotes
for (int i = 0; i < MAX_WIIMOTES; ++i)
if (wm[i])
found_wiimotes++;
bth = [[IOBluetoothHostController alloc] init];
if ([bth addressAsString] == nil) {
if ([bth addressAsString] == nil)
{
WARN_LOG(WIIMOTE, "No bluetooth host controller");
[bth release];
return found_wiimotes;
return wiimotes;
}
sbt = [[SearchBT alloc] init];
sbt->maxDevices = max_wiimotes - found_wiimotes;
sbt->maxDevices = 32;
bti = [[IOBluetoothDeviceInquiry alloc] init];
[bti setDelegate: sbt];
[bti setInquiryLength: 5];
[bti setInquiryLength: 2];
if ([bti start] == kIOReturnSuccess)
[bti retain];
@@ -136,10 +148,10 @@ int FindWiimotes(Wiimote **wm, int max_wiimotes)
CFRunLoopRun();
[bti stop];
found_devices = [[bti foundDevices] count];
int found_devices = [[bti foundDevices] count];
NOTICE_LOG(WIIMOTE, "Found %i bluetooth device%c", found_devices,
found_devices == 1 ? '\0' : 's');
if (found_devices)
NOTICE_LOG(WIIMOTE, "Found %i bluetooth devices", found_devices);
en = [[bti foundDevices] objectEnumerator];
for (int i = 0; i < found_devices; i++)
@@ -147,42 +159,44 @@ int FindWiimotes(Wiimote **wm, int max_wiimotes)
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 ||
!(g_wiimote_sources[k] & WIIMOTE_SRC_REAL))
continue;
wm[k] = new Wiimote(k);
wm[k]->btd = dev;
found_wiimotes++;
break;
}
Wiimote *wm = new Wiimote();
wm->btd = dev;
wiimotes.push_back(wm);
}
[bth release];
[bti release];
[sbt release];
return found_wiimotes;
return wiimotes;
}
bool WiimoteScanner::IsReady() const
{
// TODO: only return true when a BT device is present
return true;
}
// Connect to a wiimote with a known address.
bool Wiimote::Connect()
{
ConnectBT *cbt = [[ConnectBT alloc] init];
if (IsConnected())
return false;
ConnectBT *cbt = [[ConnectBT alloc] init];
[btd openL2CAPChannelSync: &cchan
withPSM: kBluetoothL2CAPPSMHIDControl delegate: cbt];
[btd openL2CAPChannelSync: &ichan
withPSM: kBluetoothL2CAPPSMHIDInterrupt delegate: cbt];
if (ichan == NULL || cchan == NULL) {
if (ichan == NULL || cchan == NULL)
{
ERROR_LOG(WIIMOTE, "Unable to open L2CAP channels "
"for wiimote %i", index + 1);
RealDisconnect();
Disconnect();
[cbt release];
return false;
}
@@ -196,40 +210,37 @@ bool Wiimote::Connect()
m_connected = true;
Handshake();
SetLEDs(WIIMOTE_LED_1 << index);
m_wiimote_thread = std::thread(std::mem_fun(&Wiimote::ThreadFunc), this);
[cbt release];
return true;
}
// Disconnect a wiimote.
void Wiimote::RealDisconnect()
void Wiimote::Disconnect()
{
if (btd != NULL)
[btd closeConnection];
if (ichan != NULL)
[ichan release];
if (cchan != NULL)
[cchan release];
btd = NULL;
cchan = NULL;
ichan = NULL;
if (!IsConnected())
return;
NOTICE_LOG(WIIMOTE, "Disconnecting wiimote %i", index + 1);
m_connected = false;
if (m_wiimote_thread.joinable())
m_wiimote_thread.join();
[btd closeConnection];
[ichan release];
[cchan release];
btd = NULL;
cchan = NULL;
ichan = NULL;
}
bool Wiimote::IsOpen() const
bool Wiimote::IsConnected() const
{
return IsConnected();
return m_connected;
}
int Wiimote::IORead(unsigned char *buf)
@@ -246,14 +257,14 @@ int Wiimote::IORead(unsigned char *buf)
return bytes;
}
int Wiimote::IOWrite(unsigned char *buf, int len)
int Wiimote::IOWrite(const unsigned char *buf, int len)
{
IOReturn ret;
if (!IsConnected())
return 0;
ret = [ichan writeAsync: buf length: len refcon: nil];
ret = [ichan writeAsync: const_cast<void*>((void *)buf) length: len refcon: nil];
if (ret == kIOReturnSuccess)
return len;
@@ -23,6 +23,8 @@
#include "IniFile.h"
#include "StringUtil.h"
#include "Timer.h"
#include "Host.h"
#include "ConfigManager.h"
#include "WiimoteReal.h"
@@ -33,36 +35,43 @@ unsigned int g_wiimote_sources[MAX_WIIMOTES];
namespace WiimoteReal
{
void HandleFoundWiimotes(const std::vector<Wiimote*>&);
void TryToConnectWiimote(Wiimote*);
void HandleWiimoteDisconnect(int index);
void DoneWithWiimote(int index);
bool g_real_wiimotes_initialized = false;
unsigned int g_wiimotes_found = 0;
std::mutex g_refresh_lock;
std::recursive_mutex g_refresh_lock;
Wiimote *g_wiimotes[MAX_WIIMOTES];
Wiimote* g_wiimotes[MAX_WIIMOTES];
Wiimote::Wiimote(const unsigned int _index)
: index(_index)
WiimoteScanner g_wiimote_scanner;
Wiimote::Wiimote()
: index()
#ifdef __APPLE__
, inputlen(0)
, btd(), ichan(), cchan(), inputlen(), m_connected()
#elif defined(__linux__) && HAVE_BLUEZ
, cmd_sock(-1), int_sock(-1)
#elif defined(_WIN32)
, dev_handle(0), stack(MSBT_STACK_UNKNOWN)
#endif
, leds(0), m_last_data_report(Report((u8 *)NULL, 0))
, m_channel(0), m_connected(false)
, m_last_data_report(Report((u8 *)NULL, 0))
, m_channel(0), m_run_thread(false)
{
#if defined(__linux__) && HAVE_BLUEZ
bdaddr = (bdaddr_t){{0, 0, 0, 0, 0, 0}};
#endif
DisableDataReporting();
}
Wiimote::~Wiimote()
{
RealDisconnect();
StopThread();
if (IsConnected())
Disconnect();
ClearReadQueue();
// clear write queue
@@ -71,26 +80,28 @@ Wiimote::~Wiimote()
delete[] rpt.first;
}
// Silly, copying data n stuff, o well, don't use this too often
void Wiimote::SendPacket(const u8 rpt_id, const void* const data, const unsigned int size)
// to be called from CPU thread
void Wiimote::QueueReport(u8 rpt_id, const void* _data, unsigned int size)
{
auto const data = static_cast<const u8*>(_data);
Report rpt;
rpt.second = size + 2;
rpt.first = new u8[rpt.second];
rpt.first[0] = 0xA1;
rpt.first[0] = WM_SET_REPORT | WM_BT_OUTPUT;
rpt.first[1] = rpt_id;
memcpy(rpt.first + 2, data, size);
std::copy(data, data + size, rpt.first + 2);
m_write_reports.Push(rpt);
}
void Wiimote::DisableDataReporting()
{
wm_report_mode rpt;
wm_report_mode rpt = {};
rpt.mode = WM_REPORT_CORE;
rpt.all_the_time = 0;
rpt.continuous = 0;
rpt.rumble = 0;
SendPacket(WM_REPORT_MODE, &rpt, sizeof(rpt));
QueueReport(WM_REPORT_MODE, &rpt, sizeof(rpt));
}
void Wiimote::ClearReadQueue()
@@ -111,7 +122,7 @@ void Wiimote::ControlChannel(const u16 channel, const void* const data, const u3
{
// Check for custom communication
if (99 == channel)
Disconnect();
EmuStop();
else
{
InterruptChannel(channel, data, size);
@@ -124,24 +135,24 @@ void Wiimote::ControlChannel(const u16 channel, const void* const data, const u3
}
}
void Wiimote::InterruptChannel(const u16 channel, const void* const data, const u32 size)
void Wiimote::InterruptChannel(const u16 channel, const void* const _data, const u32 size)
{
if (0 == m_channel) // first interrupt/control channel sent
// first interrupt/control channel sent
if (channel != m_channel)
{
m_channel = channel;
ClearReadQueue();
// request status
wm_request_status rpt;
rpt.rumble = 0;
SendPacket(WM_REQUEST_STATUS, &rpt, sizeof(rpt));
EmuStart();
}
m_channel = channel; // this right?
auto const data = static_cast<const u8*>(_data);
Report rpt;
rpt.first = new u8[size];
rpt.second = (u8)size;
memcpy(rpt.first, (u8*)data, size);
std::copy(data, data + size, rpt.first);
// Convert output DATA packets to SET_REPORT packets.
// Nintendo Wiimotes work without this translation, but 3rd
@@ -150,13 +161,27 @@ void Wiimote::InterruptChannel(const u16 channel, const void* const data, const
{
rpt.first[0] = WM_SET_REPORT | WM_BT_OUTPUT;
}
if (rpt.first[0] == (WM_SET_REPORT | WM_BT_OUTPUT) &&
rpt.first[1] == 0x18 && rpt.second == 23)
// Disallow games from turning off all of the LEDs.
// It makes wiimote connection status confusing.
if (rpt.first[1] == WM_LEDS)
{
m_audio_reports.Push(rpt);
return;
}
auto& leds_rpt = *reinterpret_cast<wm_leds*>(&rpt.first[2]);
if (0 == leds_rpt.leds)
{
// Turn on ALL of the LEDs.
leds_rpt.leds = 0xf;
}
}
else if (rpt.first[1] == WM_WRITE_SPEAKER_DATA
&& !SConfig::GetInstance().m_WiimoteEnableSpeaker)
{
// Translate speaker data reports into rumble reports.
rpt.first[1] = WM_CMD_RUMBLE;
// Keep only the rumble bit.
rpt.first[2] &= 0x1;
rpt.second = 3;
}
m_write_reports.Push(rpt);
}
@@ -168,7 +193,14 @@ bool Wiimote::Read()
rpt.first = new unsigned char[MAX_PAYLOAD];
rpt.second = IORead(rpt.first);
if (rpt.second > 0 && m_channel > 0) {
if (0 == rpt.second)
{
WARN_LOG(WIIMOTE, "Wiimote::IORead failed. Disconnecting wiimote %d.", index + 1);
Disconnect();
}
if (rpt.second > 0 && m_channel > 0)
{
// Add it to queue
m_read_reports.Push(rpt);
return true;
@@ -180,23 +212,25 @@ bool Wiimote::Read()
bool Wiimote::Write()
{
Report rpt;
if (last_audio_report.GetTimeDifference() > 5 && m_audio_reports.Pop(rpt))
if (!m_write_reports.Empty())
{
IOWrite(rpt.first, rpt.second);
last_audio_report.Update();
Report const& rpt = m_write_reports.Front();
delete[] rpt.first;
return true;
bool const is_speaker_data = rpt.first[1] == WM_WRITE_SPEAKER_DATA;
if (!is_speaker_data || m_last_audio_report.GetTimeDifference() > 5)
{
IOWrite(rpt.first, rpt.second);
if (is_speaker_data)
m_last_audio_report.Update();
delete[] rpt.first;
m_write_reports.Pop();
return true;
}
}
else if (m_write_reports.Pop(rpt))
{
IOWrite(rpt.first, rpt.second);
delete[] rpt.first;
return true;
}
return false;
}
@@ -221,6 +255,12 @@ Report Wiimote::ProcessReadQueue()
void Wiimote::Update()
{
if (!IsConnected())
{
HandleWiimoteDisconnect(index);
return;
}
// Pop through the queued reports
Report const rpt = ProcessReadQueue();
@@ -234,123 +274,151 @@ void Wiimote::Update()
delete[] rpt.first;
}
void Wiimote::Disconnect()
bool Wiimote::Prepare(int _index)
{
index = _index;
// core buttons, no continuous reporting
u8 const mode_report[] = {WM_SET_REPORT | WM_BT_OUTPUT, WM_CMD_REPORT_TYPE, 0, 0x30};
// Set the active LEDs and turn on rumble.
u8 const led_report[] = {WM_SET_REPORT | WM_BT_OUTPUT, WM_CMD_LED, u8(WIIMOTE_LED_1 << index | 0x1)};
// Turn off rumble
u8 rumble_report[] = {WM_SET_REPORT | WM_BT_OUTPUT, WM_CMD_RUMBLE, 0};
// Request status report
u8 const req_status_report[] = {WM_SET_REPORT | WM_BT_OUTPUT, WM_REQUEST_STATUS, 0};
// TODO: check for sane response?
return (IOWrite(mode_report, sizeof(mode_report))
&& IOWrite(led_report, sizeof(led_report))
&& (SLEEP(200), IOWrite(rumble_report, sizeof(rumble_report)))
&& IOWrite(req_status_report, sizeof(req_status_report)));
}
void Wiimote::EmuStart()
{
DisableDataReporting();
}
void Wiimote::EmuStop()
{
m_channel = 0;
DisableDataReporting();
NOTICE_LOG(WIIMOTE, "Stopping wiimote data reporting");
}
bool Wiimote::IsConnected() const
unsigned int CalculateWantedWiimotes()
{
return m_connected;
// Figure out how many real wiimotes are required
unsigned int wanted_wiimotes = 0;
for (unsigned int i = 0; i < MAX_WIIMOTES; ++i)
if (WIIMOTE_SRC_REAL & g_wiimote_sources[i] && !g_wiimotes[i])
++wanted_wiimotes;
return wanted_wiimotes;
}
// Rumble briefly
void Wiimote::Rumble()
void WiimoteScanner::WantWiimotes(bool do_want)
{
if (!IsConnected())
return;
unsigned char buffer = 0x01;
DEBUG_LOG(WIIMOTE, "Starting rumble...");
SendRequest(WM_CMD_RUMBLE, &buffer, 1);
SLEEP(200);
DEBUG_LOG(WIIMOTE, "Stopping rumble...");
buffer = 0x00;
SendRequest(WM_CMD_RUMBLE, &buffer, 1);
m_want_wiimotes = do_want;
}
// Set the active LEDs.
// leds is a bitwise or of WIIMOTE_LED_1 through WIIMOTE_LED_4.
void Wiimote::SetLEDs(int new_leds)
void WiimoteScanner::StartScanning()
{
unsigned char buffer;
if (!IsConnected())
return;
// Remove the lower 4 bits because they control rumble
buffer = leds = (new_leds & 0xF0);
SendRequest(WM_CMD_LED, &buffer, 1);
if (!m_run_thread && IsReady())
{
m_run_thread = true;
m_scan_thread = std::thread(std::mem_fun(&WiimoteScanner::ThreadFunc), this);
}
}
// Send a handshake
bool Wiimote::Handshake()
void WiimoteScanner::StopScanning()
{
// Set buffer[0] to 0x04 for continuous reporting
unsigned char buffer[2] = {0x04, 0x30};
if (!IsConnected())
return 0;
DEBUG_LOG(WIIMOTE, "Sending handshake to wiimote");
return SendRequest(WM_CMD_REPORT_TYPE, buffer, 2);
m_run_thread = false;
if (m_scan_thread.joinable())
{
m_scan_thread.join();
}
}
// Send a packet to the wiimote.
// report_type should be one of WIIMOTE_CMD_LED, WIIMOTE_CMD_RUMBLE, etc.
bool Wiimote::SendRequest(unsigned char report_type, unsigned char* data, int length)
void CheckForDisconnectedWiimotes()
{
unsigned char buffer[32] = {WM_SET_REPORT | WM_BT_OUTPUT, report_type};
std::lock_guard<std::recursive_mutex> lk(g_refresh_lock);
memcpy(buffer + 2, data, length);
for (unsigned int i = 0; i != MAX_WIIMOTES; ++i)
if (g_wiimotes[i] && !g_wiimotes[i]->IsConnected())
HandleWiimoteDisconnect(i);
}
return (IOWrite(buffer, length + 2) != 0);
void WiimoteScanner::ThreadFunc()
{
Common::SetCurrentThreadName("Wiimote Scanning Thread");
NOTICE_LOG(WIIMOTE, "Wiimote scanning has started");
while (m_run_thread)
{
std::vector<Wiimote*> found_wiimotes;
//NOTICE_LOG(WIIMOTE, "in loop");
if (m_want_wiimotes)
found_wiimotes = FindWiimotes();
else
{
// Does stuff needed to detect disconnects on Windows
Update();
}
//NOTICE_LOG(WIIMOTE, "after update");
// TODO: this is a fairly lame place for this
CheckForDisconnectedWiimotes();
HandleFoundWiimotes(found_wiimotes);
//std::this_thread::yield();
Common::SleepCurrentThread(500);
}
NOTICE_LOG(WIIMOTE, "Wiimote scanning has stopped");
}
void Wiimote::StartThread()
{
m_run_thread = true;
m_wiimote_thread = std::thread(std::mem_fun(&Wiimote::ThreadFunc), this);
}
void Wiimote::StopThread()
{
m_run_thread = false;
if (m_wiimote_thread.joinable())
m_wiimote_thread.join();
}
void Wiimote::ThreadFunc()
{
char thname[] = "Wiimote # Thread";
thname[8] = (char)('1' + index);
Common::SetCurrentThreadName(thname);
// rumble briefly
Rumble();
Common::SetCurrentThreadName("Wiimote Device Thread");
// main loop
while (IsOpen())
while (m_run_thread && IsConnected())
{
#ifdef __APPLE__
while (Write()) {}
Common::SleepCurrentThread(1);
// Reading happens elsewhere on OSX
bool const did_something = Write();
#else
bool const did_something = Write() || Read();
#endif
if (!did_something)
Common::SleepCurrentThread(1);
#endif
}
}
#ifndef _WIN32
// Connect all discovered wiimotes
// Return the number of wiimotes that successfully connected.
static int ConnectWiimotes(Wiimote** wm)
{
int connected = 0;
for (int i = 0; i < MAX_WIIMOTES; ++i)
{
if (!wm[i] || wm[i]->IsConnected())
continue;
if (wm[i]->Connect())
++connected;
else
{
delete wm[i];
wm[i] = NULL;
}
}
return connected;
}
#endif
void LoadSettings()
{
std::string ini_filename = File::GetUserPath(D_CONFIG_IDX) + WIIMOTE_INI_NAME ".ini";
@@ -368,116 +436,181 @@ void LoadSettings()
}
}
unsigned int Initialize()
// config dialog calls this when some settings change
void Initialize()
{
// Return if already initialized
if (SConfig::GetInstance().m_WiimoteContinuousScanning)
g_wiimote_scanner.StartScanning();
else
g_wiimote_scanner.StopScanning();
std::lock_guard<std::recursive_mutex> lk(g_refresh_lock);
g_wiimote_scanner.WantWiimotes(0 != CalculateWantedWiimotes());
if (g_real_wiimotes_initialized)
return g_wiimotes_found;
return;
memset(g_wiimotes, 0, sizeof(g_wiimotes));
NOTICE_LOG(WIIMOTE, "WiimoteReal::Initialize");
// Only call FindWiimotes with the number of slots configured for real wiimotes
unsigned int wanted_wiimotes = 0;
for (unsigned int i = 0; i < MAX_WIIMOTES; ++i)
if (WIIMOTE_SRC_REAL & g_wiimote_sources[i])
++wanted_wiimotes;
// Don't bother initializing if we don't want any real wiimotes
if (0 == wanted_wiimotes)
{
g_wiimotes_found = 0;
return 0;
}
// Initialized
g_real_wiimotes_initialized = true;
g_wiimotes_found = FindWiimotes(g_wiimotes, wanted_wiimotes);
DEBUG_LOG(WIIMOTE, "Found %i Real Wiimotes, %i wanted",
g_wiimotes_found, wanted_wiimotes);
#ifndef _WIN32
atexit(WiimoteReal::Shutdown);
g_wiimotes_found = ConnectWiimotes(g_wiimotes);
#endif
DEBUG_LOG(WIIMOTE, "Connected to %i Real Wiimotes", g_wiimotes_found);
return g_wiimotes_found;
}
void Shutdown(void)
{
if (false == g_real_wiimotes_initialized)
{
g_wiimote_scanner.StopScanning();
std::lock_guard<std::recursive_mutex> lk(g_refresh_lock);
if (!g_real_wiimotes_initialized)
return;
// Uninitialized
NOTICE_LOG(WIIMOTE, "WiimoteReal::Shutdown");
g_real_wiimotes_initialized = false;
// Delete wiimotes
for (unsigned int i = 0; i < MAX_WIIMOTES; ++i)
if (g_wiimotes[i])
HandleWiimoteDisconnect(i);
}
void ChangeWiimoteSource(unsigned int index, int source)
{
{
std::lock_guard<std::recursive_mutex> lk(g_refresh_lock);
g_wiimote_sources[index] = source;
g_wiimote_scanner.WantWiimotes(0 != CalculateWantedWiimotes());
// kill real connection (or swap to different slot)
DoneWithWiimote(index);
}
// reconnect to emu
Host_ConnectWiimote(index, false);
if (WIIMOTE_SRC_EMU & source)
Host_ConnectWiimote(index, true);
}
void TryToConnectWiimote(Wiimote* wm)
{
std::unique_lock<std::recursive_mutex> lk(g_refresh_lock);
for (unsigned int i = 0; i != MAX_WIIMOTES; ++i)
{
if (WIIMOTE_SRC_REAL & g_wiimote_sources[i]
&& !g_wiimotes[i])
{
delete g_wiimotes[i];
g_wiimotes[i] = NULL;
if (wm->Connect() && wm->Prepare(i))
{
NOTICE_LOG(WIIMOTE, "Connected to wiimote %i.", i + 1);
std::swap(g_wiimotes[i], wm);
g_wiimotes[i]->StartThread();
Host_ConnectWiimote(i, true);
}
break;
}
}
g_wiimote_scanner.WantWiimotes(0 != CalculateWantedWiimotes());
lk.unlock();
delete wm;
}
void DoneWithWiimote(int index)
{
std::lock_guard<std::recursive_mutex> lk(g_refresh_lock);
if (g_wiimotes[index])
{
g_wiimotes[index]->StopThread();
// First see if we can use this real wiimote in another slot.
for (unsigned int i = 0; i != MAX_WIIMOTES; ++i)
{
if (WIIMOTE_SRC_REAL & g_wiimote_sources[i]
&& !g_wiimotes[i])
{
if (g_wiimotes[index]->Prepare(i))
{
std::swap(g_wiimotes[i], g_wiimotes[index]);
g_wiimotes[i]->StartThread();
Host_ConnectWiimote(i, true);
}
break;
}
}
}
// else, just disconnect the wiimote
HandleWiimoteDisconnect(index);
}
void HandleWiimoteDisconnect(int index)
{
Wiimote* wm = NULL;
{
std::lock_guard<std::recursive_mutex> lk(g_refresh_lock);
std::swap(wm, g_wiimotes[index]);
g_wiimote_scanner.WantWiimotes(0 != CalculateWantedWiimotes());
}
if (wm)
{
delete wm;
NOTICE_LOG(WIIMOTE, "Disconnected wiimote %i.", index + 1);
}
}
void HandleFoundWiimotes(const std::vector<Wiimote*>& wiimotes)
{
std::for_each(wiimotes.begin(), wiimotes.end(), TryToConnectWiimote);
}
// This is called from the GUI thread
void Refresh()
{
std::lock_guard<std::mutex> lk(g_refresh_lock);
#ifdef _WIN32
Shutdown();
Initialize();
#else
// Make sure real wiimotes have been initialized
if (!g_real_wiimotes_initialized)
g_wiimote_scanner.StopScanning();
{
Initialize();
return;
std::unique_lock<std::recursive_mutex> lk(g_refresh_lock);
std::vector<Wiimote*> found_wiimotes;
if (0 != CalculateWantedWiimotes())
{
// Don't hang dolphin when searching
lk.unlock();
found_wiimotes = g_wiimote_scanner.FindWiimotes();
lk.lock();
}
// Find the number of slots configured for real wiimotes
unsigned int wanted_wiimotes = 0;
for (unsigned int i = 0; i < MAX_WIIMOTES; ++i)
if (WIIMOTE_SRC_REAL & g_wiimote_sources[i])
++wanted_wiimotes;
CheckForDisconnectedWiimotes();
// Remove wiimotes that are paired with slots no longer configured for a
// real wiimote or that are disconnected
for (unsigned int i = 0; i < MAX_WIIMOTES; ++i)
if (g_wiimotes[i] && (!(WIIMOTE_SRC_REAL & g_wiimote_sources[i]) ||
!g_wiimotes[i]->IsConnected()))
// Brief rumble for already connected wiimotes.
for (int i = 0; i != MAX_WIIMOTES; ++i)
{
if (g_wiimotes[i])
{
delete g_wiimotes[i];
g_wiimotes[i] = NULL;
--g_wiimotes_found;
g_wiimotes[i]->StopThread();
g_wiimotes[i]->Prepare(i);
g_wiimotes[i]->StartThread();
}
// Scan for wiimotes if we want more
if (wanted_wiimotes > g_wiimotes_found)
{
// Scan for wiimotes
unsigned int num_wiimotes = FindWiimotes(g_wiimotes, wanted_wiimotes);
DEBUG_LOG(WIIMOTE, "Found %i Real Wiimotes, %i wanted", num_wiimotes, wanted_wiimotes);
// Connect newly found wiimotes.
int num_new_wiimotes = ConnectWiimotes(g_wiimotes);
DEBUG_LOG(WIIMOTE, "Connected to %i additional Real Wiimotes", num_new_wiimotes);
g_wiimotes_found = num_wiimotes;
}
#endif
HandleFoundWiimotes(found_wiimotes);
}
Initialize();
}
void InterruptChannel(int _WiimoteNumber, u16 _channelID, const void* _pData, u32 _Size)
{
std::lock_guard<std::mutex> lk(g_refresh_lock);
std::lock_guard<std::recursive_mutex> lk(g_refresh_lock);
if (g_wiimotes[_WiimoteNumber])
g_wiimotes[_WiimoteNumber]->InterruptChannel(_channelID, _pData, _Size);
@@ -485,7 +618,7 @@ void InterruptChannel(int _WiimoteNumber, u16 _channelID, const void* _pData, u3
void ControlChannel(int _WiimoteNumber, u16 _channelID, const void* _pData, u32 _Size)
{
std::lock_guard<std::mutex> lk(g_refresh_lock);
std::lock_guard<std::recursive_mutex> lk(g_refresh_lock);
if (g_wiimotes[_WiimoteNumber])
g_wiimotes[_WiimoteNumber]->ControlChannel(_channelID, _pData, _Size);
@@ -495,15 +628,21 @@ void ControlChannel(int _WiimoteNumber, u16 _channelID, const void* _pData, u32
// Read the Wiimote once
void Update(int _WiimoteNumber)
{
std::lock_guard<std::mutex> lk(g_refresh_lock);
std::lock_guard<std::recursive_mutex> lk(g_refresh_lock);
if (g_wiimotes[_WiimoteNumber])
g_wiimotes[_WiimoteNumber]->Update();
// Wiimote::Update() may remove the wiimote if it was disconnected.
if (!g_wiimotes[_WiimoteNumber])
{
Host_ConnectWiimote(_WiimoteNumber, false);
}
}
void StateChange(EMUSTATE_CHANGE newState)
{
//std::lock_guard<std::mutex> lk(g_refresh_lock);
//std::lock_guard<std::recursive_mutex> lk(g_refresh_lock);
// TODO: disable/enable auto reporting, maybe
}
@@ -20,6 +20,7 @@
#define WIIMOTE_REAL_H
#include <functional>
#include <vector>
#include "WiimoteRealBase.h"
#include "ChunkFile.h"
@@ -42,7 +43,7 @@ class Wiimote : NonCopyable
{
friend class WiimoteEmu::Wiimote;
public:
Wiimote(const unsigned int _index);
Wiimote();
~Wiimote();
void ControlChannel(const u16 channel, const void* const data, const u32 size);
@@ -53,16 +54,29 @@ public:
bool Read();
bool Write();
bool Connect();
bool IsConnected() const;
bool IsOpen() const;
void Disconnect();
void DisableDataReporting();
void Rumble();
void SendPacket(const u8 rpt_id, const void* const data, const unsigned int size);
void RealDisconnect();
const unsigned int index;
void StartThread();
void StopThread();
// "handshake" / stop packets
void EmuStart();
void EmuStop();
// connecting and disconnecting from physical devices
// (using address inserted by FindWiimotes)
bool Connect();
void Disconnect();
// TODO: change to something like IsRelevant
bool IsConnected() const;
bool Prepare(int index);
void DisableDataReporting();
void QueueReport(u8 rpt_id, const void* data, unsigned int size);
int index;
#if defined(__APPLE__)
IOBluetoothDevice *btd;
@@ -70,21 +84,19 @@ public:
IOBluetoothL2CAPChannel *cchan;
char input[MAX_PAYLOAD];
int inputlen;
bool m_connected;
#elif defined(__linux__) && HAVE_BLUEZ
bdaddr_t bdaddr; // Bluetooth address
int cmd_sock; // Command socket
int int_sock; // Interrupt socket
void Close();
#elif defined(_WIN32)
std::string devicepath; // Unique wiimote reference
std::basic_string<TCHAR> devicepath; // Unique wiimote reference
//ULONGLONG btaddr; // Bluetooth address
HANDLE dev_handle; // HID handle
OVERLAPPED hid_overlap; // Overlap handle
OVERLAPPED hid_overlap_read, hid_overlap_write; // Overlap handle
enum win_bt_stack_t stack; // Type of bluetooth stack to use
#endif
unsigned char leds; // Currently lit leds
protected:
Report m_last_data_report;
@@ -92,23 +104,58 @@ protected:
private:
void ClearReadQueue();
bool SendRequest(unsigned char report_type, unsigned char* data, int length);
bool Handshake();
void SetLEDs(int leds);
int IORead(unsigned char* buf);
int IOWrite(unsigned char* buf, int len);
int IORead(u8* buf);
int IOWrite(u8 const* buf, int len);
void ThreadFunc();
bool m_connected;
bool m_run_thread;
std::thread m_wiimote_thread;
Common::FifoQueue<Report> m_read_reports;
Common::FifoQueue<Report> m_write_reports;
Common::FifoQueue<Report> m_audio_reports;
Common::Timer last_audio_report;
Common::Timer m_last_audio_report;
};
extern std::mutex g_refresh_lock;
class WiimoteScanner
{
public:
WiimoteScanner();
~WiimoteScanner();
bool IsReady() const;
void WantWiimotes(bool do_want);
void StartScanning();
void StopScanning();
std::vector<Wiimote*> FindWiimotes();
// function called when not looking for more wiimotes
void Update();
private:
void ThreadFunc();
std::thread m_scan_thread;
volatile bool m_run_thread;
volatile bool m_want_wiimotes;
#if defined(_WIN32)
#elif defined(__linux__) && HAVE_BLUEZ
int device_id;
int device_sock;
#endif
};
extern std::recursive_mutex g_refresh_lock;
extern WiimoteScanner g_wiimote_scanner;
extern Wiimote *g_wiimotes[4];
void InterruptChannel(int _WiimoteNumber, u16 _channelID, const void* _pData, u32 _Size);
@@ -119,6 +166,7 @@ void DoState(PointerWrap &p);
void StateChange(EMUSTATE_CHANGE newState);
int FindWiimotes(Wiimote** wm, int max_wiimotes);
void ChangeWiimoteSource(unsigned int index, int source);
bool IsValidBluetoothName(const std::string& name);
@@ -41,6 +41,7 @@
#define WM_SET_REPORT 0xA0
#endif
// TODO: duplicated in WiimoteHid.h
// Commands
#define WM_CMD_RUMBLE 0x10
#define WM_CMD_LED 0x11
@@ -66,8 +67,9 @@
// End Wiimote internal codes
#define MAX_PAYLOAD 32
#define WIIMOTE_DEFAULT_TIMEOUT 30
// It's 23. NOT 32!
#define MAX_PAYLOAD 23
#define WIIMOTE_DEFAULT_TIMEOUT 1000
#ifdef _WIN32
// Available bluetooth stacks for Windows.
@@ -33,9 +33,6 @@ std::string HLE_IPC_BuildFilename(std::string path_wii, int _size)
{
std::string path_full = File::GetUserPath(D_WIIROOT_IDX);
if ((path_wii.length() > 0) && (path_wii[1] == '0'))
path_full += std::string("/title"); // this looks and feel like a hack...
// Replaces chars that FAT32 can't support with strings defined in /sys/replace
for (auto i = replacements.begin(); i != replacements.end(); ++i)
{
@@ -48,39 +45,6 @@ std::string HLE_IPC_BuildFilename(std::string path_wii, int _size)
return path_full;
}
void HLE_IPC_CreateVirtualFATFilesystem()
{
const int cdbSize = 0x01400000;
const std::string cdbPath = Common::GetTitleDataPath(TITLEID_SYSMENU) + "cdb.vff";
if ((int)File::GetSize(cdbPath) < cdbSize)
{
// cdb.vff is a virtual Fat filesystem created on first launch of sysmenu
// we create it here as it is faster ~3 minutes for me when sysmenu does it ~1 second created here
const u8 cdbHDR[0x20] = {'V', 'F', 'F', 0x20, 0xfe, 0xff, 1, 0, 1, 0x40, 0, 0, 0, 0x20};
const u8 cdbFAT[4] = {0xf0, 0xff, 0xff, 0xff};
File::IOFile cdbFile(cdbPath, "wb");
if (cdbFile)
{
cdbFile.WriteBytes(cdbHDR, 0x20);
cdbFile.WriteBytes(cdbFAT, 0x4);
cdbFile.Seek(0x14020, SEEK_SET);
cdbFile.WriteBytes(cdbFAT, 0x4);
// 20 MiB file
cdbFile.Seek(cdbSize - 1, SEEK_SET);
// write the final 0 to 0 file from the second FAT to 20 MiB
cdbFile.WriteBytes(cdbHDR + 14, 1);
if (!cdbFile.IsGood())
{
cdbFile.Close();
File::Delete(cdbPath);
}
cdbFile.Flush();
cdbFile.Close();
}
}
}
CWII_IPC_HLE_Device_FileIO::CWII_IPC_HLE_Device_FileIO(u32 _DeviceID, const std::string& _rDeviceName)
: IWII_IPC_HLE_Device(_DeviceID, _rDeviceName, false) // not a real hardware
, m_Mode(0)
@@ -139,82 +103,81 @@ bool CWII_IPC_HLE_Device_FileIO::Open(u32 _CommandAddress, u32 _Mode)
return true;
}
File::IOFile CWII_IPC_HLE_Device_FileIO::OpenFile()
// Opens file if needed.
// Clears any error state.
// Seeks to proper position position.
void CWII_IPC_HLE_Device_FileIO::PrepareFile()
{
const char* open_mode = "";
switch (m_Mode)
if (!m_file.IsOpen())
{
case ISFS_OPEN_READ:
open_mode = "rb";
break;
case ISFS_OPEN_WRITE:
case ISFS_OPEN_RW:
open_mode = "r+b";
break;
default:
PanicAlertT("FileIO: Unknown open mode : 0x%02x", m_Mode);
break;
const char* open_mode = "";
switch (m_Mode)
{
case ISFS_OPEN_READ:
open_mode = "rb";
break;
case ISFS_OPEN_WRITE:
case ISFS_OPEN_RW:
open_mode = "r+b";
break;
default:
PanicAlertT("FileIO: Unknown open mode : 0x%02x", m_Mode);
break;
}
m_file.Open(m_filepath, open_mode);
}
return File::IOFile(m_filepath, open_mode);
m_file.Clear();
m_file.Seek(m_SeekPos, SEEK_SET);
}
bool CWII_IPC_HLE_Device_FileIO::Seek(u32 _CommandAddress)
{
u32 ReturnValue = FS_RESULT_FATAL;
const u32 SeekPosition = Memory::Read_U32(_CommandAddress + 0xC);
const u32 SeekOffset = Memory::Read_U32(_CommandAddress + 0xC);
const u32 Mode = Memory::Read_U32(_CommandAddress + 0x10);
if (auto file = OpenFile())
PrepareFile();
if (m_file)
{
ReturnValue = FS_RESULT_FATAL;
const u64 fileSize = file.GetSize();
INFO_LOG(WII_IPC_FILEIO, "FileIO: Seek Pos: 0x%08x, Mode: %i (%s, Length=0x%08llx)", SeekPosition, Mode, m_Name.c_str(), fileSize);
const u64 fileSize = m_file.GetSize();
INFO_LOG(WII_IPC_FILEIO, "FileIO: Seek Pos: 0x%08x, Mode: %i (%s, Length=0x%08llx)", SeekOffset, Mode, m_Name.c_str(), fileSize);
u64 wantedPos = 0;
switch (Mode)
{
case 0:
{
if (SeekPosition <= fileSize)
{
m_SeekPos = SeekPosition;
ReturnValue = m_SeekPos;
}
break;
}
case 1:
{
u32 wantedPos = SeekPosition+m_SeekPos;
if (wantedPos <= fileSize)
{
m_SeekPos = wantedPos;
ReturnValue = m_SeekPos;
}
break;
}
case 2:
{
u64 wantedPos = fileSize+m_SeekPos;
if (wantedPos <= fileSize)
{
m_SeekPos = wantedPos;
ReturnValue = m_SeekPos;
}
break;
}
default:
{
PanicAlert("CWII_IPC_HLE_Device_FileIO Unsupported seek mode %i", Mode);
ReturnValue = FS_RESULT_FATAL;
break;
}
case 0:
wantedPos = SeekOffset;
break;
case 1:
wantedPos = m_SeekPos + (s32)SeekOffset;
break;
case 2:
wantedPos = fileSize + (s32)SeekOffset;
break;
default:
PanicAlert("CWII_IPC_HLE_Device_FileIO Unsupported seek mode %i", Mode);
ReturnValue = FS_RESULT_FATAL;
break;
}
if (wantedPos <= fileSize)
{
m_SeekPos = wantedPos;
ReturnValue = m_SeekPos;
}
}
else
{
// TODO: This can't be right.
ReturnValue = FS_FILE_NOT_EXIST;
}
Memory::Write_U32(ReturnValue, _CommandAddress + 0x4);
@@ -227,9 +190,9 @@ bool CWII_IPC_HLE_Device_FileIO::Read(u32 _CommandAddress)
u32 ReturnValue = FS_EACCESS;
const u32 Address = Memory::Read_U32(_CommandAddress + 0xC); // Read to this memory address
const u32 Size = Memory::Read_U32(_CommandAddress + 0x10);
if (auto file = OpenFile())
PrepareFile();
if (m_file)
{
if (m_Mode == ISFS_OPEN_WRITE)
{
@@ -238,9 +201,8 @@ bool CWII_IPC_HLE_Device_FileIO::Read(u32 _CommandAddress)
else
{
INFO_LOG(WII_IPC_FILEIO, "FileIO: Read 0x%x bytes to 0x%08x from %s", Size, Address, m_Name.c_str());
file.Seek(m_SeekPos, SEEK_SET);
ReturnValue = (u32)fread(Memory::GetPointer(Address), 1, Size, file.GetHandle());
if (ReturnValue != Size && ferror(file.GetHandle()))
ReturnValue = (u32)fread(Memory::GetPointer(Address), 1, Size, m_file.GetHandle());
if (ReturnValue != Size && ferror(m_file.GetHandle()))
{
ReturnValue = FS_EACCESS;
}
@@ -267,8 +229,8 @@ bool CWII_IPC_HLE_Device_FileIO::Write(u32 _CommandAddress)
const u32 Address = Memory::Read_U32(_CommandAddress + 0xC); // Write data from this memory address
const u32 Size = Memory::Read_U32(_CommandAddress + 0x10);
if (auto file = OpenFile())
PrepareFile();
if (m_file)
{
if (m_Mode == ISFS_OPEN_READ)
{
@@ -277,8 +239,7 @@ bool CWII_IPC_HLE_Device_FileIO::Write(u32 _CommandAddress)
else
{
INFO_LOG(WII_IPC_FILEIO, "FileIO: Write 0x%04x bytes from 0x%08x to %s", Size, Address, m_Name.c_str());
file.Seek(m_SeekPos, SEEK_SET);
if (file.WriteBytes(Memory::GetPointer(Address), Size))
if (m_file.WriteBytes(Memory::GetPointer(Address), Size))
{
ReturnValue = Size;
m_SeekPos += Size;
@@ -308,9 +269,10 @@ bool CWII_IPC_HLE_Device_FileIO::IOCtl(u32 _CommandAddress)
{
case ISFS_IOCTL_GETFILESTATS:
{
if (auto file = OpenFile())
PrepareFile();
if (m_file)
{
u32 m_FileLength = (u32)file.GetSize();
u32 m_FileLength = (u32)m_file.GetSize();
const u32 BufferOut = Memory::Read_U32(_CommandAddress + 0x18);
INFO_LOG(WII_IPC_FILEIO, "FileIO: ISFS_IOCTL_GETFILESTATS");
@@ -345,6 +307,7 @@ void CWII_IPC_HLE_Device_FileIO::DoState(PointerWrap &p)
p.Do(m_Mode);
p.Do(m_SeekPos);
m_file.Close();
m_filepath = HLE_IPC_BuildFilename(m_Name, 64);
}
@@ -22,7 +22,6 @@
#include "FileUtil.h"
std::string HLE_IPC_BuildFilename(std::string _pFilename, int _size);
void HLE_IPC_CreateVirtualFATFilesystem();
class CWII_IPC_HLE_Device_FileIO : public IWII_IPC_HLE_Device
{
@@ -39,9 +38,9 @@ public:
bool IOCtl(u32 _CommandAddress);
void DoState(PointerWrap &p);
File::IOFile OpenFile();
private:
void PrepareFile();
enum
{
ISFS_OPEN_READ = 1,
@@ -77,6 +76,7 @@ private:
u32 m_Mode;
u32 m_SeekPos;
File::IOFile m_file;
std::string m_filepath;
};
@@ -58,6 +58,7 @@
#include "CommonPaths.h"
#include "IPC_HLE/WII_IPC_HLE_Device_usb.h"
#include "../Movie.h"
#include "StringUtil.h"
#ifdef _WIN32
#include <Windows.h>
@@ -926,7 +927,7 @@ u32 CWII_IPC_HLE_Device_es::ES_DIVerify(u8* _pTMD, u32 _sz)
else
{
#ifdef _WIN32
MoveFile(savePath.c_str(), (savePath + "../backup/").c_str());
MoveFile(UTF8ToTStr(savePath).c_str(), UTF8ToTStr(savePath + "../backup/").c_str());
#else
File::CopyDir(savePath.c_str(),(savePath + "../backup/").c_str());
File::DeleteDirRecursively(savePath.c_str());
@@ -940,7 +941,7 @@ u32 CWII_IPC_HLE_Device_es::ES_DIVerify(u8* _pTMD, u32 _sz)
if (File::Exists((savePath + "banner.bin").c_str()))
File::DeleteDirRecursively(savePath);
#ifdef _WIN32
MoveFile((savePath + "../backup/").c_str(), savePath.c_str());
MoveFile(UTF8ToTStr(savePath + "../backup/").c_str(), UTF8ToTStr(savePath).c_str());
#else
File::CopyDir((savePath + "../backup/").c_str(), savePath.c_str());
File::DeleteDirRecursively((savePath + "../backup/").c_str());
@@ -377,7 +377,7 @@ s32 CWII_IPC_HLE_Device_fs::ExecuteCommand(u32 _Parameter, u32 _BufferIn, u32 _B
u32 Addr = _BufferOut;
Memory::Write_U32(OwnerID, Addr); Addr += 4;
Memory::Write_U16(GroupID, Addr); Addr += 2;
memcpy(Memory::GetPointer(Addr), Filename.c_str(), Filename.size()); Addr += 64;
memcpy(Memory::GetPointer(Addr), Memory::GetPointer(_BufferIn), 64); Addr += 64;
Memory::Write_U8(OwnerPerm, Addr); Addr += 1;
Memory::Write_U8(GroupPerm, Addr); Addr += 1;
Memory::Write_U8(OtherPerm, Addr); Addr += 1;
@@ -211,8 +211,7 @@ void CWII_IPC_HLE_WiiMote::EventConnectionAccepted()
void CWII_IPC_HLE_WiiMote::EventDisconnect()
{
// Send disconnect message to plugin
u8 Message = WIIMOTE_DISCONNECT;
Wiimote::ControlChannel(m_ConnectionHandle & 0xFF, 99, &Message, 0);
Wiimote::ControlChannel(m_ConnectionHandle & 0xFF, 99, NULL, 0);
m_ConnectionState = CONN_INACTIVE;
// Clear channel flags
+1 -1
View File
@@ -34,7 +34,7 @@ struct Rpt : public std::vector<u8>
typedef std::vector<Rpt> NetWiimote;
#define NETPLAY_VERSION "Dolphin NetPlay r6423"
#define NETPLAY_VERSION "Dolphin NetPlay 2013-03-03"
// messages
enum
@@ -28,8 +28,6 @@
#undef _interlockedbittestandreset
#undef _interlockedbittestandset64
#undef _interlockedbittestandreset64
#else
#include <xmmintrin.h>
#endif
#include "../../Core.h"
@@ -514,4 +512,4 @@ void Interpreter::fsqrtx(UGeckoInstruction _inst)
rPS0(_inst.FD) = sqrt(b);
UpdateFPRF(rPS0(_inst.FD));
if (_inst.Rc) Helper_UpdateCR1(rPS0(_inst.FD));
}
}

Some files were not shown because too many files have changed in this diff Show More