mirror of
https://github.com/hrydgard/ppsspp.git
synced 2026-11-15 02:29:51 +01:00
Merge branch 'master' into TemporaryHackishBranch
# Conflicts: # UI/GameSettingsScreen.cpp
This commit is contained in:
commit
0929c0bfdf
68 files changed
+1000
-685
No files matched your search
+25
-45
@@ -2,7 +2,7 @@
|
||||
|
||||
export USE_CCACHE=1
|
||||
export NDK_CCACHE=ccache
|
||||
NDK_VER=android-ndk-r16b
|
||||
NDK_VER=android-ndk-r18b
|
||||
|
||||
download_extract() {
|
||||
aria2c -x 16 $1 -o $2
|
||||
@@ -18,53 +18,19 @@ download_extract_zip() {
|
||||
unzip $2 2>&1 | pv > /dev/null
|
||||
}
|
||||
|
||||
brew_install() {
|
||||
brew install $1
|
||||
brew outdated $1 || brew upgrade $1
|
||||
}
|
||||
|
||||
travis_before_install() {
|
||||
git submodule update --init --recursive
|
||||
|
||||
if [ "$TRAVIS_OS_NAME" = "linux" ]; then
|
||||
sudo apt-get update -qq
|
||||
sudo apt-get install software-properties-common aria2 pv build-essential libgl1-mesa-dev libglu1-mesa-dev -qq
|
||||
elif [ "$TRAVIS_OS_NAME" = "osx" ]; then
|
||||
brew update
|
||||
brew_install ccache
|
||||
fi
|
||||
}
|
||||
|
||||
setup_ccache_script() {
|
||||
if [ ! -e "$1" ]; then
|
||||
mkdir "$1"
|
||||
fi
|
||||
|
||||
echo "#!/bin/bash" > "$1/$3"
|
||||
echo "ccache $2/$3 \$*" >> "$1/$3"
|
||||
chmod +x "$1/$3"
|
||||
}
|
||||
|
||||
travis_install() {
|
||||
# Ubuntu Linux + GCC 4.8
|
||||
if [ "$PPSSPP_BUILD_TYPE" = "Linux" ]; then
|
||||
# For libsdl2-dev.
|
||||
sudo add-apt-repository ppa:zoogie/sdl2-snapshots -y
|
||||
if [ "$CXX" = "g++" ]; then
|
||||
sudo add-apt-repository ppa:ubuntu-toolchain-r/test -y
|
||||
fi
|
||||
if [ "$QT" = "TRUE" ]; then
|
||||
sudo add-apt-repository --yes ppa:ubuntu-sdk-team/ppa
|
||||
fi
|
||||
|
||||
sudo apt-get update
|
||||
sudo apt-get install libsdl2-dev -qq
|
||||
if [ "$CXX" = "g++" ]; then
|
||||
sudo apt-get install g++-4.8 -qq
|
||||
sudo apt-get install -qq g++-4.8
|
||||
fi
|
||||
|
||||
if [ "$QT" = "TRUE" ]; then
|
||||
sudo apt-get install -qq qt5-qmake qtmultimedia5-dev qtsystems5-dev qtbase5-dev qtdeclarative5-dev qttools5-dev-tools libqt5webkit5-dev libsqlite3-dev qt5-default
|
||||
sudo apt-get install -qq qt5-qmake qtmultimedia5-dev qtsystems5-dev qtbase5-dev qtdeclarative5-dev qttools5-dev-tools libqt5webkit5-dev libqt5opengl5-dev libsqlite3-dev qt5-default
|
||||
fi
|
||||
|
||||
download_extract "https://cmake.org/files/v3.6/cmake-3.6.2-Linux-x86_64.tar.gz" cmake-3.6.2-Linux-x86_64.tar.gz
|
||||
@@ -72,16 +38,12 @@ travis_install() {
|
||||
|
||||
# Android NDK + GCC 4.8
|
||||
if [ "$PPSSPP_BUILD_TYPE" = "Android" ]; then
|
||||
free -m
|
||||
sudo apt-get install ant -qq
|
||||
download_extract_zip http://dl.google.com/android/repository/${NDK_VER}-linux-x86_64.zip ${NDK_VER}-linux-x86_64.zip
|
||||
fi
|
||||
|
||||
if [ "$PPSSPP_BUILD_TYPE" = "macOS" ]; then
|
||||
brew_install sdl2
|
||||
brew upgrade python
|
||||
elif [ "$PPSSPP_BUILD_TYPE" = "iOS" ]; then
|
||||
brew upgrade python
|
||||
if [ "$PPSSPP_BUILD_TYPE" = "Windows" ]; then
|
||||
curl -L https://github.com/frerich/clcache/releases/download/v4.2.0/clcache.4.2.0.nupkg --output clcache.4.2.0.nupkg
|
||||
choco install clcache --source=.
|
||||
fi
|
||||
|
||||
# Ensure we're using ccache
|
||||
@@ -135,10 +97,28 @@ travis_script() {
|
||||
if [ "$PPSSPP_BUILD_TYPE" = "macOS" ]; then
|
||||
./b.sh --headless
|
||||
fi
|
||||
if [ "$PPSSPP_BUILD_TYPE" = "Windows" ]; then
|
||||
export "MSBUILD_PATH=/c/Program Files (x86)/Microsoft Visual Studio/2017/BuildTools/MSBuild/15.0/Bin"
|
||||
export "PATH=$MSBUILD_PATH:$PATH"
|
||||
export CLCACHE_OBJECT_CACHE_TIMEOUT_MS=120000
|
||||
|
||||
# Set DebugInformationFormat to nothing, the default is ProgramDatabase which breaks clcache.
|
||||
# Turns out it's not possible to pass this on the msbuild command line.
|
||||
for f in `find . -name *.vcxproj`; do
|
||||
sed -i 's/>ProgramDatabase<\/DebugInformationFormat>/><\/DebugInformationFormat>/g' $f
|
||||
done
|
||||
|
||||
msbuild.exe Windows\\PPSSPP.sln -m -p:CLToolExe=clcache.exe -p:Configuration=Release -p:Platform=x64 -p:TrackFileAccess=false
|
||||
fi
|
||||
}
|
||||
|
||||
travis_after_success() {
|
||||
ccache -s
|
||||
if [ "$PPSSPP_BUILD_TYPE" != "Windows" ]; then
|
||||
ccache -s
|
||||
else
|
||||
clcache -s
|
||||
clcache -z
|
||||
fi
|
||||
|
||||
if [ "$PPSSPP_BUILD_TYPE" = "Linux" ]; then
|
||||
./test.py
|
||||
|
||||
+26
-12
@@ -4,27 +4,38 @@ sudo: required
|
||||
|
||||
language: cpp
|
||||
|
||||
dist: trusty
|
||||
dist: xenial
|
||||
|
||||
addons:
|
||||
apt:
|
||||
update: true
|
||||
packages:
|
||||
- ant
|
||||
- aria2
|
||||
- build-essential
|
||||
- cmake
|
||||
- libgl1-mesa-dev
|
||||
- libglu1-mesa-dev
|
||||
- cmake
|
||||
- aria2
|
||||
- ant
|
||||
- lib32stdc++6
|
||||
- lib32z1
|
||||
- lib32z1-dev
|
||||
- lib32bz2-1.0
|
||||
- libsdl2-dev
|
||||
- pv
|
||||
- software-properties-common
|
||||
sources:
|
||||
- sourceline: 'ppa:zoogie/sdl2-snapshots'
|
||||
- sourceline: 'ppa:ubuntu-toolchain-r/test'
|
||||
- sourceline: 'ppa:ubuntu-sdk-team/ppa'
|
||||
homebrew:
|
||||
update: true
|
||||
packages:
|
||||
- ccache
|
||||
- python
|
||||
- sdl2
|
||||
|
||||
cache:
|
||||
apt: true
|
||||
ccache: true
|
||||
directories:
|
||||
- $HOME/Library/Caches/Homebrew
|
||||
- $HOME/clcache
|
||||
|
||||
# By encrypting the channel name, we disable notifications from forks by default.
|
||||
# It's not actually a big secret.
|
||||
@@ -75,19 +86,22 @@ matrix:
|
||||
env: PPSSPP_BUILD_TYPE=Linux
|
||||
LIBRETRO=TRUE
|
||||
- os: osx
|
||||
osx_image: xcode8
|
||||
osx_image: xcode8.3
|
||||
compiler: "clang"
|
||||
env: PPSSPP_BUILD_TYPE=macOS
|
||||
- os: osx
|
||||
osx_image: xcode8
|
||||
osx_image: xcode8.3
|
||||
compiler: "clang"
|
||||
env: PPSSPP_BUILD_TYPE=iOS
|
||||
- os: windows
|
||||
compiler: "msvc2017"
|
||||
env: PPSSPP_BUILD_TYPE=Windows
|
||||
|
||||
before_install:
|
||||
- bash .travis.sh travis_before_install
|
||||
- travis_retry bash .travis.sh travis_before_install
|
||||
|
||||
install:
|
||||
- bash .travis.sh travis_install
|
||||
- travis_retry bash .travis.sh travis_install
|
||||
|
||||
script:
|
||||
- bash .travis.sh travis_script
|
||||
|
||||
@@ -1874,8 +1874,6 @@ set(WindowsFiles
|
||||
Windows/InputBox.h
|
||||
Windows/InputDevice.cpp
|
||||
Windows/InputDevice.h
|
||||
Windows/KeyboardDevice.cpp
|
||||
Windows/KeyboardDevice.h
|
||||
Windows/W32Util/DialogManager.cpp
|
||||
Windows/W32Util/DialogManager.h
|
||||
Windows/W32Util/Misc.cpp
|
||||
|
||||
@@ -258,6 +258,7 @@
|
||||
<MultiProcessorCompilation>true</MultiProcessorCompilation>
|
||||
<RuntimeTypeInfo>false</RuntimeTypeInfo>
|
||||
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
|
||||
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Windows</SubSystem>
|
||||
@@ -292,6 +293,7 @@
|
||||
<RuntimeTypeInfo>false</RuntimeTypeInfo>
|
||||
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
|
||||
<StringPooling>true</StringPooling>
|
||||
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Windows</SubSystem>
|
||||
@@ -326,6 +328,7 @@
|
||||
<RuntimeTypeInfo>false</RuntimeTypeInfo>
|
||||
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
|
||||
<StringPooling>true</StringPooling>
|
||||
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Windows</SubSystem>
|
||||
@@ -360,6 +363,7 @@
|
||||
<RuntimeTypeInfo>false</RuntimeTypeInfo>
|
||||
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
|
||||
<StringPooling>true</StringPooling>
|
||||
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Windows</SubSystem>
|
||||
|
||||
@@ -705,10 +705,6 @@ struct ConfigTranslator {
|
||||
typedef ConfigTranslator<GPUBackend, GPUBackendToString, GPUBackendFromString> GPUBackendTranslator;
|
||||
|
||||
static ConfigSetting graphicsSettings[] = {
|
||||
ConfigSetting("EnableCardboard", &g_Config.bEnableCardboard, false, true, true),
|
||||
ConfigSetting("CardboardScreenSize", &g_Config.iCardboardScreenSize, 50, true, true),
|
||||
ConfigSetting("CardboardXShift", &g_Config.iCardboardXShift, 0, true, true),
|
||||
ConfigSetting("CardboardYShift", &g_Config.iCardboardXShift, 0, true, true),
|
||||
ConfigSetting("ShowFPSCounter", &g_Config.iShowFPSCounter, 0, true, true),
|
||||
ReportedConfigSetting("GraphicsBackend", &g_Config.iGPUBackend, &DefaultGPUBackend, &GPUBackendTranslator::To, &GPUBackendTranslator::From, true, false),
|
||||
ConfigSetting("FailedGraphicsBackends", &g_Config.sFailedGPUBackends, ""),
|
||||
|
||||
@@ -159,11 +159,6 @@ public:
|
||||
bool bAutoFrameSkip;
|
||||
bool bFrameSkipUnthrottle;
|
||||
|
||||
bool bEnableCardboard; // Cardboard Master Switch
|
||||
int iCardboardScreenSize; // Screen Size (in %)
|
||||
int iCardboardXShift; // X-Shift of Screen (in %)
|
||||
int iCardboardYShift; // Y-Shift of Screen (in %)
|
||||
|
||||
int iWindowX;
|
||||
int iWindowY;
|
||||
int iWindowWidth; // Windows and other windowed environments
|
||||
|
||||
@@ -238,6 +238,7 @@
|
||||
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
|
||||
<MultiProcessorCompilation>true</MultiProcessorCompilation>
|
||||
<RuntimeTypeInfo>false</RuntimeTypeInfo>
|
||||
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
@@ -271,6 +272,7 @@
|
||||
<RuntimeTypeInfo>false</RuntimeTypeInfo>
|
||||
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
|
||||
<StringPooling>true</StringPooling>
|
||||
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
@@ -300,6 +302,7 @@
|
||||
<RuntimeTypeInfo>false</RuntimeTypeInfo>
|
||||
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
|
||||
<StringPooling>true</StringPooling>
|
||||
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
@@ -329,6 +332,7 @@
|
||||
<RuntimeTypeInfo>false</RuntimeTypeInfo>
|
||||
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
|
||||
<StringPooling>true</StringPooling>
|
||||
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
|
||||
@@ -98,7 +98,7 @@ static bool FixFilenameCase(const std::string &path, std::string &filename)
|
||||
return retValue;
|
||||
}
|
||||
|
||||
bool FixPathCase(std::string& basePath, std::string &path, FixPathCaseBehavior behavior)
|
||||
bool FixPathCase(const std::string &basePath, std::string &path, FixPathCaseBehavior behavior)
|
||||
{
|
||||
size_t len = path.size();
|
||||
|
||||
@@ -158,25 +158,25 @@ DirectoryFileSystem::~DirectoryFileSystem() {
|
||||
CloseAll();
|
||||
}
|
||||
|
||||
std::string DirectoryFileHandle::GetLocalPath(std::string& basePath, std::string localpath)
|
||||
std::string DirectoryFileHandle::GetLocalPath(const std::string &basePath, std::string localpath)
|
||||
{
|
||||
if (localpath.empty())
|
||||
return basePath;
|
||||
|
||||
if (localpath[0] == '/')
|
||||
localpath.erase(0,1);
|
||||
//Convert slashes
|
||||
localpath.erase(0, 1);
|
||||
|
||||
std::string result = basePath + localpath;
|
||||
#ifdef _WIN32
|
||||
for (size_t i = 0; i < localpath.size(); i++) {
|
||||
if (localpath[i] == '/')
|
||||
localpath[i] = '\\';
|
||||
for (char &c : result) {
|
||||
if (c == '/')
|
||||
c = '\\';
|
||||
}
|
||||
#endif
|
||||
return basePath + localpath;
|
||||
return result;
|
||||
}
|
||||
|
||||
bool DirectoryFileHandle::Open(std::string &basePath, std::string &fileName, FileAccess access, u32 &error)
|
||||
{
|
||||
bool DirectoryFileHandle::Open(const std::string &basePath, std::string &fileName, FileAccess access, u32 &error) {
|
||||
error = 0;
|
||||
|
||||
#if HOST_IS_CASE_SENSITIVE
|
||||
@@ -190,7 +190,7 @@ bool DirectoryFileHandle::Open(std::string &basePath, std::string &fileName, Fil
|
||||
// else we try fopen first (in case we're lucky) before simulating case insensitivity
|
||||
#endif
|
||||
|
||||
std::string fullName = GetLocalPath(basePath,fileName);
|
||||
std::string fullName = GetLocalPath(basePath, fileName);
|
||||
VERBOSE_LOG(FILESYS,"Actually opening %s", fullName.c_str());
|
||||
|
||||
// On the PSP, truncating doesn't lose data. If you seek later, you'll recover it.
|
||||
@@ -322,6 +322,11 @@ bool DirectoryFileHandle::Open(std::string &basePath, std::string &fileName, Fil
|
||||
}
|
||||
#endif
|
||||
|
||||
// Try to detect reads/writes to PSP/GAME to avoid them in replays.
|
||||
if (fullName.find("/PSP/GAME/") != fullName.npos || fullName.find("\\PSP\\GAME\\") != fullName.npos) {
|
||||
inGameDir_ = true;
|
||||
}
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
@@ -333,7 +338,7 @@ size_t DirectoryFileHandle::Read(u8* pointer, s64 size)
|
||||
// On a PSP. it actually is truncated, but the data wasn't erased.
|
||||
off_t off = (off_t)Seek(0, FILEMOVE_CURRENT);
|
||||
if (needsTrunc_ <= off) {
|
||||
return replay_ ? ReplayApplyDiskRead(pointer, 0, (uint32_t)size, CoreTiming::GetGlobalTimeUs()) : 0;
|
||||
return replay_ ? ReplayApplyDiskRead(pointer, 0, (uint32_t)size, inGameDir_, CoreTiming::GetGlobalTimeUs()) : 0;
|
||||
}
|
||||
if (needsTrunc_ < off + size) {
|
||||
size = needsTrunc_ - off;
|
||||
@@ -344,7 +349,7 @@ size_t DirectoryFileHandle::Read(u8* pointer, s64 size)
|
||||
#else
|
||||
bytesRead = read(hFile, pointer, size);
|
||||
#endif
|
||||
return replay_ ? ReplayApplyDiskRead(pointer, (uint32_t)bytesRead, (uint32_t)size, CoreTiming::GetGlobalTimeUs()) : bytesRead;
|
||||
return replay_ ? ReplayApplyDiskRead(pointer, (uint32_t)bytesRead, (uint32_t)size, inGameDir_, CoreTiming::GetGlobalTimeUs()) : bytesRead;
|
||||
}
|
||||
|
||||
size_t DirectoryFileHandle::Write(const u8* pointer, s64 size)
|
||||
@@ -371,6 +376,10 @@ size_t DirectoryFileHandle::Write(const u8* pointer, s64 size)
|
||||
}
|
||||
}
|
||||
|
||||
if (replay_) {
|
||||
bytesWritten = ReplayApplyDiskWrite(pointer, (uint64_t)bytesWritten, (uint64_t)size, &diskFull, inGameDir_, CoreTiming::GetGlobalTimeUs());
|
||||
}
|
||||
|
||||
if (diskFull) {
|
||||
ERROR_LOG(FILESYS, "Disk full");
|
||||
I18NCategory *err = GetI18NCategory("Error");
|
||||
|
||||
@@ -54,7 +54,7 @@ enum FixPathCaseBehavior {
|
||||
FPC_PARTIAL_ALLOWED, // don't care how many exist (mkdir recursive)
|
||||
};
|
||||
|
||||
bool FixPathCase(std::string& basePath, std::string &path, FixPathCaseBehavior behavior);
|
||||
bool FixPathCase(const std::string &basePath, std::string &path, FixPathCaseBehavior behavior);
|
||||
#endif
|
||||
|
||||
struct DirectoryFileHandle {
|
||||
@@ -70,12 +70,13 @@ struct DirectoryFileHandle {
|
||||
#endif
|
||||
s64 needsTrunc_ = -1;
|
||||
bool replay_ = true;
|
||||
bool inGameDir_ = false;
|
||||
|
||||
DirectoryFileHandle(Flags flags) : replay_(flags != SKIP_REPLAY) {
|
||||
}
|
||||
|
||||
std::string GetLocalPath(std::string& basePath, std::string localpath);
|
||||
bool Open(std::string& basePath, std::string& fileName, FileAccess access, u32 &err);
|
||||
std::string GetLocalPath(const std::string &basePath, std::string localpath);
|
||||
bool Open(const std::string &basePath, std::string &fileName, FileAccess access, u32 &err);
|
||||
size_t Read(u8* pointer, s64 size);
|
||||
size_t Write(const u8* pointer, s64 size);
|
||||
size_t Seek(s32 position, FileMove type);
|
||||
|
||||
+59
-4
@@ -62,6 +62,7 @@ enum latency {
|
||||
int eventAudioUpdate = -1;
|
||||
int eventHostAudioUpdate = -1;
|
||||
int mixFrequency = 44100;
|
||||
int srcFrequency = 0;
|
||||
|
||||
const int hwSampleRate = 44100;
|
||||
|
||||
@@ -107,6 +108,7 @@ static void __AudioCPUMHzChange() {
|
||||
void __AudioInit() {
|
||||
memset(&g_AudioDebugStats, 0, sizeof(g_AudioDebugStats));
|
||||
mixFrequency = 44100;
|
||||
srcFrequency = 0;
|
||||
|
||||
switch (g_Config.iAudioLatency) {
|
||||
case LOW_LATENCY:
|
||||
@@ -149,7 +151,7 @@ void __AudioInit() {
|
||||
}
|
||||
|
||||
void __AudioDoState(PointerWrap &p) {
|
||||
auto s = p.Section("sceAudio", 1);
|
||||
auto s = p.Section("sceAudio", 1, 2);
|
||||
if (!s)
|
||||
return;
|
||||
|
||||
@@ -159,6 +161,13 @@ void __AudioDoState(PointerWrap &p) {
|
||||
CoreTiming::RestoreRegisterEvent(eventHostAudioUpdate, "AudioUpdateHost", &hleHostAudioUpdate);
|
||||
|
||||
p.Do(mixFrequency);
|
||||
if (s >= 2) {
|
||||
p.Do(srcFrequency);
|
||||
} else {
|
||||
// Assume that it was actually the SRC channel frequency.
|
||||
srcFrequency = mixFrequency;
|
||||
mixFrequency = 44100;
|
||||
}
|
||||
|
||||
// TODO: This never happens because maxVer=1.
|
||||
if (s >= 2) {
|
||||
@@ -176,6 +185,7 @@ void __AudioDoState(PointerWrap &p) {
|
||||
if (chanCount != ARRAY_SIZE(chans))
|
||||
{
|
||||
ERROR_LOG(SCEAUDIO, "Savestate failure: different number of audio channels.");
|
||||
p.SetError(p.ERROR_FAILURE);
|
||||
return;
|
||||
}
|
||||
for (int i = 0; i < chanCount; ++i)
|
||||
@@ -329,6 +339,10 @@ void __AudioSetOutputFrequency(int freq) {
|
||||
mixFrequency = freq;
|
||||
}
|
||||
|
||||
void __AudioSetSRCFrequency(int freq) {
|
||||
srcFrequency = freq;
|
||||
}
|
||||
|
||||
// Mix samples from the various audio channels into a single sample queue.
|
||||
// This single sample queue is where __AudioMix should read from. If the sample queue is full, we should
|
||||
// just sleep the main emulator thread a little.
|
||||
@@ -337,6 +351,7 @@ void __AudioUpdate(bool resetRecording) {
|
||||
// to the CPU. Much better to throttle the frame rate on frame display and just throw away audio
|
||||
// if the buffer somehow gets full.
|
||||
bool firstChannel = true;
|
||||
std::vector<int16_t> srcBuffer;
|
||||
|
||||
for (u32 i = 0; i < PSP_AUDIO_CHANNEL_MAX + 1; i++) {
|
||||
if (!chans[i].reserved)
|
||||
@@ -348,14 +363,54 @@ void __AudioUpdate(bool resetRecording) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (hwBlockSize * 2 > (int)chans[i].sampleQueue.size()) {
|
||||
ERROR_LOG(SCEAUDIO, "Channel %i buffer underrun at %i of %i", i, (int)chans[i].sampleQueue.size() / 2, hwBlockSize);
|
||||
bool needsResample = i == PSP_AUDIO_CHANNEL_SRC && srcFrequency != 0 && srcFrequency != mixFrequency;
|
||||
size_t sz = needsResample ? (hwBlockSize * 2 * srcFrequency) / mixFrequency : hwBlockSize * 2;
|
||||
if (sz > chans[i].sampleQueue.size()) {
|
||||
ERROR_LOG(SCEAUDIO, "Channel %i buffer underrun at %i of %i", i, (int)chans[i].sampleQueue.size() / 2, (int)sz / 2);
|
||||
}
|
||||
|
||||
const s16 *buf1 = 0, *buf2 = 0;
|
||||
size_t sz1, sz2;
|
||||
|
||||
chans[i].sampleQueue.popPointers(hwBlockSize * 2, &buf1, &sz1, &buf2, &sz2);
|
||||
chans[i].sampleQueue.popPointers(sz, &buf1, &sz1, &buf2, &sz2);
|
||||
|
||||
if (needsResample) {
|
||||
auto read = [&](size_t i) {
|
||||
if (i < sz1)
|
||||
return buf1[i];
|
||||
if (i < sz1 + sz2)
|
||||
return buf2[i - sz1];
|
||||
if (buf2)
|
||||
return buf2[sz2 - 1];
|
||||
return buf1[sz1 - 1];
|
||||
};
|
||||
|
||||
srcBuffer.resize(hwBlockSize * 2);
|
||||
|
||||
// TODO: This is terrible, since it's doing it by small chunk and discarding frac.
|
||||
const uint32_t ratio = (uint32_t)(65536.0 * srcFrequency / (double)mixFrequency);
|
||||
uint32_t frac = 0;
|
||||
size_t readIndex = 0;
|
||||
for (size_t outIndex = 0; readIndex < sz && outIndex < srcBuffer.size(); outIndex += 2) {
|
||||
size_t readIndex2 = readIndex + 2;
|
||||
int16_t l1 = read(readIndex);
|
||||
int16_t r1 = read(readIndex + 1);
|
||||
int16_t l2 = read(readIndex2);
|
||||
int16_t r2 = read(readIndex2 + 1);
|
||||
int sampleL = ((l1 << 16) + (l2 - l1) * (uint16_t)frac) >> 16;
|
||||
int sampleR = ((r1 << 16) + (r2 - r1) * (uint16_t)frac) >> 16;
|
||||
srcBuffer[outIndex] = sampleL;
|
||||
srcBuffer[outIndex + 1] = sampleR;
|
||||
frac += ratio;
|
||||
readIndex += 2 * (uint16_t)(frac >> 16);
|
||||
frac &= 0xffff;
|
||||
}
|
||||
|
||||
buf1 = srcBuffer.data();
|
||||
sz1 = srcBuffer.size();
|
||||
buf2 = nullptr;
|
||||
sz2 = 0;
|
||||
}
|
||||
|
||||
if (firstChannel) {
|
||||
for (size_t s = 0; s < sz1; s++)
|
||||
|
||||
@@ -36,6 +36,7 @@ void __AudioDoState(PointerWrap &p);
|
||||
void __AudioUpdate(bool resetRecording = false);
|
||||
void __AudioShutdown();
|
||||
void __AudioSetOutputFrequency(int freq);
|
||||
void __AudioSetSRCFrequency(int freq);
|
||||
|
||||
// May return SCE_ERROR_AUDIO_CHANNEL_BUSY if buffer too large
|
||||
u32 __AudioEnqueue(AudioChannel &chan, int chanNum, bool blocking);
|
||||
|
||||
+30
-19
@@ -248,10 +248,10 @@ static u32 sceAudioChRelease(u32 chan) {
|
||||
ERROR_LOG(SCEAUDIO, "sceAudioChRelease(%i) - channel not reserved", chan);
|
||||
return SCE_ERROR_AUDIO_CHANNEL_NOT_RESERVED;
|
||||
}
|
||||
DEBUG_LOG(SCEAUDIO, "sceAudioChRelease(%i)", chan);
|
||||
// TODO: Does this error if busy?
|
||||
chans[chan].reset();
|
||||
chans[chan].reserved = false;
|
||||
return 1;
|
||||
return hleLogSuccessI(SCEAUDIO, 0);
|
||||
}
|
||||
|
||||
static u32 sceAudioSetChannelDataLen(u32 chan, u32 len) {
|
||||
@@ -329,6 +329,7 @@ static u32 sceAudioOutput2Reserve(u32 sampleCount) {
|
||||
chan.sampleCount = sampleCount;
|
||||
chan.format = PSP_AUDIO_FORMAT_STEREO;
|
||||
chan.reserved = true;
|
||||
__AudioSetSRCFrequency(0);
|
||||
return hleLogSuccessI(SCEAUDIO, 0);
|
||||
}
|
||||
|
||||
@@ -339,11 +340,15 @@ static u32 sceAudioOutput2OutputBlocking(u32 vol, u32 dataPtr) {
|
||||
}
|
||||
|
||||
auto &chan = chans[PSP_AUDIO_CHANNEL_OUTPUT2];
|
||||
if (!chan.reserved) {
|
||||
return hleLogError(SCEAUDIO, SCE_ERROR_AUDIO_CHANNEL_NOT_RESERVED, "channel not reserved");
|
||||
}
|
||||
|
||||
chan.leftVolume = vol;
|
||||
chan.rightVolume = vol;
|
||||
chan.sampleAddress = dataPtr;
|
||||
hleEatCycles(10000);
|
||||
|
||||
hleEatCycles(10000);
|
||||
int result = __AudioEnqueue(chan, PSP_AUDIO_CHANNEL_OUTPUT2, true);
|
||||
if (result < 0)
|
||||
return hleLogError(SCEAUDIO, result);
|
||||
@@ -351,22 +356,25 @@ static u32 sceAudioOutput2OutputBlocking(u32 vol, u32 dataPtr) {
|
||||
}
|
||||
|
||||
static u32 sceAudioOutput2ChangeLength(u32 sampleCount) {
|
||||
if (!chans[PSP_AUDIO_CHANNEL_OUTPUT2].reserved) {
|
||||
ERROR_LOG(SCEAUDIO, "sceAudioOutput2ChangeLength(%08x) - channel not reserved ", sampleCount);
|
||||
return SCE_ERROR_AUDIO_CHANNEL_NOT_RESERVED;
|
||||
auto &chan = chans[PSP_AUDIO_CHANNEL_OUTPUT2];
|
||||
if (!chan.reserved) {
|
||||
return hleLogError(SCEAUDIO, SCE_ERROR_AUDIO_CHANNEL_NOT_RESERVED, "channel not reserved");
|
||||
}
|
||||
DEBUG_LOG(SCEAUDIO, "sceAudioOutput2ChangeLength(%08x)", sampleCount);
|
||||
chans[PSP_AUDIO_CHANNEL_OUTPUT2].sampleCount = sampleCount;
|
||||
return 0;
|
||||
chan.sampleCount = sampleCount;
|
||||
return hleLogSuccessI(SCEAUDIO, 0);
|
||||
}
|
||||
|
||||
static u32 sceAudioOutput2GetRestSample() {
|
||||
if (!chans[PSP_AUDIO_CHANNEL_OUTPUT2].reserved) {
|
||||
ERROR_LOG(SCEAUDIO, "sceAudioOutput2GetRestSample() - channel not reserved ");
|
||||
return SCE_ERROR_AUDIO_CHANNEL_NOT_RESERVED;
|
||||
auto &chan = chans[PSP_AUDIO_CHANNEL_OUTPUT2];
|
||||
if (!chan.reserved) {
|
||||
return hleLogError(SCEAUDIO, SCE_ERROR_AUDIO_CHANNEL_NOT_RESERVED, "channel not reserved");
|
||||
}
|
||||
DEBUG_LOG(SCEAUDIO, "sceAudioOutput2GetRestSample()");
|
||||
return (u32) chans[PSP_AUDIO_CHANNEL_OUTPUT2].sampleQueue.size() / 2;
|
||||
u32 size = (u32)chan.sampleQueue.size() / 2;
|
||||
if (size > chan.sampleCount) {
|
||||
// If ChangeLength reduces the size, it still gets output but this return is clamped.
|
||||
size = chan.sampleCount;
|
||||
}
|
||||
return hleLogSuccessI(SCEAUDIO, size);
|
||||
}
|
||||
|
||||
static u32 sceAudioOutput2Release() {
|
||||
@@ -382,6 +390,7 @@ static u32 sceAudioOutput2Release() {
|
||||
}
|
||||
|
||||
static u32 sceAudioSetFrequency(u32 freq) {
|
||||
// TODO: Not available from user code.
|
||||
if (freq == 44100 || freq == 48000) {
|
||||
INFO_LOG(SCEAUDIO, "sceAudioSetFrequency(%08x)", freq);
|
||||
__AudioSetOutputFrequency(freq);
|
||||
@@ -424,10 +433,8 @@ static u32 sceAudioSRCChReserve(u32 sampleCount, u32 freq, u32 format) {
|
||||
chan.reserved = true;
|
||||
chan.sampleCount = sampleCount;
|
||||
chan.format = format == 2 ? PSP_AUDIO_FORMAT_STEREO : PSP_AUDIO_FORMAT_MONO;
|
||||
// TODO: Zero probably means don't change? Or it means default?
|
||||
if (freq != 0) {
|
||||
__AudioSetOutputFrequency(freq);
|
||||
}
|
||||
// Zero means default to 44.1kHz.
|
||||
__AudioSetSRCFrequency(freq);
|
||||
return hleLogSuccessI(SCEAUDIO, 0);
|
||||
}
|
||||
|
||||
@@ -449,6 +456,10 @@ static u32 sceAudioSRCOutputBlocking(u32 vol, u32 buf) {
|
||||
}
|
||||
|
||||
auto &chan = chans[PSP_AUDIO_CHANNEL_SRC];
|
||||
if (!chan.reserved) {
|
||||
return hleLogError(SCEAUDIO, SCE_ERROR_AUDIO_CHANNEL_NOT_RESERVED, "channel not reserved");
|
||||
}
|
||||
|
||||
chan.leftVolume = vol;
|
||||
chan.rightVolume = vol;
|
||||
chan.sampleAddress = buf;
|
||||
@@ -511,7 +522,7 @@ const HLEFunction sceAudio[] =
|
||||
{0X95FD0C2D, &WrapU_UU<sceAudioChangeChannelConfig>, "sceAudioChangeChannelConfig", 'x', "ii" },
|
||||
{0XB7E1D8E7, &WrapU_UUU<sceAudioChangeChannelVolume>, "sceAudioChangeChannelVolume", 'x', "ixx" },
|
||||
|
||||
// Not sure about the point of these, maybe like traditional but with ability to do sample rate conversion?
|
||||
// Like Output2, but with ability to do sample rate conversion.
|
||||
{0X38553111, &WrapU_UUU<sceAudioSRCChReserve>, "sceAudioSRCChReserve", 'x', "iii" },
|
||||
{0X5C37C0AE, &WrapU_V<sceAudioSRCChRelease>, "sceAudioSRCChRelease", 'x', "" },
|
||||
{0XE0727056, &WrapU_UU<sceAudioSRCOutputBlocking>, "sceAudioSRCOutputBlocking", 'x', "xx" },
|
||||
|
||||
@@ -1626,6 +1626,7 @@ bool __KernelLoadExec(const char *filename, u32 paramPtr, std::string *error_str
|
||||
if (param_argp) delete[] param_argp;
|
||||
if (param_key) delete[] param_key;
|
||||
}
|
||||
__KernelShutdown();
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@@ -188,3 +188,7 @@ std::string KernelTimeNowFormatted() {
|
||||
std::string timestamp = StringFromFormat("%04d-%02d-%02d_%02d-%02d-%02d", years, months, days, hours, minutes, seconds);
|
||||
return timestamp;
|
||||
}
|
||||
|
||||
void KernelTimeSetBase(int64_t seconds) {
|
||||
start_time = (time_t)seconds;
|
||||
}
|
||||
@@ -28,6 +28,7 @@ int sceKernelSysClock2USecWide(u32 lowClock, u32 highClock, u32 lowPtr, u32 high
|
||||
u64 sceKernelUSec2SysClockWide(u32 usec);
|
||||
u32 sceKernelLibcClock();
|
||||
std::string KernelTimeNowFormatted();
|
||||
void KernelTimeSetBase(int64_t seconds);
|
||||
|
||||
void __KernelTimeInit();
|
||||
void __KernelTimeDoState(PointerWrap &p);
|
||||
+19
-2
@@ -138,6 +138,10 @@ static time_t rtc_timegm(struct tm *tm)
|
||||
|
||||
#endif
|
||||
|
||||
static void RtcUpdateBaseTicks() {
|
||||
rtcBaseTicks = 1000000ULL * rtcBaseTime.tv_sec + rtcBaseTime.tv_usec + rtcMagicOffset;
|
||||
}
|
||||
|
||||
void __RtcInit()
|
||||
{
|
||||
// This is the base time, the only case we use gettimeofday() for.
|
||||
@@ -147,7 +151,7 @@ void __RtcInit()
|
||||
rtcBaseTime.tv_sec = tv.tv_sec;
|
||||
rtcBaseTime.tv_usec = 0;
|
||||
// Precalculate the current time in microseconds (rtcMagicOffset is offset to 1970.)
|
||||
rtcBaseTicks = 1000000ULL * rtcBaseTime.tv_sec + rtcBaseTime.tv_usec + rtcMagicOffset;
|
||||
RtcUpdateBaseTicks();
|
||||
}
|
||||
|
||||
void __RtcDoState(PointerWrap &p)
|
||||
@@ -158,7 +162,7 @@ void __RtcDoState(PointerWrap &p)
|
||||
|
||||
p.Do(rtcBaseTime);
|
||||
// Update the precalc, pointless to savestate this as it's just based on the other value.
|
||||
rtcBaseTicks = 1000000ULL * rtcBaseTime.tv_sec + rtcBaseTime.tv_usec + rtcMagicOffset;
|
||||
RtcUpdateBaseTicks();
|
||||
}
|
||||
|
||||
void __RtcTimeOfDay(PSPTimeval *tv)
|
||||
@@ -171,6 +175,19 @@ void __RtcTimeOfDay(PSPTimeval *tv)
|
||||
tv->tv_usec = adjustedUs % 1000000UL;
|
||||
}
|
||||
|
||||
int32_t RtcBaseTime(int32_t *micro) {
|
||||
if (micro) {
|
||||
*micro = rtcBaseTime.tv_usec;
|
||||
}
|
||||
return rtcBaseTime.tv_sec;
|
||||
}
|
||||
|
||||
void RtcSetBaseTime(int32_t seconds, int32_t micro) {
|
||||
rtcBaseTime.tv_sec = seconds;
|
||||
rtcBaseTime.tv_usec = micro;
|
||||
RtcUpdateBaseTicks();
|
||||
}
|
||||
|
||||
static void __RtcTmToPspTime(ScePspDateTime &t, const tm *val)
|
||||
{
|
||||
t.year = val->tm_year + 1900;
|
||||
|
||||
@@ -27,6 +27,8 @@ struct PSPTimeval {
|
||||
};
|
||||
|
||||
void __RtcTimeOfDay(PSPTimeval *tv);
|
||||
int32_t RtcBaseTime(int32_t *micro = nullptr);
|
||||
void RtcSetBaseTime(int32_t seconds, int32_t micro = 0);
|
||||
|
||||
void Register_sceRtc();
|
||||
void __RtcInit();
|
||||
|
||||
@@ -56,7 +56,7 @@ static u32 sceVaudioChReserve(int sampleCount, int freq, int format) {
|
||||
chans[PSP_AUDIO_CHANNEL_VAUDIO].leftVolume = 0;
|
||||
chans[PSP_AUDIO_CHANNEL_VAUDIO].rightVolume = 0;
|
||||
vaudioReserved = true;
|
||||
__AudioSetOutputFrequency(freq);
|
||||
__AudioSetSRCFrequency(freq);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -293,4 +293,6 @@ void StereoResampler::DoState(PointerWrap &p) {
|
||||
auto s = p.Section("resampler", 1);
|
||||
if (!s)
|
||||
return;
|
||||
if (p.mode == p.MODE_READ)
|
||||
Clear();
|
||||
}
|
||||
+1
-2
@@ -54,9 +54,8 @@ enum class IdentifiedFileType {
|
||||
UNKNOWN,
|
||||
};
|
||||
|
||||
|
||||
class FileLoader {
|
||||
// NB: It is a REQUIREMENT that implementations of this class are entirely thread safe!
|
||||
class FileLoader {
|
||||
public:
|
||||
enum class Flags {
|
||||
NONE,
|
||||
|
||||
@@ -2202,7 +2202,7 @@ namespace MIPSInt
|
||||
|
||||
ReadVector(s.f, sz, vs);
|
||||
ApplySwizzleS(s.f, sz);
|
||||
ReadVector(t.f, sz, vs);
|
||||
ReadVector(t.f, sz, vt);
|
||||
ApplySwizzleT(t.f, sz);
|
||||
// Swizzle does apply to the value read as an integer.
|
||||
u8 exp = (u8)(127 + t.i[0]);
|
||||
|
||||
+111
-35
@@ -24,6 +24,8 @@
|
||||
#include "Core/Replay.h"
|
||||
#include "Core/FileSystems/FileSystem.h"
|
||||
#include "Core/HLE/sceCtrl.h"
|
||||
#include "Core/HLE/sceKernelTime.h"
|
||||
#include "Core/HLE/sceRtc.h"
|
||||
|
||||
enum class ReplayState {
|
||||
IDLE,
|
||||
@@ -31,19 +33,42 @@ enum class ReplayState {
|
||||
SAVE,
|
||||
};
|
||||
|
||||
// Overall structure of file format:
|
||||
//
|
||||
// - ReplayFileHeader with basic data about replay (mostly timestamp for sync.)
|
||||
// - An indeterminate sequence of events:
|
||||
// - ReplayItemHeader (primary event details)
|
||||
// - Side data of bytes listed in header, if SIDEDATA flag set on action.
|
||||
//
|
||||
// The header doesn't say how long the replay is, because new events are
|
||||
// appended to the file as they occur. It is usually near, and always less than:
|
||||
//
|
||||
// (fileSize - sizeof(ReplayFileHeader)) / sizeof(ReplayItemHeader)
|
||||
|
||||
// File data formats below.
|
||||
#pragma pack(push, 1)
|
||||
|
||||
static const char *REPLAY_MAGIC = "PPREPLAY";
|
||||
static const int REPLAY_VERSION_MIN = 1;
|
||||
static const int REPLAY_VERSION_CURRENT = 1;
|
||||
|
||||
struct ReplayFileHeader {
|
||||
char magic[8];
|
||||
u32_le version = REPLAY_VERSION_CURRENT;
|
||||
u32_le reserved[3]{};
|
||||
u64_le rtcBaseSeconds;
|
||||
};
|
||||
|
||||
struct ReplayItemHeader {
|
||||
ReplayAction action;
|
||||
uint64_t timestamp;
|
||||
u64_le timestamp;
|
||||
union {
|
||||
uint32_t buttons;
|
||||
u32_le buttons;
|
||||
uint8_t analog[2][2];
|
||||
uint32_t result;
|
||||
uint64_t result64;
|
||||
u32_le result;
|
||||
u64_le result64;
|
||||
// NOTE: Certain action types have data, always sized by this/result.
|
||||
uint32_t size;
|
||||
u32_le size;
|
||||
};
|
||||
|
||||
ReplayItemHeader(ReplayAction a, uint64_t t) {
|
||||
@@ -68,14 +93,14 @@ static const int REPLAY_MAX_FILENAME = 256;
|
||||
|
||||
struct ReplayFileInfo {
|
||||
char filename[REPLAY_MAX_FILENAME]{};
|
||||
int64_t size = 0;
|
||||
uint16_t access = 0;
|
||||
s64_le size = 0;
|
||||
u16_le access = 0;
|
||||
uint8_t exists = 0;
|
||||
uint8_t isDirectory = 0;
|
||||
|
||||
int64_t atime = 0;
|
||||
int64_t ctime = 0;
|
||||
int64_t mtime = 0;
|
||||
s64_le atime = 0;
|
||||
s64_le ctime = 0;
|
||||
s64_le mtime = 0;
|
||||
};
|
||||
|
||||
#pragma pack(pop)
|
||||
@@ -93,6 +118,7 @@ static std::vector<ReplayItem> replayItems;
|
||||
static size_t replayExecPos = 0;
|
||||
static bool replaySaveWroteHeader = false;
|
||||
static ReplayState replayState = ReplayState::IDLE;
|
||||
static bool replaySawGameDirWrite = false;
|
||||
|
||||
static size_t replayCtrlPos = 0;
|
||||
static uint32_t lastButtons = 0;
|
||||
@@ -101,8 +127,6 @@ static uint8_t lastAnalog[2][2]{};
|
||||
static size_t replayDiskPos = 0;
|
||||
static bool diskFailed = false;
|
||||
|
||||
// TODO: File format either needs rtc and rand seed, or must be paired with a save state.
|
||||
|
||||
void ReplayExecuteBlob(const std::vector<u8> &data) {
|
||||
ReplayAbort();
|
||||
|
||||
@@ -145,28 +169,52 @@ bool ReplayExecuteFile(const std::string &filename) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// TODO: Header handling.
|
||||
// Include initial rand state or timestamp?
|
||||
|
||||
// TODO: Maybe stream instead.
|
||||
size_t sz = File::GetFileSize(fp);
|
||||
if (sz == 0) {
|
||||
ERROR_LOG(SYSTEM, "Empty replay data");
|
||||
fclose(fp);
|
||||
return false;
|
||||
}
|
||||
|
||||
std::vector<u8> data;
|
||||
data.resize(sz);
|
||||
auto loadData = [&]() {
|
||||
// TODO: Maybe stream instead.
|
||||
size_t sz = File::GetFileSize(fp);
|
||||
if (sz <= sizeof(ReplayFileHeader)) {
|
||||
ERROR_LOG(SYSTEM, "Empty replay data");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (fread(&data[0], sz, 1, fp) != 1) {
|
||||
ERROR_LOG(SYSTEM, "Could not read replay data");
|
||||
ReplayFileHeader fh;
|
||||
if (fread(&fh, sizeof(fh), 1, fp) != 1) {
|
||||
ERROR_LOG(SYSTEM, "Could not read replay file header");
|
||||
return false;
|
||||
}
|
||||
sz -= sizeof(fh);
|
||||
|
||||
if (memcmp(fh.magic, REPLAY_MAGIC, sizeof(fh.magic)) != 0) {
|
||||
ERROR_LOG(SYSTEM, "Replay header corrupt");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (fh.version < REPLAY_VERSION_MIN) {
|
||||
ERROR_LOG(SYSTEM, "Replay version %d unsupported", fh.version);
|
||||
return false;
|
||||
} else if (fh.version > REPLAY_VERSION_CURRENT) {
|
||||
WARN_LOG(SYSTEM, "Replay version %d scary and futuristic, trying anyway", fh.version);
|
||||
}
|
||||
|
||||
data.resize(sz);
|
||||
|
||||
if (fread(&data[0], sz, 1, fp) != 1) {
|
||||
ERROR_LOG(SYSTEM, "Could not read replay data");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
};
|
||||
|
||||
if (loadData()) {
|
||||
fclose(fp);
|
||||
return false;
|
||||
ReplayExecuteBlob(data);
|
||||
return true;
|
||||
}
|
||||
|
||||
ReplayExecuteBlob(data);
|
||||
return true;
|
||||
fclose(fp);
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ReplayHasMoreEvents() {
|
||||
@@ -219,13 +267,18 @@ bool ReplayFlushFile(const std::string &filename) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// TODO: Header handling.
|
||||
// Include initial rand state or timestamp?
|
||||
replaySaveWroteHeader = true;
|
||||
bool success = true;
|
||||
if (!replaySaveWroteHeader) {
|
||||
ReplayFileHeader fh;
|
||||
memcpy(fh.magic, REPLAY_MAGIC, sizeof(fh.magic));
|
||||
fh.rtcBaseSeconds = RtcBaseTime();
|
||||
|
||||
success = fwrite(&fh, sizeof(fh), 1, fp) == 1;
|
||||
replaySaveWroteHeader = true;
|
||||
}
|
||||
|
||||
size_t c = replayItems.size();
|
||||
bool success = true;
|
||||
if (c != 0) {
|
||||
if (success && c != 0) {
|
||||
// TODO: Maybe stream instead.
|
||||
std::vector<u8> data;
|
||||
ReplayFlushBlob(&data);
|
||||
@@ -247,6 +300,7 @@ void ReplayAbort() {
|
||||
replayExecPos = 0;
|
||||
replaySaveWroteHeader = false;
|
||||
replayState = ReplayState::IDLE;
|
||||
replaySawGameDirWrite = false;
|
||||
|
||||
replayCtrlPos = 0;
|
||||
lastButtons = 0;
|
||||
@@ -387,7 +441,12 @@ uint64_t ReplayApplyDisk64(ReplayAction action, uint64_t result, uint64_t t) {
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t ReplayApplyDiskRead(void *data, uint32_t readSize, uint32_t dataSize, uint64_t t) {
|
||||
uint32_t ReplayApplyDiskRead(void *data, uint32_t readSize, uint32_t dataSize, bool inGameDir, uint64_t t) {
|
||||
// Ignore PSP/GAME reads if we haven't seen a write there.
|
||||
if (inGameDir && !replaySawGameDirWrite) {
|
||||
return readSize;
|
||||
}
|
||||
|
||||
switch (replayState) {
|
||||
case ReplayState::EXECUTE:
|
||||
{
|
||||
@@ -414,6 +473,23 @@ uint32_t ReplayApplyDiskRead(void *data, uint32_t readSize, uint32_t dataSize, u
|
||||
}
|
||||
}
|
||||
|
||||
uint64_t ReplayApplyDiskWrite(const void *data, uint64_t writeSize, uint64_t dataSize, bool *diskFull, bool inGameDir, uint64_t t) {
|
||||
switch (replayState) {
|
||||
case ReplayState::EXECUTE:
|
||||
case ReplayState::SAVE:
|
||||
// Never let the disk return full during replay.
|
||||
if (diskFull)
|
||||
*diskFull = false;
|
||||
if (inGameDir)
|
||||
replaySawGameDirWrite = true;
|
||||
return writeSize;
|
||||
|
||||
case ReplayState::IDLE:
|
||||
default:
|
||||
return writeSize;
|
||||
}
|
||||
}
|
||||
|
||||
static int64_t ConvertFromTm(const struct tm *t) {
|
||||
// Remember, mktime modifies.
|
||||
struct tm copy = *t;
|
||||
|
||||
+3
-2
@@ -46,7 +46,7 @@ enum class ReplayAction : uint8_t {
|
||||
|
||||
struct PSPFileInfo;
|
||||
|
||||
// Replay from data in memory.
|
||||
// Replay from data in memory. Does not manipulate base time / RNG state.
|
||||
void ReplayExecuteBlob(const std::vector<u8> &data);
|
||||
// Replay from data in a file. Returns false if invalid.
|
||||
bool ReplayExecuteFile(const std::string &filename);
|
||||
@@ -68,6 +68,7 @@ void ReplayAbort();
|
||||
void ReplayApplyCtrl(uint32_t &buttons, uint8_t analog[2][2], uint64_t t);
|
||||
uint32_t ReplayApplyDisk(ReplayAction action, uint32_t result, uint64_t t);
|
||||
uint64_t ReplayApplyDisk64(ReplayAction action, uint64_t result, uint64_t t);
|
||||
uint32_t ReplayApplyDiskRead(void *data, uint32_t readSize, uint32_t dataSize, uint64_t t);
|
||||
uint32_t ReplayApplyDiskRead(void *data, uint32_t readSize, uint32_t dataSize, bool inGameDir, uint64_t t);
|
||||
uint64_t ReplayApplyDiskWrite(const void *data, uint64_t writeSize, uint64_t dataSize, bool *diskFull, bool inGameDir, uint64_t t);
|
||||
PSPFileInfo ReplayApplyDiskFileInfo(const PSPFileInfo &data, uint64_t t);
|
||||
std::vector<PSPFileInfo> ReplayApplyDiskListing(const std::vector<PSPFileInfo> &data, uint64_t t);
|
||||
+240
-100
@@ -16,6 +16,8 @@
|
||||
// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/.
|
||||
|
||||
#include <algorithm>
|
||||
#include <cctype>
|
||||
#include <string>
|
||||
#include <set>
|
||||
#include <cstring>
|
||||
#include <thread>
|
||||
@@ -30,6 +32,7 @@
|
||||
|
||||
#include "Common/Log.h"
|
||||
#include "Common/FileUtil.h"
|
||||
#include "Common/StringUtils.h"
|
||||
#include "Core/Config.h"
|
||||
#include "Core/System.h"
|
||||
#include "Core/Util/GameManager.h"
|
||||
@@ -58,7 +61,7 @@ bool GameManager::IsGameInstalled(std::string name) {
|
||||
return File::Exists(pspGame + name);
|
||||
}
|
||||
|
||||
bool GameManager::DownloadAndInstall(std::string storeZipUrl) {
|
||||
bool GameManager::DownloadAndInstall(std::string storeFileUrl) {
|
||||
if (curDownload_.get() != 0) {
|
||||
ERROR_LOG(HLE, "Can only process one download at a time");
|
||||
return false;
|
||||
@@ -69,7 +72,7 @@ bool GameManager::DownloadAndInstall(std::string storeZipUrl) {
|
||||
}
|
||||
|
||||
std::string filename = GetTempFilename();
|
||||
curDownload_ = g_DownloadManager.StartDownload(storeZipUrl, filename);
|
||||
curDownload_ = g_DownloadManager.StartDownload(storeFileUrl, filename);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -88,114 +91,241 @@ bool GameManager::Uninstall(std::string name) {
|
||||
return false;
|
||||
}
|
||||
std::string gameDir = GetSysDirectory(DIRECTORY_GAME) + name;
|
||||
INFO_LOG(HLE, "Deleting %s", gameDir.c_str());
|
||||
INFO_LOG(HLE, "Deleting '%s'", gameDir.c_str());
|
||||
if (!File::Exists(gameDir)) {
|
||||
ERROR_LOG(HLE, "Game %s not installed, cannot uninstall", name.c_str());
|
||||
ERROR_LOG(HLE, "Game '%s' not installed, cannot uninstall", name.c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
bool success = File::DeleteDirRecursively(gameDir);
|
||||
if (success) {
|
||||
INFO_LOG(HLE, "Successfully deleted game %s", name.c_str());
|
||||
INFO_LOG(HLE, "Successfully deleted game '%s'", name.c_str());
|
||||
g_Config.CleanRecent();
|
||||
return true;
|
||||
} else {
|
||||
ERROR_LOG(HLE, "Failed to delete game %s", name.c_str());
|
||||
ERROR_LOG(HLE, "Failed to delete game '%s'", name.c_str());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
void GameManager::Update() {
|
||||
if (curDownload_.get() && curDownload_->Done()) {
|
||||
INFO_LOG(HLE, "Download completed! Status = %i", curDownload_->ResultCode());
|
||||
std::string zipName = curDownload_->outfile();
|
||||
INFO_LOG(HLE, "Download completed! Status = %d", curDownload_->ResultCode());
|
||||
std::string fileName = curDownload_->outfile();
|
||||
if (curDownload_->ResultCode() == 200) {
|
||||
if (!File::Exists(zipName)) {
|
||||
ERROR_LOG(HLE, "Downloaded file %s does not exist :(", zipName.c_str());
|
||||
if (!File::Exists(fileName)) {
|
||||
ERROR_LOG(HLE, "Downloaded file '%s' does not exist :(", fileName.c_str());
|
||||
curDownload_.reset();
|
||||
return;
|
||||
}
|
||||
// Game downloaded to temporary file - install it!
|
||||
InstallGameOnThread(zipName, true);
|
||||
InstallGameOnThread(curDownload_->url(), fileName, true);
|
||||
} else {
|
||||
ERROR_LOG(HLE, "Expected HTTP status code 200, got status code %i. Install cancelled, deleting partial file.", curDownload_->ResultCode());
|
||||
File::Delete(zipName.c_str());
|
||||
ERROR_LOG(HLE, "Expected HTTP status code 200, got status code %d. Install cancelled, deleting partial file '%s'",
|
||||
curDownload_->ResultCode(), fileName.c_str());
|
||||
File::Delete(fileName.c_str());
|
||||
}
|
||||
curDownload_.reset();
|
||||
}
|
||||
}
|
||||
|
||||
bool GameManager::InstallGame(std::string zipfile, bool deleteAfter) {
|
||||
void countSlashes(std::string fileName, int *slashLocation, int *slashCount) {
|
||||
*slashCount = 0;
|
||||
int lastSlashLocation = -1;
|
||||
*slashLocation = -1;
|
||||
for (size_t i = 0; i < fileName.size(); i++) {
|
||||
if (fileName[i] == '/') {
|
||||
(*slashCount)++;
|
||||
*slashLocation = lastSlashLocation;
|
||||
lastSlashLocation = (int)i;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ZipFileContents DetectZipFileContents(std::string fileName, ZipFileInfo *info) {
|
||||
int error = 0;
|
||||
#ifdef _WIN32
|
||||
struct zip *z = zip_open(ConvertUTF8ToWString(fileName).c_str(), 0, &error);
|
||||
#else
|
||||
struct zip *z = zip_open(fileName.c_str(), 0, &error);
|
||||
#endif
|
||||
if (!z) {
|
||||
return ZipFileContents::UNKNOWN;
|
||||
}
|
||||
ZipFileContents retVal = DetectZipFileContents(z, info);
|
||||
zip_close(z);
|
||||
return retVal;
|
||||
}
|
||||
|
||||
inline char asciitolower(char in) {
|
||||
if (in <= 'Z' && in >= 'A')
|
||||
return in - ('Z' - 'z');
|
||||
return in;
|
||||
}
|
||||
|
||||
ZipFileContents DetectZipFileContents(struct zip *z, ZipFileInfo *info) {
|
||||
int numFiles = zip_get_num_files(z);
|
||||
|
||||
// Verify that this is a PSP zip file with the correct layout. We also try
|
||||
// to detect simple zipped ISO files, those we'll just "install" to the current
|
||||
// directory of the Games tab (where else?).
|
||||
bool isPSPMemstickGame = false;
|
||||
bool isZippedISO = false;
|
||||
int stripChars = 0;
|
||||
int isoFileIndex = -1;
|
||||
|
||||
for (int i = 0; i < numFiles; i++) {
|
||||
const char *fn = zip_get_name(z, i, 0);
|
||||
std::string zippedName = fn;
|
||||
std::transform(zippedName.begin(), zippedName.end(), zippedName.begin(),
|
||||
[](unsigned char c) { return asciitolower(c); }); // Not using std::tolower to avoid Turkish I->ı conversion.
|
||||
if (zippedName.find("eboot.pbp") != std::string::npos) {
|
||||
int slashCount = 0;
|
||||
int slashLocation = -1;
|
||||
countSlashes(zippedName, &slashLocation, &slashCount);
|
||||
if (slashCount >= 1 && (!isPSPMemstickGame || slashLocation < stripChars + 1)) {
|
||||
stripChars = slashLocation + 1;
|
||||
isPSPMemstickGame = true;
|
||||
} else {
|
||||
INFO_LOG(HLE, "Wrong number of slashes (%i) in '%s'", slashCount, fn);
|
||||
}
|
||||
} else if (endsWith(zippedName, ".iso") || endsWith(zippedName, ".cso")) {
|
||||
int slashCount = 0;
|
||||
int slashLocation = -1;
|
||||
countSlashes(zippedName, &slashLocation, &slashCount);
|
||||
if (slashCount <= 1) {
|
||||
// We only do this if the ISO file is in the root or one level down.
|
||||
isZippedISO = true;
|
||||
isoFileIndex = i;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
info->stripChars = stripChars;
|
||||
info->numFiles = numFiles;
|
||||
info->isoFileIndex = isoFileIndex;
|
||||
// If a ZIP is detected as both, let's let the memstick game interpretation prevail.
|
||||
if (isPSPMemstickGame) {
|
||||
return ZipFileContents::PSP_GAME_DIR;
|
||||
} else if (isZippedISO) {
|
||||
return ZipFileContents::ISO_FILE;
|
||||
} else {
|
||||
return ZipFileContents::UNKNOWN;
|
||||
}
|
||||
}
|
||||
|
||||
bool GameManager::InstallGame(const std::string &url, const std::string &fileName, bool deleteAfter) {
|
||||
if (installInProgress_) {
|
||||
ERROR_LOG(HLE, "Cannot have two installs in progress at the same time");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!File::Exists(zipfile)) {
|
||||
ERROR_LOG(HLE, "ZIP file %s doesn't exist", zipfile.c_str());
|
||||
if (!File::Exists(fileName)) {
|
||||
ERROR_LOG(HLE, "Game file '%s' doesn't exist", fileName.c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
// Examine the URL to guess out what we're installing.
|
||||
if (endsWithNoCase(url, ".cso") || endsWithNoCase(url, ".iso")) {
|
||||
// It's a raw ISO or CSO file. We just copy it to the destination.
|
||||
std::string shortFilename = GetFilenameFromPath(url);
|
||||
return InstallRawISO(fileName, shortFilename, deleteAfter);
|
||||
}
|
||||
|
||||
I18NCategory *sy = GetI18NCategory("System");
|
||||
installInProgress_ = true;
|
||||
|
||||
std::string pspGame = GetSysDirectory(DIRECTORY_GAME);
|
||||
INFO_LOG(HLE, "Installing %s into %s", zipfile.c_str(), pspGame.c_str());
|
||||
int error;
|
||||
INFO_LOG(HLE, "Installing '%s' into '%s'", fileName.c_str(), pspGame.c_str());
|
||||
int error = 0;
|
||||
#ifdef _WIN32
|
||||
struct zip *z = zip_open(ConvertUTF8ToWString(zipfile).c_str(), 0, &error);
|
||||
struct zip *z = zip_open(ConvertUTF8ToWString(fileName).c_str(), 0, &error);
|
||||
#else
|
||||
struct zip *z = zip_open(zipfile.c_str(), 0, &error);
|
||||
struct zip *z = zip_open(fileName.c_str(), 0, &error);
|
||||
#endif
|
||||
if (!z) {
|
||||
ERROR_LOG(HLE, "Failed to open ZIP file %s, error code=%i", zipfile.c_str(), error);
|
||||
ERROR_LOG(HLE, "Failed to open ZIP file '%s', error code=%i", fileName.c_str(), error);
|
||||
return false;
|
||||
}
|
||||
|
||||
int numFiles = zip_get_num_files(z);
|
||||
|
||||
// First, find all the directories, and precreate them before we fill in with files.
|
||||
// Also, verify that this is a PSP zip file with the correct layout.
|
||||
bool isPSP = false;
|
||||
int stripChars = 0;
|
||||
|
||||
for (int i = 0; i < numFiles; i++) {
|
||||
const char *fn = zip_get_name(z, i, 0);
|
||||
std::string zippedName = fn;
|
||||
if (zippedName.find("EBOOT.PBP") != std::string::npos) {
|
||||
int slashCount = 0;
|
||||
int lastSlashLocation = -1;
|
||||
int slashLocation = -1;
|
||||
for (size_t i = 0; i < zippedName.size(); i++) {
|
||||
if (zippedName[i] == '/') {
|
||||
slashCount++;
|
||||
slashLocation = lastSlashLocation;
|
||||
lastSlashLocation = (int)i;
|
||||
}
|
||||
}
|
||||
if (slashCount >= 1 && (!isPSP || slashLocation < stripChars + 1)) {
|
||||
stripChars = slashLocation + 1;
|
||||
isPSP = true;
|
||||
} else {
|
||||
INFO_LOG(HLE, "Wrong number of slashes (%i) in %s", slashCount, zippedName.c_str());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!isPSP) {
|
||||
ZipFileInfo info;
|
||||
ZipFileContents contents = DetectZipFileContents(z, &info);
|
||||
switch (contents) {
|
||||
case ZipFileContents::PSP_GAME_DIR:
|
||||
// InstallMemstickGame contains code to close z.
|
||||
return InstallMemstickGame(z, fileName, pspGame, info.numFiles, info.stripChars, deleteAfter);
|
||||
case ZipFileContents::ISO_FILE:
|
||||
return InstallZippedISO(z, info.isoFileIndex, fileName, deleteAfter);
|
||||
default:
|
||||
ERROR_LOG(HLE, "File not a PSP game, no EBOOT.PBP found.");
|
||||
installProgress_ = 0.0f;
|
||||
installInProgress_ = false;
|
||||
installError_ = sy->T("Not a PSP game");
|
||||
InstallDone();
|
||||
if (deleteAfter)
|
||||
File::Delete(zipfile);
|
||||
File::Delete(fileName);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
size_t allBytes = 0, bytesCopied = 0;
|
||||
bool GameManager::ExtractFile(struct zip *z, int file_index, std::string outFilename, size_t *bytesCopied, size_t allBytes) {
|
||||
struct zip_stat zstat;
|
||||
zip_stat_index(z, file_index, 0, &zstat);
|
||||
size_t size = zstat.size;
|
||||
|
||||
// Create all the directories in one pass
|
||||
// Don't spam the log.
|
||||
if (file_index < 10) {
|
||||
INFO_LOG(HLE, "Writing %d bytes to '%s'", (int)size, outFilename.c_str());
|
||||
}
|
||||
|
||||
zip_file *zf = zip_fopen_index(z, file_index, 0);
|
||||
FILE *f = File::OpenCFile(outFilename, "wb");
|
||||
if (f) {
|
||||
size_t pos = 0;
|
||||
const size_t blockSize = 1024 * 128;
|
||||
u8 *buffer = new u8[blockSize];
|
||||
while (pos < size) {
|
||||
size_t readSize = std::min(blockSize, size - pos);
|
||||
ssize_t retval = zip_fread(zf, buffer, readSize);
|
||||
if (retval < readSize) {
|
||||
ERROR_LOG(HLE, "Failed to read %d bytes from zip (%d) - archive corrupt?", (int)readSize, (int)retval);
|
||||
delete[] buffer;
|
||||
fclose(f);
|
||||
zip_fclose(zf);
|
||||
File::Delete(outFilename.c_str());
|
||||
return false;
|
||||
}
|
||||
size_t written = fwrite(buffer, 1, readSize, f);
|
||||
if (written != readSize) {
|
||||
ERROR_LOG(HLE, "Wrote %d bytes out of %d - Disk full?", (int)written, (int)readSize);
|
||||
delete[] buffer;
|
||||
fclose(f);
|
||||
zip_fclose(zf);
|
||||
File::Delete(outFilename.c_str());
|
||||
return false;
|
||||
}
|
||||
pos += readSize;
|
||||
|
||||
*bytesCopied += readSize;
|
||||
installProgress_ = (float)*bytesCopied / (float)allBytes;
|
||||
}
|
||||
zip_fclose(zf);
|
||||
fclose(f);
|
||||
delete[] buffer;
|
||||
return true;
|
||||
} else {
|
||||
ERROR_LOG(HLE, "Failed to open file for writing");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool GameManager::InstallMemstickGame(struct zip *z, std::string zipfile, std::string pspGame, int numFiles, int stripChars, bool deleteAfter) {
|
||||
size_t allBytes = 0;
|
||||
size_t bytesCopied = 0;
|
||||
|
||||
I18NCategory *sy = GetI18NCategory("System");
|
||||
|
||||
// Create all the directories first in one pass
|
||||
std::set<std::string> createdDirs;
|
||||
for (int i = 0; i < numFiles; i++) {
|
||||
const char *fn = zip_get_name(z, i, 0);
|
||||
@@ -224,53 +354,16 @@ bool GameManager::InstallGame(std::string zipfile, bool deleteAfter) {
|
||||
// Note that we do NOT write files that are not in a directory, to avoid random
|
||||
// README files etc.
|
||||
if (strchr(fn, '/') != 0) {
|
||||
struct zip_stat zstat;
|
||||
zip_stat_index(z, i, 0, &zstat);
|
||||
size_t size = zstat.size;
|
||||
|
||||
fn += stripChars;
|
||||
|
||||
std::string outFilename = pspGame + fn;
|
||||
bool isDir = *outFilename.rbegin() == '/';
|
||||
if (isDir)
|
||||
continue;
|
||||
|
||||
if (i < 10) {
|
||||
INFO_LOG(HLE, "Writing %i bytes to %s", (int)size, outFilename.c_str());
|
||||
}
|
||||
|
||||
zip_file *zf = zip_fopen_index(z, i, 0);
|
||||
FILE *f = File::OpenCFile(outFilename, "wb");
|
||||
if (f) {
|
||||
size_t pos = 0;
|
||||
const size_t blockSize = 1024 * 128;
|
||||
u8 *buffer = new u8[blockSize];
|
||||
while (pos < size) {
|
||||
size_t bs = std::min(blockSize, size - pos);
|
||||
zip_fread(zf, buffer, bs);
|
||||
size_t written = fwrite(buffer, 1, bs, f);
|
||||
if (written != bs) {
|
||||
ERROR_LOG(HLE, "Wrote %i bytes out of %i - Disk full?", (int)written, (int)bs);
|
||||
delete [] buffer;
|
||||
buffer = 0;
|
||||
fclose(f);
|
||||
zip_fclose(zf);
|
||||
File::Delete(outFilename.c_str());
|
||||
// Yes it's a goto. Sue me. I think it's appropriate here.
|
||||
goto bail;
|
||||
}
|
||||
pos += bs;
|
||||
|
||||
bytesCopied += bs;
|
||||
installProgress_ = (float)bytesCopied / (float)allBytes;
|
||||
// printf("Progress: %f\n", installProgress_);
|
||||
}
|
||||
zip_fclose(zf);
|
||||
fclose(f);
|
||||
createdFiles.push_back(outFilename);
|
||||
delete [] buffer;
|
||||
if (!ExtractFile(z, i, outFilename, &bytesCopied, allBytes)) {
|
||||
goto bail;
|
||||
} else {
|
||||
ERROR_LOG(HLE, "Failed to open file for writing");
|
||||
createdFiles.push_back(outFilename);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -293,9 +386,7 @@ bail:
|
||||
installProgress_ = 0.0f;
|
||||
installInProgress_ = false;
|
||||
installError_ = sy->T("Storage full");
|
||||
if (deleteAfter) {
|
||||
File::Delete(zipfile.c_str());
|
||||
}
|
||||
// We don't delete the original in this case. Try to delete the files we created so far.
|
||||
for (size_t i = 0; i < createdFiles.size(); i++) {
|
||||
File::Delete(createdFiles[i].c_str());
|
||||
}
|
||||
@@ -306,15 +397,64 @@ bail:
|
||||
return false;
|
||||
}
|
||||
|
||||
bool GameManager::InstallGameOnThread(std::string zipFile, bool deleteAfter) {
|
||||
bool GameManager::InstallZippedISO(struct zip *z, int isoFileIndex, std::string zipfile, bool deleteAfter) {
|
||||
// Let's place the output file in the currently selected Games directory.
|
||||
|
||||
std::string fn = zip_get_name(z, isoFileIndex, 0);
|
||||
size_t nameOffset = fn.rfind('/');
|
||||
if (nameOffset == std::string::npos) {
|
||||
nameOffset = 0;
|
||||
} else {
|
||||
nameOffset++;
|
||||
}
|
||||
size_t allBytes = 1;
|
||||
struct zip_stat zstat;
|
||||
if (zip_stat_index(z, isoFileIndex, 0, &zstat) >= 0) {
|
||||
allBytes += zstat.size;
|
||||
}
|
||||
|
||||
std::string outputISOFilename = g_Config.currentDirectory + "/" + fn.substr(nameOffset);
|
||||
size_t bytesCopied = 0;
|
||||
if (ExtractFile(z, isoFileIndex, outputISOFilename, &bytesCopied, allBytes)) {
|
||||
ILOG("Successfully extracted ISO file to '%s'", outputISOFilename.c_str());
|
||||
}
|
||||
zip_close(z);
|
||||
if (deleteAfter) {
|
||||
File::Delete(zipfile.c_str());
|
||||
}
|
||||
|
||||
z = 0;
|
||||
installProgress_ = 1.0f;
|
||||
installInProgress_ = false;
|
||||
installError_ = "";
|
||||
InstallDone();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool GameManager::InstallGameOnThread(std::string url, std::string fileName, bool deleteAfter) {
|
||||
if (installInProgress_) {
|
||||
return false;
|
||||
}
|
||||
installThread_.reset(new std::thread(std::bind(&GameManager::InstallGame, this, zipFile, deleteAfter)));
|
||||
installThread_.reset(new std::thread(std::bind(&GameManager::InstallGame, this, url, fileName, deleteAfter)));
|
||||
installThread_->detach();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool GameManager::InstallRawISO(const std::string &file, const std::string &originalName, bool deleteAfter) {
|
||||
std::string destPath = g_Config.currentDirectory + "/" + originalName;
|
||||
// TODO: To save disk space, we should probably attempt a move first.
|
||||
if (File::Copy(file, destPath)) {
|
||||
if (deleteAfter) {
|
||||
File::Delete(file.c_str());
|
||||
}
|
||||
}
|
||||
installProgress_ = 1.0f;
|
||||
installInProgress_ = false;
|
||||
installError_ = "";
|
||||
InstallDone();
|
||||
return true;
|
||||
}
|
||||
|
||||
void GameManager::InstallDone() {
|
||||
if (installThread_.get() != 0) {
|
||||
installThread_.reset();
|
||||
|
||||
+23
-2
@@ -31,6 +31,8 @@ enum class GameManagerState {
|
||||
INSTALLING,
|
||||
};
|
||||
|
||||
struct zip;
|
||||
|
||||
class GameManager {
|
||||
public:
|
||||
GameManager();
|
||||
@@ -64,11 +66,15 @@ public:
|
||||
}
|
||||
|
||||
// Only returns false if there's already an installation in progress.
|
||||
bool InstallGameOnThread(std::string zipFile, bool deleteAfter);
|
||||
bool InstallGameOnThread(std::string url, std::string tempFileName, bool deleteAfter);
|
||||
|
||||
private:
|
||||
bool InstallGame(std::string zipfile, bool deleteAfter = false);
|
||||
bool InstallGame(const std::string &url, const std::string &tempFileName, bool deleteAfter);
|
||||
bool InstallMemstickGame(struct zip *z, std::string zipFile, std::string pspGame, int numFiles, int stripChars, bool deleteAfter);
|
||||
bool InstallZippedISO(struct zip *z, int isoFileIndex, std::string zipfile, bool deleteAfter);
|
||||
bool InstallRawISO(const std::string &zipFile, const std::string &originalName, bool deleteAfter);
|
||||
void InstallDone();
|
||||
bool ExtractFile(struct zip *z, int file_index, std::string outFilename, size_t *bytesCopied, size_t allBytes);
|
||||
|
||||
std::string GetTempFilename() const;
|
||||
std::shared_ptr<http::Download> curDownload_;
|
||||
@@ -79,3 +85,18 @@ private:
|
||||
};
|
||||
|
||||
extern GameManager g_GameManager;
|
||||
|
||||
enum class ZipFileContents {
|
||||
UNKNOWN,
|
||||
PSP_GAME_DIR,
|
||||
ISO_FILE,
|
||||
};
|
||||
|
||||
struct ZipFileInfo {
|
||||
int numFiles;
|
||||
int stripChars; // for PSP game
|
||||
int isoFileIndex; // for ISO
|
||||
};
|
||||
|
||||
ZipFileContents DetectZipFileContents(struct zip *z, ZipFileInfo *info);
|
||||
ZipFileContents DetectZipFileContents(std::string fileName, ZipFileInfo *info);
|
||||
@@ -784,9 +784,6 @@ void FramebufferManagerCommon::DrawFramebufferToOutput(const u8 *srcPixels, GEBu
|
||||
float v0 = 0.0f, v1 = 1.0f;
|
||||
MakePixelTexture(srcPixels, srcPixelFormat, srcStride, 512, 272, u1, v1);
|
||||
|
||||
struct CardboardSettings cardboardSettings;
|
||||
GetCardboardSettings(&cardboardSettings);
|
||||
|
||||
// This might draw directly at the backbuffer (if so, applyPostShader is set) so if there's a post shader, we need to apply it here.
|
||||
// Should try to unify this path with the regular path somehow, but this simple solution works for most of the post shaders
|
||||
// (it always runs at output resolution so FXAA may look odd).
|
||||
@@ -812,18 +809,9 @@ void FramebufferManagerCommon::DrawFramebufferToOutput(const u8 *srcPixels, GEBu
|
||||
|
||||
DrawTextureFlags flags = g_Config.iBufFilter == SCALE_LINEAR ? DRAWTEX_LINEAR : DRAWTEX_NEAREST;
|
||||
flags = flags | DRAWTEX_TO_BACKBUFFER;
|
||||
if (cardboardSettings.enabled) {
|
||||
// Left Eye Image
|
||||
SetViewport2D(cardboardSettings.leftEyeXPosition, cardboardSettings.screenYPosition, cardboardSettings.screenWidth, cardboardSettings.screenHeight);
|
||||
DrawActiveTexture(x, y, w, h, (float)pixelWidth_, (float)pixelHeight_, u0, v0, u1, v1, ROTATION_LOCKED_HORIZONTAL, flags | DRAWTEX_KEEP_TEX);
|
||||
// Right Eye Image
|
||||
SetViewport2D(cardboardSettings.rightEyeXPosition, cardboardSettings.screenYPosition, cardboardSettings.screenWidth, cardboardSettings.screenHeight);
|
||||
DrawActiveTexture(x, y, w, h, (float)pixelWidth_, (float)pixelHeight_, u0, v0, u1, v1, ROTATION_LOCKED_HORIZONTAL, flags);
|
||||
} else {
|
||||
// Fullscreen Image
|
||||
SetViewport2D(0, 0, pixelWidth_, pixelHeight_);
|
||||
DrawActiveTexture(x, y, w, h, (float)pixelWidth_, (float)pixelHeight_, u0, v0, u1, v1, uvRotation, flags);
|
||||
}
|
||||
// Fullscreen Image
|
||||
SetViewport2D(0, 0, pixelWidth_, pixelHeight_);
|
||||
DrawActiveTexture(x, y, w, h, (float)pixelWidth_, (float)pixelHeight_, u0, v0, u1, v1, uvRotation, flags);
|
||||
|
||||
gstate_c.Dirty(DIRTY_BLEND_STATE | DIRTY_DEPTHSTENCIL_STATE | DIRTY_RASTER_STATE);
|
||||
}
|
||||
@@ -868,9 +856,6 @@ void FramebufferManagerCommon::CopyDisplayToOutput() {
|
||||
u32 offsetX = 0;
|
||||
u32 offsetY = 0;
|
||||
|
||||
CardboardSettings cardboardSettings;
|
||||
GetCardboardSettings(&cardboardSettings);
|
||||
|
||||
VirtualFramebuffer *vfb = GetVFBAt(displayFramebufPtr_);
|
||||
if (!vfb) {
|
||||
// Let's search for a framebuf within this range. Note that we also look for
|
||||
@@ -986,19 +971,9 @@ void FramebufferManagerCommon::CopyDisplayToOutput() {
|
||||
// flip V.
|
||||
if (needBackBufferYSwap_)
|
||||
std::swap(v0, v1);
|
||||
if (cardboardSettings.enabled) {
|
||||
// Left Eye Image
|
||||
SetViewport2D(cardboardSettings.leftEyeXPosition, cardboardSettings.screenYPosition, cardboardSettings.screenWidth, cardboardSettings.screenHeight);
|
||||
DrawActiveTexture(x, y, w, h, (float)pixelWidth_, (float)pixelHeight_, u0, v0, u1, v1, ROTATION_LOCKED_HORIZONTAL, flags | DRAWTEX_KEEP_TEX);
|
||||
|
||||
// Right Eye Image
|
||||
SetViewport2D(cardboardSettings.rightEyeXPosition, cardboardSettings.screenYPosition, cardboardSettings.screenWidth, cardboardSettings.screenHeight);
|
||||
DrawActiveTexture(x, y, w, h, (float)pixelWidth_, (float)pixelHeight_, u0, v0, u1, v1, ROTATION_LOCKED_HORIZONTAL, flags);
|
||||
} else {
|
||||
// Fullscreen Image
|
||||
SetViewport2D(0, 0, pixelWidth_, pixelHeight_);
|
||||
DrawActiveTexture(x, y, w, h, (float)pixelWidth_, (float)pixelHeight_, u0, v0, u1, v1, uvRotation, flags);
|
||||
}
|
||||
// Fullscreen Image
|
||||
SetViewport2D(0, 0, pixelWidth_, pixelHeight_);
|
||||
DrawActiveTexture(x, y, w, h, (float)pixelWidth_, (float)pixelHeight_, u0, v0, u1, v1, uvRotation, flags);
|
||||
} else if (usePostShader_ && extraFBOs_.size() == 1 && !postShaderAtOutputResolution_) {
|
||||
// An additional pass, post-processing shader to the extra FBO.
|
||||
shaderManager_->DirtyLastShader(); // dirty lastShader_
|
||||
@@ -1033,19 +1008,9 @@ void FramebufferManagerCommon::CopyDisplayToOutput() {
|
||||
Bind2DShader();
|
||||
flags = (!postShaderIsUpscalingFilter_ && g_Config.iBufFilter == SCALE_LINEAR) ? DRAWTEX_LINEAR : DRAWTEX_NEAREST;
|
||||
flags = flags | DRAWTEX_TO_BACKBUFFER;
|
||||
if (g_Config.bEnableCardboard) {
|
||||
// Left Eye Image
|
||||
SetViewport2D(cardboardSettings.leftEyeXPosition, cardboardSettings.screenYPosition, cardboardSettings.screenWidth, cardboardSettings.screenHeight);
|
||||
DrawActiveTexture(x, y, w, h, (float)pixelWidth_, (float)pixelHeight_, u0, v0, u1, v1, ROTATION_LOCKED_HORIZONTAL, flags | DRAWTEX_KEEP_TEX);
|
||||
|
||||
// Right Eye Image
|
||||
SetViewport2D(cardboardSettings.rightEyeXPosition, cardboardSettings.screenYPosition, cardboardSettings.screenWidth, cardboardSettings.screenHeight);
|
||||
DrawActiveTexture(x, y, w, h, (float)pixelWidth_, (float)pixelHeight_, u0, v0, u1, v1, ROTATION_LOCKED_HORIZONTAL, flags);
|
||||
} else {
|
||||
// Fullscreen Image
|
||||
SetViewport2D(0, 0, pixelWidth_, pixelHeight_);
|
||||
DrawActiveTexture(x, y, w, h, (float)pixelWidth_, (float)pixelHeight_, u0, v0, u1, v1, uvRotation, flags);
|
||||
}
|
||||
// Fullscreen Image
|
||||
SetViewport2D(0, 0, pixelWidth_, pixelHeight_);
|
||||
DrawActiveTexture(x, y, w, h, (float)pixelWidth_, (float)pixelHeight_, u0, v0, u1, v1, uvRotation, flags);
|
||||
} else {
|
||||
shaderManager_->DirtyLastShader(); // dirty lastShader_ BEFORE drawing
|
||||
draw_->BindFramebufferAsRenderTarget(nullptr, { Draw::RPAction::CLEAR, Draw::RPAction::CLEAR, Draw::RPAction::CLEAR });
|
||||
@@ -1061,19 +1026,9 @@ void FramebufferManagerCommon::CopyDisplayToOutput() {
|
||||
PostShaderUniforms uniforms{};
|
||||
CalculatePostShaderUniforms(vfb->bufferWidth, vfb->bufferHeight, vfb->renderWidth, vfb->renderHeight, &uniforms);
|
||||
BindPostShader(uniforms);
|
||||
if (g_Config.bEnableCardboard) {
|
||||
// Left Eye Image
|
||||
SetViewport2D(cardboardSettings.leftEyeXPosition, cardboardSettings.screenYPosition, cardboardSettings.screenWidth, cardboardSettings.screenHeight);
|
||||
DrawActiveTexture(x, y, w, h, (float)pixelWidth_, (float)pixelHeight_, u0, v0, u1, v1, ROTATION_LOCKED_HORIZONTAL, flags | DRAWTEX_KEEP_TEX);
|
||||
|
||||
// Right Eye Image
|
||||
SetViewport2D(cardboardSettings.rightEyeXPosition, cardboardSettings.screenYPosition, cardboardSettings.screenWidth, cardboardSettings.screenHeight);
|
||||
DrawActiveTexture(x, y, w, h, (float)pixelWidth_, (float)pixelHeight_, u0, v0, u1, v1, ROTATION_LOCKED_HORIZONTAL, flags);
|
||||
} else {
|
||||
// Fullscreen Image
|
||||
SetViewport2D(0, 0, pixelWidth_, pixelHeight_);
|
||||
DrawActiveTexture(x, y, w, h, (float)pixelWidth_, (float)pixelHeight_, u0, v0, u1, v1, uvRotation, flags);
|
||||
}
|
||||
// Fullscreen Image
|
||||
SetViewport2D(0, 0, pixelWidth_, pixelHeight_);
|
||||
DrawActiveTexture(x, y, w, h, (float)pixelWidth_, (float)pixelHeight_, u0, v0, u1, v1, uvRotation, flags);
|
||||
}
|
||||
}
|
||||
else if (useBufferedRendering_) {
|
||||
@@ -1843,27 +1798,6 @@ void FramebufferManagerCommon::CalculatePostShaderUniforms(int bufferWidth, int
|
||||
uniforms->video = textureCache_->VideoIsPlaying();
|
||||
}
|
||||
|
||||
void FramebufferManagerCommon::GetCardboardSettings(CardboardSettings *cardboardSettings) {
|
||||
// Calculate Cardboard Settings
|
||||
float cardboardScreenScale = g_Config.iCardboardScreenSize / 100.0f;
|
||||
float cardboardScreenWidth = pixelWidth_ / 2.0f * cardboardScreenScale;
|
||||
float cardboardScreenHeight = pixelHeight_ / 2.0f * cardboardScreenScale;
|
||||
float cardboardMaxXShift = (pixelWidth_ / 2.0f - cardboardScreenWidth) / 2.0f;
|
||||
float cardboardUserXShift = g_Config.iCardboardXShift / 100.0f * cardboardMaxXShift;
|
||||
float cardboardLeftEyeX = cardboardMaxXShift + cardboardUserXShift;
|
||||
float cardboardRightEyeX = pixelWidth_ / 2.0f + cardboardMaxXShift - cardboardUserXShift;
|
||||
float cardboardMaxYShift = pixelHeight_ / 2.0f - cardboardScreenHeight / 2.0f;
|
||||
float cardboardUserYShift = g_Config.iCardboardYShift / 100.0f * cardboardMaxYShift;
|
||||
float cardboardScreenY = cardboardMaxYShift + cardboardUserYShift;
|
||||
|
||||
cardboardSettings->enabled = g_Config.bEnableCardboard;
|
||||
cardboardSettings->leftEyeXPosition = cardboardLeftEyeX;
|
||||
cardboardSettings->rightEyeXPosition = cardboardRightEyeX;
|
||||
cardboardSettings->screenYPosition = cardboardScreenY;
|
||||
cardboardSettings->screenWidth = cardboardScreenWidth;
|
||||
cardboardSettings->screenHeight = cardboardScreenHeight;
|
||||
}
|
||||
|
||||
Draw::Framebuffer *FramebufferManagerCommon::GetTempFBO(TempFBO reason, u16 w, u16 h, Draw::FBColorDepth depth) {
|
||||
u64 key = ((u64)reason << 48) | ((u64)depth << 32) | ((u32)w << 16) | h;
|
||||
auto it = tempFBOs_.find(key);
|
||||
@@ -2150,6 +2084,11 @@ void FramebufferManagerCommon::DownloadFramebufferForClut(u32 fb_address, u32 lo
|
||||
int w = std::min(pixels % vfb->fb_stride, (int)vfb->width);
|
||||
int h = std::min((pixels + vfb->fb_stride - 1) / vfb->fb_stride, (int)vfb->height);
|
||||
|
||||
if (w == 0 && h > 0) {
|
||||
// Exactly aligned (means pixels == vfb->fb_stride, so modulus gave zero.)
|
||||
w = std::min(vfb->fb_stride, (int)vfb->width);
|
||||
}
|
||||
|
||||
// We might still have a pending draw to the fb in question, flush if so.
|
||||
FlushBeforeCopy();
|
||||
|
||||
|
||||
@@ -46,15 +46,6 @@ namespace Draw {
|
||||
class Framebuffer;
|
||||
}
|
||||
|
||||
struct CardboardSettings {
|
||||
bool enabled;
|
||||
float leftEyeXPosition;
|
||||
float rightEyeXPosition;
|
||||
float screenYPosition;
|
||||
float screenWidth;
|
||||
float screenHeight;
|
||||
};
|
||||
|
||||
class VulkanFBO;
|
||||
|
||||
struct PostShaderUniforms {
|
||||
@@ -325,9 +316,6 @@ protected:
|
||||
virtual void Bind2DShader() = 0;
|
||||
virtual void BindPostShader(const PostShaderUniforms &uniforms) = 0;
|
||||
|
||||
// Cardboard Settings Calculator
|
||||
void GetCardboardSettings(CardboardSettings *cardboardSettings);
|
||||
|
||||
bool UpdateSize();
|
||||
void SetNumExtraFBOs(int num);
|
||||
|
||||
|
||||
@@ -268,6 +268,7 @@
|
||||
<MultiProcessorCompilation>true</MultiProcessorCompilation>
|
||||
<RuntimeTypeInfo>false</RuntimeTypeInfo>
|
||||
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
|
||||
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
@@ -296,6 +297,7 @@
|
||||
<PreprocessorDefinitions>USING_WIN_UI;_CRT_SECURE_NO_WARNINGS;WIN32;_ARCH_64=1;_M_X64=1;_LIB;NDEBUG;_UNICODE;UNICODE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
|
||||
<StringPooling>true</StringPooling>
|
||||
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
@@ -324,6 +326,7 @@
|
||||
<PreprocessorDefinitions>USING_WIN_UI;_CRT_SECURE_NO_WARNINGS;WIN32;_ARCH_64=1;_LIB;NDEBUG;_UNICODE;UNICODE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
|
||||
<StringPooling>true</StringPooling>
|
||||
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
@@ -352,6 +355,7 @@
|
||||
<PreprocessorDefinitions>USING_WIN_UI;_CRT_SECURE_NO_WARNINGS;WIN32;_ARCH_32=1;_LIB;NDEBUG;_UNICODE;UNICODE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
|
||||
<StringPooling>true</StringPooling>
|
||||
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
|
||||
+14
-4
@@ -720,6 +720,8 @@ u32 GPUCommon::EnqueueList(u32 listpc, u32 stall, int subIntrBase, PSPPointer<Ps
|
||||
if (currentList->state != PSP_GE_DL_STATE_PAUSED)
|
||||
return SCE_KERNEL_ERROR_INVALID_VALUE;
|
||||
currentList->state = PSP_GE_DL_STATE_QUEUED;
|
||||
// Make sure we clear the signal so we don't try to pause it again.
|
||||
currentList->signal = PSP_GE_SIGNAL_NONE;
|
||||
}
|
||||
|
||||
dl.state = PSP_GE_DL_STATE_PAUSED;
|
||||
@@ -789,8 +791,7 @@ u32 GPUCommon::Continue() {
|
||||
|
||||
if (currentList->state == PSP_GE_DL_STATE_PAUSED)
|
||||
{
|
||||
if (!isbreak)
|
||||
{
|
||||
if (!isbreak) {
|
||||
// TODO: Supposedly this returns SCE_KERNEL_ERROR_BUSY in some case, previously it had
|
||||
// currentList->signal == PSP_GE_SIGNAL_HANDLER_PAUSE, but it doesn't reproduce.
|
||||
|
||||
@@ -802,9 +803,10 @@ u32 GPUCommon::Continue() {
|
||||
|
||||
// We have a list now, so it's not complete.
|
||||
drawCompleteTicks = (u64)-1;
|
||||
}
|
||||
else
|
||||
} else {
|
||||
currentList->state = PSP_GE_DL_STATE_QUEUED;
|
||||
currentList->signal = PSP_GE_SIGNAL_NONE;
|
||||
}
|
||||
}
|
||||
else if (currentList->state == PSP_GE_DL_STATE_RUNNING)
|
||||
{
|
||||
@@ -2453,6 +2455,14 @@ void GPUCommon::InterruptEnd(int listid) {
|
||||
}
|
||||
dl.waitTicks = 0;
|
||||
__GeTriggerWait(GPU_SYNC_LIST, listid);
|
||||
|
||||
// Make sure the list isn't still queued since it's now completed.
|
||||
if (!dlQueue.empty()) {
|
||||
if (listid == dlQueue.front())
|
||||
PopDLQueue();
|
||||
else
|
||||
dlQueue.remove(listid);
|
||||
}
|
||||
}
|
||||
|
||||
ProcessDLQueue();
|
||||
|
||||
@@ -17,15 +17,12 @@ class GLRenderManager;
|
||||
#if defined(USING_EGL)
|
||||
|
||||
// TODO: Move these into the class.
|
||||
static EGLDisplay g_eglDisplay = NULL;
|
||||
static EGLContext g_eglContext = NULL;
|
||||
static EGLSurface g_eglSurface = NULL;
|
||||
#ifdef USING_FBDEV
|
||||
static EGLNativeDisplayType g_Display = NULL;
|
||||
#else
|
||||
static Display* g_Display = NULL;
|
||||
#endif
|
||||
static NativeWindowType g_Window = (NativeWindowType)NULL;
|
||||
static EGLDisplay g_eglDisplay = EGL_NO_DISPLAY;
|
||||
static EGLContext g_eglContext = nullptr;
|
||||
static EGLSurface g_eglSurface = nullptr;
|
||||
static EGLNativeDisplayType g_Display = nullptr;
|
||||
static bool g_XDisplayOpen = false;
|
||||
static EGLNativeWindowType g_Window = (EGLNativeWindowType)nullptr;
|
||||
|
||||
int CheckEGLErrors(const char *file, int line) {
|
||||
EGLenum error;
|
||||
@@ -59,18 +56,82 @@ int CheckEGLErrors(const char *file, int line) {
|
||||
return 1; \
|
||||
}
|
||||
|
||||
int8_t EGL_Open() {
|
||||
#ifdef USING_FBDEV
|
||||
g_Display = ((EGLNativeDisplayType)0);
|
||||
#else
|
||||
if ((g_Display = XOpenDisplay(NULL)) == NULL)
|
||||
EGL_ERROR("Unable to get display!", false);
|
||||
#endif
|
||||
if ((g_eglDisplay = eglGetDisplay((NativeDisplayType)g_Display)) == EGL_NO_DISPLAY)
|
||||
static bool EGL_OpenInit() {
|
||||
if ((g_eglDisplay = eglGetDisplay(g_Display)) == EGL_NO_DISPLAY) {
|
||||
EGL_ERROR("Unable to create EGL display.", true);
|
||||
if (eglInitialize(g_eglDisplay, NULL, NULL) != EGL_TRUE)
|
||||
return false;
|
||||
}
|
||||
if (eglInitialize(g_eglDisplay, NULL, NULL) != EGL_TRUE) {
|
||||
EGL_ERROR("Unable to initialize EGL display.", true);
|
||||
return 0;
|
||||
eglTerminate(g_eglDisplay);
|
||||
g_eglDisplay = EGL_NO_DISPLAY;
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static int8_t EGL_Open(SDL_Window *window) {
|
||||
#if defined(USING_FBDEV)
|
||||
g_Display = (EGLNativeDisplayType)nullptr;
|
||||
g_Window = (EGLNativeWindowType)nullptr;
|
||||
#elif defined(__APPLE__)
|
||||
g_Display = (EGLNativeDisplayType)XOpenDisplay(nullptr);
|
||||
g_XDisplayOpen = g_Display != nullptr;
|
||||
if (!g_XDisplayOpen)
|
||||
EGL_ERROR("Unable to get display!", false);
|
||||
g_Window = (EGLNativeWindowType)nullptr;
|
||||
#else
|
||||
// Get the SDL window native handle
|
||||
SDL_SysWMinfo sysInfo{};
|
||||
SDL_VERSION(&sysInfo.version);
|
||||
if (!SDL_GetWindowWMInfo(window, &sysInfo)) {
|
||||
printf("ERROR: Unable to retrieve native window handle\n");
|
||||
g_Display = (EGLNativeDisplayType)XOpenDisplay(nullptr);
|
||||
g_XDisplayOpen = g_Display != nullptr;
|
||||
if (!g_XDisplayOpen)
|
||||
EGL_ERROR("Unable to get display!", false);
|
||||
g_Window = (EGLNativeWindowType)nullptr;
|
||||
} else {
|
||||
switch (sysInfo.subsystem) {
|
||||
case SDL_SYSWM_X11:
|
||||
g_Display = (EGLNativeDisplayType)sysInfo.info.x11.display;
|
||||
g_Window = (EGLNativeWindowType)sysInfo.info.x11.window;
|
||||
break;
|
||||
#if defined(SDL_VIDEO_DRIVER_DIRECTFB)
|
||||
case SDL_SYSWM_DIRECTFB:
|
||||
g_Display = (EGLNativeDisplayType)EGL_DEFAULT_DISPLAY;
|
||||
g_Window = (EGLNativeWindowType)sysInfo.info.dfb.surface;
|
||||
break;
|
||||
#endif
|
||||
#if SDL_VERSION_ATLEAST(2, 0, 2) && defined(SDL_VIDEO_DRIVER_WAYLAND)
|
||||
case SDL_SYSWM_WAYLAND:
|
||||
g_Display = (EGLNativeDisplayType)sysInfo.info.wl.display;
|
||||
g_Window = (EGLNativeWindowType)sysInfo.info.wl.shell_surface;
|
||||
break;
|
||||
#endif
|
||||
#if SDL_VERSION_ATLEAST(2, 0, 5) && defined(SDL_VIDEO_DRIVER_VIVANTE)
|
||||
case SDL_SYSWM_VIVANTE:
|
||||
g_Display = (EGLNativeDisplayType)sysInfo.info.vivante.display;
|
||||
g_Window = (EGLNativeWindowType)sysInfo.info.vivante.window;
|
||||
break;
|
||||
#endif
|
||||
}
|
||||
|
||||
if (!EGL_OpenInit()) {
|
||||
// Let's try again with X11.
|
||||
g_Display = (EGLNativeDisplayType)XOpenDisplay(nullptr);
|
||||
g_XDisplayOpen = g_Display != nullptr;
|
||||
if (!g_XDisplayOpen)
|
||||
EGL_ERROR("Unable to get display!", false);
|
||||
g_Window = (EGLNativeWindowType)nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
if (g_eglDisplay == EGL_NO_DISPLAY)
|
||||
EGL_OpenInit();
|
||||
return g_eglDisplay == EGL_NO_DISPLAY ? 1 : 0;
|
||||
}
|
||||
|
||||
#ifndef EGL_OPENGL_ES3_BIT_KHR
|
||||
@@ -193,15 +254,6 @@ int8_t EGL_Init(SDL_Window *window) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
#if !defined(USING_FBDEV) && !defined(__APPLE__)
|
||||
// Get the SDL window handle
|
||||
SDL_SysWMinfo sysInfo; //Will hold our Window information
|
||||
SDL_VERSION(&sysInfo.version); //Set SDL version
|
||||
SDL_GetWindowWMInfo(window, &sysInfo);
|
||||
g_Window = (NativeWindowType)sysInfo.info.x11.window;
|
||||
#else
|
||||
g_Window = (NativeWindowType)NULL;
|
||||
#endif
|
||||
g_eglSurface = eglCreateWindowSurface(g_eglDisplay, eglConfig, g_Window, nullptr);
|
||||
if (g_eglSurface == EGL_NO_SURFACE) {
|
||||
EGL_ERROR("Unable to create EGL surface!", true);
|
||||
@@ -217,7 +269,7 @@ int8_t EGL_Init(SDL_Window *window) {
|
||||
}
|
||||
|
||||
void EGL_Close() {
|
||||
if (g_eglDisplay != NULL) {
|
||||
if (g_eglDisplay != EGL_NO_DISPLAY) {
|
||||
eglMakeCurrent(g_eglDisplay, NULL, NULL, EGL_NO_CONTEXT);
|
||||
if (g_eglContext != NULL) {
|
||||
eglDestroyContext(g_eglDisplay, g_eglContext);
|
||||
@@ -226,13 +278,15 @@ void EGL_Close() {
|
||||
eglDestroySurface(g_eglDisplay, g_eglSurface);
|
||||
}
|
||||
eglTerminate(g_eglDisplay);
|
||||
g_eglDisplay = NULL;
|
||||
g_eglDisplay = EGL_NO_DISPLAY;
|
||||
}
|
||||
if (g_Display != NULL) {
|
||||
if (g_Display != nullptr) {
|
||||
#if !defined(USING_FBDEV)
|
||||
XCloseDisplay(g_Display);
|
||||
if (g_XDisplayOpen)
|
||||
XCloseDisplay((Display *)g_Display);
|
||||
#endif
|
||||
g_Display = NULL;
|
||||
g_XDisplayOpen = false;
|
||||
g_Display = nullptr;
|
||||
}
|
||||
g_eglSurface = NULL;
|
||||
g_eglContext = NULL;
|
||||
@@ -320,6 +374,10 @@ int SDLGLGraphicsContext::Init(SDL_Window *&window, int x, int y, int mode, std:
|
||||
SDL_ShowWindow(window);
|
||||
|
||||
#ifdef USING_EGL
|
||||
if (EGL_Open(window) != 0) {
|
||||
printf("EGL_Open() failed\n");
|
||||
return 1;
|
||||
}
|
||||
if (EGL_Init(window) != 0) {
|
||||
printf("EGL_Init() failed\n");
|
||||
return 1;
|
||||
|
||||
@@ -7,11 +7,6 @@
|
||||
#include "gfx/gl_common.h"
|
||||
#include "Common/GraphicsContext.h"
|
||||
|
||||
// TODO: Move this to a better place.
|
||||
#if defined(USING_EGL)
|
||||
int8_t EGL_Open();
|
||||
#endif
|
||||
|
||||
class SDLGLGraphicsContext : public DummyGraphicsContext {
|
||||
public:
|
||||
SDLGLGraphicsContext() {
|
||||
@@ -54,5 +49,3 @@ private:
|
||||
SDL_GLContext glContext = nullptr;
|
||||
GLRenderManager *renderManager_ = nullptr;
|
||||
};
|
||||
|
||||
|
||||
@@ -426,12 +426,6 @@ int main(int argc, char *argv[]) {
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: How do we get this into the GraphicsContext?
|
||||
#ifdef USING_EGL
|
||||
if (EGL_Open())
|
||||
return 1;
|
||||
#endif
|
||||
|
||||
// Get the video info before doing anything else, so we don't get skewed resolution results.
|
||||
// TODO: support multiple displays correctly
|
||||
SDL_DisplayMode displayMode;
|
||||
|
||||
@@ -466,18 +466,6 @@ void GameSettingsScreen::CreateViews() {
|
||||
static const char *bufFilters[] = { "Linear", "Nearest", };
|
||||
graphicsSettings->Add(new PopupMultiChoice(&g_Config.iBufFilter, gr->T("Screen Scaling Filter"), bufFilters, 1, ARRAY_SIZE(bufFilters), gr->GetName(), screenManager()));
|
||||
|
||||
#ifdef __ANDROID__
|
||||
graphicsSettings->Add(new ItemHeader(gr->T("Cardboard Settings", "Cardboard Settings")));
|
||||
CheckBox *cardboardMode = graphicsSettings->Add(new CheckBox(&g_Config.bEnableCardboard, gr->T("Enable Cardboard", "Enable Cardboard")));
|
||||
cardboardMode->SetDisabledPtr(&g_Config.bSoftwareRendering);
|
||||
PopupSliderChoice * cardboardScreenSize = graphicsSettings->Add(new PopupSliderChoice(&g_Config.iCardboardScreenSize, 30, 100, gr->T("Cardboard Screen Size", "Screen Size (in % of the viewport)"), 1, screenManager(), gr->T("% of viewport")));
|
||||
cardboardScreenSize->SetDisabledPtr(&g_Config.bSoftwareRendering);
|
||||
PopupSliderChoice *cardboardXShift = graphicsSettings->Add(new PopupSliderChoice(&g_Config.iCardboardXShift, -100, 100, gr->T("Cardboard Screen X Shift", "X Shift (in % of the void)"), 1, screenManager(), gr->T("% of the void")));
|
||||
cardboardXShift->SetDisabledPtr(&g_Config.bSoftwareRendering);
|
||||
PopupSliderChoice *cardboardYShift = graphicsSettings->Add(new PopupSliderChoice(&g_Config.iCardboardYShift, -100, 100, gr->T("Cardboard Screen Y Shift", "Y Shift (in % of the void)"), 1, screenManager(), gr->T("% of the void")));
|
||||
cardboardYShift->SetDisabledPtr(&g_Config.bSoftwareRendering);
|
||||
#endif
|
||||
|
||||
graphicsSettings->Add(new ItemHeader(gr->T("Hack Settings")));
|
||||
|
||||
static const char *bloomHackOptions[] = { "Off", "Safe", "Balanced", "Aggressive" };
|
||||
|
||||
+31
-18
@@ -42,24 +42,34 @@ void InstallZipScreen::CreateViews() {
|
||||
root_ = new LinearLayout(ORIENT_HORIZONTAL);
|
||||
|
||||
ViewGroup *leftColumn = new AnchorLayout(new LinearLayoutParams(1.0f));
|
||||
root_->Add(leftColumn);
|
||||
|
||||
std::string shortFilename = GetFilenameFromPath(zipPath_);
|
||||
leftColumn->Add(new TextView(iz->T("Install game from ZIP file?"), ALIGN_LEFT, false, new AnchorLayoutParams(10, 10, NONE, NONE)));
|
||||
leftColumn->Add(new TextView(shortFilename, ALIGN_LEFT, false, new AnchorLayoutParams(10, 60, NONE, NONE)));
|
||||
|
||||
doneView_ = leftColumn->Add(new TextView("", new AnchorLayoutParams(10, 120, NONE, NONE)));
|
||||
progressBar_ = leftColumn->Add(new ProgressBar(new AnchorLayoutParams(10, 200, 200, NONE)));
|
||||
|
||||
ViewGroup *rightColumnItems = new LinearLayout(ORIENT_VERTICAL, new LinearLayoutParams(300, FILL_PARENT, actionMenuMargins));
|
||||
root_->Add(leftColumn);
|
||||
root_->Add(rightColumnItems);
|
||||
|
||||
installChoice_ = rightColumnItems->Add(new Choice(iz->T("Install")));
|
||||
installChoice_->OnClick.Handle(this, &InstallZipScreen::OnInstall);
|
||||
backChoice_ = rightColumnItems->Add(new Choice(di->T("Back")));
|
||||
backChoice_->OnClick.Handle<UIScreen>(this, &UIScreen::OnOK); // OK so that EmuScreen will handle it right
|
||||
std::string shortFilename = GetFilenameFromPath(zipPath_);
|
||||
|
||||
// TODO: Do in the background?
|
||||
ZipFileInfo zipInfo;
|
||||
ZipFileContents contents = DetectZipFileContents(zipPath_, &zipInfo);
|
||||
|
||||
rightColumnItems->Add(new CheckBox(&deleteZipFile_, iz->T("Delete ZIP file")));
|
||||
if (contents == ZipFileContents::ISO_FILE || contents == ZipFileContents::PSP_GAME_DIR) {
|
||||
std::string question = iz->T("Install game from ZIP file?");
|
||||
leftColumn->Add(new TextView(question, ALIGN_LEFT, false, new AnchorLayoutParams(10, 10, NONE, NONE)));
|
||||
leftColumn->Add(new TextView(shortFilename, ALIGN_LEFT, false, new AnchorLayoutParams(10, 60, NONE, NONE)));
|
||||
|
||||
doneView_ = leftColumn->Add(new TextView("", new AnchorLayoutParams(10, 120, NONE, NONE)));
|
||||
progressBar_ = leftColumn->Add(new ProgressBar(new AnchorLayoutParams(10, 200, 200, NONE)));
|
||||
|
||||
installChoice_ = rightColumnItems->Add(new Choice(iz->T("Install")));
|
||||
installChoice_->OnClick.Handle(this, &InstallZipScreen::OnInstall);
|
||||
backChoice_ = rightColumnItems->Add(new Choice(di->T("Back")));
|
||||
backChoice_->OnClick.Handle<UIScreen>(this, &UIScreen::OnOK); // OK so that EmuScreen will handle it right
|
||||
rightColumnItems->Add(new CheckBox(&deleteZipFile_, iz->T("Delete ZIP file")));
|
||||
} else {
|
||||
leftColumn->Add(new TextView(iz->T("Zip file does not contain PSP software"), ALIGN_LEFT, false, new AnchorLayoutParams(10, 10, NONE, NONE)));
|
||||
backChoice_ = rightColumnItems->Add(new Choice(di->T("Back")));
|
||||
backChoice_->OnClick.Handle<UIScreen>(this, &UIScreen::OnOK); // OK so that EmuScreen will handle it right
|
||||
}
|
||||
}
|
||||
|
||||
bool InstallZipScreen::key(const KeyInput &key) {
|
||||
@@ -71,7 +81,7 @@ bool InstallZipScreen::key(const KeyInput &key) {
|
||||
}
|
||||
|
||||
UI::EventReturn InstallZipScreen::OnInstall(UI::EventParams ¶ms) {
|
||||
if (g_GameManager.InstallGameOnThread(zipPath_, deleteZipFile_)) {
|
||||
if (g_GameManager.InstallGameOnThread(zipPath_, zipPath_, deleteZipFile_)) {
|
||||
installStarted_ = true;
|
||||
installChoice_->SetEnabled(false);
|
||||
}
|
||||
@@ -87,13 +97,16 @@ void InstallZipScreen::update() {
|
||||
progressBar_->SetProgress(g_GameManager.GetCurrentInstallProgressPercentage());
|
||||
backChoice_->SetEnabled(false);
|
||||
} else {
|
||||
progressBar_->SetVisibility(V_GONE);
|
||||
if (progressBar_)
|
||||
progressBar_->SetVisibility(V_GONE);
|
||||
backChoice_->SetEnabled(true);
|
||||
std::string err = g_GameManager.GetInstallError();
|
||||
if (!err.empty()) {
|
||||
doneView_->SetText(iz->T(err.c_str()));
|
||||
if (doneView_)
|
||||
doneView_->SetText(iz->T(err.c_str()));
|
||||
} else if (installStarted_) {
|
||||
doneView_->SetText(iz->T("Installed!"));
|
||||
if (doneView_)
|
||||
doneView_->SetText(iz->T("Installed!"));
|
||||
MainScreen::showHomebrewTab = true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -26,7 +26,7 @@
|
||||
|
||||
class InstallZipScreen : public UIDialogScreenWithBackground {
|
||||
public:
|
||||
InstallZipScreen(std::string zipPath) : installChoice_(0), doneView_(0), zipPath_(zipPath), installStarted_(false), deleteZipFile_(false) {}
|
||||
InstallZipScreen(std::string zipPath) : zipPath_(zipPath) {}
|
||||
virtual void update() override;
|
||||
virtual bool key(const KeyInput &key) override;
|
||||
|
||||
@@ -36,12 +36,12 @@ protected:
|
||||
private:
|
||||
UI::EventReturn OnInstall(UI::EventParams ¶ms);
|
||||
|
||||
UI::Choice *installChoice_;
|
||||
UI::Choice *backChoice_;
|
||||
UI::ProgressBar *progressBar_;
|
||||
UI::TextView *doneView_;
|
||||
UI::Choice *installChoice_ = nullptr;
|
||||
UI::Choice *backChoice_ = nullptr;
|
||||
UI::ProgressBar *progressBar_ = nullptr;
|
||||
UI::TextView *doneView_ = nullptr;
|
||||
std::string zipPath_;
|
||||
bool installStarted_;
|
||||
bool deleteZipFile_;
|
||||
bool installStarted_ = false;
|
||||
bool deleteZipFile_ = false;
|
||||
};
|
||||
|
||||
+8
-5
@@ -284,13 +284,16 @@ void ProductView::Update() {
|
||||
}
|
||||
|
||||
UI::EventReturn ProductView::OnInstall(UI::EventParams &e) {
|
||||
std::string zipUrl;
|
||||
std::string fileUrl;
|
||||
if (entry_.downloadURL.empty()) {
|
||||
// Construct the URL, easy to predict from our server
|
||||
zipUrl = storeBaseUrl + "files/" + entry_.file + ".zip";
|
||||
std::string shortName = entry_.file;
|
||||
if (shortName.find('.') == std::string::npos)
|
||||
shortName += ".zip";
|
||||
fileUrl = storeBaseUrl + "files/" + shortName;
|
||||
} else {
|
||||
// Use the provided URL, for external hosting.
|
||||
zipUrl = entry_.downloadURL;
|
||||
fileUrl = entry_.downloadURL;
|
||||
}
|
||||
if (installButton_) {
|
||||
installButton_->SetEnabled(false);
|
||||
@@ -298,8 +301,8 @@ UI::EventReturn ProductView::OnInstall(UI::EventParams &e) {
|
||||
if (cancelButton_) {
|
||||
cancelButton_->SetVisibility(UI::V_VISIBLE);
|
||||
}
|
||||
INFO_LOG(SYSTEM, "Triggering install of %s", zipUrl.c_str());
|
||||
g_GameManager.DownloadAndInstall(zipUrl);
|
||||
INFO_LOG(SYSTEM, "Triggering install of '%s'", fileUrl.c_str());
|
||||
g_GameManager.DownloadAndInstall(fileUrl);
|
||||
return UI::EVENT_DONE;
|
||||
}
|
||||
|
||||
|
||||
@@ -317,6 +317,7 @@
|
||||
<RuntimeTypeInfo>false</RuntimeTypeInfo>
|
||||
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
|
||||
<AdditionalOptions>$(EXTERNAL_COMPILE_OPTIONS)</AdditionalOptions>
|
||||
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Windows</SubSystem>
|
||||
@@ -347,6 +348,7 @@
|
||||
<AdditionalOptions>$(EXTERNAL_COMPILE_OPTIONS)</AdditionalOptions>
|
||||
<OmitFramePointers>false</OmitFramePointers>
|
||||
<FavorSizeOrSpeed>Size</FavorSizeOrSpeed>
|
||||
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Windows</SubSystem>
|
||||
@@ -377,6 +379,7 @@
|
||||
<AdditionalOptions>$(EXTERNAL_COMPILE_OPTIONS)</AdditionalOptions>
|
||||
<OmitFramePointers>false</OmitFramePointers>
|
||||
<FavorSizeOrSpeed>Size</FavorSizeOrSpeed>
|
||||
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Windows</SubSystem>
|
||||
@@ -407,6 +410,7 @@
|
||||
<AdditionalOptions>$(EXTERNAL_COMPILE_OPTIONS)</AdditionalOptions>
|
||||
<OmitFramePointers>false</OmitFramePointers>
|
||||
<FavorSizeOrSpeed>Size</FavorSizeOrSpeed>
|
||||
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Windows</SubSystem>
|
||||
|
||||
+3
-7
@@ -38,7 +38,7 @@
|
||||
UWPHost::UWPHost() {
|
||||
|
||||
// add first XInput device to respond
|
||||
input.push_back(std::shared_ptr<InputDevice>(new XinputDevice()));
|
||||
input.push_back(std::make_unique<XinputDevice>());
|
||||
}
|
||||
|
||||
UWPHost::~UWPHost() {
|
||||
@@ -86,14 +86,10 @@ void UWPHost::SetDebugMode(bool mode) {
|
||||
}
|
||||
|
||||
void UWPHost::PollControllers() {
|
||||
bool doPad = true;
|
||||
for (auto iter = this->input.begin(); iter != this->input.end(); iter++)
|
||||
for (const auto& device : this->input)
|
||||
{
|
||||
auto device = *iter;
|
||||
if (!doPad && device->IsPad())
|
||||
continue;
|
||||
if (device->UpdateState() == InputDevice::UPDATESTATE_SKIP_PAD)
|
||||
doPad = false;
|
||||
break;
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
+1
-1
@@ -45,5 +45,5 @@ private:
|
||||
void SetConsolePosition();
|
||||
void UpdateConsolePosition();
|
||||
|
||||
std::list<std::shared_ptr<InputDevice>> input;
|
||||
std::list<std::unique_ptr<InputDevice>> input;
|
||||
};
|
||||
@@ -24,7 +24,7 @@
|
||||
#include "InputDevice.h"
|
||||
#include "dinput.h"
|
||||
|
||||
class DinputDevice :
|
||||
class DinputDevice final :
|
||||
public InputDevice
|
||||
{
|
||||
public:
|
||||
@@ -32,8 +32,7 @@ public:
|
||||
//getDevices(), enumerates all devices if not done yet
|
||||
DinputDevice(int devnum);
|
||||
~DinputDevice();
|
||||
virtual int UpdateState();
|
||||
virtual bool IsPad() { return true; }
|
||||
virtual int UpdateState() override;
|
||||
static size_t getNumPads();
|
||||
static void CheckDevices() {
|
||||
needsCheck_ = true;
|
||||
|
||||
@@ -193,7 +193,6 @@ CGEDebugger::CGEDebugger(HINSTANCE _hInstance, HWND _hParent)
|
||||
}
|
||||
|
||||
CGEDebugger::~CGEDebugger() {
|
||||
DestroyWindow(displayList->GetHWND());
|
||||
CleanupPrimPreview();
|
||||
delete flags;
|
||||
delete lighting;
|
||||
|
||||
+12
-30
@@ -15,28 +15,21 @@
|
||||
// Official git repository and contact information can be found at
|
||||
// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/.
|
||||
|
||||
#include <list>
|
||||
#include <thread>
|
||||
#include <memory>
|
||||
#include <mutex>
|
||||
#include <condition_variable>
|
||||
#include <atomic>
|
||||
|
||||
#include "input/input_state.h"
|
||||
#include "thread/threadutil.h"
|
||||
#include "Core/Config.h"
|
||||
#include "Core/Host.h"
|
||||
#include "Windows/InputDevice.h"
|
||||
#include "Windows/WindowsHost.h"
|
||||
|
||||
static volatile bool inputThreadStatus = false;
|
||||
static volatile bool inputThreadEnabled = false;
|
||||
static std::thread *inputThread = NULL;
|
||||
static std::mutex inputMutex;
|
||||
static std::condition_variable inputEndCond;
|
||||
static bool focused = true;
|
||||
static std::atomic_flag threadRunningFlag;
|
||||
static std::thread inputThread;
|
||||
static std::atomic_bool focused = true;
|
||||
|
||||
inline static void ExecuteInputPoll() {
|
||||
if (host && (focused || !g_Config.bGamepadOnlyFocused)) {
|
||||
if (host && (focused.load(std::memory_order_relaxed) || !g_Config.bGamepadOnlyFocused)) {
|
||||
host->PollControllers();
|
||||
}
|
||||
}
|
||||
@@ -47,40 +40,29 @@ static void RunInputThread() {
|
||||
// NOTE: The keyboard and mouse buttons are handled via raw input, not here.
|
||||
// This is mainly for controllers which need to be polled, instead of generating events.
|
||||
|
||||
while (inputThreadEnabled) {
|
||||
while (threadRunningFlag.test_and_set(std::memory_order_relaxed)) {
|
||||
ExecuteInputPoll();
|
||||
|
||||
// Try to update 250 times per second.
|
||||
Sleep(4);
|
||||
}
|
||||
|
||||
std::lock_guard<std::mutex> guard(inputMutex);
|
||||
inputThreadStatus = false;
|
||||
inputEndCond.notify_one();
|
||||
}
|
||||
|
||||
void InputDevice::BeginPolling() {
|
||||
std::lock_guard<std::mutex> guard(inputMutex);
|
||||
inputThreadEnabled = true;
|
||||
inputThread = new std::thread(&RunInputThread);
|
||||
inputThread->detach();
|
||||
threadRunningFlag.test_and_set(std::memory_order_relaxed);
|
||||
inputThread = std::thread(&RunInputThread);
|
||||
}
|
||||
|
||||
void InputDevice::StopPolling() {
|
||||
inputThreadEnabled = false;
|
||||
threadRunningFlag.clear(std::memory_order_relaxed);
|
||||
|
||||
std::unique_lock<std::mutex> guard(inputMutex);
|
||||
if (inputThreadStatus) {
|
||||
inputEndCond.wait(guard);
|
||||
}
|
||||
delete inputThread;
|
||||
inputThread = NULL;
|
||||
inputThread.join();
|
||||
}
|
||||
|
||||
void InputDevice::GainFocus() {
|
||||
focused = true;
|
||||
focused.store(true, std::memory_order_relaxed);
|
||||
}
|
||||
|
||||
void InputDevice::LoseFocus() {
|
||||
focused = false;
|
||||
focused.store(false, std::memory_order_relaxed);
|
||||
}
|
||||
@@ -26,7 +26,6 @@ class InputDevice {
|
||||
public:
|
||||
enum { UPDATESTATE_SKIP_PAD = 0x1234};
|
||||
virtual int UpdateState() = 0;
|
||||
virtual bool IsPad() = 0;
|
||||
|
||||
static void BeginPolling();
|
||||
static void StopPolling();
|
||||
|
||||
@@ -1,126 +0,0 @@
|
||||
#include "base/NativeApp.h"
|
||||
#include "input/input_state.h"
|
||||
#include "input/keycodes.h"
|
||||
#include "util/const_map.h"
|
||||
#include "KeyMap.h"
|
||||
#include "KeyboardDevice.h"
|
||||
#include "../Common/CommonTypes.h"
|
||||
#include "../Common/CommonWindows.h"
|
||||
|
||||
|
||||
// TODO: More keys need to be added, but this is more than
|
||||
// a fair start.
|
||||
std::map<int, int> windowsTransTable = InitConstMap<int, int>
|
||||
('A', NKCODE_A)
|
||||
('B', NKCODE_B)
|
||||
('C', NKCODE_C)
|
||||
('D', NKCODE_D)
|
||||
('E', NKCODE_E)
|
||||
('F', NKCODE_F)
|
||||
('G', NKCODE_G)
|
||||
('H', NKCODE_H)
|
||||
('I', NKCODE_I)
|
||||
('J', NKCODE_J)
|
||||
('K', NKCODE_K)
|
||||
('L', NKCODE_L)
|
||||
('M', NKCODE_M)
|
||||
('N', NKCODE_N)
|
||||
('O', NKCODE_O)
|
||||
('P', NKCODE_P)
|
||||
('Q', NKCODE_Q)
|
||||
('R', NKCODE_R)
|
||||
('S', NKCODE_S)
|
||||
('T', NKCODE_T)
|
||||
('U', NKCODE_U)
|
||||
('V', NKCODE_V)
|
||||
('W', NKCODE_W)
|
||||
('X', NKCODE_X)
|
||||
('Y', NKCODE_Y)
|
||||
('Z', NKCODE_Z)
|
||||
('0', NKCODE_0)
|
||||
('1', NKCODE_1)
|
||||
('2', NKCODE_2)
|
||||
('3', NKCODE_3)
|
||||
('4', NKCODE_4)
|
||||
('5', NKCODE_5)
|
||||
('6', NKCODE_6)
|
||||
('7', NKCODE_7)
|
||||
('8', NKCODE_8)
|
||||
('9', NKCODE_9)
|
||||
(VK_OEM_PERIOD, NKCODE_PERIOD)
|
||||
(VK_OEM_COMMA, NKCODE_COMMA)
|
||||
(VK_NUMPAD0, NKCODE_NUMPAD_0)
|
||||
(VK_NUMPAD1, NKCODE_NUMPAD_1)
|
||||
(VK_NUMPAD2, NKCODE_NUMPAD_2)
|
||||
(VK_NUMPAD3, NKCODE_NUMPAD_3)
|
||||
(VK_NUMPAD4, NKCODE_NUMPAD_4)
|
||||
(VK_NUMPAD5, NKCODE_NUMPAD_5)
|
||||
(VK_NUMPAD6, NKCODE_NUMPAD_6)
|
||||
(VK_NUMPAD7, NKCODE_NUMPAD_7)
|
||||
(VK_NUMPAD8, NKCODE_NUMPAD_8)
|
||||
(VK_NUMPAD9, NKCODE_NUMPAD_9)
|
||||
(VK_DECIMAL, NKCODE_NUMPAD_DOT)
|
||||
(VK_DIVIDE, NKCODE_NUMPAD_DIVIDE)
|
||||
(VK_MULTIPLY, NKCODE_NUMPAD_MULTIPLY)
|
||||
(VK_SUBTRACT, NKCODE_NUMPAD_SUBTRACT)
|
||||
(VK_ADD, NKCODE_NUMPAD_ADD)
|
||||
(VK_SEPARATOR, NKCODE_NUMPAD_COMMA)
|
||||
(VK_OEM_MINUS, NKCODE_MINUS)
|
||||
(VK_OEM_PLUS, NKCODE_PLUS)
|
||||
(VK_LCONTROL, NKCODE_CTRL_LEFT)
|
||||
(VK_RCONTROL, NKCODE_CTRL_RIGHT)
|
||||
(VK_LSHIFT, NKCODE_SHIFT_LEFT)
|
||||
(VK_RSHIFT, NKCODE_SHIFT_RIGHT)
|
||||
(VK_LMENU, NKCODE_ALT_LEFT)
|
||||
(VK_RMENU, NKCODE_ALT_RIGHT)
|
||||
(VK_BACK, NKCODE_DEL) // yes! http://stackoverflow.com/questions/4886858/android-edittext-deletebackspace-key-event
|
||||
(VK_SPACE, NKCODE_SPACE)
|
||||
(VK_ESCAPE, NKCODE_ESCAPE)
|
||||
(VK_UP, NKCODE_DPAD_UP)
|
||||
(VK_INSERT, NKCODE_INSERT)
|
||||
(VK_HOME, NKCODE_MOVE_HOME)
|
||||
(VK_PRIOR, NKCODE_PAGE_UP)
|
||||
(VK_NEXT, NKCODE_PAGE_DOWN)
|
||||
(VK_DELETE, NKCODE_FORWARD_DEL)
|
||||
(VK_END, NKCODE_MOVE_END)
|
||||
(VK_TAB, NKCODE_TAB)
|
||||
(VK_DOWN, NKCODE_DPAD_DOWN)
|
||||
(VK_LEFT, NKCODE_DPAD_LEFT)
|
||||
(VK_RIGHT, NKCODE_DPAD_RIGHT)
|
||||
(VK_CAPITAL, NKCODE_CAPS_LOCK)
|
||||
(VK_CLEAR, NKCODE_CLEAR)
|
||||
(VK_SNAPSHOT, NKCODE_SYSRQ)
|
||||
(VK_SCROLL, NKCODE_SCROLL_LOCK)
|
||||
(VK_OEM_1, NKCODE_SEMICOLON)
|
||||
(VK_OEM_2, NKCODE_SLASH)
|
||||
(VK_OEM_3, NKCODE_GRAVE)
|
||||
(VK_OEM_4, NKCODE_LEFT_BRACKET)
|
||||
(VK_OEM_5, NKCODE_BACKSLASH)
|
||||
(VK_OEM_6, NKCODE_RIGHT_BRACKET)
|
||||
(VK_OEM_7, NKCODE_APOSTROPHE)
|
||||
(VK_RETURN, NKCODE_ENTER)
|
||||
(VK_APPS, NKCODE_MENU) // Context menu key, let's call this "menu".
|
||||
(VK_PAUSE, NKCODE_BREAK)
|
||||
(VK_F1, NKCODE_F1)
|
||||
(VK_F2, NKCODE_F2)
|
||||
(VK_F3, NKCODE_F3)
|
||||
(VK_F4, NKCODE_F4)
|
||||
(VK_F5, NKCODE_F5)
|
||||
(VK_F6, NKCODE_F6)
|
||||
(VK_F7, NKCODE_F7)
|
||||
(VK_F8, NKCODE_F8)
|
||||
(VK_F9, NKCODE_F9)
|
||||
(VK_F10, NKCODE_F10)
|
||||
(VK_F11, NKCODE_F11)
|
||||
(VK_F12, NKCODE_F12)
|
||||
(VK_OEM_102, NKCODE_EXT_PIPE)
|
||||
(VK_LBUTTON, NKCODE_EXT_MOUSEBUTTON_1)
|
||||
(VK_RBUTTON, NKCODE_EXT_MOUSEBUTTON_2)
|
||||
(VK_MBUTTON, NKCODE_EXT_MOUSEBUTTON_3)
|
||||
(VK_XBUTTON1, NKCODE_EXT_MOUSEBUTTON_4)
|
||||
(VK_XBUTTON2, NKCODE_EXT_MOUSEBUTTON_5);
|
||||
|
||||
int KeyboardDevice::UpdateState() {
|
||||
// Nothing to do, all done in WM_INPUT
|
||||
return 0;
|
||||
}
|
||||
@@ -1,14 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <map>
|
||||
#include "InputDevice.h"
|
||||
|
||||
extern std::map<int, int> windowsTransTable;
|
||||
|
||||
class KeyboardDevice : public InputDevice {
|
||||
public:
|
||||
virtual int UpdateState();
|
||||
virtual bool IsPad() { return false; }
|
||||
|
||||
private:
|
||||
};
|
||||
@@ -1,4 +1,4 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup Label="ProjectConfigurations">
|
||||
<ProjectConfiguration Include="Debug|ARM">
|
||||
@@ -740,7 +740,6 @@
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|ARM'">true</ExcludedFromBuild>
|
||||
</ClCompile>
|
||||
<ClCompile Include="InputDevice.cpp" />
|
||||
<ClCompile Include="KeyboardDevice.cpp" />
|
||||
<ClCompile Include="MainWindowMenu.cpp" />
|
||||
<ClCompile Include="RawInput.cpp" />
|
||||
<ClCompile Include="TouchInputHandler.cpp" />
|
||||
@@ -926,7 +925,6 @@
|
||||
</ClInclude>
|
||||
<ClInclude Include="GPU\WindowsGraphicsContext.h" />
|
||||
<ClInclude Include="InputDevice.h" />
|
||||
<ClInclude Include="KeyboardDevice.h" />
|
||||
<ClInclude Include="MainWindowMenu.h" />
|
||||
<ClInclude Include="RawInput.h" />
|
||||
<ClInclude Include="TouchInputHandler.h" />
|
||||
|
||||
@@ -82,9 +82,6 @@
|
||||
<ClCompile Include="XinputDevice.cpp">
|
||||
<Filter>Windows\Input</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="KeyboardDevice.cpp">
|
||||
<Filter>Windows\Input</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="InputDevice.cpp">
|
||||
<Filter>Windows\Input</Filter>
|
||||
</ClCompile>
|
||||
@@ -246,9 +243,6 @@
|
||||
<ClInclude Include="XinputDevice.h">
|
||||
<Filter>Windows\Input</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="KeyboardDevice.h">
|
||||
<Filter>Windows\Input</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="stdafx.h" />
|
||||
<ClInclude Include="..\android\jni\ArmEmitterTest.h">
|
||||
<Filter>Other Platforms</Filter>
|
||||
|
||||
+113
-1
@@ -24,7 +24,6 @@
|
||||
#include "input/input_state.h"
|
||||
#include "Common/Log.h"
|
||||
#include "Windows/RawInput.h"
|
||||
#include "Windows/KeyboardDevice.h"
|
||||
#include "Windows/MainWindow.h"
|
||||
#include "Windows/WindowsHost.h"
|
||||
#include "Common/CommonFuncs.h"
|
||||
@@ -65,6 +64,119 @@ namespace WindowsRawInput {
|
||||
static float mouseX = 0.0f;
|
||||
static float mouseY = 0.0f;
|
||||
|
||||
// TODO: More keys need to be added, but this is more than
|
||||
// a fair start.
|
||||
static std::map<int, int> windowsTransTable = {
|
||||
{ 'A', NKCODE_A },
|
||||
{ 'B', NKCODE_B },
|
||||
{ 'C', NKCODE_C },
|
||||
{ 'D', NKCODE_D },
|
||||
{ 'E', NKCODE_E },
|
||||
{ 'F', NKCODE_F },
|
||||
{ 'G', NKCODE_G },
|
||||
{ 'H', NKCODE_H },
|
||||
{ 'I', NKCODE_I },
|
||||
{ 'J', NKCODE_J },
|
||||
{ 'K', NKCODE_K },
|
||||
{ 'L', NKCODE_L },
|
||||
{ 'M', NKCODE_M },
|
||||
{ 'N', NKCODE_N },
|
||||
{ 'O', NKCODE_O },
|
||||
{ 'P', NKCODE_P },
|
||||
{ 'Q', NKCODE_Q },
|
||||
{ 'R', NKCODE_R },
|
||||
{ 'S', NKCODE_S },
|
||||
{ 'T', NKCODE_T },
|
||||
{ 'U', NKCODE_U },
|
||||
{ 'V', NKCODE_V },
|
||||
{ 'W', NKCODE_W },
|
||||
{ 'X', NKCODE_X },
|
||||
{ 'Y', NKCODE_Y },
|
||||
{ 'Z', NKCODE_Z },
|
||||
{ '0', NKCODE_0 },
|
||||
{ '1', NKCODE_1 },
|
||||
{ '2', NKCODE_2 },
|
||||
{ '3', NKCODE_3 },
|
||||
{ '4', NKCODE_4 },
|
||||
{ '5', NKCODE_5 },
|
||||
{ '6', NKCODE_6 },
|
||||
{ '7', NKCODE_7 },
|
||||
{ '8', NKCODE_8 },
|
||||
{ '9', NKCODE_9 },
|
||||
{ VK_OEM_PERIOD, NKCODE_PERIOD },
|
||||
{ VK_OEM_COMMA, NKCODE_COMMA },
|
||||
{ VK_NUMPAD0, NKCODE_NUMPAD_0 },
|
||||
{ VK_NUMPAD1, NKCODE_NUMPAD_1 },
|
||||
{ VK_NUMPAD2, NKCODE_NUMPAD_2 },
|
||||
{ VK_NUMPAD3, NKCODE_NUMPAD_3 },
|
||||
{ VK_NUMPAD4, NKCODE_NUMPAD_4 },
|
||||
{ VK_NUMPAD5, NKCODE_NUMPAD_5 },
|
||||
{ VK_NUMPAD6, NKCODE_NUMPAD_6 },
|
||||
{ VK_NUMPAD7, NKCODE_NUMPAD_7 },
|
||||
{ VK_NUMPAD8, NKCODE_NUMPAD_8 },
|
||||
{ VK_NUMPAD9, NKCODE_NUMPAD_9 },
|
||||
{ VK_DECIMAL, NKCODE_NUMPAD_DOT },
|
||||
{ VK_DIVIDE, NKCODE_NUMPAD_DIVIDE },
|
||||
{ VK_MULTIPLY, NKCODE_NUMPAD_MULTIPLY },
|
||||
{ VK_SUBTRACT, NKCODE_NUMPAD_SUBTRACT },
|
||||
{ VK_ADD, NKCODE_NUMPAD_ADD },
|
||||
{ VK_SEPARATOR, NKCODE_NUMPAD_COMMA },
|
||||
{ VK_OEM_MINUS, NKCODE_MINUS },
|
||||
{ VK_OEM_PLUS, NKCODE_PLUS },
|
||||
{ VK_LCONTROL, NKCODE_CTRL_LEFT },
|
||||
{ VK_RCONTROL, NKCODE_CTRL_RIGHT },
|
||||
{ VK_LSHIFT, NKCODE_SHIFT_LEFT },
|
||||
{ VK_RSHIFT, NKCODE_SHIFT_RIGHT },
|
||||
{ VK_LMENU, NKCODE_ALT_LEFT },
|
||||
{ VK_RMENU, NKCODE_ALT_RIGHT },
|
||||
{ VK_BACK, NKCODE_DEL }, // yes! http://stackoverflow.com/questions/4886858/android-edittext-deletebackspace-key-event
|
||||
{ VK_SPACE, NKCODE_SPACE },
|
||||
{ VK_ESCAPE, NKCODE_ESCAPE },
|
||||
{ VK_UP, NKCODE_DPAD_UP },
|
||||
{ VK_INSERT, NKCODE_INSERT },
|
||||
{ VK_HOME, NKCODE_MOVE_HOME },
|
||||
{ VK_PRIOR, NKCODE_PAGE_UP },
|
||||
{ VK_NEXT, NKCODE_PAGE_DOWN },
|
||||
{ VK_DELETE, NKCODE_FORWARD_DEL },
|
||||
{ VK_END, NKCODE_MOVE_END },
|
||||
{ VK_TAB, NKCODE_TAB },
|
||||
{ VK_DOWN, NKCODE_DPAD_DOWN },
|
||||
{ VK_LEFT, NKCODE_DPAD_LEFT },
|
||||
{ VK_RIGHT, NKCODE_DPAD_RIGHT },
|
||||
{ VK_CAPITAL, NKCODE_CAPS_LOCK },
|
||||
{ VK_CLEAR, NKCODE_CLEAR },
|
||||
{ VK_SNAPSHOT, NKCODE_SYSRQ },
|
||||
{ VK_SCROLL, NKCODE_SCROLL_LOCK },
|
||||
{ VK_OEM_1, NKCODE_SEMICOLON },
|
||||
{ VK_OEM_2, NKCODE_SLASH },
|
||||
{ VK_OEM_3, NKCODE_GRAVE },
|
||||
{ VK_OEM_4, NKCODE_LEFT_BRACKET },
|
||||
{ VK_OEM_5, NKCODE_BACKSLASH },
|
||||
{ VK_OEM_6, NKCODE_RIGHT_BRACKET },
|
||||
{ VK_OEM_7, NKCODE_APOSTROPHE },
|
||||
{ VK_RETURN, NKCODE_ENTER },
|
||||
{ VK_APPS, NKCODE_MENU }, // Context menu key, let's call this "menu".
|
||||
{ VK_PAUSE, NKCODE_BREAK },
|
||||
{ VK_F1, NKCODE_F1 },
|
||||
{ VK_F2, NKCODE_F2 },
|
||||
{ VK_F3, NKCODE_F3 },
|
||||
{ VK_F4, NKCODE_F4 },
|
||||
{ VK_F5, NKCODE_F5 },
|
||||
{ VK_F6, NKCODE_F6 },
|
||||
{ VK_F7, NKCODE_F7 },
|
||||
{ VK_F8, NKCODE_F8 },
|
||||
{ VK_F9, NKCODE_F9 },
|
||||
{ VK_F10, NKCODE_F10 },
|
||||
{ VK_F11, NKCODE_F11 },
|
||||
{ VK_F12, NKCODE_F12 },
|
||||
{ VK_OEM_102, NKCODE_EXT_PIPE },
|
||||
{ VK_LBUTTON, NKCODE_EXT_MOUSEBUTTON_1 },
|
||||
{ VK_RBUTTON, NKCODE_EXT_MOUSEBUTTON_2 },
|
||||
{ VK_MBUTTON, NKCODE_EXT_MOUSEBUTTON_3 },
|
||||
{ VK_XBUTTON1, NKCODE_EXT_MOUSEBUTTON_4 },
|
||||
{ VK_XBUTTON2, NKCODE_EXT_MOUSEBUTTON_5 },
|
||||
};
|
||||
|
||||
void Init() {
|
||||
RAWINPUTDEVICE dev[3];
|
||||
memset(dev, 0, sizeof(dev));
|
||||
|
||||
+4
-11
@@ -66,7 +66,6 @@
|
||||
#include "Windows/DinputDevice.h"
|
||||
#endif
|
||||
#include "Windows/XinputDevice.h"
|
||||
#include "Windows/KeyboardDevice.h"
|
||||
|
||||
#include "Windows/main.h"
|
||||
#include "UI/OnScreenDisplay.h"
|
||||
@@ -89,17 +88,14 @@ WindowsHost::WindowsHost(HINSTANCE hInstance, HWND mainWindow, HWND displayWindo
|
||||
g_mouseDeltaY = 0;
|
||||
|
||||
//add first XInput device to respond
|
||||
input.push_back(std::shared_ptr<InputDevice>(new XinputDevice()));
|
||||
input.push_back(std::make_unique<XinputDevice>());
|
||||
#ifndef _M_ARM
|
||||
//find all connected DInput devices of class GamePad
|
||||
numDinputDevices_ = DinputDevice::getNumPads();
|
||||
for (size_t i = 0; i < numDinputDevices_; i++) {
|
||||
input.push_back(std::shared_ptr<InputDevice>(new DinputDevice(static_cast<int>(i))));
|
||||
input.push_back(std::make_unique<DinputDevice>(static_cast<int>(i)));
|
||||
}
|
||||
#endif
|
||||
keyboard = std::shared_ptr<KeyboardDevice>(new KeyboardDevice());
|
||||
input.push_back(keyboard);
|
||||
|
||||
SetConsolePosition();
|
||||
}
|
||||
|
||||
@@ -221,7 +217,7 @@ void WindowsHost::PollControllers() {
|
||||
if (newCount > numDinputDevices_) {
|
||||
INFO_LOG(SYSTEM, "New controller device detected");
|
||||
for (size_t i = numDinputDevices_; i < newCount; i++) {
|
||||
input.push_back(std::shared_ptr<InputDevice>(new DinputDevice(static_cast<int>(i))));
|
||||
input.push_back(std::make_unique<DinputDevice>(static_cast<int>(i)));
|
||||
}
|
||||
numDinputDevices_ = newCount;
|
||||
}
|
||||
@@ -229,12 +225,9 @@ void WindowsHost::PollControllers() {
|
||||
checkCounter = 0;
|
||||
}
|
||||
|
||||
bool doPad = true;
|
||||
for (const auto &device : input) {
|
||||
if (!doPad && device->IsPad())
|
||||
continue;
|
||||
if (device->UpdateState() == InputDevice::UPDATESTATE_SKIP_PAD)
|
||||
doPad = false;
|
||||
break;
|
||||
}
|
||||
|
||||
// Disabled by default, needs a workaround to map to psp keys.
|
||||
|
||||
@@ -17,7 +17,6 @@
|
||||
|
||||
#include "../Core/Host.h"
|
||||
#include "InputDevice.h"
|
||||
#include "KeyboardDevice.h"
|
||||
#include "Common/CommonWindows.h"
|
||||
#include <list>
|
||||
#include <memory>
|
||||
@@ -63,8 +62,6 @@ public:
|
||||
void NotifyUserMessage(const std::string &message, float duration = 1.0f, u32 color = 0x00FFFFFF, const char *id = nullptr) override;
|
||||
void SendUIMessage(const std::string &message, const std::string &value) override;
|
||||
|
||||
std::shared_ptr<KeyboardDevice> keyboard;
|
||||
|
||||
GraphicsContext *GetGraphicsContext() { return gfx_; }
|
||||
|
||||
private:
|
||||
@@ -77,5 +74,5 @@ private:
|
||||
GraphicsContext *gfx_ = nullptr;
|
||||
size_t numDinputDevices_ = 0;
|
||||
|
||||
std::list<std::shared_ptr<InputDevice>> input;
|
||||
std::list<std::unique_ptr<InputDevice>> input;
|
||||
};
|
||||
+15
-11
@@ -17,12 +17,8 @@
|
||||
#if !PPSSPP_PLATFORM(UWP)
|
||||
|
||||
typedef DWORD (WINAPI *XInputGetState_t) (DWORD dwUserIndex, XINPUT_STATE* pState);
|
||||
typedef DWORD (WINAPI *XInputSetState_t) (DWORD dwUserIndex, XINPUT_VIBRATION* pVibration);
|
||||
typedef DWORD (WINAPI *XInputGetCapabilities_t) (DWORD dwUserIndex, DWORD dwFlags, XINPUT_CAPABILITIES* pCapabilities);
|
||||
|
||||
static XInputGetState_t PPSSPP_XInputGetState = NULL;
|
||||
static XInputSetState_t PPSSPP_XInputSetState = NULL;
|
||||
static XInputGetCapabilities_t PPSSPP_XInputGetCapabilities = NULL;
|
||||
static DWORD PPSSPP_XInputVersion = 0;
|
||||
static HMODULE s_pXInputDLL = 0;
|
||||
static int s_XInputDLLRefCount = 0;
|
||||
@@ -42,6 +38,10 @@ static int LoadXInputDLL() {
|
||||
if (!s_pXInputDLL) {
|
||||
version = (1 << 16) | 3;
|
||||
s_pXInputDLL = LoadLibrary( L"XInput1_3.dll" ); // 1.3 Ships with Vista and Win7, can be installed as a restributable component.
|
||||
if (!s_pXInputDLL) {
|
||||
version = (1 << 16) | 0;
|
||||
s_pXInputDLL = LoadLibrary( L"XInput9_1_0.dll" ); // 1.0 ships with any Windows since WinXP
|
||||
}
|
||||
}
|
||||
if (!s_pXInputDLL) {
|
||||
return -1;
|
||||
@@ -50,11 +50,17 @@ static int LoadXInputDLL() {
|
||||
PPSSPP_XInputVersion = version;
|
||||
s_XInputDLLRefCount = 1;
|
||||
|
||||
/* 100 is the ordinal for _XInputGetStateEx, which returns the same struct as XinputGetState, but with extra data in wButtons for the guide button, we think... */
|
||||
PPSSPP_XInputGetState = (XInputGetState_t)GetProcAddress( (HMODULE)s_pXInputDLL, (LPCSTR)100 );
|
||||
PPSSPP_XInputSetState = (XInputSetState_t)GetProcAddress( (HMODULE)s_pXInputDLL, "XInputSetState" );
|
||||
PPSSPP_XInputGetCapabilities = (XInputGetCapabilities_t)GetProcAddress( (HMODULE)s_pXInputDLL, "XInputGetCapabilities" );
|
||||
if ( !PPSSPP_XInputGetState || !PPSSPP_XInputSetState || !PPSSPP_XInputGetCapabilities ) {
|
||||
/* 100 is the ordinal for _XInputGetStateEx, which returns the same struct as XinputGetState, but with extra data in wButtons for the guide button, we think...
|
||||
Let's try the name first, though - then fall back to ordinal, then to a non-Ex version (xinput9_1_0.dll doesn't have Ex) */
|
||||
PPSSPP_XInputGetState = (XInputGetState_t)GetProcAddress( (HMODULE)s_pXInputDLL, "XInputGetStateEx" );
|
||||
if ( !PPSSPP_XInputGetState ) {
|
||||
PPSSPP_XInputGetState = (XInputGetState_t)GetProcAddress( (HMODULE)s_pXInputDLL, (LPCSTR)100 );
|
||||
if ( !PPSSPP_XInputGetState ) {
|
||||
PPSSPP_XInputGetState = (XInputGetState_t)GetProcAddress( (HMODULE)s_pXInputDLL, "XInputGetState" );
|
||||
}
|
||||
}
|
||||
|
||||
if ( !PPSSPP_XInputGetState ) {
|
||||
UnloadXInputDLL();
|
||||
return -1;
|
||||
}
|
||||
@@ -75,8 +81,6 @@ static void UnloadXInputDLL() {
|
||||
static int LoadXInputDLL() { return 0; }
|
||||
static void UnloadXInputDLL() {}
|
||||
#define PPSSPP_XInputGetState XInputGetState
|
||||
#define PPSSPP_XInputSetState XInputSetState
|
||||
#define PPSSPP_XInputGetCapabilities XInputGetCapabilities
|
||||
#endif
|
||||
|
||||
#ifndef XUSER_MAX_COUNT
|
||||
|
||||
@@ -4,12 +4,11 @@
|
||||
#include "Xinput.h"
|
||||
|
||||
|
||||
class XinputDevice : public InputDevice {
|
||||
class XinputDevice final : public InputDevice {
|
||||
public:
|
||||
XinputDevice();
|
||||
~XinputDevice();
|
||||
virtual int UpdateState();
|
||||
virtual bool IsPad() { return true; }
|
||||
virtual int UpdateState() override;
|
||||
|
||||
private:
|
||||
void UpdatePad(int pad, const XINPUT_STATE &state);
|
||||
|
||||
+1
-3
@@ -572,7 +572,7 @@ int WINAPI WinMain(HINSTANCE _hInstance, HINSTANCE hPrevInstance, LPSTR szCmdLin
|
||||
|
||||
#ifndef _DEBUG
|
||||
// See #11719 - too many Vulkan drivers crash on basic init.
|
||||
if (g_Config.IsBackendEnabled(GPUBackend::VULKAN)) {
|
||||
if (g_Config.IsBackendEnabled(GPUBackend::VULKAN, false)) {
|
||||
VulkanSetAvailable(DetectVulkanInExternalProcess());
|
||||
}
|
||||
#endif
|
||||
@@ -674,8 +674,6 @@ int WINAPI WinMain(HINSTANCE _hInstance, HINSTANCE hPrevInstance, LPSTR szCmdLin
|
||||
|
||||
VFSShutdown();
|
||||
|
||||
InputDevice::StopPolling();
|
||||
|
||||
MainWindow::DestroyDebugWindows();
|
||||
DialogManager::DestroyAll();
|
||||
timeEndPeriod(1);
|
||||
|
||||
@@ -12,3 +12,4 @@ ui_atlas.zim.png
|
||||
#assets/ui_atlas_luna.zim
|
||||
#jni/ui_atlas.cpp
|
||||
#jni/ui_atlas.h
|
||||
.cxx
|
||||
+1
-1
Submodule assets/lang updated: 7c3eae3b49...03707d64bf.
@@ -1,4 +1,10 @@
|
||||
if(NOT EXISTS "/opt/vc/include/bcm_host.h")
|
||||
file(READ "/sys/firmware/devicetree/base/compatible" PPSSPP_PI_MODEL)
|
||||
|
||||
if(PPSSPP_PI_MODEL MATCHES "raspberrypi,4")
|
||||
set(PPSSPP_PI_MODEL4 ON)
|
||||
endif()
|
||||
|
||||
if(NOT PPSSPP_PI_MODEL4 AND NOT EXISTS "/opt/vc/include/bcm_host.h")
|
||||
message(FATAL_ERROR "RaspberryPI platform not recognized")
|
||||
endif()
|
||||
|
||||
@@ -8,21 +14,29 @@ include_directories(SYSTEM
|
||||
/opt/vc/include/interface/vmcx_host/linux
|
||||
)
|
||||
|
||||
add_definitions(
|
||||
-DPPSSPP_PLATFORM_RPI=1
|
||||
-U__GCC_HAVE_SYNC_COMPARE_AND_SWAP_2
|
||||
)
|
||||
if(NOT PPSSPP_PI_MODEL4)
|
||||
add_definitions(
|
||||
-DPPSSPP_PLATFORM_RPI=1
|
||||
-U__GCC_HAVE_SYNC_COMPARE_AND_SWAP_2
|
||||
)
|
||||
endif()
|
||||
|
||||
set(ARCH_FLAGS "-mcpu=cortex-a7 -mfpu=neon -mfloat-abi=hard")
|
||||
if(PPSSPP_PI_MODEL4)
|
||||
set(ARCH_FLAGS "-march=armv7-a -mcpu=cortex-a72 -mtune=cortex-a72 -mfpu=neon-vfpv4 -mfloat-abi=hard")
|
||||
else()
|
||||
set(ARCH_FLAGS "-mcpu=cortex-a7 -mfpu=neon -mfloat-abi=hard")
|
||||
endif()
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${ARCH_FLAGS}" CACHE STRING "" FORCE)
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${ARCH_FLAGS}" CACHE STRING "" FORCE)
|
||||
set(CMAKE_ASM_FLAGS "${CMAKE_ASM_FLAGS} ${ARCH_FLAGS}" CACHE STRING "" FORCE)
|
||||
|
||||
set(CMAKE_EXE_LINKER_FLAGS "-L/opt/vc/lib" CACHE STRING "" FORCE)
|
||||
|
||||
set(OPENGL_LIBRARIES brcmGLESv2 bcm_host)
|
||||
set(EGL_LIBRARIES brcmEGL)
|
||||
if(NOT PPSSPP_PI_MODEL4)
|
||||
set(OPENGL_LIBRARIES brcmGLESv2 bcm_host)
|
||||
set(EGL_LIBRARIES brcmEGL)
|
||||
set(USING_FBDEV ON)
|
||||
endif()
|
||||
set(USING_GLES2 ON)
|
||||
set(USING_FBDEV ON)
|
||||
set(ARMV7 ON)
|
||||
set(USE_WAYLAND_WSI OFF)
|
||||
@@ -239,6 +239,7 @@
|
||||
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
|
||||
<BufferSecurityCheck>false</BufferSecurityCheck>
|
||||
<MultiProcessorCompilation>true</MultiProcessorCompilation>
|
||||
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Windows</SubSystem>
|
||||
@@ -259,6 +260,7 @@
|
||||
<BufferSecurityCheck>false</BufferSecurityCheck>
|
||||
<MultiProcessorCompilation>true</MultiProcessorCompilation>
|
||||
<OmitFramePointers>false</OmitFramePointers>
|
||||
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Windows</SubSystem>
|
||||
@@ -279,6 +281,7 @@
|
||||
<BufferSecurityCheck>false</BufferSecurityCheck>
|
||||
<MultiProcessorCompilation>true</MultiProcessorCompilation>
|
||||
<OmitFramePointers>false</OmitFramePointers>
|
||||
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Windows</SubSystem>
|
||||
@@ -299,6 +302,7 @@
|
||||
<BufferSecurityCheck>false</BufferSecurityCheck>
|
||||
<MultiProcessorCompilation>true</MultiProcessorCompilation>
|
||||
<OmitFramePointers>false</OmitFramePointers>
|
||||
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Windows</SubSystem>
|
||||
|
||||
@@ -187,6 +187,7 @@
|
||||
<MultiProcessorCompilation>true</MultiProcessorCompilation>
|
||||
<OmitFramePointers>false</OmitFramePointers>
|
||||
<BufferSecurityCheck>false</BufferSecurityCheck>
|
||||
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Windows</SubSystem>
|
||||
@@ -208,6 +209,7 @@
|
||||
<MultiProcessorCompilation>true</MultiProcessorCompilation>
|
||||
<OmitFramePointers>false</OmitFramePointers>
|
||||
<BufferSecurityCheck>false</BufferSecurityCheck>
|
||||
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Windows</SubSystem>
|
||||
@@ -229,6 +231,7 @@
|
||||
<MultiProcessorCompilation>true</MultiProcessorCompilation>
|
||||
<OmitFramePointers>false</OmitFramePointers>
|
||||
<BufferSecurityCheck>false</BufferSecurityCheck>
|
||||
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Windows</SubSystem>
|
||||
@@ -313,6 +316,7 @@
|
||||
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
|
||||
<MultiProcessorCompilation>true</MultiProcessorCompilation>
|
||||
<BufferSecurityCheck>false</BufferSecurityCheck>
|
||||
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Windows</SubSystem>
|
||||
|
||||
@@ -221,6 +221,7 @@
|
||||
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
|
||||
<BufferSecurityCheck>false</BufferSecurityCheck>
|
||||
<MultiProcessorCompilation>true</MultiProcessorCompilation>
|
||||
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Windows</SubSystem>
|
||||
@@ -243,6 +244,7 @@
|
||||
<BufferSecurityCheck>false</BufferSecurityCheck>
|
||||
<MultiProcessorCompilation>true</MultiProcessorCompilation>
|
||||
<OmitFramePointers>false</OmitFramePointers>
|
||||
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Windows</SubSystem>
|
||||
@@ -265,6 +267,7 @@
|
||||
<BufferSecurityCheck>false</BufferSecurityCheck>
|
||||
<MultiProcessorCompilation>true</MultiProcessorCompilation>
|
||||
<OmitFramePointers>false</OmitFramePointers>
|
||||
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Windows</SubSystem>
|
||||
@@ -287,6 +290,7 @@
|
||||
<BufferSecurityCheck>false</BufferSecurityCheck>
|
||||
<MultiProcessorCompilation>true</MultiProcessorCompilation>
|
||||
<OmitFramePointers>false</OmitFramePointers>
|
||||
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Windows</SubSystem>
|
||||
|
||||
@@ -404,6 +404,7 @@
|
||||
<AdditionalIncludeDirectories>armips</AdditionalIncludeDirectories>
|
||||
<MultiProcessorCompilation>true</MultiProcessorCompilation>
|
||||
<BufferSecurityCheck>false</BufferSecurityCheck>
|
||||
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Windows</SubSystem>
|
||||
@@ -426,6 +427,7 @@
|
||||
<StringPooling>true</StringPooling>
|
||||
<MultiProcessorCompilation>true</MultiProcessorCompilation>
|
||||
<OmitFramePointers>false</OmitFramePointers>
|
||||
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Windows</SubSystem>
|
||||
@@ -448,6 +450,7 @@
|
||||
<StringPooling>true</StringPooling>
|
||||
<MultiProcessorCompilation>true</MultiProcessorCompilation>
|
||||
<OmitFramePointers>false</OmitFramePointers>
|
||||
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Windows</SubSystem>
|
||||
@@ -470,6 +473,7 @@
|
||||
<StringPooling>true</StringPooling>
|
||||
<MultiProcessorCompilation>true</MultiProcessorCompilation>
|
||||
<OmitFramePointers>false</OmitFramePointers>
|
||||
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Windows</SubSystem>
|
||||
|
||||
@@ -211,20 +211,19 @@ bool FileInfo::operator <(const FileInfo &other) const {
|
||||
size_t getFilesInDir(const char *directory, std::vector<FileInfo> *files, const char *filter, int flags) {
|
||||
size_t foundEntries = 0;
|
||||
std::set<std::string> filters;
|
||||
std::string tmp;
|
||||
if (filter) {
|
||||
std::string tmp;
|
||||
while (*filter) {
|
||||
if (*filter == ':') {
|
||||
filters.insert(tmp);
|
||||
tmp = "";
|
||||
filters.insert(std::move(tmp));
|
||||
} else {
|
||||
tmp.push_back(*filter);
|
||||
}
|
||||
filter++;
|
||||
}
|
||||
if (!tmp.empty())
|
||||
filters.insert(std::move(tmp));
|
||||
}
|
||||
if (tmp.size())
|
||||
filters.insert(tmp);
|
||||
#ifdef _WIN32
|
||||
// Find the first file in the directory.
|
||||
WIN32_FIND_DATA ffd;
|
||||
@@ -252,14 +251,20 @@ size_t getFilesInDir(const char *directory, std::vector<FileInfo> *files, const
|
||||
const std::string virtualName(result->d_name);
|
||||
#endif
|
||||
// check for "." and ".."
|
||||
if (((virtualName[0] == '.') && (virtualName[1] == '\0')) ||
|
||||
((virtualName[0] == '.') && (virtualName[1] == '.') &&
|
||||
(virtualName[2] == '\0')))
|
||||
if (virtualName == "." || virtualName == "..")
|
||||
continue;
|
||||
|
||||
// Remove dotfiles (optional with flag.)
|
||||
if (!(flags & GETFILES_GETHIDDEN) && virtualName[0] == '.')
|
||||
continue;
|
||||
if (!(flags & GETFILES_GETHIDDEN))
|
||||
{
|
||||
#ifdef _WIN32
|
||||
if ((ffd.dwFileAttributes & FILE_ATTRIBUTE_HIDDEN) != 0)
|
||||
continue;
|
||||
#else
|
||||
if (virtualName[0] == '.')
|
||||
continue;
|
||||
#endif
|
||||
}
|
||||
|
||||
FileInfo info;
|
||||
info.name = virtualName;
|
||||
@@ -283,7 +288,7 @@ size_t getFilesInDir(const char *directory, std::vector<FileInfo> *files, const
|
||||
}
|
||||
|
||||
if (files)
|
||||
files->push_back(info);
|
||||
files->push_back(std::move(info));
|
||||
foundEntries++;
|
||||
#ifdef _WIN32
|
||||
} while (FindNextFile(hFind, &ffd) != 0);
|
||||
|
||||
@@ -257,6 +257,7 @@
|
||||
<MultiProcessorCompilation>true</MultiProcessorCompilation>
|
||||
<RuntimeTypeInfo>false</RuntimeTypeInfo>
|
||||
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
|
||||
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
|
||||
<BufferSecurityCheck>false</BufferSecurityCheck>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
@@ -284,6 +285,7 @@
|
||||
<MultiProcessorCompilation>true</MultiProcessorCompilation>
|
||||
<RuntimeTypeInfo>false</RuntimeTypeInfo>
|
||||
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
|
||||
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
|
||||
<BufferSecurityCheck>false</BufferSecurityCheck>
|
||||
<StringPooling>true</StringPooling>
|
||||
<OmitFramePointers>false</OmitFramePointers>
|
||||
@@ -313,6 +315,7 @@
|
||||
<MultiProcessorCompilation>true</MultiProcessorCompilation>
|
||||
<RuntimeTypeInfo>false</RuntimeTypeInfo>
|
||||
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
|
||||
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
|
||||
<BufferSecurityCheck>false</BufferSecurityCheck>
|
||||
<StringPooling>true</StringPooling>
|
||||
<OmitFramePointers>false</OmitFramePointers>
|
||||
@@ -342,6 +345,7 @@
|
||||
<MultiProcessorCompilation>true</MultiProcessorCompilation>
|
||||
<RuntimeTypeInfo>false</RuntimeTypeInfo>
|
||||
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
|
||||
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
|
||||
<BufferSecurityCheck>false</BufferSecurityCheck>
|
||||
<StringPooling>true</StringPooling>
|
||||
<OmitFramePointers>false</OmitFramePointers>
|
||||
|
||||
@@ -268,6 +268,7 @@
|
||||
<MultiProcessorCompilation>true</MultiProcessorCompilation>
|
||||
<RuntimeTypeInfo>false</RuntimeTypeInfo>
|
||||
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
|
||||
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Windows</SubSystem>
|
||||
@@ -294,6 +295,7 @@
|
||||
<MultiProcessorCompilation>true</MultiProcessorCompilation>
|
||||
<RuntimeTypeInfo>false</RuntimeTypeInfo>
|
||||
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
|
||||
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
|
||||
<StringPooling>true</StringPooling>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
@@ -321,6 +323,7 @@
|
||||
<MultiProcessorCompilation>true</MultiProcessorCompilation>
|
||||
<RuntimeTypeInfo>false</RuntimeTypeInfo>
|
||||
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
|
||||
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
|
||||
<StringPooling>true</StringPooling>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
@@ -348,6 +351,7 @@
|
||||
<MultiProcessorCompilation>true</MultiProcessorCompilation>
|
||||
<RuntimeTypeInfo>false</RuntimeTypeInfo>
|
||||
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
|
||||
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
|
||||
<StringPooling>true</StringPooling>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
|
||||
@@ -379,6 +379,7 @@ int main(int argc, const char* argv[])
|
||||
g_Config.bHighQualityDepth = true;
|
||||
g_Config.bMemStickInserted = true;
|
||||
g_Config.bFragmentTestCache = true;
|
||||
g_Config.iAudioLatency = 1;
|
||||
|
||||
#ifdef _WIN32
|
||||
InitSysDirectories();
|
||||
|
||||
@@ -309,6 +309,7 @@
|
||||
<MultiProcessorCompilation>true</MultiProcessorCompilation>
|
||||
<RuntimeTypeInfo>false</RuntimeTypeInfo>
|
||||
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
|
||||
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Console</SubSystem>
|
||||
@@ -345,6 +346,7 @@
|
||||
<RuntimeTypeInfo>false</RuntimeTypeInfo>
|
||||
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
|
||||
<StringPooling>true</StringPooling>
|
||||
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Console</SubSystem>
|
||||
@@ -381,6 +383,7 @@
|
||||
<RuntimeTypeInfo>false</RuntimeTypeInfo>
|
||||
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
|
||||
<StringPooling>true</StringPooling>
|
||||
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Console</SubSystem>
|
||||
@@ -414,6 +417,7 @@
|
||||
<RuntimeTypeInfo>false</RuntimeTypeInfo>
|
||||
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
|
||||
<StringPooling>true</StringPooling>
|
||||
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Console</SubSystem>
|
||||
|
||||
+6
-4
@@ -61,10 +61,12 @@ bool System_GetPropertyBool(SystemProperty prop) {
|
||||
|
||||
void System_SendMessage(const char *command, const char *parameter) {
|
||||
if (!strcmp(command, "finish")) {
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
[sharedViewController shutdown];
|
||||
exit(0);
|
||||
});
|
||||
exit(0);
|
||||
// The below seems right, but causes hangs. See #12140.
|
||||
// dispatch_async(dispatch_get_main_queue(), ^{
|
||||
// [sharedViewController shutdown];
|
||||
// exit(0);
|
||||
// });
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -324,10 +324,14 @@ void retro_init(void) {
|
||||
g_Config.bFrameSkipUnthrottle = false;
|
||||
g_Config.bMemStickInserted = PSP_MEMORYSTICK_STATE_INSERTED;
|
||||
g_Config.iGlobalVolume = VOLUME_MAX - 1;
|
||||
g_Config.iAltSpeedVolume = -1;
|
||||
g_Config.bEnableSound = true;
|
||||
g_Config.bAudioResampler = false;
|
||||
g_Config.iCwCheatRefreshRate = 60;
|
||||
|
||||
|
||||
g_Config.iFirmwareVersion = PSP_DEFAULT_FIRMWARE;
|
||||
g_Config.iPSPModel = PSP_MODEL_SLIM;
|
||||
|
||||
LogManager::Init();
|
||||
|
||||
host = new LibretroHost;
|
||||
|
||||
@@ -270,6 +270,7 @@
|
||||
<MultiProcessorCompilation>true</MultiProcessorCompilation>
|
||||
<RuntimeTypeInfo>false</RuntimeTypeInfo>
|
||||
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
|
||||
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Console</SubSystem>
|
||||
@@ -298,6 +299,7 @@
|
||||
<StringPooling>true</StringPooling>
|
||||
<FavorSizeOrSpeed>Size</FavorSizeOrSpeed>
|
||||
<OmitFramePointers>false</OmitFramePointers>
|
||||
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Console</SubSystem>
|
||||
@@ -326,6 +328,7 @@
|
||||
<StringPooling>true</StringPooling>
|
||||
<FavorSizeOrSpeed>Size</FavorSizeOrSpeed>
|
||||
<OmitFramePointers>false</OmitFramePointers>
|
||||
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Console</SubSystem>
|
||||
@@ -354,6 +357,7 @@
|
||||
<StringPooling>true</StringPooling>
|
||||
<FavorSizeOrSpeed>Size</FavorSizeOrSpeed>
|
||||
<OmitFramePointers>false</OmitFramePointers>
|
||||
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Console</SubSystem>
|
||||
|
||||
Reference in new issue
Block a user