Compare commits
12 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| dc55d5be8f | |||
| 06546b5195 | |||
| ca9c1674f7 | |||
| ede76033a7 | |||
| 41bd07274f | |||
| 5266dd6c60 | |||
| cf1c45dfe8 | |||
| ae7e275a9d | |||
| b60f29282a | |||
| bda466c3bd | |||
| 4c6ceeff11 | |||
| 77f2b521e1 |
@@ -60,7 +60,6 @@ rpcs3/git-version.h
|
||||
# Visual Studio Files
|
||||
.vs/*
|
||||
.vscode/*
|
||||
*.ipch
|
||||
*.vspx
|
||||
*.psess
|
||||
*.VC.*
|
||||
|
||||
+3
-7
@@ -7,14 +7,14 @@
|
||||
ignore = dirty
|
||||
[submodule "llvm"]
|
||||
path = llvm
|
||||
url = https://github.com/llvm-mirror/llvm
|
||||
url = https://github.com/RPCS3/llvm
|
||||
branch = release_60
|
||||
[submodule "GSL"]
|
||||
path = 3rdparty/GSL
|
||||
url = https://github.com/Microsoft/GSL.git
|
||||
[submodule "libpng"]
|
||||
path = 3rdparty/libpng
|
||||
url = https://github.com/Zangetsu38/libpng
|
||||
url = https://github.com/RPCS3/libpng
|
||||
ignore = dirty
|
||||
[submodule "Vulkan/glslang"]
|
||||
path = Vulkan/glslang
|
||||
@@ -33,7 +33,7 @@
|
||||
url = https://github.com/madler/zlib
|
||||
[submodule "3rdparty/hidapi"]
|
||||
path = 3rdparty/hidapi
|
||||
url = https://github.com/Zangetsu38/hidapi
|
||||
url = https://github.com/RPCS3/hidapi
|
||||
branch = master
|
||||
ignore = dirty
|
||||
[submodule "3rdparty/Optional"]
|
||||
@@ -42,7 +42,3 @@
|
||||
[submodule "3rdparty/pugixml"]
|
||||
path = 3rdparty/pugixml
|
||||
url = https://github.com/zeux/pugixml
|
||||
[submodule "polly"]
|
||||
path = polly
|
||||
url = https://github.com/llvm-mirror/polly
|
||||
branch = release_60
|
||||
|
||||
+3
-1
@@ -81,7 +81,9 @@ before_script:
|
||||
export PATH=${TRAVIS_BUILD_DIR}/build/squashfs-root/usr/bin/:${PATH} ;
|
||||
./squashfs-root/usr/bin/appimagetool ${TRAVIS_BUILD_DIR}/build/appdir ;
|
||||
find ./appdir -executable -type f -exec ldd {} \; | grep " => /usr" | cut -d " " -f 2-3 | sort | uniq ;
|
||||
curl ${UPLOAD_URL}${TRAVIS_COMMIT:0:7}-${TRAVIS_BUILD_NUMBER}_linux64 --upload-file ./RPCS3*.AppImage;
|
||||
COMM_TAG="$(git describe --tags $(git rev-list --tags --max-count=1))"
|
||||
COMM_COUNT="$(git rev-list --count HEAD)"
|
||||
curl "${UPLOAD_URL}${TRAVIS_COMMIT:0:8}&t=${COMM_TAG}&a=${COMM_COUNT}" --upload-file ./RPCS3*.AppImage;
|
||||
fi;
|
||||
|
||||
script:
|
||||
|
||||
Vendored
+1
-1
Submodule 3rdparty/hidapi updated: 4c2750112e...ca39ce8939
Vendored
+1
-1
Submodule 3rdparty/libpng updated: bbbcaf1122...1dcba4d6eb
@@ -20,11 +20,11 @@ If you want to contribute please take a look at the [Coding Style](https://githu
|
||||
## Dependencies
|
||||
|
||||
### Windows
|
||||
* [Visual Studio 2017](https://www.visualstudio.com/en/downloads/)
|
||||
* [Visual C++ Redistributable Packages for Visual Studio 2017](https://go.microsoft.com/fwlink/?LinkId=746572)
|
||||
* [Visual Studio 2015](https://www.visualstudio.com/vs/older-downloads/)
|
||||
* [Visual C++ Redistributable Packages for Visual Studio 2015](http://www.microsoft.com/en-us/download/details.aspx?id=48145)
|
||||
* [Cmake 3.1.0+](https://www.cmake.org/download/) (required; add to PATH)
|
||||
* [Python 3.3+](https://www.python.org/downloads/) (required; add to PATH)
|
||||
* [Qt 5.10+](https://www.qt.io/download-open-source/) (required; add QTDIR environment variable if you do not want to use the Visual Studio Qt Plugin: e.g. `<QtInstallFolder>\5.10.1\msvc2017_64\`)
|
||||
* [Qt 5.10+](https://www.qt.io/download-open-source/) (required; add QTDIR environment variable if you do not want to use the Visual Studio Qt Plugin: e.g. `<QtInstallFolder>\5.10.1\msvc2015_64\`)
|
||||
* [Visual Studio Qt Plugin](https://marketplace.visualstudio.com/items?itemName=TheQtCompany.QtVisualStudioTools2015) (optional; see above)
|
||||
|
||||
### Linux
|
||||
@@ -48,14 +48,14 @@ To initialize the repository don't forget to execute `git submodule update --ini
|
||||
### Configuring Qt
|
||||
|
||||
*If you're using Visual Studio 2017 without Qt plugin support (or simply dont want to use it):*
|
||||
1) Add `QTDIR` environment variable and set it to e.g `<QtInstallFolder>\5.10.1\msvc2017_64\` </br>
|
||||
1) Add `QTDIR` environment variable and set it to e.g `<QtInstallFolder>\5.10.1\msvc2015_64\` </br>
|
||||
|
||||
|
||||
Open `rpcs3.sln`
|
||||
|
||||
|
||||
*If you wish to use the Visual Studio plugin for Qt:* </br>
|
||||
1) Go to the Qt5 menu and edit Qt5 options. Add the path to your Qt installation with compiler e.g. `C:\Qt\5.10.1\msvc2017_64`. </br>
|
||||
1) Go to the Qt5 menu and edit Qt5 options. Add the path to your Qt installation with compiler e.g. `C:\Qt\5.10.1\msvc2015_64`. </br>
|
||||
2) While selecting the rpcs3qt project, go to Qt5->Project Setting and select the version you added.
|
||||
|
||||
### Building the projects
|
||||
|
||||
+3
-3
@@ -293,7 +293,7 @@ struct MemoryManager : llvm::RTDyldMemoryManager
|
||||
return RTDyldMemoryManager::registerEHFrames(addr, load_addr, size);
|
||||
}
|
||||
|
||||
virtual void deregisterEHFrames() override
|
||||
void deregisterEHFrames(u8* addr, u64 load_addr, std::size_t size) override
|
||||
{
|
||||
}
|
||||
};
|
||||
@@ -376,11 +376,11 @@ public:
|
||||
LOG_SUCCESS(GENERAL, "LLVM: Created module: %s", module->getName().data());
|
||||
}
|
||||
|
||||
static std::unique_ptr<llvm::WritableMemoryBuffer> load(const std::string& path)
|
||||
static std::unique_ptr<llvm::MemoryBuffer> load(const std::string& path)
|
||||
{
|
||||
if (fs::file cached{path, fs::read})
|
||||
{
|
||||
auto buf = llvm::WritableMemoryBuffer::getNewUninitMemBuffer(cached.size());
|
||||
auto buf = llvm::MemoryBuffer::getNewUninitMemBuffer(cached.size());
|
||||
cached.read(const_cast<char*>(buf->getBufferStart()), buf->getBufferSize());
|
||||
return buf;
|
||||
}
|
||||
|
||||
@@ -1890,34 +1890,32 @@ u16 thread_ctrl::get_affinity_mask(thread_class group)
|
||||
}
|
||||
case native_core_arrangement::amd_ccx:
|
||||
{
|
||||
u16 spu_mask, ppu_mask, rsx_mask, general;
|
||||
u16 spu_mask, ppu_mask, rsx_mask;
|
||||
if (thread_count >= 16)
|
||||
{
|
||||
// Threadripper, R7
|
||||
// Assign threads 1-16
|
||||
// Assign threads 8-16
|
||||
// It appears some windows code is bound to lower core addresses, binding 8-16 is alot faster than 0-7
|
||||
ppu_mask = spu_mask = 0b1111111100000000;
|
||||
rsx_mask = 0b11110000;
|
||||
general = 0b00001111;
|
||||
rsx_mask = all_cores_mask;
|
||||
}
|
||||
else if (thread_count == 12)
|
||||
{
|
||||
// 1600/2600 (x)
|
||||
ppu_mask = spu_mask = 0b111111000000;
|
||||
rsx_mask = 0b111000;
|
||||
general = 0b000111;
|
||||
rsx_mask = all_cores_mask;
|
||||
}
|
||||
else
|
||||
{
|
||||
// R5 & R3 don't seem to improve performance no matter how these are shuffled
|
||||
ppu_mask = spu_mask = rsx_mask = general = 0b11111111;
|
||||
ppu_mask = spu_mask = rsx_mask = 0b11111111 & all_cores_mask;
|
||||
}
|
||||
|
||||
switch (group)
|
||||
{
|
||||
default:
|
||||
case thread_class::general:
|
||||
return general = all_cores_mask;
|
||||
return all_cores_mask;
|
||||
case thread_class::rsx:
|
||||
return rsx_mask;
|
||||
case thread_class::ppu:
|
||||
|
||||
+2
-12
@@ -14,10 +14,7 @@ void shared_mutex::imp_lock_shared(s64 _old)
|
||||
|
||||
for (int i = 0; i < 10; i++)
|
||||
{
|
||||
if (i != 0)
|
||||
{
|
||||
busy_wait();
|
||||
}
|
||||
busy_wait();
|
||||
|
||||
const s64 value = m_value.load();
|
||||
|
||||
@@ -176,10 +173,7 @@ void shared_mutex::imp_lock(s64 _old)
|
||||
|
||||
for (int i = 0; i < 10; i++)
|
||||
{
|
||||
if (i != 0)
|
||||
{
|
||||
busy_wait();
|
||||
}
|
||||
busy_wait();
|
||||
|
||||
const s64 value = m_value.load();
|
||||
|
||||
@@ -242,10 +236,6 @@ void shared_mutex::imp_lock_degrade()
|
||||
|
||||
bool shared_mutex::try_lock_shared()
|
||||
{
|
||||
if (m_value < c_min) // Fast path
|
||||
{
|
||||
return false;
|
||||
}
|
||||
// Conditional decrement
|
||||
return m_value.fetch_op([](s64& value) { if (value >= c_min) value -= c_min; }) >= c_min;
|
||||
}
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
<PropertyGroup Label="Configuration">
|
||||
<ConfigurationType>StaticLibrary</ConfigurationType>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
<PlatformToolset>v141</PlatformToolset>
|
||||
<PlatformToolset>v140</PlatformToolset>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
|
||||
<ImportGroup Label="ExtensionSettings">
|
||||
|
||||
@@ -19,12 +19,12 @@
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
|
||||
<ConfigurationType>Makefile</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<PlatformToolset>v141</PlatformToolset>
|
||||
<PlatformToolset>v140</PlatformToolset>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
|
||||
<ConfigurationType>Makefile</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<PlatformToolset>v141</PlatformToolset>
|
||||
<PlatformToolset>v140</PlatformToolset>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
|
||||
<ImportGroup Label="ExtensionSettings">
|
||||
@@ -40,23 +40,23 @@
|
||||
<PropertyGroup Label="UserMacros" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<NMakeBuildCommandLine>start /W /B pre-build.bat
|
||||
cmake -G "Visual Studio 15 2017 Win64" -DCMAKE_CONFIGURATION_TYPES="Debug;Release" -DBUILD_TESTS=OFF -DBUILD_DEMOS=OFF -DBUILD_LAYERS=OFF -DBUILD_VKJSON=OFF ../Vulkan-LoaderAndValidationLayers
|
||||
cmake -G "Visual Studio 14 2015 Win64" -DCMAKE_CONFIGURATION_TYPES="Debug;Release" -DBUILD_TESTS=OFF -DBUILD_DEMOS=OFF -DBUILD_LAYERS=OFF -DBUILD_VKJSON=OFF ../Vulkan-LoaderAndValidationLayers
|
||||
msbuild.exe ALL_BUILD.vcxproj /t:build /p:Configuration=Release /m</NMakeBuildCommandLine>
|
||||
<NMakeCleanCommandLine>cmake -G "Visual Studio 15 2017 Win64" -DCMAKE_CONFIGURATION_TYPES="Debug;Release" -DBUILD_TESTS=OFF -DBUILD_DEMOS=OFF -DBUILD_LAYERS=OFF -DBUILD_VKJSON=OFF ../Vulkan-LoaderAndValidationLayers
|
||||
<NMakeCleanCommandLine>cmake -G "Visual Studio 14 2015 Win64" -DCMAKE_CONFIGURATION_TYPES="Debug;Release" -DBUILD_TESTS=OFF -DBUILD_DEMOS=OFF -DBUILD_LAYERS=OFF -DBUILD_VKJSON=OFF ../Vulkan-LoaderAndValidationLayers
|
||||
msbuild.exe ALL_BUILD.vcxproj /t:clean /p:Configuration=Release /m</NMakeCleanCommandLine>
|
||||
<NMakeReBuildCommandLine>start /W /B pre-build.bat
|
||||
cmake -G "Visual Studio 15 2017 Win64" -DCMAKE_CONFIGURATION_TYPES="Debug;Release" -DBUILD_TESTS=OFF -DBUILD_DEMOS=OFF -DBUILD_LAYERS=OFF -DBUILD_VKJSON=OFF ../Vulkan-LoaderAndValidationLayers
|
||||
cmake -G "Visual Studio 14 2015 Win64" -DCMAKE_CONFIGURATION_TYPES="Debug;Release" -DBUILD_TESTS=OFF -DBUILD_DEMOS=OFF -DBUILD_LAYERS=OFF -DBUILD_VKJSON=OFF ../Vulkan-LoaderAndValidationLayers
|
||||
msbuild.exe ALL_BUILD.vcxproj /t:rebuild /p:Configuration=Release /m
|
||||
</NMakeReBuildCommandLine>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<NMakeBuildCommandLine>start /W /B pre-build.bat
|
||||
cmake -G "Visual Studio 15 2017 Win64" -DCMAKE_CONFIGURATION_TYPES="Debug;Release" -DBUILD_TESTS=OFF -DBUILD_DEMOS=OFF -DBUILD_LAYERS=OFF -DBUILD_VKJSON=OFF ../Vulkan-LoaderAndValidationLayers
|
||||
cmake -G "Visual Studio 14 2015 Win64" -DCMAKE_CONFIGURATION_TYPES="Debug;Release" -DBUILD_TESTS=OFF -DBUILD_DEMOS=OFF -DBUILD_LAYERS=OFF -DBUILD_VKJSON=OFF ../Vulkan-LoaderAndValidationLayers
|
||||
msbuild.exe ALL_BUILD.vcxproj /t:build /p:Configuration=Debug /m</NMakeBuildCommandLine>
|
||||
<NMakeReBuildCommandLine>start /W /B pre-build.bat
|
||||
cmake -G "Visual Studio 15 2017 Win64" -DCMAKE_CONFIGURATION_TYPES="Debug;Release" -DBUILD_TESTS=OFF -DBUILD_DEMOS=OFF -DBUILD_LAYERS=OFF -DBUILD_VKJSON=OFF ../Vulkan-LoaderAndValidationLayers
|
||||
cmake -G "Visual Studio 14 2015 Win64" -DCMAKE_CONFIGURATION_TYPES="Debug;Release" -DBUILD_TESTS=OFF -DBUILD_DEMOS=OFF -DBUILD_LAYERS=OFF -DBUILD_VKJSON=OFF ../Vulkan-LoaderAndValidationLayers
|
||||
msbuild.exe ALL_BUILD.vcxproj /t:rebuild /p:Configuration=Debug /m</NMakeReBuildCommandLine>
|
||||
<NMakeCleanCommandLine>cmake -G "Visual Studio 15 2017 Win64" -DCMAKE_CONFIGURATION_TYPES="Debug;Release" -DBUILD_TESTS=OFF -DBUILD_DEMOS=OFF -DBUILD_LAYERS=OFF -DBUILD_VKJSON=OFF ../Vulkan-LoaderAndValidationLayers
|
||||
<NMakeCleanCommandLine>cmake -G "Visual Studio 14 2015 Win64" -DCMAKE_CONFIGURATION_TYPES="Debug;Release" -DBUILD_TESTS=OFF -DBUILD_DEMOS=OFF -DBUILD_LAYERS=OFF -DBUILD_VKJSON=OFF ../Vulkan-LoaderAndValidationLayers
|
||||
msbuild.exe ALL_BUILD.vcxproj /t:clean /p:Configuration=Debug /m</NMakeCleanCommandLine>
|
||||
</PropertyGroup>
|
||||
<ItemDefinitionGroup>
|
||||
|
||||
@@ -19,12 +19,12 @@
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
|
||||
<ConfigurationType>Makefile</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<PlatformToolset>v141</PlatformToolset>
|
||||
<PlatformToolset>v140</PlatformToolset>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
|
||||
<ConfigurationType>Makefile</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<PlatformToolset>v141</PlatformToolset>
|
||||
<PlatformToolset>v140</PlatformToolset>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
|
||||
<ImportGroup Label="ExtensionSettings">
|
||||
@@ -39,24 +39,24 @@
|
||||
</ImportGroup>
|
||||
<PropertyGroup Label="UserMacros" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<NMakeBuildCommandLine>cmake -G "Visual Studio 15 2017 Win64" -DCMAKE_CONFIGURATION_TYPES="Debug;Release" ../glslang
|
||||
<NMakeBuildCommandLine>cmake -G "Visual Studio 14 2015 Win64" -DCMAKE_CONFIGURATION_TYPES="Debug;Release" ../glslang
|
||||
msbuild.exe ALL_BUILD.vcxproj /t:build /p:Configuration=Release /m</NMakeBuildCommandLine>
|
||||
<NMakeReBuildCommandLine>cmake -G "Visual Studio 15 2017 Win64" -DCMAKE_CONFIGURATION_TYPES="Debug;Release" ../glslang
|
||||
<NMakeReBuildCommandLine>cmake -G "Visual Studio 14 2015 Win64" -DCMAKE_CONFIGURATION_TYPES="Debug;Release" ../glslang
|
||||
msbuild.exe ALL_BUILD.vcxproj /t:rebuild /p:Configuration=Release /m</NMakeReBuildCommandLine>
|
||||
<NMakeCleanCommandLine>cmake -G "Visual Studio 15 2017 Win64" -DCMAKE_CONFIGURATION_TYPES="Debug;Release" ../glslang
|
||||
<NMakeCleanCommandLine>cmake -G "Visual Studio 14 2015 Win64" -DCMAKE_CONFIGURATION_TYPES="Debug;Release" ../glslang
|
||||
msbuild.exe ALL_BUILD.vcxproj /t:clean /p:Configuration=Release /m</NMakeCleanCommandLine>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<NMakeBuildCommandLine>
|
||||
cmake -G "Visual Studio 15 2017 Win64" -DCMAKE_CONFIGURATION_TYPES="Debug;Release" ../glslang
|
||||
cmake -G "Visual Studio 14 2015 Win64" -DCMAKE_CONFIGURATION_TYPES="Debug;Release" ../glslang
|
||||
msbuild.exe ALL_BUILD.vcxproj /t:build /p:Configuration=Debug /m
|
||||
</NMakeBuildCommandLine>
|
||||
<NMakeReBuildCommandLine>
|
||||
cmake -G "Visual Studio 15 2017 Win64" -DCMAKE_CONFIGURATION_TYPES="Debug;Release" ../glslang
|
||||
cmake -G "Visual Studio 14 2015 Win64" -DCMAKE_CONFIGURATION_TYPES="Debug;Release" ../glslang
|
||||
msbuild.exe ALL_BUILD.vcxproj /t:rebuild /p:Configuration=Debug /m
|
||||
</NMakeReBuildCommandLine>
|
||||
<NMakeCleanCommandLine>
|
||||
cmake -G "Visual Studio 15 2017 Win64" -DCMAKE_CONFIGURATION_TYPES="Debug;Release" ../glslang
|
||||
cmake -G "Visual Studio 14 2015 Win64" -DCMAKE_CONFIGURATION_TYPES="Debug;Release" ../glslang
|
||||
msbuild.exe ALL_BUILD.vcxproj /t:clean /p:Configuration=Debug /m
|
||||
</NMakeCleanCommandLine>
|
||||
</PropertyGroup>
|
||||
|
||||
+17
-10
@@ -1,10 +1,10 @@
|
||||
|
||||
version: '{build}'
|
||||
|
||||
image: Visual Studio 2017
|
||||
image: Visual Studio 2015
|
||||
|
||||
environment:
|
||||
QTDIR: C:\Qt\5.10.0\msvc2017_64
|
||||
QTDIR: C:\Qt\5.10.0\msvc2015_64
|
||||
LLVMLIBS: https://drive.google.com/uc?export=download&id=0B8A6NaxhQAGRY2k3Q2Yya05lcm8
|
||||
VULKAN: https://drive.google.com/uc?export=download&id=1A2eOMmCO714i0U7J0qI4aEMKnuWl8l_R
|
||||
COMPATDB: https://rpcs3.net/compatibility?api=v1&export
|
||||
@@ -16,12 +16,19 @@ cache:
|
||||
|
||||
install:
|
||||
- ps: | # set env vars for versioning
|
||||
$commDate = $env:APPVEYOR_REPO_COMMIT_TIMESTAMP.Substring(0,10)
|
||||
$commSha = $env:APPVEYOR_REPO_COMMIT.Substring(0,8)
|
||||
$commTag = $(git describe --tags $(git rev-list --tags --max-count=1))
|
||||
$commCount = $(git rev-list --count HEAD)
|
||||
$commHash = $env:APPVEYOR_REPO_COMMIT.Substring(0,8)
|
||||
|
||||
if ($env:APPVEYOR_PULL_REQUEST_NUMBER) {
|
||||
$env:BUILD = "{0}-{1}" -f $commTag, $commHash
|
||||
}
|
||||
else {
|
||||
$env:BUILD = "{0}-{1}-{2}" -f $commTag, $commCount, $commHash
|
||||
}
|
||||
|
||||
$env:AVVER = "{0}-{1}" -f $commTag.TrimStart("v"), $env:APPVEYOR_BUILD_NUMBER
|
||||
$env:BUILD = "rpcs3-{0}-{1}-{2}_win64.7z" -f $commTag, $commDate, $commSha
|
||||
$env:RPCS3 = "rpcs3-{0}_win64.7z" -f $env:BUILD
|
||||
|
||||
- ps: | # used for experimental build warnings for pr builds
|
||||
$env:BRANCH = "{0}/{1}/#{2}" -f $env:APPVEYOR_REPO_NAME, `
|
||||
@@ -75,20 +82,20 @@ after_build:
|
||||
copy-item compat_database.dat .\bin\GuiConfigs\compat_database.dat
|
||||
|
||||
- ps: | # package artifacts
|
||||
7z a -m0=LZMA2 -mx9 $env:BUILD .\bin\*
|
||||
7z a -m0=LZMA2 -mx9 $env:RPCS3 .\bin\*
|
||||
7z a -m0=LZMA2 -mx9 openssl_win64.7z C:\OpenSSL-Win64\bin\libeay32.dll `
|
||||
C:\OpenSSL-Win64\bin\ssleay32.dll
|
||||
|
||||
- ps: | # generate sha256 hashes
|
||||
(Get-FileHash $env:BUILD -Algorithm SHA256).Hash | Out-File -encoding ASCII "$($env:BUILD).sha256"
|
||||
(Get-FileHash openssl_win64.7z -Algorithm SHA256).Hash | Out-File -encoding ASCII "openssl_win64.7z.sha256"
|
||||
(get-filehash $env:RPCS3 -algorithm SHA256).Hash > ("{0}.sha256" -f $env:RPCS3)
|
||||
(get-filehash openssl_win64.7z -algorithm SHA256).Hash > "openssl_win64.7z.sha256"
|
||||
|
||||
test: off
|
||||
|
||||
artifacts:
|
||||
- path: $(BUILD)
|
||||
- path: $(RPCS3)
|
||||
name: rpcs3
|
||||
- path: $(BUILD).sha256
|
||||
- path: $(RPCS3).sha256
|
||||
name: rpcs3 sha256 hash
|
||||
- path: openssl_win64.7z
|
||||
name: openssl
|
||||
|
||||
@@ -93,7 +93,7 @@
|
||||
<PropertyGroup Label="Configuration">
|
||||
<ConfigurationType>StaticLibrary</ConfigurationType>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
<PlatformToolset>v141</PlatformToolset>
|
||||
<PlatformToolset>v140</PlatformToolset>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
|
||||
<ImportGroup Label="ExtensionSettings">
|
||||
|
||||
+1
-1
Submodule llvm updated: 16ebb58ea4...4423e35117
@@ -1,7 +1,7 @@
|
||||
REM You need cmake and python to update the project files
|
||||
REM this script relies on CWD being the path that this script is in
|
||||
|
||||
cmake -G "Visual Studio 14 2015 Win64" -DCMAKE_CONFIGURATION_TYPES="Debug;Release" -DLLVM_TARGETS_TO_BUILD=X86 -DLLVM_EXTERNAL_POLLY_SOURCE_DIR=../polly -DLLVM_BUILD_RUNTIME=OFF -DLLVM_BUILD_TOOLS=OFF -DLLVM_INCLUDE_DOCS=OFF -DLLVM_INCLUDE_EXAMPLES=OFF -DLLVM_INCLUDE_TESTS=OFF -DLLVM_INCLUDE_TOOLS=ON -DLLVM_INCLUDE_UTILS=ON -DWITH_POLLY=ON -DCMAKE_SYSTEM_VERSION=6.1 -DCMAKE_VS_WINDOWS_TARGET_PLATFORM_VERSION=8.1 ../llvm
|
||||
cmake -G "Visual Studio 14 2015 Win64" -DCMAKE_CONFIGURATION_TYPES="Debug;Release" -DLLVM_TARGETS_TO_BUILD=X86 -DLLVM_BUILD_RUNTIME=OFF -DLLVM_BUILD_TOOLS=OFF -DLLVM_INCLUDE_DOCS=OFF -DLLVM_INCLUDE_EXAMPLES=OFF -DLLVM_INCLUDE_TESTS=OFF -DLLVM_INCLUDE_TOOLS=OFF -DLLVM_INCLUDE_UTILS=OFF -DWITH_POLLY=OFF -DCMAKE_SYSTEM_VERSION=6.1 -DCMAKE_VS_WINDOWS_TARGET_PLATFORM_VERSION=8.1 ../llvm
|
||||
|
||||
RD /S /Q cmake
|
||||
RD /S /Q CMakeFiles
|
||||
|
||||
@@ -18,12 +18,12 @@
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
|
||||
<ConfigurationType>Makefile</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<PlatformToolset>v141</PlatformToolset>
|
||||
<PlatformToolset>v140</PlatformToolset>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
|
||||
<ConfigurationType>Makefile</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<PlatformToolset>v141</PlatformToolset>
|
||||
<PlatformToolset>v140</PlatformToolset>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
|
||||
<ImportGroup Label="ExtensionSettings">
|
||||
@@ -39,30 +39,30 @@
|
||||
<NMakePreprocessorDefinitions>
|
||||
</NMakePreprocessorDefinitions>
|
||||
<NMakeBuildCommandLine>
|
||||
cmake -G "Visual Studio 15 2017 Win64" -DCMAKE_CONFIGURATION_TYPES="Debug;Release" -DLLVM_TARGETS_TO_BUILD=X86 -DLLVM_EXTERNAL_POLLY_SOURCE_DIR=../polly -DLLVM_BUILD_RUNTIME=OFF -DLLVM_BUILD_TOOLS=OFF -DLLVM_INCLUDE_DOCS=OFF -DLLVM_INCLUDE_EXAMPLES=OFF -DLLVM_INCLUDE_TESTS=OFF -DLLVM_INCLUDE_TOOLS=ON -DLLVM_INCLUDE_UTILS=ON -DWITH_POLLY=ON -DCMAKE_SYSTEM_VERSION=6.1 -DCMAKE_VS_WINDOWS_TARGET_PLATFORM_VERSION=8.1 ../llvm
|
||||
cmake -G "Visual Studio 14 2015 Win64" -DCMAKE_CONFIGURATION_TYPES="Debug;Release" -DLLVM_TARGETS_TO_BUILD=X86 -DLLVM_BUILD_RUNTIME=OFF -DLLVM_BUILD_TOOLS=OFF -DLLVM_INCLUDE_DOCS=OFF -DLLVM_INCLUDE_EXAMPLES=OFF -DLLVM_INCLUDE_TESTS=OFF -DLLVM_INCLUDE_TOOLS=OFF -DLLVM_INCLUDE_UTILS=OFF -DWITH_POLLY=OFF -DCMAKE_SYSTEM_VERSION=6.1 -DCMAKE_VS_WINDOWS_TARGET_PLATFORM_VERSION=8.1 ../llvm
|
||||
msbuild.exe ALL_BUILD.vcxproj /t:build /p:Configuration=Debug /m
|
||||
</NMakeBuildCommandLine>
|
||||
<NMakeReBuildCommandLine>
|
||||
cmake -G "Visual Studio 15 2017 Win64" -DCMAKE_CONFIGURATION_TYPES="Debug;Release" -DLLVM_TARGETS_TO_BUILD=X86 -DLLVM_EXTERNAL_POLLY_SOURCE_DIR=../polly -DLLVM_BUILD_RUNTIME=OFF -DLLVM_BUILD_TOOLS=OFF -DLLVM_INCLUDE_DOCS=OFF -DLLVM_INCLUDE_EXAMPLES=OFF -DLLVM_INCLUDE_TESTS=OFF -DLLVM_INCLUDE_TOOLS=ON -DLLVM_INCLUDE_UTILS=ON -DWITH_POLLY=ON -DCMAKE_SYSTEM_VERSION=6.1 -DCMAKE_VS_WINDOWS_TARGET_PLATFORM_VERSION=8.1 ../llvm
|
||||
cmake -G "Visual Studio 14 2015 Win64" -DCMAKE_CONFIGURATION_TYPES="Debug;Release" -DLLVM_TARGETS_TO_BUILD=X86 -DLLVM_BUILD_RUNTIME=OFF -DLLVM_BUILD_TOOLS=OFF -DLLVM_INCLUDE_DOCS=OFF -DLLVM_INCLUDE_EXAMPLES=OFF -DLLVM_INCLUDE_TESTS=OFF -DLLVM_INCLUDE_TOOLS=OFF -DLLVM_INCLUDE_UTILS=OFF -DWITH_POLLY=OFF -DCMAKE_SYSTEM_VERSION=6.1 -DCMAKE_VS_WINDOWS_TARGET_PLATFORM_VERSION=8.1 ../llvm
|
||||
msbuild.exe ALL_BUILD.vcxproj /t:rebuild /p:Configuration=Debug /m
|
||||
</NMakeReBuildCommandLine>
|
||||
<NMakeCleanCommandLine>
|
||||
cmake -G "Visual Studio 15 2017 Win64" -DCMAKE_CONFIGURATION_TYPES="Debug;Release" -DLLVM_TARGETS_TO_BUILD=X86 -DLLVM_EXTERNAL_POLLY_SOURCE_DIR=../polly -DLLVM_BUILD_RUNTIME=OFF -DLLVM_BUILD_TOOLS=OFF -DLLVM_INCLUDE_DOCS=OFF -DLLVM_INCLUDE_EXAMPLES=OFF -DLLVM_INCLUDE_TESTS=OFF -DLLVM_INCLUDE_TOOLS=ON -DLLVM_INCLUDE_UTILS=ON -DWITH_POLLY=ON -DCMAKE_SYSTEM_VERSION=6.1 -DCMAKE_VS_WINDOWS_TARGET_PLATFORM_VERSION=8.1 ../llvm
|
||||
cmake -G "Visual Studio 14 2015 Win64" -DCMAKE_CONFIGURATION_TYPES="Debug;Release" -DLLVM_TARGETS_TO_BUILD=X86 -DLLVM_BUILD_RUNTIME=OFF -DLLVM_BUILD_TOOLS=OFF -DLLVM_INCLUDE_DOCS=OFF -DLLVM_INCLUDE_EXAMPLES=OFF -DLLVM_INCLUDE_TESTS=OFF -DLLVM_INCLUDE_TOOLS=OFF -DLLVM_INCLUDE_UTILS=OFF -DWITH_POLLY=OFF -DCMAKE_SYSTEM_VERSION=6.1 -DCMAKE_VS_WINDOWS_TARGET_PLATFORM_VERSION=8.1 ../llvm
|
||||
msbuild.exe ALL_BUILD.vcxproj /t:clean /p:Configuration=Debug /m
|
||||
</NMakeCleanCommandLine>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<NMakePreprocessorDefinitions />
|
||||
<NMakeBuildCommandLine>
|
||||
cmake -G "Visual Studio 15 2017 Win64" -DCMAKE_CONFIGURATION_TYPES="Debug;Release" -DLLVM_TARGETS_TO_BUILD=X86 -DLLVM_EXTERNAL_POLLY_SOURCE_DIR=../polly -DLLVM_BUILD_RUNTIME=OFF -DLLVM_BUILD_TOOLS=OFF -DLLVM_INCLUDE_DOCS=OFF -DLLVM_INCLUDE_EXAMPLES=OFF -DLLVM_INCLUDE_TESTS=OFF -DLLVM_INCLUDE_TOOLS=ON -DLLVM_INCLUDE_UTILS=ON -DWITH_POLLY=ON -DCMAKE_SYSTEM_VERSION=6.1 -DCMAKE_VS_WINDOWS_TARGET_PLATFORM_VERSION=8.1 ../llvm
|
||||
cmake -G "Visual Studio 14 2015 Win64" -DCMAKE_CONFIGURATION_TYPES="Debug;Release" -DLLVM_TARGETS_TO_BUILD=X86 -DLLVM_BUILD_RUNTIME=OFF -DLLVM_BUILD_TOOLS=OFF -DLLVM_INCLUDE_DOCS=OFF -DLLVM_INCLUDE_EXAMPLES=OFF -DLLVM_INCLUDE_TESTS=OFF -DLLVM_INCLUDE_TOOLS=OFF -DLLVM_INCLUDE_UTILS=OFF -DWITH_POLLY=OFF -DCMAKE_SYSTEM_VERSION=6.1 -DCMAKE_VS_WINDOWS_TARGET_PLATFORM_VERSION=8.1 ../llvm
|
||||
msbuild.exe ALL_BUILD.vcxproj /t:build /p:Configuration=Release /m
|
||||
</NMakeBuildCommandLine>
|
||||
<NMakeReBuildCommandLine>
|
||||
cmake -G "Visual Studio 15 2017 Win64" -DCMAKE_CONFIGURATION_TYPES="Debug;Release" -DLLVM_TARGETS_TO_BUILD=X86 -DLLVM_EXTERNAL_POLLY_SOURCE_DIR=../polly -DLLVM_BUILD_RUNTIME=OFF -DLLVM_BUILD_TOOLS=OFF -DLLVM_INCLUDE_DOCS=OFF -DLLVM_INCLUDE_EXAMPLES=OFF -DLLVM_INCLUDE_TESTS=OFF -DLLVM_INCLUDE_TOOLS=ON -DLLVM_INCLUDE_UTILS=ON -DWITH_POLLY=ON -DCMAKE_SYSTEM_VERSION=6.1 -DCMAKE_VS_WINDOWS_TARGET_PLATFORM_VERSION=8.1 ../llvm
|
||||
cmake -G "Visual Studio 14 2015 Win64" -DCMAKE_CONFIGURATION_TYPES="Debug;Release" -DLLVM_TARGETS_TO_BUILD=X86 -DLLVM_BUILD_RUNTIME=OFF -DLLVM_BUILD_TOOLS=OFF -DLLVM_INCLUDE_DOCS=OFF -DLLVM_INCLUDE_EXAMPLES=OFF -DLLVM_INCLUDE_TESTS=OFF -DLLVM_INCLUDE_TOOLS=OFF -DLLVM_INCLUDE_UTILS=OFF -DWITH_POLLY=OFF -DCMAKE_SYSTEM_VERSION=6.1 -DCMAKE_VS_WINDOWS_TARGET_PLATFORM_VERSION=8.1 ../llvm
|
||||
msbuild.exe ALL_BUILD.vcxproj /t:rebuild /p:Configuration=Release /m
|
||||
</NMakeReBuildCommandLine>
|
||||
<NMakeCleanCommandLine>
|
||||
cmake -G "Visual Studio 15 2017 Win64" -DCMAKE_CONFIGURATION_TYPES="Debug;Release" -DLLVM_TARGETS_TO_BUILD=X86 -DLLVM_EXTERNAL_POLLY_SOURCE_DIR=../polly -DLLVM_BUILD_RUNTIME=OFF -DLLVM_BUILD_TOOLS=OFF -DLLVM_INCLUDE_DOCS=OFF -DLLVM_INCLUDE_EXAMPLES=OFF -DLLVM_INCLUDE_TESTS=OFF -DLLVM_INCLUDE_TOOLS=ON -DLLVM_INCLUDE_UTILS=ON -DWITH_POLLY=ON -DCMAKE_SYSTEM_VERSION=6.1 -DCMAKE_VS_WINDOWS_TARGET_PLATFORM_VERSION=8.1 ../llvm
|
||||
cmake -G "Visual Studio 14 2015 Win64" -DCMAKE_CONFIGURATION_TYPES="Debug;Release" -DLLVM_TARGETS_TO_BUILD=X86 -DLLVM_BUILD_RUNTIME=OFF -DLLVM_BUILD_TOOLS=OFF -DLLVM_INCLUDE_DOCS=OFF -DLLVM_INCLUDE_EXAMPLES=OFF -DLLVM_INCLUDE_TESTS=OFF -DLLVM_INCLUDE_TOOLS=OFF -DLLVM_INCLUDE_UTILS=OFF -DWITH_POLLY=OFF -DCMAKE_SYSTEM_VERSION=6.1 -DCMAKE_VS_WINDOWS_TARGET_PLATFORM_VERSION=8.1 ../llvm
|
||||
msbuild.exe ALL_BUILD.vcxproj /t:clean /p:Configuration=Release /m
|
||||
</NMakeCleanCommandLine>
|
||||
</PropertyGroup>
|
||||
|
||||
@@ -62,9 +62,6 @@ vcxproj_files = ["lib\Analysis\LLVMAnalysis.vcxproj",
|
||||
"lib\Transforms\Utils\LLVMTransformUtils.vcxproj",
|
||||
"lib\Transforms\Vectorize\LLVMVectorize.vcxproj",
|
||||
"include\llvm\IR\intrinsics_gen.vcxproj",
|
||||
"tools\polly\lib\Polly.vcxproj",
|
||||
"tools\polly\lib\External\PollyISL.vcxproj",
|
||||
"tools\polly\lib\External\PollyPPCG.vcxproj",
|
||||
"utils\TableGen\llvm-tblgen.vcxproj",
|
||||
]
|
||||
|
||||
|
||||
-1
Submodule polly deleted from 7f7d8e3954
@@ -20,14 +20,14 @@
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
|
||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<PlatformToolset>v141</PlatformToolset>
|
||||
<PlatformToolset>v140</PlatformToolset>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
<UseOfMfc>false</UseOfMfc>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
|
||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<PlatformToolset>v141</PlatformToolset>
|
||||
<PlatformToolset>v140</PlatformToolset>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
<UseOfMfc>false</UseOfMfc>
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio 15
|
||||
VisualStudioVersion = 15.0.27130.2027
|
||||
# Visual Studio 14
|
||||
VisualStudioVersion = 14.0.25420.1
|
||||
MinimumVisualStudioVersion = 10.0.40219.1
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "asmjit", "asmjitsrc\asmjit.vcxproj", "{AC40FF01-426E-4838-A317-66354CEFAE88}"
|
||||
EndProject
|
||||
@@ -243,7 +243,4 @@ Global
|
||||
{FDC361C5-7734-493B-8CFB-037308B35122} = {DDF904CA-2771-441A-8629-5DF2EB922A79}
|
||||
{A107C21C-418A-4697-BB10-20C3AA60E2E4} = {FA1E6C16-CA63-45F8-8D52-E21DF396BE36}
|
||||
EndGlobalSection
|
||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||
SolutionGuid = {06CC7920-E085-4B81-9582-8DE8AAD42510}
|
||||
EndGlobalSection
|
||||
EndGlobal
|
||||
|
||||
+2
-30
@@ -96,7 +96,7 @@ if(NOT MSVC)
|
||||
if(NOT APPLE)
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wl,--exclude-libs,ALL")
|
||||
endif()
|
||||
|
||||
|
||||
if(WIN32)
|
||||
set(CMAKE_RC_COMPILER_INIT windres)
|
||||
enable_language(RC)
|
||||
@@ -173,7 +173,7 @@ set(CMAKE_MODULE_PATH "${RPCS3_SRC_DIR}/cmake_modules")
|
||||
find_package(OpenGL REQUIRED)
|
||||
find_package(OpenAL REQUIRED)
|
||||
if(NOT WITHOUT_LLVM)
|
||||
find_package(LLVM 6.0 CONFIG)
|
||||
find_package(LLVM 4.0 CONFIG)
|
||||
if(NOT LLVM_FOUND)
|
||||
message("System LLVM was not found, LLVM will be built from the submodule.")
|
||||
|
||||
@@ -198,28 +198,6 @@ if(NOT WITHOUT_LLVM)
|
||||
endif()
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# Now let's look for polly.
|
||||
find_package(Polly)
|
||||
if(Polly_FOUND)
|
||||
add_definitions(-DPOLLY_AVAILABLE)
|
||||
endif()
|
||||
# Polly LLVM Compiler checks
|
||||
CHECK_C_COMPILER_FLAG("-mllvm -polly" HAS_POLLY)
|
||||
CHECK_C_COMPILER_FLAG("-mllvm -polly-target=hybrid" HAS_POLLY_HYBRID)
|
||||
CHECK_C_COMPILER_FLAG("-mllvm -polly-target=cpu" HAS_POLLY_CPU)
|
||||
|
||||
if (HAS_POLLY)
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -mllvm -polly -mllvm -polly-parallel -lgomp -mllvm -polly-vectorizer=stripmine")
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -mllvm -polly -mllvm -polly-parallel -lgomp -mllvm -polly-vectorizer=stripmine")
|
||||
if(HAS_POLLY_HYBRID)
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -mllvm -polly-target=hybrid")
|
||||
set(CMAKE_C_FLAGS "${CMAKE_CXX_FLAGS} -mllvm -polly-target=cpu")
|
||||
elseif(HAS_POLLY_CPU)
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -mllvm -polly-target=cpu")
|
||||
set(CMAKE_C_FLAGS "${CMAKE_CXX_FLAGS} -mllvm -polly-target=cpu")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
|
||||
if(APPLE)
|
||||
@@ -296,7 +274,6 @@ endif()
|
||||
include_directories(
|
||||
${OPENAL_INCLUDE_DIR}
|
||||
${LLVM_INCLUDE_DIRS}
|
||||
${Polly_INCLUDE_DIRS}
|
||||
"${RPCS3_SRC_DIR}/../3rdparty/pugixml/src"
|
||||
"${RPCS3_SRC_DIR}"
|
||||
"${RPCS3_SRC_DIR}/Loader"
|
||||
@@ -342,7 +319,6 @@ endif()
|
||||
link_directories(
|
||||
"${RPCS3_SRC_DIR}/../3rdparty/minidx12/"
|
||||
"${RPCS3_SRC_DIR}/../Vulkan"
|
||||
"${Polly_LIBRARY_DIRS}"
|
||||
)
|
||||
|
||||
|
||||
@@ -417,10 +393,6 @@ if(NOT MSVC)
|
||||
target_link_libraries(rpcs3 GLEW::GLEW)
|
||||
endif()
|
||||
|
||||
if(Polly_FOUND)
|
||||
target_link_libraries(rpcs3 Polly PollyISL PollyPPCG)
|
||||
endif()
|
||||
|
||||
if(WIN32)
|
||||
target_link_libraries(rpcs3 ws2_32.lib Winmm.lib Psapi.lib gdi32.lib VKstatic.1 glslang OSDependent OGLCompiler SPIRV HLSL setupapi.lib hidapi-hid Shlwapi.lib)
|
||||
if(NOT MSVC)
|
||||
|
||||
@@ -31,7 +31,7 @@
|
||||
<PropertyGroup Label="Configuration">
|
||||
<ConfigurationType>StaticLibrary</ConfigurationType>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
<PlatformToolset>v141</PlatformToolset>
|
||||
<PlatformToolset>v140</PlatformToolset>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
|
||||
<ImportGroup Label="ExtensionSettings">
|
||||
|
||||
@@ -711,6 +711,38 @@ public:
|
||||
return result;
|
||||
}
|
||||
|
||||
template <typename T, typename T2>
|
||||
value_t<T> bitcast(T2 expr)
|
||||
{
|
||||
value_t<T> result;
|
||||
result.value = m_ir->CreateBitCast(expr.eval(m_ir), result.get_type(m_context));
|
||||
return result;
|
||||
}
|
||||
|
||||
template <typename T, typename T2>
|
||||
value_t<T> trunc(T2 expr)
|
||||
{
|
||||
value_t<T> result;
|
||||
result.value = m_ir->CreateTrunc(expr.eval(m_ir), result.get_type(m_context));
|
||||
return result;
|
||||
}
|
||||
|
||||
template <typename T, typename T2>
|
||||
value_t<T> sext(T2 expr)
|
||||
{
|
||||
value_t<T> result;
|
||||
result.value = m_ir->CreateSExt(expr.eval(m_ir), result.get_type(m_context));
|
||||
return result;
|
||||
}
|
||||
|
||||
template <typename T, typename T2>
|
||||
value_t<T> zext(T2 expr)
|
||||
{
|
||||
value_t<T> result;
|
||||
result.value = m_ir->CreateZExt(expr.eval(m_ir), result.get_type(m_context));
|
||||
return result;
|
||||
}
|
||||
|
||||
// Get unsigned addition carry into the sign bit (s = a + b)
|
||||
template <typename T>
|
||||
static inline auto ucarry(T a, T b, T s)
|
||||
|
||||
@@ -176,16 +176,14 @@ void mfc_thread::cpu_task()
|
||||
|
||||
data = to_write;
|
||||
vm::reservation_update(cmd.eal, 128);
|
||||
_xend();
|
||||
vm::notify(cmd.eal, 128);
|
||||
_xend();
|
||||
}
|
||||
else
|
||||
{
|
||||
{
|
||||
vm::writer_lock lock(0);
|
||||
data = to_write;
|
||||
vm::reservation_update(cmd.eal, 128);
|
||||
}
|
||||
vm::writer_lock lock(0);
|
||||
data = to_write;
|
||||
vm::reservation_update(cmd.eal, 128);
|
||||
vm::notify(cmd.eal, 128);
|
||||
}
|
||||
}
|
||||
@@ -358,6 +356,7 @@ void mfc_thread::cpu_task()
|
||||
}
|
||||
else
|
||||
{
|
||||
vm::reader_lock lock;
|
||||
vm::notify_all();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#include "stdafx.h"
|
||||
#include "stdafx.h"
|
||||
#include "Emu/System.h"
|
||||
#include "Emu/Cell/PPUModule.h"
|
||||
|
||||
@@ -554,7 +554,7 @@ s32 cellFontExtend(u32 a1, u32 a2, u32 a3)
|
||||
//Something happens
|
||||
}
|
||||
//Something happens?
|
||||
return -1;
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
s32 cellFontRenderCharGlyphImageVertical()
|
||||
|
||||
@@ -1436,7 +1436,7 @@ void ppu_module::analyse(u32 lib_toc, u32 entry)
|
||||
|
||||
void ppu_acontext::UNK(ppu_opcode_t op)
|
||||
{
|
||||
std::fill_n(gpr, 32, spec_gpr());
|
||||
std::fill_n(gpr, 32, spec_gpr{});
|
||||
LOG_ERROR(PPU, "Unknown/Illegal opcode: 0x%08x at 0x%x" HERE, op.opcode, cia);
|
||||
}
|
||||
|
||||
@@ -2563,7 +2563,7 @@ void ppu_acontext::MULHW(ppu_opcode_t op)
|
||||
|
||||
void ppu_acontext::LDARX(ppu_opcode_t op)
|
||||
{
|
||||
gpr[op.rd] = spec_gpr();
|
||||
gpr[op.rd] = {};
|
||||
}
|
||||
|
||||
void ppu_acontext::DCBF(ppu_opcode_t op)
|
||||
@@ -2879,7 +2879,7 @@ void ppu_acontext::LVRX(ppu_opcode_t op)
|
||||
|
||||
void ppu_acontext::LSWI(ppu_opcode_t op)
|
||||
{
|
||||
std::fill_n(gpr, 32, spec_gpr());
|
||||
std::fill_n(gpr, 32, spec_gpr{});
|
||||
}
|
||||
|
||||
void ppu_acontext::LFSUX(ppu_opcode_t op)
|
||||
@@ -3106,7 +3106,7 @@ void ppu_acontext::STHU(ppu_opcode_t op)
|
||||
|
||||
void ppu_acontext::LMW(ppu_opcode_t op)
|
||||
{
|
||||
std::fill_n(gpr, 32, spec_gpr());
|
||||
std::fill_n(gpr, 32, spec_gpr{});
|
||||
}
|
||||
|
||||
void ppu_acontext::STMW(ppu_opcode_t op)
|
||||
|
||||
@@ -40,12 +40,6 @@
|
||||
#include "llvm/Transforms/Scalar.h"
|
||||
#include "llvm/Transforms/IPO.h"
|
||||
#include "llvm/Transforms/Vectorize.h"
|
||||
|
||||
#ifdef POLLY_AVAILABLE
|
||||
#include <polly/RegisterPasses.h>
|
||||
#include <polly/ScopDetection.h>
|
||||
#endif
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning(pop)
|
||||
#endif
|
||||
@@ -967,18 +961,14 @@ extern bool ppu_stwcx(ppu_thread& ppu, u32 addr, u32 reg_value)
|
||||
return result;
|
||||
}
|
||||
|
||||
bool result;
|
||||
vm::writer_lock lock(0);
|
||||
|
||||
const bool result = ppu.rtime == vm::reservation_acquire(addr, sizeof(u32)) && data.compare_and_swap_test(static_cast<u32>(ppu.rdata), reg_value);
|
||||
|
||||
if (result)
|
||||
{
|
||||
vm::writer_lock lock(0);
|
||||
|
||||
result = ppu.rtime == vm::reservation_acquire(addr, sizeof(u32)) && data.compare_and_swap_test(static_cast<u32>(ppu.rdata), reg_value);
|
||||
|
||||
if (result)
|
||||
{
|
||||
vm::reservation_update(addr, sizeof(u32));
|
||||
lock.unlock();
|
||||
vm::notify(addr, sizeof(u32));
|
||||
}
|
||||
vm::reservation_update(addr, sizeof(u32));
|
||||
vm::notify(addr, sizeof(u32));
|
||||
}
|
||||
|
||||
ppu.raddr = 0;
|
||||
@@ -1015,18 +1005,14 @@ extern bool ppu_stdcx(ppu_thread& ppu, u32 addr, u64 reg_value)
|
||||
return result;
|
||||
}
|
||||
|
||||
bool result;
|
||||
vm::writer_lock lock(0);
|
||||
|
||||
const bool result = ppu.rtime == vm::reservation_acquire(addr, sizeof(u64)) && data.compare_and_swap_test(ppu.rdata, reg_value);
|
||||
|
||||
if (result)
|
||||
{
|
||||
vm::writer_lock lock(0);
|
||||
|
||||
result = ppu.rtime == vm::reservation_acquire(addr, sizeof(u64)) && data.compare_and_swap_test(ppu.rdata, reg_value);
|
||||
|
||||
if (result)
|
||||
{
|
||||
vm::reservation_update(addr, sizeof(u64));
|
||||
lock.unlock();
|
||||
vm::notify(addr, sizeof(u64));
|
||||
}
|
||||
vm::reservation_update(addr, sizeof(u64));
|
||||
vm::notify(addr, sizeof(u64));
|
||||
}
|
||||
|
||||
ppu.raddr = 0;
|
||||
@@ -1478,11 +1464,6 @@ static void ppu_initialize2(jit_compiler& jit, const ppu_module& module_part, co
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef POLLY_AVAILABLE
|
||||
PassRegistry &Registry = *PassRegistry::getPassRegistry();
|
||||
polly::initializePollyPasses(Registry);
|
||||
initializeAnalysis(Registry);
|
||||
#endif
|
||||
std::shared_ptr<MsgDialogBase> dlg;
|
||||
|
||||
{
|
||||
@@ -1500,9 +1481,6 @@ static void ppu_initialize2(jit_compiler& jit, const ppu_module& module_part, co
|
||||
//pm.add(createLoopInstSimplifyPass());
|
||||
//pm.add(createNewGVNPass());
|
||||
pm.add(createDeadStoreEliminationPass());
|
||||
#ifdef POLLY_AVAILABLE
|
||||
polly::registerPollyPasses(pm);
|
||||
#endif
|
||||
//pm.add(createSCCPPass());
|
||||
//pm.add(createReassociatePass());
|
||||
//pm.add(createInstructionCombiningPass());
|
||||
|
||||
@@ -14,7 +14,7 @@ const ppu_decoder<PPUTranslator> s_ppu_decoder;
|
||||
PPUTranslator::PPUTranslator(LLVMContext& context, Module* module, const ppu_module& info)
|
||||
: cpu_translator(context, module, false)
|
||||
, m_info(info)
|
||||
, m_pure_attr(AttributeList::get(m_context,AttributeList::FunctionIndex, AttrBuilder().addAttribute(Attribute::NoUnwind).addAttribute(Attribute::ReadNone)))
|
||||
, m_pure_attr(AttributeSet::get(m_context, AttributeSet::FunctionIndex, {Attribute::NoUnwind, Attribute::ReadNone}))
|
||||
{
|
||||
// There is no weak linkage on JIT, so let's create variables with different names for each module part
|
||||
const u32 gsuffix = m_info.name.empty() ? info.funcs[0].addr : info.funcs[0].addr - m_info.segs[0].addr;
|
||||
|
||||
@@ -10,6 +10,11 @@
|
||||
|
||||
#include <cmath>
|
||||
|
||||
#define ASMJIT_STATIC
|
||||
#define ASMJIT_DEBUG
|
||||
|
||||
#include "asmjit.h"
|
||||
|
||||
#define SPU_OFF_128(x, ...) asmjit::x86::oword_ptr(*cpu, offset32(&SPUThread::x, ##__VA_ARGS__))
|
||||
#define SPU_OFF_64(x, ...) asmjit::x86::qword_ptr(*cpu, offset32(&SPUThread::x, ##__VA_ARGS__))
|
||||
#define SPU_OFF_32(x, ...) asmjit::x86::dword_ptr(*cpu, offset32(&SPUThread::x, ##__VA_ARGS__))
|
||||
@@ -31,25 +36,25 @@ spu_recompiler::spu_recompiler()
|
||||
}
|
||||
}
|
||||
|
||||
bool spu_recompiler::compile(spu_function_contents_t* f)
|
||||
void spu_recompiler::compile(spu_function_t& f)
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(m_mutex);
|
||||
|
||||
if (f->compiled)
|
||||
if (f.compiled)
|
||||
{
|
||||
// return if function already compiled
|
||||
return true;
|
||||
return;
|
||||
}
|
||||
|
||||
if (f->addr >= 0x40000 || f->addr % 4 || f->size == 0 || f->size > 0x40000 - f->addr || f->size % 4)
|
||||
if (f.addr >= 0x40000 || f.addr % 4 || f.size == 0 || f.size > 0x40000 - f.addr || f.size % 4)
|
||||
{
|
||||
fmt::throw_exception("Invalid SPU function (addr=0x%05x, size=0x%x)" HERE, f->addr, f->size);
|
||||
fmt::throw_exception("Invalid SPU function (addr=0x%05x, size=0x%x)" HERE, f.addr, f.size);
|
||||
}
|
||||
|
||||
using namespace asmjit;
|
||||
|
||||
SPUDisAsm dis_asm(CPUDisAsm_InterpreterMode);
|
||||
dis_asm.offset = reinterpret_cast<u8*>(f->data.data()) - f->addr;
|
||||
dis_asm.offset = reinterpret_cast<u8*>(f.data.data()) - f.addr;
|
||||
|
||||
StringLogger logger;
|
||||
logger.addOptions(Logger::kOptionBinaryForm);
|
||||
@@ -58,10 +63,10 @@ bool spu_recompiler::compile(spu_function_contents_t* f)
|
||||
|
||||
if (g_cfg.core.spu_debug)
|
||||
{
|
||||
fmt::append(log, "========== SPU FUNCTION 0x%05x - 0x%05x ==========\n\n", f->addr, f->addr + f->size);
|
||||
fmt::append(log, "========== SPU FUNCTION 0x%05x - 0x%05x ==========\n\n", f.addr, f.addr + f.size);
|
||||
}
|
||||
|
||||
this->m_func = f;
|
||||
this->m_func = &f;
|
||||
|
||||
asmjit::CodeHolder code;
|
||||
code.init(m_jit->getCodeInfo());
|
||||
@@ -116,13 +121,13 @@ bool spu_recompiler::compile(spu_function_contents_t* f)
|
||||
compiler.alloc(vec_vars[5], asmjit::x86::xmm5);
|
||||
|
||||
// Initialize labels
|
||||
this->labels = std::unique_ptr<Label[]>(reinterpret_cast<Label*>(new u8[0x10000 * sizeof(Label)]()));
|
||||
auto pos_labels = this->labels.get();
|
||||
std::vector<Label> pos_labels{ 0x10000 };
|
||||
this->labels = pos_labels.data();
|
||||
|
||||
// Register labels for block entries
|
||||
for (const u32 addr : f->blocks)
|
||||
for (const u32 addr : f.blocks)
|
||||
{
|
||||
if (addr < f->addr || addr >= f->addr + f->size || addr % 4)
|
||||
if (addr < f.addr || addr >= f.addr + f.size || addr % 4)
|
||||
{
|
||||
fmt::throw_exception("Invalid function block entry (0x%05x)" HERE, addr);
|
||||
}
|
||||
@@ -131,15 +136,15 @@ bool spu_recompiler::compile(spu_function_contents_t* f)
|
||||
}
|
||||
|
||||
// Register label for post-the-end address
|
||||
pos_labels[(f->addr + f->size) / 4 % 0x10000] = compiler.newLabel();
|
||||
pos_labels[(f.addr + f.size) / 4 % 0x10000] = compiler.newLabel();
|
||||
|
||||
// Register label for jump table resolver
|
||||
Label jt_label = compiler.newLabel();
|
||||
this->jt = &jt_label;
|
||||
|
||||
for (const u32 addr : f->jtable)
|
||||
for (const u32 addr : f.jtable)
|
||||
{
|
||||
if (addr < f->addr || addr >= f->addr + f->size || addr % 4)
|
||||
if (addr < f.addr || addr >= f.addr + f.size || addr % 4)
|
||||
{
|
||||
fmt::throw_exception("Invalid jump table entry (0x%05x)" HERE, addr);
|
||||
}
|
||||
@@ -150,16 +155,24 @@ bool spu_recompiler::compile(spu_function_contents_t* f)
|
||||
this->end = &end_label;
|
||||
|
||||
// Start compilation
|
||||
m_pos = f->addr;
|
||||
m_pos = f.addr;
|
||||
|
||||
for (const u32 op : f->data)
|
||||
if (utils::has_avx())
|
||||
{
|
||||
compiler.vzeroupper();
|
||||
//compiler.pxor(asmjit::x86::xmm0, asmjit::x86::xmm0);
|
||||
//compiler.vptest(asmjit::x86::ymm0, asmjit::x86::ymm0);
|
||||
//compiler.jnz(end_label);
|
||||
}
|
||||
|
||||
for (const u32 op : f.data)
|
||||
{
|
||||
// Bind label if initialized
|
||||
if (pos_labels[m_pos / 4].isValid())
|
||||
{
|
||||
compiler.bind(pos_labels[m_pos / 4]);
|
||||
|
||||
if (f->blocks.find(m_pos) != f->blocks.end())
|
||||
if (f.blocks.find(m_pos) != f.blocks.end())
|
||||
{
|
||||
compiler.comment("Block:");
|
||||
}
|
||||
@@ -206,12 +219,12 @@ bool spu_recompiler::compile(spu_function_contents_t* f)
|
||||
// Generate jump table resolver (uses addr_var)
|
||||
compiler.bind(jt_label);
|
||||
|
||||
if (f->jtable.size())
|
||||
if (f.jtable.size())
|
||||
{
|
||||
compiler.comment("Jump table resolver:");
|
||||
}
|
||||
|
||||
for (const u32 addr : f->jtable)
|
||||
for (const u32 addr : f.jtable)
|
||||
{
|
||||
if ((addr % 4) == 0 && addr < 0x40000 && pos_labels[addr / 4].isValid())
|
||||
{
|
||||
@@ -240,8 +253,8 @@ bool spu_recompiler::compile(spu_function_contents_t* f)
|
||||
Func fn;
|
||||
m_jit->add(&fn, codeHolder);
|
||||
|
||||
f->compiled = asmjit::Internal::ptr_cast<decltype(f->compiled)>(fn);
|
||||
|
||||
f.compiled = asmjit::Internal::ptr_cast<decltype(f.compiled)>(fn);
|
||||
|
||||
if (g_cfg.core.spu_debug)
|
||||
{
|
||||
// Add ASMJIT logs
|
||||
@@ -449,29 +462,16 @@ void spu_recompiler::LNOP(spu_opcode_t op)
|
||||
{
|
||||
}
|
||||
|
||||
void invalidate_jit(SPUThread* _spu)
|
||||
{
|
||||
for (u32 i = _spu->first_clean_func_index; i < _spu->last_clean_func_index; i++)
|
||||
{
|
||||
_spu->compiled_functions[i].dirty_bit = true;
|
||||
}
|
||||
_spu->first_clean_func_index = -1;
|
||||
_spu->last_clean_func_index = 0;
|
||||
}
|
||||
|
||||
void spu_recompiler::SYNC(spu_opcode_t op)
|
||||
{
|
||||
asmjit::CCFuncCall* call = c->call(asmjit::imm_ptr(asmjit::Internal::ptr_cast<void*, void(SPUThread*)>(invalidate_jit)), asmjit::FuncSignature1<u32, SPUThread*>(asmjit::CallConv::kIdHost));
|
||||
call->setArg(0, *cpu);
|
||||
// This instruction must be used following a store instruction that modifies the instruction stream.
|
||||
c->mfence();
|
||||
}
|
||||
|
||||
void spu_recompiler::DSYNC(spu_opcode_t op)
|
||||
{
|
||||
// This instruction forces all earlier load, store, and channel instructions to complete before proceeding.
|
||||
c->mfence();
|
||||
asmjit::CCFuncCall* call = c->call(asmjit::imm_ptr(asmjit::Internal::ptr_cast<void*, void(SPUThread*)>(invalidate_jit)), asmjit::FuncSignature1<u32, SPUThread*>(asmjit::CallConv::kIdHost));
|
||||
call->setArg(0, *cpu);
|
||||
}
|
||||
|
||||
void spu_recompiler::MFSPR(spu_opcode_t op)
|
||||
@@ -623,6 +623,16 @@ void spu_recompiler::ROT(spu_opcode_t op)
|
||||
return;
|
||||
}
|
||||
|
||||
if (utils::has_xop())
|
||||
{
|
||||
const XmmLink& va = XmmGet(op.ra, XmmType::Int);
|
||||
const XmmLink& vb = XmmGet(op.rb, XmmType::Int);
|
||||
const XmmLink& vt = XmmAlloc();
|
||||
c->vprotd(vt, va, vb);
|
||||
c->movdqa(SPU_OFF_128(gpr, op.rt), vt);
|
||||
return;
|
||||
}
|
||||
|
||||
auto body = [](u32* t, const u32* a, const s32* b) noexcept
|
||||
{
|
||||
for (u32 i = 0; i < 4; i++)
|
||||
@@ -662,6 +672,22 @@ void spu_recompiler::ROTM(spu_opcode_t op)
|
||||
return;
|
||||
}
|
||||
|
||||
if (utils::has_xop())
|
||||
{
|
||||
const XmmLink& va = XmmGet(op.ra, XmmType::Int);
|
||||
const XmmLink& vb = XmmGet(op.rb, XmmType::Int);
|
||||
const XmmLink& vt = XmmAlloc();
|
||||
c->psubd(vb, XmmConst(_mm_set1_epi32(1)));
|
||||
c->pandn(vb, XmmConst(_mm_set1_epi32(0x3f)));
|
||||
c->pxor(vt, vt);
|
||||
c->psubd(vt, vb);
|
||||
c->pcmpgtd(vb, XmmConst(_mm_set1_epi32(31)));
|
||||
c->vpshld(vt, va, vt);
|
||||
c->vpandn(vt, vb, vt);
|
||||
c->movdqa(SPU_OFF_128(gpr, op.rt), vt);
|
||||
return;
|
||||
}
|
||||
|
||||
auto body = [](u32* t, const u32* a, const u32* b) noexcept
|
||||
{
|
||||
for (u32 i = 0; i < 4; i++)
|
||||
@@ -702,6 +728,21 @@ void spu_recompiler::ROTMA(spu_opcode_t op)
|
||||
return;
|
||||
}
|
||||
|
||||
if (utils::has_xop())
|
||||
{
|
||||
const XmmLink& va = XmmGet(op.ra, XmmType::Int);
|
||||
const XmmLink& vb = XmmGet(op.rb, XmmType::Int);
|
||||
const XmmLink& vt = XmmAlloc();
|
||||
c->psubd(vb, XmmConst(_mm_set1_epi32(1)));
|
||||
c->pandn(vb, XmmConst(_mm_set1_epi32(0x3f)));
|
||||
c->pxor(vt, vt);
|
||||
c->pminud(vb, XmmConst(_mm_set1_epi32(31)));
|
||||
c->psubd(vt, vb);
|
||||
c->vpshad(vt, va, vt);
|
||||
c->movdqa(SPU_OFF_128(gpr, op.rt), vt);
|
||||
return;
|
||||
}
|
||||
|
||||
auto body = [](s32* t, const s32* a, const u32* b) noexcept
|
||||
{
|
||||
for (u32 i = 0; i < 4; i++)
|
||||
@@ -741,6 +782,19 @@ void spu_recompiler::SHL(spu_opcode_t op)
|
||||
return;
|
||||
}
|
||||
|
||||
if (utils::has_xop())
|
||||
{
|
||||
const XmmLink& va = XmmGet(op.ra, XmmType::Int);
|
||||
const XmmLink& vb = XmmGet(op.rb, XmmType::Int);
|
||||
const XmmLink& vt = XmmAlloc();
|
||||
c->pand(vb, XmmConst(_mm_set1_epi32(0x3f)));
|
||||
c->vpcmpgtd(vt, vb, XmmConst(_mm_set1_epi32(31)));
|
||||
c->vpshld(vb, va, vb);
|
||||
c->pandn(vt, vb);
|
||||
c->movdqa(SPU_OFF_128(gpr, op.rt), vt);
|
||||
return;
|
||||
}
|
||||
|
||||
auto body = [](u32* t, const u32* a, const u32* b) noexcept
|
||||
{
|
||||
for (u32 i = 0; i < 4; i++)
|
||||
@@ -774,13 +828,24 @@ void spu_recompiler::ROTH(spu_opcode_t op) //nf
|
||||
const XmmLink& vb = XmmGet(op.rb, XmmType::Int);
|
||||
const XmmLink& vt = XmmAlloc();
|
||||
const XmmLink& v4 = XmmAlloc();
|
||||
c->movdqa(v4, XmmConst(_mm_set1_epi16(0xf)));
|
||||
c->pand(vb, v4);
|
||||
c->vpsllvw(vt, va, vb);
|
||||
c->psubw(vb, XmmConst(_mm_set1_epi16(1)));
|
||||
c->pandn(vb, v4);
|
||||
c->vpsrlvw(va, va, vb);
|
||||
c->por(vt, va);
|
||||
c->vmovdqa(v4, XmmConst(_mm_set_epi32(0x0d0c0d0c, 0x09080908, 0x05040504, 0x01000100)));
|
||||
c->vpshufb(vt, va, v4); // duplicate low word
|
||||
c->vpsrld(va, va, 16);
|
||||
c->vpshufb(va, va, v4);
|
||||
c->vpsrld(v4, vb, 16);
|
||||
c->vprolvd(va, va, v4);
|
||||
c->vprolvd(vb, vt, vb);
|
||||
c->vpblendw(vt, vb, va, 0xaa);
|
||||
c->vmovdqa(SPU_OFF_128(gpr, op.rt), vt);
|
||||
return;
|
||||
}
|
||||
|
||||
if (utils::has_xop())
|
||||
{
|
||||
const XmmLink& va = XmmGet(op.ra, XmmType::Int);
|
||||
const XmmLink& vb = XmmGet(op.rb, XmmType::Int);
|
||||
const XmmLink& vt = XmmAlloc();
|
||||
c->vprotw(vt, va, vb);
|
||||
c->movdqa(SPU_OFF_128(gpr, op.rt), vt);
|
||||
return;
|
||||
}
|
||||
@@ -824,6 +889,42 @@ void spu_recompiler::ROTHM(spu_opcode_t op)
|
||||
return;
|
||||
}
|
||||
|
||||
if (utils::has_avx2())
|
||||
{
|
||||
const XmmLink& va = XmmGet(op.ra, XmmType::Int);
|
||||
const XmmLink& vb = XmmGet(op.rb, XmmType::Int);
|
||||
const XmmLink& vt = XmmAlloc();
|
||||
const XmmLink& v4 = XmmAlloc();
|
||||
const XmmLink& v5 = XmmAlloc();
|
||||
c->psubw(vb, XmmConst(_mm_set1_epi16(1)));
|
||||
c->pandn(vb, XmmConst(_mm_set1_epi16(0x1f)));
|
||||
c->movdqa(vt, XmmConst(_mm_set1_epi32(0xffff0000))); // mask: select high words
|
||||
c->vpsrld(v4, vb, 16);
|
||||
c->vpsubusw(v5, vb, vt); // clear high words (using saturation sub for throughput)
|
||||
c->vpandn(vb, vt, va); // clear high words
|
||||
c->vpsrlvd(va, va, v4);
|
||||
c->vpsrlvd(vb, vb, v5);
|
||||
c->vpblendw(vt, vb, va, 0xaa); // can use vpblendvb with 0xffff0000 mask (vt)
|
||||
c->movdqa(SPU_OFF_128(gpr, op.rt), vt);
|
||||
return;
|
||||
}
|
||||
|
||||
if (utils::has_xop())
|
||||
{
|
||||
const XmmLink& va = XmmGet(op.ra, XmmType::Int);
|
||||
const XmmLink& vb = XmmGet(op.rb, XmmType::Int);
|
||||
const XmmLink& vt = XmmAlloc();
|
||||
c->psubw(vb, XmmConst(_mm_set1_epi16(1)));
|
||||
c->pandn(vb, XmmConst(_mm_set1_epi16(0x1f)));
|
||||
c->pxor(vt, vt);
|
||||
c->psubw(vt, vb);
|
||||
c->pcmpgtw(vb, XmmConst(_mm_set1_epi16(15)));
|
||||
c->vpshlw(vt, va, vt);
|
||||
c->vpandn(vt, vb, vt);
|
||||
c->movdqa(SPU_OFF_128(gpr, op.rt), vt);
|
||||
return;
|
||||
}
|
||||
|
||||
auto body = [](u16* t, const u16* a, const u16* b) noexcept
|
||||
{
|
||||
for (u32 i = 0; i < 8; i++)
|
||||
@@ -864,6 +965,43 @@ void spu_recompiler::ROTMAH(spu_opcode_t op)
|
||||
return;
|
||||
}
|
||||
|
||||
if (utils::has_avx2())
|
||||
{
|
||||
const XmmLink& va = XmmGet(op.ra, XmmType::Int);
|
||||
const XmmLink& vb = XmmGet(op.rb, XmmType::Int);
|
||||
const XmmLink& vt = XmmAlloc();
|
||||
const XmmLink& v4 = XmmAlloc();
|
||||
const XmmLink& v5 = XmmAlloc();
|
||||
c->psubw(vb, XmmConst(_mm_set1_epi16(1)));
|
||||
c->movdqa(vt, XmmConst(_mm_set1_epi16(0x1f)));
|
||||
c->vpandn(v4, vb, vt);
|
||||
c->vpand(v5, vb, vt);
|
||||
c->movdqa(vt, XmmConst(_mm_set1_epi32(0x2f)));
|
||||
c->vpsrld(v4, v4, 16);
|
||||
c->vpsubusw(v5, vt, v5); // clear high word and add 16 to low word
|
||||
c->vpslld(vb, va, 16);
|
||||
c->vpsravd(va, va, v4);
|
||||
c->vpsravd(vb, vb, v5);
|
||||
c->vpblendw(vt, vb, va, 0xaa);
|
||||
c->movdqa(SPU_OFF_128(gpr, op.rt), vt);
|
||||
return;
|
||||
}
|
||||
|
||||
if (utils::has_xop())
|
||||
{
|
||||
const XmmLink& va = XmmGet(op.ra, XmmType::Int);
|
||||
const XmmLink& vb = XmmGet(op.rb, XmmType::Int);
|
||||
const XmmLink& vt = XmmAlloc();
|
||||
c->psubw(vb, XmmConst(_mm_set1_epi16(1)));
|
||||
c->pandn(vb, XmmConst(_mm_set1_epi16(0x1f)));
|
||||
c->pxor(vt, vt);
|
||||
c->pminuw(vb, XmmConst(_mm_set1_epi16(15)));
|
||||
c->psubw(vt, vb);
|
||||
c->vpshaw(vt, va, vt);
|
||||
c->movdqa(SPU_OFF_128(gpr, op.rt), vt);
|
||||
return;
|
||||
}
|
||||
|
||||
auto body = [](s16* t, const s16* a, const u16* b) noexcept
|
||||
{
|
||||
for (u32 i = 0; i < 8; i++)
|
||||
@@ -903,6 +1041,38 @@ void spu_recompiler::SHLH(spu_opcode_t op)
|
||||
return;
|
||||
}
|
||||
|
||||
if (utils::has_avx2())
|
||||
{
|
||||
const XmmLink& va = XmmGet(op.ra, XmmType::Int);
|
||||
const XmmLink& vb = XmmGet(op.rb, XmmType::Int);
|
||||
const XmmLink& vt = XmmAlloc();
|
||||
const XmmLink& v4 = XmmAlloc();
|
||||
const XmmLink& v5 = XmmAlloc();
|
||||
c->pand(vb, XmmConst(_mm_set1_epi16(0x1f)));
|
||||
c->movdqa(vt, XmmConst(_mm_set1_epi32(0xffff0000))); // mask: select high words
|
||||
c->vpsrld(v4, vb, 16);
|
||||
c->vpsubusw(v5, vb, vt); // clear high words (using saturation sub for throughput)
|
||||
c->vpand(vb, vt, va); // clear low words
|
||||
c->vpsllvd(va, va, v5);
|
||||
c->vpsllvd(vb, vb, v4);
|
||||
c->vpblendw(vt, vb, va, 0x55);
|
||||
c->movdqa(SPU_OFF_128(gpr, op.rt), vt);
|
||||
return;
|
||||
}
|
||||
|
||||
if (utils::has_xop())
|
||||
{
|
||||
const XmmLink& va = XmmGet(op.ra, XmmType::Int);
|
||||
const XmmLink& vb = XmmGet(op.rb, XmmType::Int);
|
||||
const XmmLink& vt = XmmAlloc();
|
||||
c->pand(vb, XmmConst(_mm_set1_epi16(0x1f)));
|
||||
c->vpcmpgtw(vt, vb, XmmConst(_mm_set1_epi16(15)));
|
||||
c->vpshlw(vb, va, vb);
|
||||
c->pandn(vt, vb);
|
||||
c->movdqa(SPU_OFF_128(gpr, op.rt), vt);
|
||||
return;
|
||||
}
|
||||
|
||||
auto body = [](u16* t, const u16* a, const u16* b) noexcept
|
||||
{
|
||||
for (u32 i = 0; i < 8; i++)
|
||||
@@ -941,6 +1111,14 @@ void spu_recompiler::ROTI(spu_opcode_t op)
|
||||
return;
|
||||
}
|
||||
|
||||
if (utils::has_xop())
|
||||
{
|
||||
const XmmLink& va = XmmGet(op.ra, XmmType::Int);
|
||||
c->vprotd(va, va, s);
|
||||
c->movdqa(SPU_OFF_128(gpr, op.rt), va);
|
||||
return;
|
||||
}
|
||||
|
||||
const XmmLink& va = XmmGet(op.ra, XmmType::Int);
|
||||
const XmmLink& v1 = XmmAlloc();
|
||||
c->movdqa(v1, va);
|
||||
@@ -1538,50 +1716,57 @@ void spu_recompiler::CDX(spu_opcode_t op)
|
||||
|
||||
void spu_recompiler::ROTQBI(spu_opcode_t op)
|
||||
{
|
||||
c->mov(*qw0, SPU_OFF_64(gpr, op.ra, &v128::_u64, 0));
|
||||
c->mov(*qw1, SPU_OFF_64(gpr, op.ra, &v128::_u64, 1));
|
||||
c->mov(*qw2, *qw0);
|
||||
c->mov(*addr, SPU_OFF_32(gpr, op.rb, &v128::_u32, 3));
|
||||
c->and_(*addr, 7);
|
||||
c->shld(*qw0, *qw1, *addr);
|
||||
c->shld(*qw1, *qw2, *addr);
|
||||
c->mov(SPU_OFF_64(gpr, op.rt, &v128::_u64, 0), *qw0);
|
||||
c->mov(SPU_OFF_64(gpr, op.rt, &v128::_u64, 1), *qw1);
|
||||
c->unuse(*addr);
|
||||
c->unuse(*qw0);
|
||||
c->unuse(*qw1);
|
||||
c->unuse(*qw2);
|
||||
const XmmLink& va = XmmGet(op.ra, XmmType::Int);
|
||||
const XmmLink& vb = XmmGet(op.rb, XmmType::Int);
|
||||
const XmmLink& vt = XmmAlloc();
|
||||
const XmmLink& v4 = XmmAlloc();
|
||||
c->psrldq(vb, 12);
|
||||
c->pand(vb, XmmConst(_mm_set_epi64x(0, 7)));
|
||||
c->movdqa(v4, XmmConst(_mm_set_epi64x(0, 64)));
|
||||
c->pshufd(vt, va, 0x4e);
|
||||
c->psubq(v4, vb);
|
||||
c->psllq(va, vb);
|
||||
c->psrlq(vt, v4);
|
||||
c->por(vt, va);
|
||||
c->movdqa(SPU_OFF_128(gpr, op.rt), vt);
|
||||
}
|
||||
|
||||
void spu_recompiler::ROTQMBI(spu_opcode_t op)
|
||||
{
|
||||
c->mov(*qw0, SPU_OFF_64(gpr, op.ra, &v128::_u64, 0));
|
||||
c->mov(*qw1, SPU_OFF_64(gpr, op.ra, &v128::_u64, 1));
|
||||
c->mov(*addr, SPU_OFF_32(gpr, op.rb, &v128::_u32, 3));
|
||||
c->neg(*addr);
|
||||
c->and_(*addr, 7);
|
||||
c->shrd(*qw0, *qw1, *addr);
|
||||
c->shr(*qw1, *addr);
|
||||
c->mov(SPU_OFF_64(gpr, op.rt, &v128::_u64, 0), *qw0);
|
||||
c->mov(SPU_OFF_64(gpr, op.rt, &v128::_u64, 1), *qw1);
|
||||
c->unuse(*addr);
|
||||
c->unuse(*qw0);
|
||||
c->unuse(*qw1);
|
||||
const XmmLink& va = XmmGet(op.ra, XmmType::Int);
|
||||
const XmmLink& vb = XmmAlloc();
|
||||
const XmmLink& vt = XmmGet(op.rb, XmmType::Int);
|
||||
const XmmLink& v4 = XmmAlloc();
|
||||
c->psrldq(vt, 12);
|
||||
c->pxor(vb, vb);
|
||||
c->psubq(vb, vt);
|
||||
c->pand(vb, XmmConst(_mm_set_epi64x(0, 7)));
|
||||
c->movdqa(v4, XmmConst(_mm_set_epi64x(0, 64)));
|
||||
c->movdqa(vt, va);
|
||||
c->psrldq(vt, 8);
|
||||
c->psubq(v4, vb);
|
||||
c->psrlq(va, vb);
|
||||
c->psllq(vt, v4);
|
||||
c->por(vt, va);
|
||||
c->movdqa(SPU_OFF_128(gpr, op.rt), vt);
|
||||
}
|
||||
|
||||
void spu_recompiler::SHLQBI(spu_opcode_t op)
|
||||
{
|
||||
c->mov(*qw0, SPU_OFF_64(gpr, op.ra, &v128::_u64, 0));
|
||||
c->mov(*qw1, SPU_OFF_64(gpr, op.ra, &v128::_u64, 1));
|
||||
c->mov(*addr, SPU_OFF_32(gpr, op.rb, &v128::_u32, 3));
|
||||
c->and_(*addr, 7);
|
||||
c->shld(*qw1, *qw0, *addr);
|
||||
c->shl(*qw0, *addr);
|
||||
c->mov(SPU_OFF_64(gpr, op.rt, &v128::_u64, 0), *qw0);
|
||||
c->mov(SPU_OFF_64(gpr, op.rt, &v128::_u64, 1), *qw1);
|
||||
c->unuse(*addr);
|
||||
c->unuse(*qw0);
|
||||
c->unuse(*qw1);
|
||||
const XmmLink& va = XmmGet(op.ra, XmmType::Int);
|
||||
const XmmLink& vb = XmmGet(op.rb, XmmType::Int);
|
||||
const XmmLink& vt = XmmAlloc();
|
||||
const XmmLink& v4 = XmmAlloc();
|
||||
c->psrldq(vb, 12);
|
||||
c->pand(vb, XmmConst(_mm_set_epi64x(0, 7)));
|
||||
c->movdqa(v4, XmmConst(_mm_set_epi64x(0, 64)));
|
||||
c->movdqa(vt, va);
|
||||
c->pslldq(vt, 8);
|
||||
c->psubq(v4, vb);
|
||||
c->psllq(va, vb);
|
||||
c->psrlq(vt, v4);
|
||||
c->por(vt, va);
|
||||
c->movdqa(SPU_OFF_128(gpr, op.rt), vt);
|
||||
}
|
||||
|
||||
void spu_recompiler::ROTQBY(spu_opcode_t op)
|
||||
@@ -1682,16 +1867,14 @@ void spu_recompiler::SHLQBY(spu_opcode_t op)
|
||||
|
||||
void spu_recompiler::ORX(spu_opcode_t op)
|
||||
{
|
||||
c->mov(*addr, SPU_OFF_32(gpr, op.ra, &v128::_u32, 0));
|
||||
c->or_(*addr, SPU_OFF_32(gpr, op.ra, &v128::_u32, 1));
|
||||
c->or_(*addr, SPU_OFF_32(gpr, op.ra, &v128::_u32, 2));
|
||||
c->or_(*addr, SPU_OFF_32(gpr, op.ra, &v128::_u32, 3));
|
||||
c->mov(SPU_OFF_32(gpr, op.rt, &v128::_u32, 3), *addr);
|
||||
c->xor_(*addr, *addr);
|
||||
c->mov(SPU_OFF_32(gpr, op.rt, &v128::_u32, 0), *addr);
|
||||
c->mov(SPU_OFF_32(gpr, op.rt, &v128::_u32, 1), *addr);
|
||||
c->mov(SPU_OFF_32(gpr, op.rt, &v128::_u32, 2), *addr);
|
||||
c->unuse(*addr);
|
||||
const XmmLink& va = XmmGet(op.ra, XmmType::Int);
|
||||
const XmmLink& v1 = XmmAlloc();
|
||||
c->pshufd(v1, va, 0xb1);
|
||||
c->por(va, v1);
|
||||
c->pshufd(v1, va, 0x4e);
|
||||
c->por(va, v1);
|
||||
c->pslldq(va, 12);
|
||||
c->movdqa(SPU_OFF_128(gpr, op.rt), va);
|
||||
}
|
||||
|
||||
void spu_recompiler::CBD(spu_opcode_t op)
|
||||
@@ -1798,40 +1981,37 @@ void spu_recompiler::CDD(spu_opcode_t op)
|
||||
|
||||
void spu_recompiler::ROTQBII(spu_opcode_t op)
|
||||
{
|
||||
c->mov(*qw0, SPU_OFF_64(gpr, op.ra, &v128::_u64, 0));
|
||||
c->mov(*qw1, SPU_OFF_64(gpr, op.ra, &v128::_u64, 1));
|
||||
c->mov(*qw2, *qw0);
|
||||
c->shld(*qw0, *qw1, op.i7 & 0x7);
|
||||
c->shld(*qw1, *qw2, op.i7 & 0x7);
|
||||
c->mov(SPU_OFF_64(gpr, op.rt, &v128::_u64, 0), *qw0);
|
||||
c->mov(SPU_OFF_64(gpr, op.rt, &v128::_u64, 1), *qw1);
|
||||
c->unuse(*qw0);
|
||||
c->unuse(*qw1);
|
||||
c->unuse(*qw2);
|
||||
const XmmLink& va = XmmGet(op.ra, XmmType::Int);
|
||||
const XmmLink& vt = XmmAlloc();
|
||||
c->pshufd(vt, va, 0x4e); // swap 64-bit parts
|
||||
c->psllq(va, (op.i7 & 0x7));
|
||||
c->psrlq(vt, 64 - (op.i7 & 0x7));
|
||||
c->por(vt, va);
|
||||
c->movdqa(SPU_OFF_128(gpr, op.rt), vt);
|
||||
}
|
||||
|
||||
void spu_recompiler::ROTQMBII(spu_opcode_t op)
|
||||
{
|
||||
c->mov(*qw0, SPU_OFF_64(gpr, op.ra, &v128::_u64, 0));
|
||||
c->mov(*qw1, SPU_OFF_64(gpr, op.ra, &v128::_u64, 1));
|
||||
c->shrd(*qw0, *qw1, 0-op.i7 & 0x7);
|
||||
c->shr(*qw1, 0-op.i7 & 0x7);
|
||||
c->mov(SPU_OFF_64(gpr, op.rt, &v128::_u64, 0), *qw0);
|
||||
c->mov(SPU_OFF_64(gpr, op.rt, &v128::_u64, 1), *qw1);
|
||||
c->unuse(*qw0);
|
||||
c->unuse(*qw1);
|
||||
const XmmLink& va = XmmGet(op.ra, XmmType::Int);
|
||||
const XmmLink& vt = XmmAlloc();
|
||||
c->movdqa(vt, va);
|
||||
c->psrldq(vt, 8);
|
||||
c->psrlq(va, ((0 - op.i7) & 0x7));
|
||||
c->psllq(vt, 64 - ((0 - op.i7) & 0x7));
|
||||
c->por(vt, va);
|
||||
c->movdqa(SPU_OFF_128(gpr, op.rt), vt);
|
||||
}
|
||||
|
||||
void spu_recompiler::SHLQBII(spu_opcode_t op)
|
||||
{
|
||||
c->mov(*qw0, SPU_OFF_64(gpr, op.ra, &v128::_u64, 0));
|
||||
c->mov(*qw1, SPU_OFF_64(gpr, op.ra, &v128::_u64, 1));
|
||||
c->shld(*qw1, *qw0, op.i7 & 0x7);
|
||||
c->shl(*qw0, op.i7 & 0x7);
|
||||
c->mov(SPU_OFF_64(gpr, op.rt, &v128::_u64, 0), *qw0);
|
||||
c->mov(SPU_OFF_64(gpr, op.rt, &v128::_u64, 1), *qw1);
|
||||
c->unuse(*qw0);
|
||||
c->unuse(*qw1);
|
||||
const XmmLink& va = XmmGet(op.ra, XmmType::Int);
|
||||
const XmmLink& vt = XmmAlloc();
|
||||
c->movdqa(vt, va);
|
||||
c->pslldq(vt, 8);
|
||||
c->psllq(va, (op.i7 & 0x7));
|
||||
c->psrlq(vt, 64 - (op.i7 & 0x7));
|
||||
c->por(vt, va);
|
||||
c->movdqa(SPU_OFF_128(gpr, op.rt), vt);
|
||||
}
|
||||
|
||||
void spu_recompiler::ROTQBYI(spu_opcode_t op)
|
||||
@@ -3298,6 +3478,13 @@ void spu_recompiler::SELB(spu_opcode_t op)
|
||||
return;
|
||||
}
|
||||
|
||||
if (utils::has_xop())
|
||||
{
|
||||
c->vpcmov(vc, vb, SPU_OFF_128(gpr, op.ra), vc);
|
||||
c->movdqa(SPU_OFF_128(gpr, op.rt4), vc);
|
||||
return;
|
||||
}
|
||||
|
||||
c->pand(vb, vc);
|
||||
c->pandn(vc, SPU_OFF_128(gpr, op.ra));
|
||||
c->por(vb, vc);
|
||||
@@ -3422,6 +3609,10 @@ void spu_recompiler::SHUFB(spu_opcode_t op)
|
||||
{
|
||||
c->vpternlogd(vc, va, vb, 0xca /* A?B:C */);
|
||||
}
|
||||
else if (utils::has_xop())
|
||||
{
|
||||
c->vpcmov(vc, va, vb, vc);
|
||||
}
|
||||
else
|
||||
{
|
||||
c->pand(va, vc);
|
||||
|
||||
@@ -1,12 +1,18 @@
|
||||
#pragma once
|
||||
|
||||
#define ASMJIT_STATIC
|
||||
#define ASMJIT_DEBUG
|
||||
|
||||
#include "asmjit.h"
|
||||
|
||||
#include "SPURecompiler.h"
|
||||
|
||||
namespace asmjit
|
||||
{
|
||||
struct JitRuntime;
|
||||
struct CodeHolder;
|
||||
struct X86Compiler;
|
||||
struct X86Gp;
|
||||
struct X86Xmm;
|
||||
struct X86Mem;
|
||||
struct Label;
|
||||
}
|
||||
|
||||
// SPU ASMJIT Recompiler
|
||||
class spu_recompiler : public spu_recompiler_base
|
||||
{
|
||||
@@ -15,7 +21,7 @@ class spu_recompiler : public spu_recompiler_base
|
||||
public:
|
||||
spu_recompiler();
|
||||
|
||||
virtual bool compile(spu_function_contents_t* f) override;
|
||||
virtual void compile(spu_function_t& f) override;
|
||||
|
||||
private:
|
||||
// emitter:
|
||||
@@ -35,7 +41,7 @@ private:
|
||||
std::array<asmjit::X86Xmm*, 6> vec;
|
||||
|
||||
// labels:
|
||||
std::unique_ptr<asmjit::Label[]> labels; // array[0x10000]
|
||||
asmjit::Label* labels; // array[0x10000]
|
||||
asmjit::Label* jt; // jump table resolver (uses *addr)
|
||||
asmjit::Label* end; // function end (return *addr)
|
||||
|
||||
|
||||
@@ -5,18 +5,16 @@
|
||||
|
||||
const spu_decoder<spu_itype> s_spu_itype;
|
||||
|
||||
spu_function_contents_t* SPUDatabase::find(const be_t<u32>* data, u64 key, u32 max_size, void* ignore)
|
||||
spu_function_t* SPUDatabase::find(const be_t<u32>* data, u64 key, u32 max_size)
|
||||
{
|
||||
for (auto found = m_db.equal_range(key); found.first != found.second; found.first++)
|
||||
{
|
||||
const auto & func = found.first->second;
|
||||
|
||||
// TODO remove code after a while if it hasn't been touched, else there's a big memory bloat here and switch memcmp with compare_func
|
||||
const auto& func = found.first->second;
|
||||
|
||||
// Compare binary data explicitly (TODO: optimize)
|
||||
if (func != ignore && LIKELY(func->size <= max_size) && std::memcmp(func->data.data(), data, func->size) == 0)
|
||||
if (LIKELY(func->size <= max_size) && std::memcmp(func->data.data(), data, func->size) == 0)
|
||||
{
|
||||
return func;
|
||||
return func.get();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -35,17 +33,8 @@ SPUDatabase::~SPUDatabase()
|
||||
// TODO: serialize database
|
||||
}
|
||||
|
||||
bool IsDeterministicBranch(spu_itype::type type)
|
||||
spu_function_t* SPUDatabase::analyse(const be_t<u32>* ls, u32 entry, u32 max_limit)
|
||||
{
|
||||
return type == spu_itype::BR || type == spu_itype::BRSL
|
||||
|| type == spu_itype::BRA || type == spu_itype::BRASL
|
||||
|| type == spu_itype::BI || type == spu_itype::BISL
|
||||
|| type == spu_itype::IRET;
|
||||
}
|
||||
|
||||
spu_function_contents_t* SPUDatabase::analyse(const be_t<u32>* ls, u32 entry, void* ignore /*=nullptr*/)
|
||||
{
|
||||
const u32 max_limit = 0x40000;
|
||||
// Check arguments (bounds and alignment)
|
||||
if (max_limit > 0x40000 || entry >= max_limit || entry % 4 || max_limit % 4)
|
||||
{
|
||||
@@ -53,12 +42,7 @@ spu_function_contents_t* SPUDatabase::analyse(const be_t<u32>* ls, u32 entry, vo
|
||||
}
|
||||
|
||||
// Key for multimap
|
||||
u32 xor_base = 0;
|
||||
for (u32 i = 0; i < 10; i++)
|
||||
{
|
||||
xor_base ^= ls[(entry / 4) + i];
|
||||
}
|
||||
const u64 key = entry | u64{ xor_base } << 32;
|
||||
const u64 key = entry | u64{ ls[entry / 4] } << 32;
|
||||
const be_t<u32>* base = ls + entry / 4;
|
||||
const u32 block_sz = max_limit - entry;
|
||||
|
||||
@@ -72,11 +56,19 @@ spu_function_contents_t* SPUDatabase::analyse(const be_t<u32>* ls, u32 entry, vo
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
writer_lock lock(m_mutex);
|
||||
|
||||
// Double-check
|
||||
if (auto func = find(base, key, block_sz))
|
||||
{
|
||||
return func;
|
||||
}
|
||||
}
|
||||
|
||||
// Initialize block entries with the function entry point
|
||||
std::set<u32> blocks{ entry };
|
||||
|
||||
std::vector<u32> blocks_size;
|
||||
|
||||
// Entries of adjacent functions; jump table entries
|
||||
std::set<u32> adjacent, jt;
|
||||
|
||||
@@ -92,21 +84,15 @@ spu_function_contents_t* SPUDatabase::analyse(const be_t<u32>* ls, u32 entry, vo
|
||||
// Find preliminary set of possible block entries (first pass), `start` is the current block address
|
||||
for (u32 start = entry, pos = entry; pos < limit; pos += 4)
|
||||
{
|
||||
u32 xor_base = 0;
|
||||
for (u32 i = 0; i < 10; i++)
|
||||
{
|
||||
xor_base ^= ls[(pos / 4) + i];
|
||||
}
|
||||
const spu_opcode_t op{ ls[pos / 4] };
|
||||
|
||||
const auto type = s_spu_itype.decode(op.opcode);
|
||||
|
||||
if (pos != entry)
|
||||
{
|
||||
reader_lock lock(m_mutex);
|
||||
|
||||
// Find existing function
|
||||
if (find(ls + pos / 4, pos | u64{ ls[pos / 4] } << 32, limit - pos))
|
||||
if (pos != entry && find(ls + pos / 4, pos | u64{ op.opcode } << 32, limit - pos))
|
||||
{
|
||||
limit = pos;
|
||||
break;
|
||||
@@ -321,27 +307,8 @@ spu_function_contents_t* SPUDatabase::analyse(const be_t<u32>* ls, u32 entry, vo
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
blocks_size.reserve(blocks.size());
|
||||
for (u32 block : blocks)
|
||||
{
|
||||
u32 size = 0;
|
||||
for (u32 i = block / 4; i < 0x10000; i++)
|
||||
{
|
||||
if (ls[i] == 0 || IsDeterministicBranch(s_spu_itype.decode(ls[i])))
|
||||
{
|
||||
size = (i * 4) - block + 4;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (size == 0)
|
||||
{
|
||||
verify("No way out of a block"), size != 0;
|
||||
}
|
||||
blocks_size.push_back(size);
|
||||
}
|
||||
|
||||
// Prepare new function (set addr and size)
|
||||
auto func = new spu_function_contents_t(entry, limit - entry);
|
||||
auto func = std::make_shared<spu_function_t>(entry, limit - entry);
|
||||
|
||||
// Copy function contents
|
||||
func->data = { ls + entry / 4, ls + limit / 4 };
|
||||
@@ -373,8 +340,6 @@ spu_function_contents_t* SPUDatabase::analyse(const be_t<u32>* ls, u32 entry, vo
|
||||
}
|
||||
}
|
||||
|
||||
func->blocks_size = std::move(blocks_size);
|
||||
|
||||
// Set whether the function can reset stack
|
||||
func->does_reset_stack = ila_sp_pos < limit;
|
||||
|
||||
@@ -389,5 +354,5 @@ spu_function_contents_t* SPUDatabase::analyse(const be_t<u32>* ls, u32 entry, vo
|
||||
|
||||
LOG_NOTICE(SPU, "Function detected [0x%05x-0x%05x] (size=0x%x)", func->addr, func->addr + func->size, func->size);
|
||||
|
||||
return func;
|
||||
return func.get();
|
||||
}
|
||||
|
||||
@@ -2,9 +2,7 @@
|
||||
|
||||
#include "Utilities/mutex.h"
|
||||
|
||||
#include <map>
|
||||
#include <set>
|
||||
#include <memory>
|
||||
|
||||
// SPU Instruction Type
|
||||
struct spu_itype
|
||||
@@ -248,10 +246,8 @@ struct spu_itype
|
||||
|
||||
class SPUThread;
|
||||
|
||||
typedef u32(*CompiledFunc)(SPUThread* _spu, be_t<u32>* _ls);
|
||||
|
||||
// SPU basic function information structure
|
||||
struct spu_function_contents_t
|
||||
struct spu_function_t
|
||||
{
|
||||
// Entry point (LS address)
|
||||
const u32 addr;
|
||||
@@ -265,9 +261,6 @@ struct spu_function_contents_t
|
||||
// Basic blocks (start addresses)
|
||||
std::set<u32> blocks;
|
||||
|
||||
// Basic blocks size
|
||||
std::vector<u32> blocks_size;
|
||||
|
||||
// Functions possibly called by this function (may not be available)
|
||||
std::set<u32> adjacent;
|
||||
|
||||
@@ -278,48 +271,30 @@ struct spu_function_contents_t
|
||||
bool does_reset_stack;
|
||||
|
||||
// Pointer to the compiled function
|
||||
CompiledFunc compiled = nullptr;
|
||||
u32(*compiled)(SPUThread* _spu, be_t<u32>* _ls) = nullptr;
|
||||
|
||||
spu_function_contents_t(u32 addr, u32 size)
|
||||
: addr(addr),
|
||||
size(size)
|
||||
spu_function_t(u32 addr, u32 size)
|
||||
: addr(addr)
|
||||
, size(size)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
// A single instance of a compiled function, currently in use
|
||||
union spu_function_t
|
||||
{
|
||||
// The function itself and its data
|
||||
spu_function_contents_t * contents;
|
||||
|
||||
// Whether pages the function is in were written to since its last execution
|
||||
bool dirty_bit : 1;
|
||||
|
||||
operator bool()
|
||||
{
|
||||
return contents != nullptr;
|
||||
}
|
||||
|
||||
spu_function_t() : contents(nullptr) {};
|
||||
~spu_function_t() {};
|
||||
};
|
||||
|
||||
// SPU Function Database (must be global or PS3 process-local)
|
||||
class SPUDatabase final : spu_itype
|
||||
{
|
||||
shared_mutex m_mutex;
|
||||
|
||||
// All registered functions (uses addr and first instruction as a key)
|
||||
std::unordered_multimap<u64, spu_function_contents_t*> m_db;
|
||||
std::unordered_multimap<u64, std::shared_ptr<spu_function_t>> m_db;
|
||||
|
||||
// For internal use
|
||||
spu_function_contents_t* find(const be_t<u32>* data, u64 key, u32 max_size, void* ignore = nullptr);
|
||||
spu_function_t* find(const be_t<u32>* data, u64 key, u32 max_size);
|
||||
|
||||
public:
|
||||
SPUDatabase();
|
||||
~SPUDatabase();
|
||||
|
||||
// Try to retrieve SPU function information
|
||||
spu_function_contents_t* analyse(const be_t<u32>* ls, u32 entry, void * ignore=nullptr);
|
||||
spu_function_t* analyse(const be_t<u32>* ls, u32 entry, u32 limit = 0x40000);
|
||||
};
|
||||
|
||||
@@ -101,8 +101,7 @@ void spu_interpreter::RDCH(SPUThread& spu, spu_opcode_t op)
|
||||
}
|
||||
else
|
||||
{
|
||||
memset(&spu.gpr[op.rt], 0, 3*sizeof(u32));
|
||||
spu.gpr[op.rt]._u32[3] = result;
|
||||
spu.gpr[op.rt] = v128::from32r(result);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -24,57 +24,39 @@ void spu_recompiler_base::enter(SPUThread& spu)
|
||||
const auto _ls = vm::_ptr<u32>(spu.offset);
|
||||
|
||||
// Search if cached data matches
|
||||
auto func_ptr = spu.compiled_cache[spu.pc / 4];
|
||||
auto func = spu.compiled_cache[spu.pc / 4];
|
||||
|
||||
// Dirty bit check commented out until another code invalidation is found - SYNC, SYNCC, DSYNC and DMAs aren't covering everything
|
||||
if (func_ptr/* && func_ptr->dirty_bit*/)
|
||||
// Check shared db if we dont have a match
|
||||
if (!func || !std::equal(func->data.begin(), func->data.end(), _ls + spu.pc / 4, [](const be_t<u32>& l, const be_t<u32>& r) { return *(u32*)(u8*)&l == *(u32*)(u8*)&r; }))
|
||||
{
|
||||
auto & func = *func_ptr;
|
||||
func.dirty_bit = false;
|
||||
u32 index = (reinterpret_cast<size_t>(func_ptr) - reinterpret_cast<size_t>(&spu.compiled_functions[0])) / sizeof(func);
|
||||
spu.first_clean_func_index = std::min<u32>(index, spu.first_clean_func_index);
|
||||
spu.last_clean_func_index = std::max<u32>(index + 1, spu.last_clean_func_index);
|
||||
|
||||
if (!spu.same_function(func.contents, _ls + (spu.pc / 4)))
|
||||
{
|
||||
func.contents = spu.spu_db->analyse(_ls, spu.pc, func.contents);
|
||||
}
|
||||
}
|
||||
else if (!func_ptr)
|
||||
{
|
||||
auto & func = spu.compiled_functions[++spu.next_compiled_func_index];
|
||||
func.contents = spu.spu_db->analyse(_ls, spu.pc);
|
||||
func_ptr = &func;
|
||||
spu.compiled_cache[spu.pc / 4] = func_ptr;
|
||||
spu.last_clean_func_index = spu.next_compiled_func_index + 1;
|
||||
spu.first_clean_func_index = std::min<u32>(spu.first_clean_func_index, spu.next_compiled_func_index);
|
||||
func = spu.spu_db->analyse(_ls, spu.pc);
|
||||
spu.compiled_cache[spu.pc / 4] = func;
|
||||
}
|
||||
|
||||
// Reset callstack if necessary
|
||||
if ((func_ptr->contents->does_reset_stack && spu.recursion_level) || spu.recursion_level >= 128)
|
||||
if ((func->does_reset_stack && spu.recursion_level) || spu.recursion_level >= 128)
|
||||
{
|
||||
spu.state += cpu_flag::ret;
|
||||
return;
|
||||
}
|
||||
|
||||
// Compile if needed
|
||||
if (!func_ptr->contents->compiled)
|
||||
if (!func->compiled)
|
||||
{
|
||||
if (!spu.spu_rec)
|
||||
{
|
||||
spu.spu_rec = fxm::get_always<spu_recompiler>();
|
||||
}
|
||||
|
||||
spu.spu_rec->compile(func_ptr->contents);
|
||||
spu.spu_rec->compile(*func);
|
||||
|
||||
if (!func_ptr->contents->compiled) fmt::throw_exception("Compilation failed" HERE);
|
||||
if (!func->compiled) fmt::throw_exception("Compilation failed" HERE);
|
||||
}
|
||||
|
||||
const u32 res = func_ptr->contents->compiled(&spu, _ls);
|
||||
const u32 res = func->compiled(&spu, _ls);
|
||||
|
||||
if (spu.pending_exception)
|
||||
if (const auto exception = spu.pending_exception)
|
||||
{
|
||||
const auto exception = spu.pending_exception;
|
||||
spu.pending_exception = nullptr;
|
||||
std::rethrow_exception(exception);
|
||||
}
|
||||
|
||||
@@ -10,7 +10,7 @@ class spu_recompiler_base
|
||||
protected:
|
||||
std::mutex m_mutex; // must be locked in compile()
|
||||
|
||||
const spu_function_contents_t* m_func; // current function
|
||||
const spu_function_t* m_func; // current function
|
||||
|
||||
u32 m_pos; // current position
|
||||
|
||||
@@ -18,7 +18,7 @@ public:
|
||||
virtual ~spu_recompiler_base();
|
||||
|
||||
// Compile specified function
|
||||
virtual bool compile(spu_function_contents_t*) = 0;
|
||||
virtual void compile(spu_function_t& f) = 0;
|
||||
|
||||
// Run
|
||||
static void enter(class SPUThread&);
|
||||
|
||||
+129
-126
@@ -41,18 +41,6 @@ bool operator ==(const u128& lhs, const u128& rhs)
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef _MSC_VER
|
||||
FORCE_INLINE void __movsq(unsigned long * Destination, const unsigned long * Source, size_t Count)
|
||||
{
|
||||
__asm__ __volatile__
|
||||
(
|
||||
"rep; movsq" :
|
||||
[Destination] "=D" (Destination), [Source] "=S" (Source), [Count] "=c" (Count) :
|
||||
"[Destination]" (Destination), "[Source]" (Source), "[Count]" (Count)
|
||||
);
|
||||
}
|
||||
#endif
|
||||
|
||||
extern u64 get_timebased_time();
|
||||
extern u64 get_system_time();
|
||||
|
||||
@@ -146,8 +134,8 @@ namespace spu
|
||||
{
|
||||
if (timeout_ms > 0)
|
||||
{
|
||||
const auto timeout = timeout_ms * 1000ull; //convert to microseconds
|
||||
const auto start = get_system_time();
|
||||
const u64 timeout = timeout_ms * 1000u; //convert to microseconds
|
||||
const u64 start = get_system_time();
|
||||
auto remaining = timeout;
|
||||
|
||||
while (atomic_instruction_table[pc_offset].load(std::memory_order_consume) >= max_concurrent_instructions)
|
||||
@@ -174,14 +162,14 @@ namespace spu
|
||||
}
|
||||
}
|
||||
|
||||
++atomic_instruction_table[pc_offset];
|
||||
atomic_instruction_table[pc_offset]++;
|
||||
}
|
||||
|
||||
void release_pc_address(u32 pc)
|
||||
{
|
||||
const u32 pc_offset = pc >> 2;
|
||||
|
||||
--atomic_instruction_table[pc_offset];
|
||||
atomic_instruction_table[pc_offset]--;
|
||||
}
|
||||
|
||||
struct concurrent_execution_watchdog
|
||||
@@ -302,8 +290,6 @@ void SPUThread::on_spawn()
|
||||
{
|
||||
thread_ctrl::set_native_priority(-1);
|
||||
}
|
||||
|
||||
++g_num_spu_threads;
|
||||
}
|
||||
|
||||
void SPUThread::on_init(const std::shared_ptr<void>& _this)
|
||||
@@ -470,7 +456,6 @@ void SPUThread::do_dma_transfer(const spu_mfc_cmd& args, bool from_mfc)
|
||||
|
||||
u32 eal = args.eal;
|
||||
u32 lsa = args.lsa & 0x3ffff;
|
||||
SPUThread * spu = nullptr;
|
||||
|
||||
if (eal >= SYS_SPU_THREAD_BASE_LOW && offset < RAW_SPU_BASE_ADDR) // SPU Thread Group MMIO (LS and SNR)
|
||||
{
|
||||
@@ -479,15 +464,15 @@ void SPUThread::do_dma_transfer(const spu_mfc_cmd& args, bool from_mfc)
|
||||
|
||||
if (group && index < group->num && group->threads[index])
|
||||
{
|
||||
spu = group->threads[index].get();
|
||||
auto& spu = static_cast<SPUThread&>(*group->threads[index]);
|
||||
|
||||
if (offset + args.size - 1 < 0x40000) // LS access
|
||||
{
|
||||
eal = spu->offset + offset; // redirect access
|
||||
eal = spu.offset + offset; // redirect access
|
||||
}
|
||||
else if (!is_get && args.size == 4 && (offset == SYS_SPU_THREAD_SNR1 || offset == SYS_SPU_THREAD_SNR2))
|
||||
{
|
||||
spu->push_snr(SYS_SPU_THREAD_SNR2 == offset, _ref<u32>(lsa));
|
||||
spu.push_snr(SYS_SPU_THREAD_SNR2 == offset, _ref<u32>(lsa));
|
||||
return;
|
||||
}
|
||||
else
|
||||
@@ -547,27 +532,82 @@ void SPUThread::do_dma_transfer(const spu_mfc_cmd& args, bool from_mfc)
|
||||
}
|
||||
default:
|
||||
{
|
||||
auto vdst = static_cast<u64*>(dst);
|
||||
auto vsrc = static_cast<const u64*>(src);
|
||||
auto vcnt = size / sizeof(u64);
|
||||
auto vdst = static_cast<__m128i*>(dst);
|
||||
auto vsrc = static_cast<const __m128i*>(src);
|
||||
auto vcnt = size / sizeof(__m128i);
|
||||
|
||||
__movsq(vdst, vsrc, vcnt);
|
||||
}
|
||||
}
|
||||
|
||||
if (spu)
|
||||
{
|
||||
for (u32 i = 0; i < spu->next_compiled_func_index; i++)
|
||||
//if (is_get && !from_mfc)
|
||||
{
|
||||
auto& func = spu->compiled_functions[i];
|
||||
auto faddr = func.contents->addr;
|
||||
auto fsize = func.contents->size;
|
||||
|
||||
if (fsize + faddr > eal && eal + args.size > faddr)
|
||||
while (vcnt >= 8)
|
||||
{
|
||||
func.dirty_bit = true;
|
||||
const __m128i data[]
|
||||
{
|
||||
_mm_load_si128(vsrc + 0),
|
||||
_mm_load_si128(vsrc + 1),
|
||||
_mm_load_si128(vsrc + 2),
|
||||
_mm_load_si128(vsrc + 3),
|
||||
_mm_load_si128(vsrc + 4),
|
||||
_mm_load_si128(vsrc + 5),
|
||||
_mm_load_si128(vsrc + 6),
|
||||
_mm_load_si128(vsrc + 7),
|
||||
};
|
||||
|
||||
_mm_store_si128(vdst + 0, data[0]);
|
||||
_mm_store_si128(vdst + 1, data[1]);
|
||||
_mm_store_si128(vdst + 2, data[2]);
|
||||
_mm_store_si128(vdst + 3, data[3]);
|
||||
_mm_store_si128(vdst + 4, data[4]);
|
||||
_mm_store_si128(vdst + 5, data[5]);
|
||||
_mm_store_si128(vdst + 6, data[6]);
|
||||
_mm_store_si128(vdst + 7, data[7]);
|
||||
|
||||
vcnt -= 8;
|
||||
vsrc += 8;
|
||||
vdst += 8;
|
||||
}
|
||||
|
||||
while (vcnt--)
|
||||
{
|
||||
_mm_store_si128(vdst++, _mm_load_si128(vsrc++));
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
// Disabled
|
||||
while (vcnt >= 8)
|
||||
{
|
||||
const __m128i data[]
|
||||
{
|
||||
_mm_load_si128(vsrc + 0),
|
||||
_mm_load_si128(vsrc + 1),
|
||||
_mm_load_si128(vsrc + 2),
|
||||
_mm_load_si128(vsrc + 3),
|
||||
_mm_load_si128(vsrc + 4),
|
||||
_mm_load_si128(vsrc + 5),
|
||||
_mm_load_si128(vsrc + 6),
|
||||
_mm_load_si128(vsrc + 7),
|
||||
};
|
||||
|
||||
_mm_stream_si128(vdst + 0, data[0]);
|
||||
_mm_stream_si128(vdst + 1, data[1]);
|
||||
_mm_stream_si128(vdst + 2, data[2]);
|
||||
_mm_stream_si128(vdst + 3, data[3]);
|
||||
_mm_stream_si128(vdst + 4, data[4]);
|
||||
_mm_stream_si128(vdst + 5, data[5]);
|
||||
_mm_stream_si128(vdst + 6, data[6]);
|
||||
_mm_stream_si128(vdst + 7, data[7]);
|
||||
|
||||
vcnt -= 8;
|
||||
vsrc += 8;
|
||||
vdst += 8;
|
||||
}
|
||||
|
||||
while (vcnt--)
|
||||
{
|
||||
_mm_stream_si128(vdst++, _mm_load_si128(vsrc++));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (is_get && from_mfc)
|
||||
@@ -622,14 +662,15 @@ void SPUThread::process_mfc_cmd()
|
||||
|
||||
if (is_polling)
|
||||
{
|
||||
vm::waiter* waiter = new vm::waiter();
|
||||
waiter->owner = this;
|
||||
waiter->addr = raddr;
|
||||
waiter->stamp = rtime;
|
||||
waiter->data = rdata.data();
|
||||
waiter->init();
|
||||
vm::waiter waiter;
|
||||
waiter.owner = this;
|
||||
waiter.addr = raddr;
|
||||
waiter.size = 128;
|
||||
waiter.stamp = rtime;
|
||||
waiter.data = rdata.data();
|
||||
waiter.init();
|
||||
|
||||
while (vm::reservation_acquire(raddr, 128) == waiter->stamp && rdata == data)
|
||||
while (vm::reservation_acquire(raddr, 128) == waiter.stamp && rdata == data)
|
||||
{
|
||||
if (test(state, cpu_flag::stop))
|
||||
{
|
||||
@@ -638,9 +679,6 @@ void SPUThread::process_mfc_cmd()
|
||||
|
||||
thread_ctrl::wait_for(100);
|
||||
}
|
||||
|
||||
waiter->remove();
|
||||
waiter = nullptr;
|
||||
}
|
||||
else if (s_use_rtm && utils::transaction_enter())
|
||||
{
|
||||
@@ -666,11 +704,9 @@ void SPUThread::process_mfc_cmd()
|
||||
if (is_polling || UNLIKELY(vm::reservation_acquire(raddr, 128) != rtime))
|
||||
{
|
||||
// TODO: vm::check_addr
|
||||
{
|
||||
vm::reader_lock lock;
|
||||
rtime = vm::reservation_acquire(raddr, 128);
|
||||
}
|
||||
memcpy(rdata.data(), data.data(), rdata.size() * sizeof(rdata[0]));
|
||||
vm::reader_lock lock;
|
||||
rtime = vm::reservation_acquire(raddr, 128);
|
||||
rdata = data;
|
||||
}
|
||||
|
||||
// Copy to LS
|
||||
@@ -687,13 +723,12 @@ void SPUThread::process_mfc_cmd()
|
||||
|
||||
bool result = false;
|
||||
|
||||
// Check for fast exit in the beginning as well
|
||||
if (raddr == ch_mfc_cmd.eal && rtime == vm::reservation_acquire(raddr, 128) && rdata == data)
|
||||
{
|
||||
// TODO: vm::check_addr
|
||||
if (s_use_rtm && utils::transaction_enter())
|
||||
{
|
||||
if (!vm::reader_lock{ vm::try_to_lock })
|
||||
if (!vm::reader_lock{vm::try_to_lock})
|
||||
{
|
||||
_xabort(0);
|
||||
}
|
||||
@@ -711,16 +746,14 @@ void SPUThread::process_mfc_cmd()
|
||||
}
|
||||
else
|
||||
{
|
||||
// TODO maybe timeout and check if the lock is still needed in long waits (If rtime changes, no use)
|
||||
vm::writer_lock lock;
|
||||
|
||||
if (rtime == vm::reservation_acquire(raddr, 128))
|
||||
if (rtime == vm::reservation_acquire(raddr, 128) && rdata == data)
|
||||
{
|
||||
data = to_write;
|
||||
vm::reservation_update(raddr, 128);
|
||||
lock.unlock();
|
||||
|
||||
result = true;
|
||||
|
||||
vm::reservation_update(raddr, 128);
|
||||
vm::notify(raddr, 128);
|
||||
}
|
||||
}
|
||||
@@ -733,10 +766,11 @@ void SPUThread::process_mfc_cmd()
|
||||
else
|
||||
{
|
||||
ch_atomic_stat.set_value(MFC_PUTLLC_FAILURE);
|
||||
if (raddr)
|
||||
{
|
||||
ch_event_stat |= SPU_EVENT_LR;
|
||||
}
|
||||
}
|
||||
|
||||
if (raddr && !result)
|
||||
{
|
||||
ch_event_stat |= SPU_EVENT_LR;
|
||||
}
|
||||
|
||||
raddr = 0;
|
||||
@@ -774,11 +808,9 @@ void SPUThread::process_mfc_cmd()
|
||||
return;
|
||||
}
|
||||
|
||||
vm::writer_lock lock(0);
|
||||
data = to_write;
|
||||
{
|
||||
vm::writer_lock lock(0);
|
||||
vm::reservation_update(ch_mfc_cmd.eal, 128);
|
||||
}
|
||||
vm::reservation_update(ch_mfc_cmd.eal, 128);
|
||||
vm::notify(ch_mfc_cmd.eal, 128);
|
||||
|
||||
ch_atomic_stat.set_value(MFC_PUTLLUC_SUCCESS);
|
||||
@@ -809,22 +841,18 @@ void SPUThread::process_mfc_cmd()
|
||||
// Try to process small transfers immediately
|
||||
if (ch_mfc_cmd.size <= max_imm_dma_size && mfc_queue.size() == 0)
|
||||
{
|
||||
/* TODO catch the exception (Currently they are ignored and slow things down by grabbing a lock)
|
||||
vm::reader_lock lock(vm::try_to_lock);
|
||||
|
||||
if (!lock)
|
||||
{
|
||||
vm::reader_lock lock(vm::try_to_lock);
|
||||
|
||||
if (!lock)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
if (!vm::check_addr(ch_mfc_cmd.eal, ch_mfc_cmd.size, vm::page_readable | (ch_mfc_cmd.cmd & MFC_PUT_CMD ? vm::page_writable : 0)))
|
||||
{
|
||||
// TODO
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if (!vm::check_addr(ch_mfc_cmd.eal, ch_mfc_cmd.size, vm::page_readable | (ch_mfc_cmd.cmd & MFC_PUT_CMD ? vm::page_writable : 0)))
|
||||
{
|
||||
// TODO
|
||||
break;
|
||||
}
|
||||
*/
|
||||
|
||||
do_dma_transfer(ch_mfc_cmd, false);
|
||||
return;
|
||||
@@ -844,6 +872,13 @@ void SPUThread::process_mfc_cmd()
|
||||
{
|
||||
if (ch_mfc_cmd.size <= max_imm_dma_size && mfc_queue.size() == 0)
|
||||
{
|
||||
vm::reader_lock lock(vm::try_to_lock);
|
||||
|
||||
if (!lock)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
struct list_element
|
||||
{
|
||||
be_t<u16> sb;
|
||||
@@ -874,20 +909,11 @@ void SPUThread::process_mfc_cmd()
|
||||
break;
|
||||
}
|
||||
|
||||
/* TODO Catch and handle exceptions here
|
||||
if (!vm::check_addr(addr, size, vm::page_readable | (ch_mfc_cmd.cmd & MFC_PUT_CMD ? vm::page_writable : 0)))
|
||||
{
|
||||
vm::reader_lock lock(vm::try_to_lock);
|
||||
|
||||
if (!lock)
|
||||
{
|
||||
break;
|
||||
}
|
||||
if (!vm::check_addr(addr, size, vm::page_readable | (ch_mfc_cmd.cmd & MFC_PUT_CMD ? vm::page_writable : 0)))
|
||||
{
|
||||
// TODO
|
||||
break;
|
||||
}
|
||||
}*/
|
||||
// TODO
|
||||
break;
|
||||
}
|
||||
|
||||
spu_mfc_cmd transfer;
|
||||
transfer.eal = addr;
|
||||
@@ -1163,35 +1189,28 @@ bool SPUThread::get_ch_value(u32 ch, u32& out)
|
||||
return true;
|
||||
}
|
||||
|
||||
vm::waiter* waiter = nullptr;
|
||||
vm::waiter waiter;
|
||||
|
||||
if (ch_event_mask & SPU_EVENT_LR)
|
||||
{
|
||||
waiter = new vm::waiter();
|
||||
waiter->owner = this;
|
||||
waiter->addr = raddr;
|
||||
waiter->stamp = rtime;
|
||||
waiter->data = rdata.data();
|
||||
waiter->init();
|
||||
waiter.owner = this;
|
||||
waiter.addr = raddr;
|
||||
waiter.size = 128;
|
||||
waiter.stamp = rtime;
|
||||
waiter.data = rdata.data();
|
||||
waiter.init();
|
||||
}
|
||||
|
||||
while (!(res = get_events(true)))
|
||||
{
|
||||
if (test(state & cpu_flag::stop))
|
||||
{
|
||||
waiter->remove();
|
||||
waiter = nullptr;
|
||||
return false;
|
||||
}
|
||||
|
||||
thread_ctrl::wait_for(100);
|
||||
}
|
||||
|
||||
if (waiter != nullptr)
|
||||
{
|
||||
waiter->remove();
|
||||
waiter = nullptr;
|
||||
}
|
||||
|
||||
out = res;
|
||||
return true;
|
||||
}
|
||||
@@ -1823,22 +1842,6 @@ bool SPUThread::stop_and_signal(u32 code)
|
||||
}
|
||||
}
|
||||
|
||||
bool SPUThread::same_function(const spu_function_contents_t * func, const void * addr)
|
||||
{
|
||||
auto size = func->blocks_size.cbegin();
|
||||
auto dst = reinterpret_cast<const u8 *>(addr);
|
||||
auto src = vm::ps3::_ptr<u8>(offset);
|
||||
|
||||
for (auto block : func->blocks)
|
||||
{
|
||||
u32 offset = block - func->addr;
|
||||
if (memcmp(src + offset, dst + offset, *size) != 0) return false;
|
||||
size++;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void SPUThread::halt()
|
||||
{
|
||||
LOG_TRACE(SPU, "halt()");
|
||||
|
||||
+14
-17
@@ -3,7 +3,6 @@
|
||||
#include "Emu/Cell/Common.h"
|
||||
#include "Emu/CPU/CPUThread.h"
|
||||
#include "Emu/Cell/SPUInterpreter.h"
|
||||
#include "Emu/Cell/SPURecompiler.h"
|
||||
#include "MFC.h"
|
||||
|
||||
struct lv2_event_queue;
|
||||
@@ -213,14 +212,21 @@ public:
|
||||
// returns true on success
|
||||
bool try_pop(u32& out)
|
||||
{
|
||||
const auto old = data.fetch_op([](sync_var_t& data)
|
||||
const auto old = data.fetch_op([&](sync_var_t& data)
|
||||
{
|
||||
sync_var_t t{};
|
||||
t.wait = !data.count;
|
||||
data = t;
|
||||
});
|
||||
if (data.count)
|
||||
{
|
||||
data.wait = false;
|
||||
out = data.value;
|
||||
}
|
||||
else
|
||||
{
|
||||
data.wait = true;
|
||||
}
|
||||
|
||||
out = old.value;
|
||||
data.count = false;
|
||||
data.value = 0; // ???
|
||||
});
|
||||
|
||||
return old.count;
|
||||
}
|
||||
@@ -579,15 +585,7 @@ public:
|
||||
|
||||
std::exception_ptr pending_exception;
|
||||
|
||||
// No need for shared_ptr in the following two, as whenever something is removed or added to one,
|
||||
// the same goes for the other.
|
||||
std::array<spu_function_t*, 65536> compiled_cache{};
|
||||
std::array<spu_function_t, 65536> compiled_functions{};
|
||||
u32 next_compiled_func_index = -1;
|
||||
u32 first_clean_func_index = 0;
|
||||
u32 last_clean_func_index = 0;
|
||||
|
||||
|
||||
std::array<struct spu_function_t*, 65536> compiled_cache{};
|
||||
std::shared_ptr<class SPUDatabase> spu_db;
|
||||
std::shared_ptr<class spu_recompiler_base> spu_rec;
|
||||
u32 recursion_level = 0;
|
||||
@@ -603,7 +601,6 @@ public:
|
||||
bool get_ch_value(u32 ch, u32& out);
|
||||
bool set_ch_value(u32 ch, u32 value);
|
||||
bool stop_and_signal(u32 code);
|
||||
bool same_function(const spu_function_contents_t * func, const void * addr);
|
||||
void halt();
|
||||
|
||||
void fast_call(u32 ls_addr);
|
||||
|
||||
@@ -777,12 +777,6 @@ error_code sys_spu_thread_write_ls(u32 id, u32 lsa, u64 value, u32 type)
|
||||
default: return CELL_EINVAL;
|
||||
}
|
||||
|
||||
auto func = thread->compiled_cache[lsa / 4];
|
||||
if (func)
|
||||
{
|
||||
func->dirty_bit = true;
|
||||
}
|
||||
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
|
||||
@@ -131,20 +131,25 @@ u64 get_timebased_time()
|
||||
// Returns some relative time in microseconds, don't change this fact
|
||||
u64 get_system_time()
|
||||
{
|
||||
#ifdef _WIN32
|
||||
// Pull the time directly from Windows shared page (Constant location on all Windows machines)
|
||||
return *reinterpret_cast<u64*>(0x7ffe0014) / 10;
|
||||
#else
|
||||
while (true)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
LARGE_INTEGER count;
|
||||
verify(HERE), QueryPerformanceCounter(&count);
|
||||
|
||||
const u64 time = count.QuadPart;
|
||||
const u64 freq = s_time_aux_info.perf_freq;
|
||||
|
||||
const u64 result = time / freq * 1000000u + (time % freq) * 1000000u / freq;
|
||||
#else
|
||||
struct timespec ts;
|
||||
verify(HERE), ::clock_gettime(CLOCK_MONOTONIC, &ts) == 0;
|
||||
|
||||
const u64 result = static_cast<u64>(ts.tv_sec) * 1000000u + static_cast<u64>(ts.tv_nsec) / 1000u;
|
||||
#endif
|
||||
|
||||
if (result) return result;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
// Functions
|
||||
|
||||
+76
-76
@@ -8,15 +8,16 @@
|
||||
#include "Emu/Cell/lv2/sys_memory.h"
|
||||
#include "Emu/RSX/GSRender.h"
|
||||
|
||||
#include <atomic>
|
||||
#include <deque>
|
||||
|
||||
namespace vm
|
||||
{
|
||||
std::array<memory_page, 0x100000000 / 4096> g_pages{};
|
||||
|
||||
static u8* memory_reserve_4GiB(const std::uintptr_t _addr = 0)
|
||||
static u8* memory_reserve_4GiB(std::uintptr_t _addr = 0)
|
||||
{
|
||||
for (auto addr = _addr + 0x100000000;; addr += 0x100000000)
|
||||
for (u64 addr = _addr + 0x100000000;; addr += 0x100000000)
|
||||
{
|
||||
if (const auto ptr = utils::memory_reserve(0x100000000, reinterpret_cast<void*>(addr)))
|
||||
if (auto ptr = utils::memory_reserve(0x100000000, (void*)addr))
|
||||
{
|
||||
return static_cast<u8*>(ptr);
|
||||
}
|
||||
@@ -38,13 +39,11 @@ namespace vm
|
||||
// Memory locations
|
||||
std::vector<std::shared_ptr<block_t>> g_locations;
|
||||
|
||||
// Registered waiters
|
||||
std::vector<vm::waiter*> g_waiters;
|
||||
shared_mutex g_waiters_lock;
|
||||
// Reservations (lock lines) in a single memory page
|
||||
using reservation_info = std::array<std::atomic<u64>, 4096 / 128>;
|
||||
|
||||
// Waiters which will be removed once the lock is freed
|
||||
shared_mutex g_waiters_to_remove_lock;
|
||||
std::vector<vm::waiter*> g_waiters_to_remove;
|
||||
// Registered waiters
|
||||
std::deque<vm::waiter*> g_waiters;
|
||||
|
||||
// Memory mutex core
|
||||
shared_mutex g_mutex;
|
||||
@@ -202,38 +201,78 @@ namespace vm
|
||||
{
|
||||
}
|
||||
|
||||
void writer_lock::unlock()
|
||||
writer_lock::~writer_lock()
|
||||
{
|
||||
if (locked)
|
||||
{
|
||||
g_mutex.unlock();
|
||||
|
||||
locked = false;
|
||||
}
|
||||
}
|
||||
|
||||
writer_lock::~writer_lock()
|
||||
// Page information
|
||||
struct memory_page
|
||||
{
|
||||
unlock();
|
||||
// Memory flags
|
||||
atomic_t<u8> flags;
|
||||
|
||||
atomic_t<u32> waiters;
|
||||
|
||||
// Reservations
|
||||
atomic_t<reservation_info*> reservations;
|
||||
|
||||
// Access reservation info
|
||||
std::atomic<u64>& operator [](u32 addr)
|
||||
{
|
||||
auto ptr = reservations.load();
|
||||
|
||||
if (!ptr)
|
||||
{
|
||||
// Opportunistic memory allocation
|
||||
ptr = new reservation_info{};
|
||||
|
||||
if (auto old_ptr = reservations.compare_and_swap(nullptr, ptr))
|
||||
{
|
||||
delete ptr;
|
||||
ptr = old_ptr;
|
||||
}
|
||||
}
|
||||
|
||||
return (*ptr)[(addr & 0xfff) >> 7];
|
||||
}
|
||||
};
|
||||
|
||||
// Memory pages
|
||||
std::array<memory_page, 0x100000000 / 4096> g_pages{};
|
||||
|
||||
u64 reservation_acquire(u32 addr, u32 _size)
|
||||
{
|
||||
// Access reservation info: stamp and the lock bit
|
||||
return g_pages[addr >> 12][addr].load(std::memory_order_acquire);
|
||||
}
|
||||
|
||||
void reservation_update(u32 addr, u32 _size)
|
||||
{
|
||||
// Update reservation info with new timestamp (unsafe, assume allocated)
|
||||
(*g_pages[addr >> 12].reservations)[(addr & 0xfff) >> 7].store(__rdtsc(), std::memory_order_release);
|
||||
}
|
||||
|
||||
void waiter::init()
|
||||
{
|
||||
// Register waiter
|
||||
g_waiters_lock.lock();
|
||||
writer_lock lock(0);
|
||||
|
||||
g_waiters.emplace_back(this);
|
||||
g_waiters_lock.unlock();
|
||||
}
|
||||
|
||||
void waiter::test() const
|
||||
{
|
||||
const auto owner_copy = owner;
|
||||
if (!owner_copy)
|
||||
if (std::memcmp(data, vm::base(addr), size) == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
memory_page& page = g_pages[addr >> 12];
|
||||
|
||||
if (page.reservations == nullptr)
|
||||
{
|
||||
return;
|
||||
@@ -244,44 +283,28 @@ namespace vm
|
||||
return;
|
||||
}
|
||||
|
||||
if (memcmp(data, vm::base(addr), size) == 0)
|
||||
if (owner)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
owner_copy->notify();
|
||||
}
|
||||
|
||||
void remove_old_waiters()
|
||||
{
|
||||
if (!g_waiters_to_remove.empty())
|
||||
{
|
||||
g_waiters_to_remove_lock.lock();
|
||||
for (auto ptr : g_waiters_to_remove)
|
||||
{
|
||||
const auto found = std::find(g_waiters.cbegin(), g_waiters.cend(), ptr);
|
||||
if (found != g_waiters.cend())
|
||||
{
|
||||
g_waiters.erase(found);
|
||||
}
|
||||
delete ptr;
|
||||
}
|
||||
g_waiters_to_remove.clear();
|
||||
g_waiters_to_remove_lock.unlock();
|
||||
owner->notify();
|
||||
}
|
||||
}
|
||||
|
||||
void waiter::remove()
|
||||
waiter::~waiter()
|
||||
{
|
||||
this->owner = nullptr; // Iterations of the object will ignore it from now on
|
||||
g_waiters_to_remove_lock.lock();
|
||||
g_waiters_to_remove.push_back(this);
|
||||
g_waiters_to_remove_lock.unlock();
|
||||
// Unregister waiter
|
||||
writer_lock lock(0);
|
||||
|
||||
// Find waiter
|
||||
const auto found = std::find(g_waiters.cbegin(), g_waiters.cend(), this);
|
||||
|
||||
if (found != g_waiters.cend())
|
||||
{
|
||||
g_waiters.erase(found);
|
||||
}
|
||||
}
|
||||
|
||||
void notify(u32 addr, u32 size)
|
||||
{
|
||||
g_waiters_lock.lock_shared();
|
||||
for (const waiter* ptr : g_waiters)
|
||||
{
|
||||
if (ptr->addr / 128 == addr / 128)
|
||||
@@ -289,37 +312,14 @@ namespace vm
|
||||
ptr->test();
|
||||
}
|
||||
}
|
||||
|
||||
if (g_waiters_to_remove.size() > 10)
|
||||
{
|
||||
g_waiters_lock.lock_upgrade();
|
||||
remove_old_waiters();
|
||||
g_waiters_lock.unlock();
|
||||
}
|
||||
else
|
||||
{
|
||||
g_waiters_lock.unlock_shared();
|
||||
}
|
||||
}
|
||||
|
||||
void notify_all()
|
||||
{
|
||||
g_waiters_lock.lock_shared();
|
||||
for (const waiter* ptr : g_waiters)
|
||||
{
|
||||
ptr->test();
|
||||
}
|
||||
|
||||
if (g_waiters_to_remove.size() > 10)
|
||||
{
|
||||
g_waiters_lock.lock_upgrade();
|
||||
remove_old_waiters();
|
||||
g_waiters_lock.unlock();
|
||||
}
|
||||
else
|
||||
{
|
||||
g_waiters_lock.unlock_shared();
|
||||
}
|
||||
}
|
||||
|
||||
void _page_map(u32 addr, u32 size, u8 flags)
|
||||
@@ -369,8 +369,8 @@ namespace vm
|
||||
|
||||
const u8 flags_both = flags_set & flags_clear;
|
||||
|
||||
flags_test |= page_allocated;
|
||||
flags_set &= ~flags_both;
|
||||
flags_test |= page_allocated;
|
||||
flags_set &= ~flags_both;
|
||||
flags_clear &= ~flags_both;
|
||||
|
||||
for (u32 i = addr / 4096; i < addr / 4096 + size / 4096; i++)
|
||||
@@ -736,7 +736,7 @@ namespace vm
|
||||
{
|
||||
writer_lock lock(0);
|
||||
|
||||
for (auto it = g_locations.begin(); it != g_locations.end(); ++it)
|
||||
for (auto it = g_locations.begin(); it != g_locations.end(); it++)
|
||||
{
|
||||
if (*it && (*it)->addr == addr)
|
||||
{
|
||||
@@ -835,7 +835,7 @@ void fmt_class_string<vm::_ptr_base<const char>>::format(std::string& out, u64 a
|
||||
|
||||
out += u8"“";
|
||||
|
||||
for (vm::_ptr_base<const volatile char> ptr = vm::cast(arg);; ++ptr)
|
||||
for (vm::_ptr_base<const volatile char> ptr = vm::cast(arg);; ptr++)
|
||||
{
|
||||
if (!vm::check_addr(ptr.addr()))
|
||||
{
|
||||
|
||||
+8
-51
@@ -1,8 +1,8 @@
|
||||
#pragma once
|
||||
|
||||
#include <map>
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
#include <atomic>
|
||||
|
||||
class named_thread;
|
||||
class cpu_thread;
|
||||
@@ -42,9 +42,9 @@ namespace vm
|
||||
{
|
||||
named_thread* owner;
|
||||
u32 addr;
|
||||
u32 size;
|
||||
u64 stamp;
|
||||
const void* data;
|
||||
static const u32 size = 128; // Always 128 currently
|
||||
|
||||
waiter() = default;
|
||||
|
||||
@@ -53,7 +53,7 @@ namespace vm
|
||||
void init();
|
||||
void test() const;
|
||||
|
||||
void remove();
|
||||
~waiter();
|
||||
};
|
||||
|
||||
// Address type
|
||||
@@ -90,64 +90,21 @@ namespace vm
|
||||
|
||||
struct writer_lock final
|
||||
{
|
||||
bool locked;
|
||||
const bool locked;
|
||||
|
||||
writer_lock(const writer_lock&) = delete;
|
||||
writer_lock(int full = 1);
|
||||
writer_lock(const try_to_lock_t&);
|
||||
void unlock();
|
||||
~writer_lock();
|
||||
|
||||
explicit operator bool() const { return locked; }
|
||||
};
|
||||
|
||||
// Reservations (lock lines) in a single memory page
|
||||
using reservation_info = std::array<std::atomic<u64>, 4096 / 128>;
|
||||
// Get reservation status for further atomic update: last update timestamp
|
||||
u64 reservation_acquire(u32 addr, u32 size);
|
||||
|
||||
// Page information
|
||||
struct memory_page
|
||||
{
|
||||
// Reservations
|
||||
atomic_t<reservation_info*> reservations;
|
||||
//atomic_t<u32> waiters;
|
||||
// Memory flags
|
||||
atomic_t<u8> flags;
|
||||
|
||||
// Access reservation info
|
||||
FORCE_INLINE std::atomic<u64>& operator [](const u32 addr)
|
||||
{
|
||||
auto ptr = reservations.load();
|
||||
|
||||
if (!ptr)
|
||||
{
|
||||
ptr = new reservation_info();
|
||||
// Opportunistic memory allocation
|
||||
|
||||
if (const auto old_ptr = reservations.compare_and_swap(nullptr, ptr))
|
||||
{
|
||||
delete ptr;
|
||||
ptr = old_ptr;
|
||||
}
|
||||
}
|
||||
|
||||
return (*ptr)[(addr & 0xfff) >> 7];
|
||||
}
|
||||
};
|
||||
|
||||
// Memory pages
|
||||
extern std::array<memory_page, 0x100000000 / 4096> g_pages;
|
||||
|
||||
FORCE_INLINE u64 reservation_acquire(u32 addr, u32 _size)
|
||||
{
|
||||
// Access reservation info: stamp and the lock bit
|
||||
return g_pages[addr >> 12][addr].load(std::memory_order_acquire);
|
||||
}
|
||||
|
||||
FORCE_INLINE void reservation_update(u32 addr, u32 _size)
|
||||
{
|
||||
// Update reservation info with new timestamp (unsafe, assume allocated)
|
||||
(*g_pages[addr >> 12].reservations)[(addr & 0xfff) >> 7].store(__rdtsc(), std::memory_order_release);
|
||||
}
|
||||
// End atomic update
|
||||
void reservation_update(u32 addr, u32 size);
|
||||
|
||||
// Check and notify memory changes at address
|
||||
void notify(u32 addr, u32 size);
|
||||
|
||||
@@ -532,7 +532,7 @@ std::tuple<T, T, u32> upload_untouched(gsl::span<to_be_t<const T>> src, gsl::spa
|
||||
|
||||
verify(HERE), (dst.size_bytes() >= src.size_bytes());
|
||||
|
||||
u32 dst_idx = -1;
|
||||
u32 dst_idx = 0;
|
||||
for (T index : src)
|
||||
{
|
||||
if (is_primitive_restart_enabled && index == primitive_restart_index)
|
||||
@@ -549,9 +549,9 @@ std::tuple<T, T, u32> upload_untouched(gsl::span<to_be_t<const T>> src, gsl::spa
|
||||
min_index = std::min(min_index, index);
|
||||
}
|
||||
|
||||
dst[++dst_idx] = index;
|
||||
dst[dst_idx++] = index;
|
||||
}
|
||||
return std::make_tuple(min_index, max_index, dst_idx + 1);
|
||||
return std::make_tuple(min_index, max_index, dst_idx);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
|
||||
@@ -111,7 +111,7 @@ void FragmentProgramDecompiler::SetDst(std::string code, bool append_mask)
|
||||
}
|
||||
|
||||
u32 reg_index = dst.fp16 ? dst.dest_reg >> 1 : dst.dest_reg;
|
||||
temp_registers[reg_index].tag(dst.dest_reg, !!dst.fp16, dst.mask_x, dst.mask_y, dst.mask_z, dst.mask_w);
|
||||
temp_registers[reg_index].tag(dst.dest_reg, !!dst.fp16);
|
||||
}
|
||||
|
||||
void FragmentProgramDecompiler::AddFlowOp(std::string code)
|
||||
@@ -283,15 +283,14 @@ std::string FragmentProgramDecompiler::Format(const std::string& code, bool igno
|
||||
{ "$_i", [this]() -> std::string {return std::to_string(dst.tex_num);} },
|
||||
{ "$m", std::bind(std::mem_fn(&FragmentProgramDecompiler::GetMask), this) },
|
||||
{ "$ifcond ", [this]() -> std::string
|
||||
{
|
||||
const std::string& cond = GetCond();
|
||||
if (cond == "true") return "";
|
||||
return "if(" + cond + ") ";
|
||||
}
|
||||
{
|
||||
const std::string& cond = GetCond();
|
||||
if (cond == "true") return "";
|
||||
return "if(" + cond + ") ";
|
||||
}
|
||||
},
|
||||
{ "$cond", std::bind(std::mem_fn(&FragmentProgramDecompiler::GetCond), this) },
|
||||
{ "$_c", std::bind(std::mem_fn(&FragmentProgramDecompiler::AddConst), this) },
|
||||
{ "$float4", [this]() -> std::string { return getFloatTypeName(4); } }
|
||||
{ "$_c", std::bind(std::mem_fn(&FragmentProgramDecompiler::AddConst), this) }
|
||||
};
|
||||
|
||||
if (!ignore_redirects)
|
||||
@@ -408,13 +407,20 @@ template<typename T> std::string FragmentProgramDecompiler::GetSRC(T src)
|
||||
dst.opcode == RSX_FP_OPCODE_UPB ||
|
||||
dst.opcode == RSX_FP_OPCODE_UPG)
|
||||
{
|
||||
//TODO: Implement aliased gather for half floats
|
||||
bool xy_read = false;
|
||||
bool zw_read = false;
|
||||
|
||||
if (src.swizzle_x < 2 || src.swizzle_y < 2 || src.swizzle_z < 2 || src.swizzle_w < 2)
|
||||
xy_read = true;
|
||||
if (src.swizzle_x > 1 || src.swizzle_y > 1 || src.swizzle_z > 1 || src.swizzle_w > 1)
|
||||
zw_read = true;
|
||||
|
||||
auto ® = temp_registers[src.tmp_reg_index];
|
||||
if (reg.requires_gather(src.swizzle_x))
|
||||
if (reg.requires_gather(xy_read, zw_read))
|
||||
{
|
||||
properties.has_gather_op = true;
|
||||
AddReg(src.tmp_reg_index, src.fp16);
|
||||
ret = getFloatTypeName(4) + reg.gather_r();
|
||||
break;
|
||||
AddCode(reg.gather_r());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,41 +24,25 @@ class FragmentProgramDecompiler
|
||||
bool aliased_r0 = false;
|
||||
bool aliased_h0 = false;
|
||||
bool aliased_h1 = false;
|
||||
bool last_write_half[4] = { false, false, false, false };
|
||||
bool last_write_half = false;
|
||||
|
||||
u32 real_index = UINT32_MAX;
|
||||
|
||||
void tag(u32 index, bool half_register, bool x, bool y, bool z, bool w)
|
||||
void tag(u32 index, bool half_register)
|
||||
{
|
||||
if (half_register)
|
||||
{
|
||||
last_write_half = true;
|
||||
|
||||
if (index & 1)
|
||||
{
|
||||
if (x) last_write_half[2] = true;
|
||||
if (y) last_write_half[2] = true;
|
||||
if (z) last_write_half[3] = true;
|
||||
if (w) last_write_half[3] = true;
|
||||
|
||||
aliased_h1 = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (x) last_write_half[0] = true;
|
||||
if (y) last_write_half[0] = true;
|
||||
if (z) last_write_half[1] = true;
|
||||
if (w) last_write_half[1] = true;
|
||||
|
||||
aliased_h0 = true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (x) last_write_half[0] = false;
|
||||
if (y) last_write_half[1] = false;
|
||||
if (z) last_write_half[2] = false;
|
||||
if (w) last_write_half[3] = false;
|
||||
|
||||
aliased_r0 = true;
|
||||
last_write_half = false;
|
||||
}
|
||||
|
||||
if (real_index == UINT32_MAX)
|
||||
@@ -70,19 +54,12 @@ class FragmentProgramDecompiler
|
||||
}
|
||||
}
|
||||
|
||||
bool requires_gather(u8 channel) const
|
||||
bool requires_gather(bool xy, bool zw) const
|
||||
{
|
||||
//Data fetched from the single precision register requires merging of the two half registers
|
||||
verify(HERE), channel < 4;
|
||||
if (aliased_h0 && channel < 2)
|
||||
{
|
||||
return last_write_half[channel];
|
||||
}
|
||||
|
||||
if (aliased_h1 && channel > 1)
|
||||
{
|
||||
return last_write_half[channel];
|
||||
}
|
||||
//TODO: Check individual swizzle channels
|
||||
if ((aliased_h0 && xy) || (aliased_h1 && zw))
|
||||
return last_write_half;
|
||||
|
||||
return false;
|
||||
}
|
||||
@@ -90,7 +67,7 @@ class FragmentProgramDecompiler
|
||||
bool requires_split(u32 /*index*/) const
|
||||
{
|
||||
//Data fetched from any of the two half registers requires sync with the full register
|
||||
if (!(last_write_half[0] || last_write_half[1]) && aliased_r0)
|
||||
if (!last_write_half && aliased_r0)
|
||||
{
|
||||
//r0 has been written to
|
||||
//TODO: Check for specific elements in real32 register
|
||||
@@ -108,12 +85,15 @@ class FragmentProgramDecompiler
|
||||
std::string ret = "//Invalid gather";
|
||||
|
||||
if (aliased_h0 && aliased_h1)
|
||||
ret = "(gather(" + h0 + ", " + h1 + "))";
|
||||
ret = reg + " = gather(" + h0 + ", " + h1 + ");";
|
||||
else if (aliased_h0)
|
||||
ret = "(gather(" + h0 + "), " + reg + ".zw)";
|
||||
ret = reg + ".xy = gather(" + h0 + ");";
|
||||
else if (aliased_h1)
|
||||
ret = "(" + reg + ".xy, gather(" + h1 + "))";
|
||||
ret = reg + ".zw = gather(" + h1 + ");";
|
||||
|
||||
last_write_half = false;
|
||||
aliased_h0 = false;
|
||||
aliased_h1 = false;
|
||||
return ret;
|
||||
}
|
||||
};
|
||||
|
||||
@@ -78,7 +78,6 @@ namespace program_hash_util
|
||||
* - static void recompile_fragment_program(RSXFragmentProgram *RSXFP, FragmentProgramData& fragmentProgramData, size_t ID);
|
||||
* - static void recompile_vertex_program(RSXVertexProgram *RSXVP, VertexProgramData& vertexProgramData, size_t ID);
|
||||
* - static PipelineData build_program(VertexProgramData &vertexProgramData, FragmentProgramData &fragmentProgramData, const PipelineProperties &pipelineProperties, const ExtraData& extraData);
|
||||
* - static void validate_pipeline_properties(const VertexProgramData &vertexProgramData, const FragmentProgramData &fragmentProgramData, PipelineProperties& props);
|
||||
*/
|
||||
template<typename backend_traits>
|
||||
class program_state_cache
|
||||
@@ -262,7 +261,7 @@ public:
|
||||
pipeline_storage_type& getGraphicPipelineState(
|
||||
const RSXVertexProgram& vertexShader,
|
||||
const RSXFragmentProgram& fragmentShader,
|
||||
pipeline_properties& pipelineProperties,
|
||||
const pipeline_properties& pipelineProperties,
|
||||
Args&& ...args
|
||||
)
|
||||
{
|
||||
@@ -274,7 +273,6 @@ public:
|
||||
bool already_existing_fragment_program = std::get<1>(fp_search);
|
||||
bool already_existing_vertex_program = std::get<1>(vp_search);
|
||||
|
||||
backend_traits::validate_pipeline_properties(vertex_program, fragment_program, pipelineProperties);
|
||||
pipeline_key key = { vertex_program.id, fragment_program.id, pipelineProperties };
|
||||
|
||||
if (already_existing_fragment_program && already_existing_vertex_program)
|
||||
@@ -307,7 +305,7 @@ public:
|
||||
return 0;
|
||||
}
|
||||
|
||||
void fill_fragment_constants_buffer(gsl::span<f32, gsl::dynamic_range> dst_buffer, const RSXFragmentProgram &fragment_program, bool sanitize = false) const
|
||||
void fill_fragment_constants_buffer(gsl::span<f32, gsl::dynamic_range> dst_buffer, const RSXFragmentProgram &fragment_program) const
|
||||
{
|
||||
const auto I = m_fragment_shader_cache.find(fragment_program);
|
||||
if (I == m_fragment_shader_cache.end())
|
||||
@@ -347,12 +345,6 @@ public:
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (sanitize)
|
||||
{
|
||||
//Lower NaNs to 0
|
||||
const auto mask = _mm_cmpunord_ps((__m128&)shuffled_vector, _mm_set1_ps(1.f));
|
||||
_mm_stream_si128((__m128i*)dst, (__m128i&)_mm_andnot_ps(mask, (__m128&)shuffled_vector));
|
||||
}
|
||||
else
|
||||
{
|
||||
_mm_stream_si128((__m128i*)dst, shuffled_vector);
|
||||
|
||||
@@ -131,9 +131,4 @@ public:
|
||||
else
|
||||
fmt::throw_exception("m_put_pos == m_get_pos!" HERE);
|
||||
}
|
||||
|
||||
size_t size() const
|
||||
{
|
||||
return m_size;
|
||||
}
|
||||
};
|
||||
|
||||
@@ -370,7 +370,6 @@ namespace rsx
|
||||
virtual void set_up_remap_vector(section_storage_type& section, const std::pair<std::array<u8, 4>, std::array<u8, 4>>& remap_vector) = 0;
|
||||
virtual void insert_texture_barrier(commandbuffer_type&, image_storage_type* tex) = 0;
|
||||
virtual image_view_type generate_cubemap_from_images(commandbuffer_type&, u32 gcm_format, u16 size, const std::array<image_resource_type, 6>& sources) = 0;
|
||||
virtual bool render_target_format_is_compatible(image_storage_type* tex, u32 gcm_format) = 0;
|
||||
|
||||
constexpr u32 get_block_size() const { return 0x1000000; }
|
||||
inline u32 get_block_address(u32 address) const { return (address & ~0xFFFFFF); }
|
||||
@@ -1386,12 +1385,6 @@ namespace rsx
|
||||
}
|
||||
}
|
||||
|
||||
if (!requires_processing)
|
||||
{
|
||||
//Check if we need to do anything about the formats
|
||||
requires_processing = !render_target_format_is_compatible(texptr, format);
|
||||
}
|
||||
|
||||
if (requires_processing)
|
||||
{
|
||||
const auto w = rsx::apply_resolution_scale(internal_width, true);
|
||||
@@ -1627,24 +1620,13 @@ namespace rsx
|
||||
auto subresources_layout = get_subresources_layout(tex);
|
||||
auto remap_vector = tex.decoded_remap();
|
||||
|
||||
bool is_depth_format = false;
|
||||
switch (format)
|
||||
{
|
||||
case CELL_GCM_TEXTURE_DEPTH16:
|
||||
case CELL_GCM_TEXTURE_DEPTH16_FLOAT:
|
||||
case CELL_GCM_TEXTURE_DEPTH24_D8:
|
||||
case CELL_GCM_TEXTURE_DEPTH24_D8_FLOAT:
|
||||
is_depth_format = true;
|
||||
break;
|
||||
}
|
||||
|
||||
//Invalidate with writing=false, discard=false, rebuild=false, native_flush=true
|
||||
invalidate_range_impl_base(texaddr, tex_size, false, false, false, true, std::forward<Args>(extras)...);
|
||||
|
||||
m_texture_memory_in_use += (tex_pitch * tex_height);
|
||||
return{ upload_image_from_cpu(cmd, texaddr, tex_width, tex_height, depth, tex.get_exact_mipmap_count(), tex_pitch, format,
|
||||
texture_upload_context::shader_read, subresources_layout, extended_dimension, is_swizzled, remap_vector)->get_raw_view(),
|
||||
texture_upload_context::shader_read, is_depth_format, scale_x, scale_y, extended_dimension };
|
||||
texture_upload_context::shader_read, false, scale_x, scale_y, extended_dimension };
|
||||
}
|
||||
|
||||
template <typename surface_store_type, typename blitter_type, typename ...Args>
|
||||
|
||||
@@ -145,11 +145,6 @@ struct D3D12Traits
|
||||
vertexProgramData.id = (u32)ID;
|
||||
}
|
||||
|
||||
static
|
||||
void validate_pipeline_properties(const vertex_program_type&, const fragment_program_type&, pipeline_properties&)
|
||||
{
|
||||
}
|
||||
|
||||
static
|
||||
pipeline_storage_type build_pipeline(
|
||||
const vertex_program_type &vertexProgramData, const fragment_program_type &fragmentProgramData, const pipeline_properties &pipelineProperties,
|
||||
|
||||
@@ -736,16 +736,14 @@ void GLGSRender::on_init_thread()
|
||||
m_index_ring_buffer.reset(new gl::ring_buffer());
|
||||
}
|
||||
|
||||
m_attrib_ring_buffer->create(gl::buffer::target::texture, 256 * 0x100000);
|
||||
m_index_ring_buffer->create(gl::buffer::target::element_array, 64 * 0x100000);
|
||||
m_transform_constants_buffer->create(gl::buffer::target::uniform, 64 * 0x100000);
|
||||
m_fragment_constants_buffer->create(gl::buffer::target::uniform, 16 * 0x100000);
|
||||
m_vertex_state_buffer->create(gl::buffer::target::uniform, 16 * 0x100000);
|
||||
m_attrib_ring_buffer->create(gl::buffer::target::texture, std::min<GLsizeiptr>(m_max_texbuffer_size, 256 * 0x100000));
|
||||
m_index_ring_buffer->create(gl::buffer::target::element_array, std::min<GLsizeiptr>(m_max_texbuffer_size, 64 * 0x100000));
|
||||
m_transform_constants_buffer->create(gl::buffer::target::uniform, std::min<GLsizeiptr>(m_max_texbuffer_size, 16 * 0x100000));
|
||||
m_fragment_constants_buffer->create(gl::buffer::target::uniform, std::min<GLsizeiptr>(m_max_texbuffer_size, 16 * 0x100000));
|
||||
m_vertex_state_buffer->create(gl::buffer::target::uniform, std::min<GLsizeiptr>(m_max_texbuffer_size, 16 * 0x100000));
|
||||
|
||||
m_persistent_stream_view.update(m_attrib_ring_buffer.get(), 0, m_max_texbuffer_size);
|
||||
m_volatile_stream_view.update(m_attrib_ring_buffer.get(), 0, m_max_texbuffer_size);
|
||||
m_gl_persistent_stream_buffer.copy_from(m_persistent_stream_view);
|
||||
m_gl_volatile_stream_buffer.copy_from(m_volatile_stream_view);
|
||||
m_gl_persistent_stream_buffer.copy_from(*m_attrib_ring_buffer, GL_R8UI, 0, (u32)m_attrib_ring_buffer->size());
|
||||
m_gl_volatile_stream_buffer.copy_from(*m_attrib_ring_buffer, GL_R8UI, 0, (u32)m_attrib_ring_buffer->size());
|
||||
|
||||
m_vao.element_array_buffer = *m_index_ring_buffer;
|
||||
|
||||
@@ -1036,7 +1034,7 @@ bool GLGSRender::check_program_state()
|
||||
return (rsx::method_registers.shader_program_address() != 0);
|
||||
}
|
||||
|
||||
void GLGSRender::load_program(const gl::vertex_upload_info& upload_info)
|
||||
void GLGSRender::load_program(const vertex_upload_info& upload_info)
|
||||
{
|
||||
get_current_fragment_program(fs_sampler_state);
|
||||
verify(HERE), current_fragment_program.valid;
|
||||
@@ -1112,10 +1110,7 @@ void GLGSRender::load_program(const gl::vertex_upload_info& upload_info)
|
||||
buf = static_cast<u8*>(mapping.first);
|
||||
fragment_constants_offset = mapping.second;
|
||||
if (fragment_constants_size)
|
||||
{
|
||||
m_prog_buffer.fill_fragment_constants_buffer({ reinterpret_cast<float*>(buf), gsl::narrow<int>(fragment_constants_size) },
|
||||
fragment_program, gl::get_driver_caps().vendor_NVIDIA);
|
||||
}
|
||||
m_prog_buffer.fill_fragment_constants_buffer({ reinterpret_cast<float*>(buf), gsl::narrow<int>(fragment_constants_size) }, fragment_program);
|
||||
|
||||
// Fragment state
|
||||
fill_fragment_state_buffer(buf+fragment_constants_size, fragment_program);
|
||||
@@ -1404,6 +1399,14 @@ void GLGSRender::flip(int buffer)
|
||||
m_textures_upload_time = 0;
|
||||
}
|
||||
|
||||
|
||||
u64 GLGSRender::timestamp() const
|
||||
{
|
||||
GLint64 result;
|
||||
glGetInteger64v(GL_TIMESTAMP, &result);
|
||||
return result;
|
||||
}
|
||||
|
||||
bool GLGSRender::on_access_violation(u32 address, bool is_writing)
|
||||
{
|
||||
bool can_flush = (std::this_thread::get_id() == m_thread_id);
|
||||
|
||||
@@ -21,16 +21,6 @@ namespace gl
|
||||
using null_vertex_cache = vertex_cache;
|
||||
|
||||
using shader_cache = rsx::shaders_cache<void*, GLProgramBuffer>;
|
||||
|
||||
struct vertex_upload_info
|
||||
{
|
||||
u32 vertex_draw_count;
|
||||
u32 allocated_vertex_count;
|
||||
u32 vertex_index_base;
|
||||
u32 persistent_mapping_offset;
|
||||
u32 volatile_mapping_offset;
|
||||
std::optional<std::tuple<GLenum, u32> > index_info;
|
||||
};
|
||||
}
|
||||
|
||||
struct work_item
|
||||
@@ -98,7 +88,7 @@ struct driver_state
|
||||
return !!test;
|
||||
}
|
||||
|
||||
inline bool test_property(GLenum property, u32 test) const
|
||||
const bool test_property(GLenum property, u32 test) const
|
||||
{
|
||||
auto found = properties.find(property);
|
||||
if (found == properties.end())
|
||||
@@ -265,6 +255,16 @@ struct driver_state
|
||||
}
|
||||
};
|
||||
|
||||
struct vertex_upload_info
|
||||
{
|
||||
u32 vertex_draw_count;
|
||||
u32 allocated_vertex_count;
|
||||
u32 vertex_index_base;
|
||||
u32 persistent_mapping_offset;
|
||||
u32 volatile_mapping_offset;
|
||||
std::optional<std::tuple<GLenum, u32> > index_info;
|
||||
};
|
||||
|
||||
class GLGSRender : public GSRender
|
||||
{
|
||||
private:
|
||||
@@ -279,8 +279,6 @@ private:
|
||||
|
||||
gl::texture_cache m_gl_texture_cache;
|
||||
|
||||
gl::buffer_view m_persistent_stream_view;
|
||||
gl::buffer_view m_volatile_stream_view;
|
||||
gl::texture m_gl_persistent_stream_buffer;
|
||||
gl::texture m_gl_volatile_stream_buffer;
|
||||
|
||||
@@ -342,14 +340,14 @@ private:
|
||||
driver_state gl_state;
|
||||
|
||||
// Return element to draw and in case of indexed draw index type and offset in index buffer
|
||||
gl::vertex_upload_info set_vertex_buffer();
|
||||
vertex_upload_info set_vertex_buffer();
|
||||
rsx::vertex_input_layout m_vertex_layout = {};
|
||||
|
||||
void clear_surface(u32 arg);
|
||||
void init_buffers(rsx::framebuffer_creation_context context, bool skip_reading = false);
|
||||
|
||||
bool check_program_state();
|
||||
void load_program(const gl::vertex_upload_info& upload_info);
|
||||
void load_program(const vertex_upload_info& upload_info);
|
||||
|
||||
void update_draw_state();
|
||||
|
||||
@@ -376,6 +374,7 @@ protected:
|
||||
void on_exit() override;
|
||||
bool do_method(u32 id, u32 arg) override;
|
||||
void flip(int buffer) override;
|
||||
u64 timestamp() const override;
|
||||
|
||||
void do_local_task(bool idle) override;
|
||||
|
||||
|
||||
@@ -85,9 +85,8 @@ namespace gl
|
||||
bool ARB_texture_barrier_supported = false;
|
||||
bool NV_texture_barrier_supported = false;
|
||||
bool initialized = false;
|
||||
bool vendor_INTEL = false; //has broken GLSL compiler
|
||||
bool vendor_AMD = false; //has broken ARB_multidraw
|
||||
bool vendor_NVIDIA = false; //has NaN poisoning issues
|
||||
bool vendor_INTEL = false;
|
||||
bool vendor_AMD = false;
|
||||
|
||||
void initialize()
|
||||
{
|
||||
@@ -105,35 +104,35 @@ namespace gl
|
||||
if (ext_name == "GL_ARB_shader_draw_parameters")
|
||||
{
|
||||
ARB_shader_draw_parameters_supported = true;
|
||||
find_count--;
|
||||
find_count --;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (ext_name == "GL_EXT_direct_state_access")
|
||||
{
|
||||
EXT_dsa_supported = true;
|
||||
find_count--;
|
||||
find_count --;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (ext_name == "GL_ARB_direct_state_access")
|
||||
{
|
||||
ARB_dsa_supported = true;
|
||||
find_count--;
|
||||
find_count --;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (ext_name == "GL_ARB_buffer_storage")
|
||||
{
|
||||
ARB_buffer_storage_supported = true;
|
||||
find_count--;
|
||||
find_count --;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (ext_name == "GL_ARB_texture_buffer_object")
|
||||
{
|
||||
ARB_texture_buffer_supported = true;
|
||||
find_count--;
|
||||
find_count --;
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -196,10 +195,6 @@ namespace gl
|
||||
if (!EXT_dsa_supported && glGetTextureImageEXT && glTextureBufferRangeEXT)
|
||||
EXT_dsa_supported = true;
|
||||
}
|
||||
else if (vendor_string.find("nvidia") != std::string::npos)
|
||||
{
|
||||
vendor_NVIDIA = true;
|
||||
}
|
||||
#ifdef _WIN32
|
||||
else if (vendor_string.find("amd") != std::string::npos || vendor_string.find("ati") != std::string::npos)
|
||||
{
|
||||
@@ -869,7 +864,7 @@ namespace gl
|
||||
buffer::create();
|
||||
|
||||
glBindBuffer((GLenum)m_target, m_id);
|
||||
glBufferStorage((GLenum)m_target, size, data, GL_MAP_WRITE_BIT | GL_MAP_PERSISTENT_BIT | GL_MAP_COHERENT_BIT);
|
||||
glBufferStorage((GLenum)m_target, size, data, GL_MAP_WRITE_BIT | GL_MAP_PERSISTENT_BIT | GL_CLIENT_STORAGE_BIT | GL_MAP_COHERENT_BIT);
|
||||
m_memory_mapping = glMapBufferRange((GLenum)m_target, 0, size, GL_MAP_WRITE_BIT | GL_MAP_PERSISTENT_BIT | GL_MAP_COHERENT_BIT);
|
||||
|
||||
verify(HERE), m_memory_mapping != nullptr;
|
||||
@@ -891,19 +886,15 @@ namespace gl
|
||||
if ((offset + alloc_size) > m_size)
|
||||
{
|
||||
if (!m_fence.is_empty())
|
||||
{
|
||||
m_fence.wait_for_signal();
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG_ERROR(RSX, "OOM Error: Ring buffer was likely being used without notify() being called");
|
||||
glFinish();
|
||||
}
|
||||
|
||||
m_data_loc = 0;
|
||||
offset = 0;
|
||||
}
|
||||
|
||||
if (!m_data_loc)
|
||||
m_fence.reset();
|
||||
|
||||
//Align data loc to 256; allows some "guard" region so we dont trample our own data inadvertently
|
||||
m_data_loc = align(offset + alloc_size, 256);
|
||||
return std::make_pair(((char*)m_memory_mapping) + offset, offset);
|
||||
@@ -937,8 +928,7 @@ namespace gl
|
||||
//Notification of a draw command
|
||||
virtual void notify()
|
||||
{
|
||||
//Insert fence about 25% into the buffer
|
||||
if (m_fence.is_empty() && (m_data_loc > (m_size >> 2)))
|
||||
if (m_fence.is_empty())
|
||||
m_fence.reset();
|
||||
}
|
||||
};
|
||||
@@ -1056,69 +1046,6 @@ namespace gl
|
||||
void notify() override {}
|
||||
};
|
||||
|
||||
class buffer_view
|
||||
{
|
||||
buffer* m_buffer = nullptr;
|
||||
u32 m_offset = 0;
|
||||
u32 m_range = 0;
|
||||
GLenum m_format = GL_R8UI;
|
||||
|
||||
public:
|
||||
buffer_view(buffer *_buffer, u32 offset, u32 range, GLenum format = GL_R8UI)
|
||||
: m_buffer(_buffer), m_offset(offset), m_range(range), m_format(format)
|
||||
{}
|
||||
|
||||
buffer_view()
|
||||
{}
|
||||
|
||||
void update(buffer *_buffer, u32 offset, u32 range, GLenum format = GL_R8UI)
|
||||
{
|
||||
m_buffer = _buffer;
|
||||
m_offset = offset;
|
||||
m_range = range;
|
||||
m_format = format;
|
||||
}
|
||||
|
||||
u32 offset() const
|
||||
{
|
||||
return m_offset;
|
||||
}
|
||||
|
||||
u32 range() const
|
||||
{
|
||||
return m_range;
|
||||
}
|
||||
|
||||
u32 format() const
|
||||
{
|
||||
return m_format;
|
||||
}
|
||||
|
||||
buffer* buffer() const
|
||||
{
|
||||
return m_buffer;
|
||||
}
|
||||
|
||||
bool in_range(u32 address, u32 size, u32& new_offset) const
|
||||
{
|
||||
if (address < m_offset)
|
||||
return false;
|
||||
|
||||
const u32 _offset = address - m_offset;
|
||||
if (m_range < _offset)
|
||||
return false;
|
||||
|
||||
const auto remaining = m_range - _offset;
|
||||
if (size <= remaining)
|
||||
{
|
||||
new_offset = _offset;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
class vao
|
||||
{
|
||||
template<buffer::target BindId, uint GetStateId>
|
||||
@@ -1754,11 +1681,6 @@ namespace gl
|
||||
__glcheck glTextureBufferRange(id(), gl_format_type, buf.id(), offset, length);
|
||||
}
|
||||
|
||||
void copy_from(buffer_view &view)
|
||||
{
|
||||
copy_from(*view.buffer(), view.format(), view.offset(), view.range());
|
||||
}
|
||||
|
||||
void copy_from(const buffer& buf, texture::format format, texture::type type, class pixel_unpack_settings pixel_settings)
|
||||
{
|
||||
buffer::save_binding_state save_buffer(buffer::target::pixel_unpack, buf);
|
||||
@@ -2843,4 +2765,17 @@ namespace gl
|
||||
set_id(0);
|
||||
}
|
||||
};
|
||||
|
||||
class buffer_view : public buffer
|
||||
{
|
||||
public:
|
||||
buffer_view(GLuint id) : buffer(id)
|
||||
{
|
||||
}
|
||||
|
||||
~buffer_view()
|
||||
{
|
||||
set_id(0);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@@ -24,11 +24,6 @@ struct GLTraits
|
||||
vertexProgramData.Compile();
|
||||
}
|
||||
|
||||
static
|
||||
void validate_pipeline_properties(const vertex_program_type&, const fragment_program_type&, pipeline_properties&)
|
||||
{
|
||||
}
|
||||
|
||||
static
|
||||
pipeline_storage_type build_pipeline(const vertex_program_type &vertexProgramData, const fragment_program_type &fragmentProgramData, const pipeline_properties&)
|
||||
{
|
||||
|
||||
@@ -947,35 +947,6 @@ namespace gl
|
||||
glTextureBarrierNV();
|
||||
}
|
||||
|
||||
bool render_target_format_is_compatible(gl::texture* tex, u32 gcm_format) override
|
||||
{
|
||||
if (auto as_rtt = dynamic_cast<gl::render_target*>(tex))
|
||||
{
|
||||
auto ifmt = as_rtt->get_compatible_internal_format();
|
||||
switch (gcm_format)
|
||||
{
|
||||
default:
|
||||
//TODO
|
||||
LOG_TRACE(RSX, "Format incompatibility detected, reporting failure to force data copy (GL_INTERNAL_FORMAT=0x%X, GCM_FORMAT=0x%X)", (u32)ifmt, gcm_format);
|
||||
return false;
|
||||
case CELL_GCM_TEXTURE_W16_Z16_Y16_X16_FLOAT:
|
||||
return (ifmt == gl::texture::internal_format::rgba16f);
|
||||
case CELL_GCM_TEXTURE_W32_Z32_Y32_X32_FLOAT:
|
||||
return (ifmt == gl::texture::internal_format::rgba32f);
|
||||
case CELL_GCM_TEXTURE_X32_FLOAT:
|
||||
return (ifmt == gl::texture::internal_format::r32f);
|
||||
case CELL_GCM_TEXTURE_R5G6B5:
|
||||
return (ifmt == gl::texture::internal_format::r5g6b5);
|
||||
case CELL_GCM_TEXTURE_DEPTH24_D8:
|
||||
return (ifmt == gl::texture::internal_format::depth24_stencil8 || ifmt == gl::texture::internal_format::depth32f_stencil8);
|
||||
case CELL_GCM_TEXTURE_A8R8G8B8:
|
||||
return (ifmt == gl::texture::internal_format::rgba8 || ifmt == gl::texture::internal_format::depth24_stencil8 || ifmt == gl::texture::internal_format::depth32f_stencil8);
|
||||
}
|
||||
}
|
||||
|
||||
fmt::throw_exception("Format comparison for non-rendertargets is not implemented" HERE);
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
texture_cache() {}
|
||||
|
||||
@@ -180,7 +180,7 @@ namespace
|
||||
};
|
||||
}
|
||||
|
||||
gl::vertex_upload_info GLGSRender::set_vertex_buffer()
|
||||
vertex_upload_info GLGSRender::set_vertex_buffer()
|
||||
{
|
||||
std::chrono::time_point<steady_clock> then = steady_clock::now();
|
||||
|
||||
@@ -196,7 +196,7 @@ gl::vertex_upload_info GLGSRender::set_vertex_buffer()
|
||||
auto required = calculate_memory_requirements(m_vertex_layout, vertex_count);
|
||||
|
||||
std::pair<void*, u32> persistent_mapping = {}, volatile_mapping = {};
|
||||
gl::vertex_upload_info upload_info = { result.vertex_draw_count, result.allocated_vertex_count, result.vertex_index_base, 0u, 0u, result.index_info };
|
||||
vertex_upload_info upload_info = { result.vertex_draw_count, result.allocated_vertex_count, result.vertex_index_base, 0u, 0u, result.index_info };
|
||||
|
||||
if (required.first > 0)
|
||||
{
|
||||
@@ -233,32 +233,12 @@ gl::vertex_upload_info GLGSRender::set_vertex_buffer()
|
||||
m_vertex_cache->store_range(storage_address, GL_R8UI, required.first, persistent_mapping.second);
|
||||
}
|
||||
}
|
||||
|
||||
if (!m_persistent_stream_view.in_range(upload_info.persistent_mapping_offset, required.first, upload_info.persistent_mapping_offset))
|
||||
{
|
||||
const size_t view_size = ((upload_info.persistent_mapping_offset + m_max_texbuffer_size) > m_attrib_ring_buffer->size()) ?
|
||||
(m_attrib_ring_buffer->size() - upload_info.persistent_mapping_offset) : m_max_texbuffer_size;
|
||||
|
||||
m_persistent_stream_view.update(m_attrib_ring_buffer.get(), upload_info.persistent_mapping_offset, (u32)view_size);
|
||||
m_gl_persistent_stream_buffer.copy_from(m_persistent_stream_view);
|
||||
upload_info.persistent_mapping_offset = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (required.second > 0)
|
||||
{
|
||||
volatile_mapping = m_attrib_ring_buffer->alloc_from_heap(required.second, m_min_texbuffer_alignment);
|
||||
upload_info.volatile_mapping_offset = volatile_mapping.second;
|
||||
|
||||
if (!m_volatile_stream_view.in_range(upload_info.volatile_mapping_offset, required.second, upload_info.volatile_mapping_offset))
|
||||
{
|
||||
const size_t view_size = ((upload_info.volatile_mapping_offset + m_max_texbuffer_size) > m_attrib_ring_buffer->size()) ?
|
||||
(m_attrib_ring_buffer->size() - upload_info.volatile_mapping_offset) : m_max_texbuffer_size;
|
||||
|
||||
m_volatile_stream_view.update(m_attrib_ring_buffer.get(), upload_info.volatile_mapping_offset, (u32)view_size);
|
||||
m_gl_volatile_stream_buffer.copy_from(m_volatile_stream_view);
|
||||
upload_info.volatile_mapping_offset = 0;
|
||||
}
|
||||
}
|
||||
|
||||
//Write all the data
|
||||
|
||||
@@ -1257,7 +1257,6 @@ namespace rsx
|
||||
if (state.current_draw_clause.command == rsx::draw_command::inlined_array)
|
||||
{
|
||||
vertex_input_layout result = {};
|
||||
result.interleaved_blocks.reserve(8);
|
||||
|
||||
interleaved_range_info info = {};
|
||||
info.interleaved = true;
|
||||
@@ -1282,8 +1281,6 @@ namespace rsx
|
||||
|
||||
const u32 frequency_divider_mask = rsx::method_registers.frequency_divider_operation_mask();
|
||||
vertex_input_layout result = {};
|
||||
result.interleaved_blocks.reserve(8);
|
||||
result.referenced_registers.reserve(4);
|
||||
|
||||
for (u8 index = 0; index < rsx::limits::vertex_count; ++index)
|
||||
{
|
||||
|
||||
@@ -96,10 +96,7 @@ void VKFragmentDecompilerThread::insertOutputs(std::stringstream & OS)
|
||||
for (int i = 0; i < sizeof(table) / sizeof(*table); ++i)
|
||||
{
|
||||
if (m_parr.HasParam(PF_PARAM_NONE, "vec4", table[i].second))
|
||||
{
|
||||
OS << "layout(location=" << std::to_string(output_index++) << ") " << "out vec4 " << table[i].first << ";\n";
|
||||
vk_prog->output_color_masks[i] = UINT32_MAX;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -52,8 +52,6 @@ public:
|
||||
std::string shader;
|
||||
std::vector<size_t> FragmentConstantOffsetCache;
|
||||
|
||||
std::array<u32, 4> output_color_masks{ {} };
|
||||
|
||||
std::vector<vk::glsl::program_input> uniforms;
|
||||
void SetInputs(std::vector<vk::glsl::program_input>& uniforms);
|
||||
/**
|
||||
|
||||
@@ -666,9 +666,6 @@ VKGSRender::~VKGSRender()
|
||||
vk::finalize_compiler_context();
|
||||
m_prog_buffer->clear();
|
||||
|
||||
m_persistent_attribute_storage.reset();
|
||||
m_volatile_attribute_storage.reset();
|
||||
|
||||
//Global resources
|
||||
vk::destroy_global_resources();
|
||||
|
||||
@@ -1129,8 +1126,22 @@ void VKGSRender::end()
|
||||
|
||||
if (replace)
|
||||
{
|
||||
fs_sampler_handles[i] = std::make_unique<vk::sampler>(*m_device, wrap_s, wrap_t, wrap_r, false, lod_bias, af_level, min_lod, max_lod,
|
||||
min_filter, mag_filter, mip_mode, border_color, compare_enabled, depth_compare_mode);
|
||||
for (auto &sampler : m_current_frame->samplers_to_clean)
|
||||
{
|
||||
if (sampler->matches(wrap_s, wrap_t, wrap_r, false, lod_bias, af_level, min_lod, max_lod,
|
||||
min_filter, mag_filter, mip_mode, border_color, compare_enabled, depth_compare_mode))
|
||||
{
|
||||
fs_sampler_handles[i] = std::move(sampler);
|
||||
replace = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (replace)
|
||||
{
|
||||
fs_sampler_handles[i] = std::make_unique<vk::sampler>(*m_device, wrap_s, wrap_t, wrap_r, false, lod_bias, af_level, min_lod, max_lod,
|
||||
min_filter, mag_filter, mip_mode, border_color, compare_enabled, depth_compare_mode);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
@@ -1174,6 +1185,7 @@ void VKGSRender::end()
|
||||
|
||||
if (replace)
|
||||
{
|
||||
//This is unlikely, there is no need to check the dirty pool
|
||||
vs_sampler_handles[i] = std::make_unique<vk::sampler>(
|
||||
*m_device,
|
||||
VK_SAMPLER_ADDRESS_MODE_REPEAT, VK_SAMPLER_ADDRESS_MODE_REPEAT, VK_SAMPLER_ADDRESS_MODE_REPEAT,
|
||||
@@ -1197,12 +1209,10 @@ void VKGSRender::end()
|
||||
|
||||
//Load program
|
||||
std::chrono::time_point<steady_clock> program_start = textures_end;
|
||||
load_program(upload_info);
|
||||
load_program(std::get<2>(upload_info), std::get<3>(upload_info));
|
||||
|
||||
VkBufferView persistent_buffer = m_persistent_attribute_storage ? m_persistent_attribute_storage->value : null_buffer_view->value;
|
||||
VkBufferView volatile_buffer = m_volatile_attribute_storage ? m_volatile_attribute_storage->value : null_buffer_view->value;
|
||||
m_program->bind_uniform(persistent_buffer, "persistent_input_stream", m_current_frame->descriptor_set);
|
||||
m_program->bind_uniform(volatile_buffer, "volatile_input_stream", m_current_frame->descriptor_set);
|
||||
m_program->bind_uniform(m_persistent_attribute_storage, "persistent_input_stream", m_current_frame->descriptor_set);
|
||||
m_program->bind_uniform(m_volatile_attribute_storage, "volatile_input_stream", m_current_frame->descriptor_set);
|
||||
|
||||
std::chrono::time_point<steady_clock> program_stop = steady_clock::now();
|
||||
m_setup_time += std::chrono::duration_cast<std::chrono::microseconds>(program_stop - program_start).count();
|
||||
@@ -1435,6 +1445,8 @@ void VKGSRender::end()
|
||||
vkCmdClearAttachments(*m_current_command_buffer, static_cast<u32>(buffers_to_clear.size()), buffers_to_clear.data(), 1, &clear_rect);
|
||||
}
|
||||
|
||||
std::optional<std::tuple<VkDeviceSize, VkIndexType> > index_info = std::get<4>(upload_info);
|
||||
|
||||
bool primitive_emulated = false;
|
||||
vk::get_appropriate_topology(rsx::method_registers.current_draw_clause.primitive, primitive_emulated);
|
||||
|
||||
@@ -1449,11 +1461,12 @@ void VKGSRender::end()
|
||||
m_occlusion_map[m_active_query_info->driver_handle].command_buffer_to_wait = m_current_command_buffer;
|
||||
}
|
||||
|
||||
if (!upload_info.index_info)
|
||||
if (!index_info)
|
||||
{
|
||||
if (single_draw)
|
||||
{
|
||||
vkCmdDraw(*m_current_command_buffer, upload_info.vertex_draw_count, 1, 0, 0);
|
||||
const auto vertex_count = std::get<1>(upload_info);
|
||||
vkCmdDraw(*m_current_command_buffer, vertex_count, 1, 0, 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -1467,10 +1480,10 @@ void VKGSRender::end()
|
||||
else
|
||||
{
|
||||
VkIndexType index_type;
|
||||
const u32 index_count = upload_info.vertex_draw_count;
|
||||
u32 index_count = std::get<1>(upload_info);
|
||||
VkDeviceSize offset;
|
||||
|
||||
std::tie(offset, index_type) = upload_info.index_info.value();
|
||||
std::tie(offset, index_type) = index_info.value();
|
||||
vkCmdBindIndexBuffer(*m_current_command_buffer, m_index_buffer_ring_info.heap->value, offset, index_type);
|
||||
|
||||
if (single_draw)
|
||||
@@ -2147,7 +2160,7 @@ bool VKGSRender::check_program_status()
|
||||
return (rsx::method_registers.shader_program_address() != 0);
|
||||
}
|
||||
|
||||
void VKGSRender::load_program(const vk::vertex_upload_info& vertex_info)
|
||||
void VKGSRender::load_program(u32 vertex_count, u32 vertex_base)
|
||||
{
|
||||
get_current_fragment_program(fs_sampler_state);
|
||||
verify(HERE), current_fragment_program.valid;
|
||||
@@ -2330,13 +2343,11 @@ void VKGSRender::load_program(const vk::vertex_upload_info& vertex_info)
|
||||
fill_scale_offset_data(buf, false);
|
||||
fill_user_clip_data(buf + 64);
|
||||
*(reinterpret_cast<u32*>(buf + 128)) = rsx::method_registers.transform_branch_bits();
|
||||
*(reinterpret_cast<u32*>(buf + 132)) = vertex_info.vertex_index_base;
|
||||
*(reinterpret_cast<u32*>(buf + 132)) = vertex_base;
|
||||
*(reinterpret_cast<f32*>(buf + 136)) = rsx::method_registers.point_size();
|
||||
*(reinterpret_cast<f32*>(buf + 140)) = rsx::method_registers.clip_min();
|
||||
*(reinterpret_cast<f32*>(buf + 144)) = rsx::method_registers.clip_max();
|
||||
|
||||
fill_vertex_layout_state(m_vertex_layout, vertex_info.allocated_vertex_count, reinterpret_cast<s32*>(buf + 160),
|
||||
vertex_info.persistent_window_offset, vertex_info.volatile_window_offset);
|
||||
fill_vertex_layout_state(m_vertex_layout, vertex_count, reinterpret_cast<s32*>(buf + 160));
|
||||
|
||||
//Vertex constants
|
||||
buf = buf + 512;
|
||||
@@ -2346,10 +2357,7 @@ void VKGSRender::load_program(const vk::vertex_upload_info& vertex_info)
|
||||
//Fragment constants
|
||||
buf = buf + 8192;
|
||||
if (fragment_constants_sz)
|
||||
{
|
||||
m_prog_buffer->fill_fragment_constants_buffer({ reinterpret_cast<float*>(buf), ::narrow<int>(fragment_constants_sz) },
|
||||
fragment_program, vk::sanitize_fp_values());
|
||||
}
|
||||
m_prog_buffer->fill_fragment_constants_buffer({ reinterpret_cast<float*>(buf), ::narrow<int>(fragment_constants_sz) }, fragment_program);
|
||||
|
||||
fill_fragment_state_buffer(buf + fragment_constants_sz, fragment_program);
|
||||
|
||||
|
||||
@@ -23,24 +23,13 @@ namespace vk
|
||||
using null_vertex_cache = vertex_cache;
|
||||
|
||||
using shader_cache = rsx::shaders_cache<vk::pipeline_props, VKProgramBuffer>;
|
||||
|
||||
struct vertex_upload_info
|
||||
{
|
||||
VkPrimitiveTopology primitive;
|
||||
u32 vertex_draw_count;
|
||||
u32 allocated_vertex_count;
|
||||
u32 vertex_index_base;
|
||||
u32 persistent_window_offset;
|
||||
u32 volatile_window_offset;
|
||||
std::optional<std::tuple<VkDeviceSize, VkIndexType>> index_info;
|
||||
};
|
||||
}
|
||||
|
||||
//Heap allocation sizes in MB
|
||||
//NOTE: Texture uploads can be huge, upto 16MB for a single texture (4096x4096px)
|
||||
#define VK_ATTRIB_RING_BUFFER_SIZE_M 256
|
||||
#define VK_TEXTURE_UPLOAD_RING_BUFFER_SIZE_M 256
|
||||
#define VK_UBO_RING_BUFFER_SIZE_M 128
|
||||
#define VK_UBO_RING_BUFFER_SIZE_M 64
|
||||
#define VK_INDEX_RING_BUFFER_SIZE_M 64
|
||||
|
||||
#define VK_MAX_ASYNC_CB_COUNT 64
|
||||
@@ -273,8 +262,8 @@ private:
|
||||
std::array<std::unique_ptr<vk::sampler>, rsx::limits::fragment_textures_count> fs_sampler_handles;
|
||||
std::array<std::unique_ptr<vk::sampler>, rsx::limits::vertex_textures_count> vs_sampler_handles;
|
||||
|
||||
std::unique_ptr<vk::buffer_view> m_persistent_attribute_storage;
|
||||
std::unique_ptr<vk::buffer_view> m_volatile_attribute_storage;
|
||||
VkBufferView m_persistent_attribute_storage;
|
||||
VkBufferView m_volatile_attribute_storage;
|
||||
|
||||
public:
|
||||
//vk::fbo draw_fbo;
|
||||
@@ -390,11 +379,11 @@ private:
|
||||
|
||||
void check_heap_status();
|
||||
|
||||
vk::vertex_upload_info upload_vertex_data();
|
||||
|
||||
/// returns primitive topology, index_count, allocated_verts, vertex_base_index, (offset in index buffer, index type)
|
||||
std::tuple<VkPrimitiveTopology, u32, u32, u32, std::optional<std::tuple<VkDeviceSize, VkIndexType> > > upload_vertex_data();
|
||||
public:
|
||||
bool check_program_status();
|
||||
void load_program(const vk::vertex_upload_info& vertex_info);
|
||||
void load_program(u32 vertex_count, u32 vertex_base);
|
||||
void init_buffers(rsx::framebuffer_creation_context context, bool skip_reading = false);
|
||||
void read_buffers();
|
||||
void write_buffers();
|
||||
|
||||
@@ -14,11 +14,8 @@ namespace vk
|
||||
VkSampler g_null_sampler = nullptr;
|
||||
|
||||
atomic_t<bool> g_cb_no_interrupt_flag { false };
|
||||
|
||||
//Driver compatibility workarounds
|
||||
bool g_drv_no_primitive_restart_flag = false;
|
||||
bool g_drv_force_32bit_indices = false;
|
||||
bool g_drv_sanitize_fp_values = false;
|
||||
atomic_t<bool> g_drv_no_primitive_restart_flag { false };
|
||||
atomic_t<bool> g_drv_force_32bit_indices{ false };
|
||||
|
||||
u64 g_num_processed_frames = 0;
|
||||
u64 g_num_total_frames = 0;
|
||||
@@ -315,12 +312,6 @@ namespace vk
|
||||
g_drv_force_32bit_indices = true;
|
||||
}
|
||||
#endif
|
||||
|
||||
//Nvidia cards are easily susceptible to NaN poisoning
|
||||
if (gpu_name.find("NVIDIA") != std::string::npos || gpu_name.find("GeForce") != std::string::npos)
|
||||
{
|
||||
g_drv_sanitize_fp_values = true;
|
||||
}
|
||||
}
|
||||
|
||||
bool emulate_primitive_restart()
|
||||
@@ -333,11 +324,6 @@ namespace vk
|
||||
return g_drv_force_32bit_indices;
|
||||
}
|
||||
|
||||
bool sanitize_fp_values()
|
||||
{
|
||||
return g_drv_sanitize_fp_values;
|
||||
}
|
||||
|
||||
void change_image_layout(VkCommandBuffer cmd, VkImage image, VkImageLayout current_layout, VkImageLayout new_layout, VkImageSubresourceRange range)
|
||||
{
|
||||
//Prepare an image to match the new layout..
|
||||
|
||||
@@ -72,7 +72,6 @@ namespace vk
|
||||
//Compatibility workarounds
|
||||
bool emulate_primitive_restart();
|
||||
bool force_32bit_index_buffer();
|
||||
bool sanitize_fp_values();
|
||||
|
||||
VkComponentMapping default_component_map();
|
||||
VkImageSubresource default_image_subresource();
|
||||
@@ -617,25 +616,6 @@ namespace vk
|
||||
buffer_view(const buffer_view&) = delete;
|
||||
buffer_view(buffer_view&&) = delete;
|
||||
|
||||
bool in_range(u32 address, u32 size, u32& offset) const
|
||||
{
|
||||
if (address < info.offset)
|
||||
return false;
|
||||
|
||||
const u32 _offset = address - (u32)info.offset;
|
||||
if (info.range < _offset)
|
||||
return false;
|
||||
|
||||
const auto remaining = info.range - _offset;
|
||||
if (size <= remaining)
|
||||
{
|
||||
offset = _offset;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private:
|
||||
VkDevice m_device;
|
||||
};
|
||||
|
||||
@@ -95,16 +95,6 @@ struct VKTraits
|
||||
vertexProgramData.Compile();
|
||||
}
|
||||
|
||||
static
|
||||
void validate_pipeline_properties(const VKVertexProgram&, const VKFragmentProgram &fp, vk::pipeline_props& properties)
|
||||
{
|
||||
//Explicitly disable writing to undefined registers
|
||||
properties.att_state[0].colorWriteMask &= fp.output_color_masks[0];
|
||||
properties.att_state[1].colorWriteMask &= fp.output_color_masks[1];
|
||||
properties.att_state[2].colorWriteMask &= fp.output_color_masks[2];
|
||||
properties.att_state[3].colorWriteMask &= fp.output_color_masks[3];
|
||||
}
|
||||
|
||||
static
|
||||
pipeline_storage_type build_pipeline(const vertex_program_type &vertexProgramData, const fragment_program_type &fragmentProgramData,
|
||||
const vk::pipeline_props &pipelineProperties, VkDevice dev, VkPipelineLayout common_pipeline_layout)
|
||||
|
||||
@@ -901,30 +901,6 @@ namespace vk
|
||||
vk::insert_texture_barrier(cmd, tex);
|
||||
}
|
||||
|
||||
bool render_target_format_is_compatible(vk::image* tex, u32 gcm_format) override
|
||||
{
|
||||
auto vk_format = tex->info.format;
|
||||
switch (gcm_format)
|
||||
{
|
||||
default:
|
||||
//TODO
|
||||
LOG_TRACE(RSX, "Format incompatibility detected, reporting failure to force data copy (VK_FORMAT=0x%X, GCM_FORMAT=0x%X)", (u32)vk_format, gcm_format);
|
||||
return false;
|
||||
case CELL_GCM_TEXTURE_W16_Z16_Y16_X16_FLOAT:
|
||||
return (vk_format == VK_FORMAT_R16G16B16A16_SFLOAT);
|
||||
case CELL_GCM_TEXTURE_W32_Z32_Y32_X32_FLOAT:
|
||||
return (vk_format == VK_FORMAT_R32G32B32A32_SFLOAT);
|
||||
case CELL_GCM_TEXTURE_X32_FLOAT:
|
||||
return (vk_format == VK_FORMAT_R32_SFLOAT);
|
||||
case CELL_GCM_TEXTURE_R5G6B5:
|
||||
return (vk_format == VK_FORMAT_R5G6B5_UNORM_PACK16);
|
||||
case CELL_GCM_TEXTURE_DEPTH24_D8:
|
||||
return (vk_format == VK_FORMAT_D24_UNORM_S8_UINT || vk_format == VK_FORMAT_D32_SFLOAT_S8_UINT);
|
||||
case CELL_GCM_TEXTURE_A8R8G8B8:
|
||||
return (vk_format == VK_FORMAT_B8G8R8A8_UNORM || vk_format == VK_FORMAT_D24_UNORM_S8_UINT || vk_format == VK_FORMAT_D32_SFLOAT_S8_UINT);
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
struct vk_blit_op_result : public blit_op_result
|
||||
|
||||
@@ -253,7 +253,8 @@ namespace
|
||||
};
|
||||
}
|
||||
|
||||
vk::vertex_upload_info VKGSRender::upload_vertex_data()
|
||||
std::tuple<VkPrimitiveTopology, u32, u32, u32, std::optional<std::tuple<VkDeviceSize, VkIndexType> > >
|
||||
VKGSRender::upload_vertex_data()
|
||||
{
|
||||
m_vertex_layout = analyse_inputs_interleaved();
|
||||
|
||||
@@ -265,9 +266,11 @@ vk::vertex_upload_info VKGSRender::upload_vertex_data()
|
||||
|
||||
//Do actual vertex upload
|
||||
auto required = calculate_memory_requirements(m_vertex_layout, vertex_count);
|
||||
u32 persistent_range_base = UINT32_MAX, volatile_range_base = UINT32_MAX;
|
||||
size_t persistent_offset = UINT64_MAX, volatile_offset = UINT64_MAX;
|
||||
|
||||
m_persistent_attribute_storage = VK_NULL_HANDLE;
|
||||
m_volatile_attribute_storage = VK_NULL_HANDLE;
|
||||
|
||||
if (required.first > 0)
|
||||
{
|
||||
//Check if cacheable
|
||||
@@ -284,7 +287,8 @@ vk::vertex_upload_info VKGSRender::upload_vertex_data()
|
||||
if (auto cached = m_vertex_cache->find_vertex_range(storage_address, VK_FORMAT_R8_UINT, required.first))
|
||||
{
|
||||
in_cache = true;
|
||||
persistent_range_base = cached->offset_in_heap;
|
||||
m_current_frame->buffer_views_to_clean.push_back(std::make_unique<vk::buffer_view>(*m_device,
|
||||
m_attrib_ring_info.heap->value, VK_FORMAT_R8_UINT, cached->offset_in_heap, required.first));
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -295,7 +299,8 @@ vk::vertex_upload_info VKGSRender::upload_vertex_data()
|
||||
if (!in_cache)
|
||||
{
|
||||
persistent_offset = (u32)m_attrib_ring_info.alloc<256>(required.first);
|
||||
persistent_range_base = (u32)persistent_offset;
|
||||
m_current_frame->buffer_views_to_clean.push_back(std::make_unique<vk::buffer_view>(*m_device,
|
||||
m_attrib_ring_info.heap->value, VK_FORMAT_R8_UINT, persistent_offset, required.first));
|
||||
|
||||
if (to_store)
|
||||
{
|
||||
@@ -303,12 +308,25 @@ vk::vertex_upload_info VKGSRender::upload_vertex_data()
|
||||
m_vertex_cache->store_range(storage_address, VK_FORMAT_R8_UINT, required.first, (u32)persistent_offset);
|
||||
}
|
||||
}
|
||||
|
||||
m_persistent_attribute_storage = m_current_frame->buffer_views_to_clean.back()->value;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_persistent_attribute_storage = null_buffer_view->value;
|
||||
}
|
||||
|
||||
if (required.second > 0)
|
||||
{
|
||||
volatile_offset = (u32)m_attrib_ring_info.alloc<256>(required.second);
|
||||
volatile_range_base = (u32)volatile_offset;
|
||||
m_current_frame->buffer_views_to_clean.push_back(std::make_unique<vk::buffer_view>(*m_device,
|
||||
m_attrib_ring_info.heap->value, VK_FORMAT_R8_UINT, volatile_offset, required.second));
|
||||
|
||||
m_volatile_attribute_storage = m_current_frame->buffer_views_to_clean.back()->value;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_volatile_attribute_storage = null_buffer_view->value;
|
||||
}
|
||||
|
||||
//Write all the data once if possible
|
||||
@@ -340,32 +358,5 @@ vk::vertex_upload_info VKGSRender::upload_vertex_data()
|
||||
}
|
||||
}
|
||||
|
||||
if (persistent_range_base != UINT32_MAX)
|
||||
{
|
||||
if (!m_persistent_attribute_storage || !m_persistent_attribute_storage->in_range(persistent_range_base, required.first, persistent_range_base))
|
||||
{
|
||||
if (m_persistent_attribute_storage)
|
||||
m_current_frame->buffer_views_to_clean.push_back(std::move(m_persistent_attribute_storage));
|
||||
|
||||
//View 64M blocks at a time (different drivers will only allow a fixed viewable heap size, 64M should be safe)
|
||||
const size_t view_size = (persistent_range_base + 0x4000000) > m_attrib_ring_info.size() ? m_attrib_ring_info.size() - persistent_range_base : 0x4000000;
|
||||
m_persistent_attribute_storage = std::make_unique<vk::buffer_view>(*m_device, m_attrib_ring_info.heap->value, VK_FORMAT_R8_UINT, persistent_range_base, view_size);
|
||||
persistent_range_base = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (volatile_range_base != UINT32_MAX)
|
||||
{
|
||||
if (!m_volatile_attribute_storage || !m_volatile_attribute_storage->in_range(volatile_range_base, required.second, volatile_range_base))
|
||||
{
|
||||
if (m_volatile_attribute_storage)
|
||||
m_current_frame->buffer_views_to_clean.push_back(std::move(m_volatile_attribute_storage));
|
||||
|
||||
const size_t view_size = (volatile_range_base + 0x4000000) > m_attrib_ring_info.size() ? m_attrib_ring_info.size() - volatile_range_base : 0x4000000;
|
||||
m_volatile_attribute_storage = std::make_unique<vk::buffer_view>(*m_device, m_attrib_ring_info.heap->value, VK_FORMAT_R8_UINT, volatile_range_base, view_size);
|
||||
volatile_range_base = 0;
|
||||
}
|
||||
}
|
||||
|
||||
return{ result.native_primitive_type, result.vertex_draw_count, result.allocated_vertex_count, result.vertex_index_base, persistent_range_base, volatile_range_base, result.index_info };
|
||||
return std::make_tuple(result.native_primitive_type, result.vertex_draw_count, result.allocated_vertex_count, result.vertex_index_base, result.index_info);
|
||||
}
|
||||
|
||||
@@ -21,10 +21,10 @@ void fmt_class_string<frame_limit_type>::format(std::string& out, u64 arg)
|
||||
switch (value)
|
||||
{
|
||||
case frame_limit_type::none: return "Off";
|
||||
case frame_limit_type::_30: return "30";
|
||||
case frame_limit_type::_50: return "50";
|
||||
case frame_limit_type::_59_94: return "59.94";
|
||||
case frame_limit_type::_50: return "50";
|
||||
case frame_limit_type::_60: return "60";
|
||||
case frame_limit_type::_30: return "30";
|
||||
case frame_limit_type::_auto: return "Auto";
|
||||
}
|
||||
|
||||
@@ -35,7 +35,7 @@ void fmt_class_string<frame_limit_type>::format(std::string& out, u64 arg)
|
||||
namespace rsx
|
||||
{
|
||||
rsx_state method_registers;
|
||||
|
||||
|
||||
std::array<rsx_method_t, 0x10000 / 4> methods{};
|
||||
|
||||
void invalid_method(thread* rsx, u32 _reg, u32 arg)
|
||||
@@ -64,10 +64,10 @@ namespace rsx
|
||||
{
|
||||
rsx->sync_point_request = true;
|
||||
const u32 addr = get_address(method_registers.semaphore_offset_406e(), method_registers.semaphore_context_dma_406e());
|
||||
if (vm::ps3::read32(addr) == arg) return;
|
||||
if (vm::read32(addr) == arg) return;
|
||||
|
||||
u64 start = get_system_time();
|
||||
while (vm::ps3::read32(addr) != arg)
|
||||
while (vm::read32(addr) != arg)
|
||||
{
|
||||
// todo: LLE: why does this one keep hanging? is it vsh system semaphore? whats actually pushing this to the command buffer?!
|
||||
if (addr == 0x40000030)
|
||||
@@ -116,11 +116,12 @@ namespace rsx
|
||||
if (addr >> 28 == 0x4)
|
||||
{
|
||||
// TODO: check no reservation area instead
|
||||
vm::ps3::write32(addr, arg);
|
||||
vm::write32(addr, arg);
|
||||
return;
|
||||
}
|
||||
|
||||
vm::ps3::write32(addr, arg);
|
||||
vm::reader_lock lock;
|
||||
vm::write32(addr, arg);
|
||||
vm::notify(addr, 4);
|
||||
}
|
||||
}
|
||||
@@ -161,7 +162,7 @@ namespace rsx
|
||||
{
|
||||
//
|
||||
}
|
||||
auto& sema = vm::ps3::_ref<RsxReports>(rsx->label_addr);
|
||||
auto& sema = vm::_ref<RsxReports>(rsx->label_addr);
|
||||
sema.semaphore[index].val = arg;
|
||||
sema.semaphore[index].pad = 0;
|
||||
sema.semaphore[index].timestamp = rsx->timestamp();
|
||||
@@ -176,7 +177,7 @@ namespace rsx
|
||||
}
|
||||
u32 val = (arg & 0xff00ff00) | ((arg & 0xff) << 16) | ((arg >> 16) & 0xff);
|
||||
|
||||
auto& sema = vm::ps3::_ref<RsxReports>(rsx->label_addr);
|
||||
auto& sema = vm::_ref<RsxReports>(rsx->label_addr);
|
||||
sema.semaphore[index].val = val;
|
||||
sema.semaphore[index].pad = 0;
|
||||
sema.semaphore[index].timestamp = rsx->timestamp();
|
||||
@@ -351,7 +352,7 @@ namespace rsx
|
||||
{
|
||||
rsx::method_registers.current_draw_clause.first_count_commands.resize(0);
|
||||
rsx::method_registers.current_draw_clause.command = draw_command::none;
|
||||
rsx::method_registers.current_draw_clause.primitive = rsx::method_registers.primitive_mode();
|
||||
rsx::method_registers.current_draw_clause.primitive = to_primitive_type(arg);
|
||||
rsxthr->begin();
|
||||
return;
|
||||
}
|
||||
@@ -415,7 +416,7 @@ namespace rsx
|
||||
return;
|
||||
}
|
||||
|
||||
vm::ps3::ptr<CellGcmReportData> result = address_ptr;
|
||||
vm::ptr<CellGcmReportData> result = address_ptr;
|
||||
|
||||
switch (type)
|
||||
{
|
||||
@@ -483,7 +484,7 @@ namespace rsx
|
||||
return;
|
||||
}
|
||||
|
||||
vm::ps3::ptr<CellGcmReportData> result = address_ptr;
|
||||
vm::ptr<CellGcmReportData> result = address_ptr;
|
||||
rsx->conditional_render_test_failed = (result->value == 0);
|
||||
}
|
||||
|
||||
@@ -552,7 +553,7 @@ namespace rsx
|
||||
|
||||
const u32 pixel_offset = (method_registers.blit_engine_output_pitch_nv3062() * y) + (x << 2);
|
||||
u32 address = get_address(method_registers.blit_engine_output_offset_nv3062() + pixel_offset + index * 4, method_registers.blit_engine_output_location_nv3062());
|
||||
vm::ps3::write32(address, arg);
|
||||
vm::write32(address, arg);
|
||||
}
|
||||
};
|
||||
}
|
||||
@@ -661,7 +662,7 @@ namespace rsx
|
||||
const tiled_region dst_region = rsx->get_tiled_address(dst_offset + out_offset, dst_dma & 0xf);
|
||||
|
||||
u8* pixels_src = src_region.tile ? src_region.ptr + src_region.base : src_region.ptr;
|
||||
u8* pixels_dst = vm::ps3::_ptr<u8>(get_address(dst_offset + out_offset, dst_dma));
|
||||
u8* pixels_dst = vm::_ptr<u8>(get_address(dst_offset + out_offset, dst_dma));
|
||||
|
||||
if (out_pitch == 0)
|
||||
{
|
||||
@@ -693,7 +694,8 @@ namespace rsx
|
||||
|
||||
if (convert_w == 0 || convert_h == 0)
|
||||
{
|
||||
LOG_ERROR(RSX, "NV3089_IMAGE_IN: Invalid dimensions or scaling factor. Request ignored");
|
||||
LOG_ERROR(RSX, "NV3089_IMAGE_IN: Invalid dimensions or scaling factor. Request ignored (ds_dx=%d, dt_dy=%d)",
|
||||
method_registers.blit_engine_ds_dx(), method_registers.blit_engine_dt_dy());
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -788,7 +790,7 @@ namespace rsx
|
||||
if (method_registers.blit_engine_context_surface() != blit_engine::context_surface::swizzle2d)
|
||||
{
|
||||
if (need_convert || need_clip)
|
||||
{
|
||||
{
|
||||
if (need_clip)
|
||||
{
|
||||
if (need_convert)
|
||||
@@ -854,7 +856,7 @@ namespace rsx
|
||||
pixels_src = temp2.get();
|
||||
}
|
||||
|
||||
// It looks like rsx may ignore the requested swizzle size and just always
|
||||
// It looks like rsx may ignore the requested swizzle size and just always
|
||||
// round up to nearest power of 2
|
||||
/*u8 sw_width_log2 = method_registers.nv309e_sw_width_log2();
|
||||
u8 sw_height_log2 = method_registers.nv309e_sw_height_log2();
|
||||
@@ -932,7 +934,7 @@ namespace rsx
|
||||
LOG_ERROR(RSX, "NV0039_OFFSET_IN: Unsupported format: inFormat=%d, outFormat=%d", in_format, out_format);
|
||||
}
|
||||
|
||||
LOG_NOTICE(RSX, "NV0039_OFFSET_IN: pitch(in=0x%x, out=0x%x), line(len=0x%x, cnt=0x%x), fmt(in=0x%x, out=0x%x), notify=0x%x",
|
||||
LOG_TRACE(RSX, "NV0039_OFFSET_IN: pitch(in=0x%x, out=0x%x), line(len=0x%x, cnt=0x%x), fmt(in=0x%x, out=0x%x), notify=0x%x",
|
||||
in_pitch, out_pitch, line_length, line_count, in_format, out_format, notify);
|
||||
|
||||
if (!in_pitch)
|
||||
@@ -995,10 +997,10 @@ namespace rsx
|
||||
switch (g_cfg.video.frame_limit)
|
||||
{
|
||||
case frame_limit_type::none: limit = 0.; break;
|
||||
case frame_limit_type::_30: limit = 30.; break;
|
||||
case frame_limit_type::_50: limit = 50.; break;
|
||||
case frame_limit_type::_59_94: limit = 59.94; break;
|
||||
case frame_limit_type::_50: limit = 50.; break;
|
||||
case frame_limit_type::_60: limit = 60.; break;
|
||||
case frame_limit_type::_30: limit = 30.; break;
|
||||
case frame_limit_type::_auto: limit = rsx->fps_limit; break; // TODO
|
||||
}
|
||||
|
||||
@@ -1026,7 +1028,7 @@ namespace rsx
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
rsx->int_flip_index++;
|
||||
rsx->current_display_buffer = arg;
|
||||
rsx->flip(arg);
|
||||
@@ -1188,6 +1190,11 @@ namespace rsx
|
||||
registers[reg] = value;
|
||||
}
|
||||
|
||||
bool rsx_state::test(u32 reg, u32 value) const
|
||||
{
|
||||
return registers[reg] == value;
|
||||
}
|
||||
|
||||
namespace method_detail
|
||||
{
|
||||
template<int Id, int Step, int Count, template<u32> class T, int Index = 0>
|
||||
@@ -1560,7 +1567,7 @@ namespace rsx
|
||||
|
||||
//Some custom GCM methods
|
||||
methods[GCM_SET_DRIVER_OBJECT] = nullptr;
|
||||
|
||||
|
||||
bind_array<GCM_FLIP_HEAD, 1, 2, nullptr>();
|
||||
bind_array<GCM_DRIVER_QUEUE, 1, 8, nullptr>();
|
||||
|
||||
@@ -1677,8 +1684,8 @@ namespace rsx
|
||||
|
||||
// custom methods
|
||||
bind<GCM_FLIP_COMMAND, flip_command>();
|
||||
|
||||
|
||||
return true;
|
||||
|
||||
return true;
|
||||
}();
|
||||
}
|
||||
|
||||
@@ -96,7 +96,7 @@ void fmt_class_string<video_renderer>::format(std::string& out, u64 arg)
|
||||
case video_renderer::opengl: return "OpenGL";
|
||||
case video_renderer::vulkan: return "Vulkan";
|
||||
#ifdef _MSC_VER
|
||||
case video_renderer::dx12: return "DirectX 12";
|
||||
case video_renderer::dx12: return "D3D12";
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
+6
-6
@@ -127,10 +127,10 @@ enum class video_aspect
|
||||
enum class frame_limit_type
|
||||
{
|
||||
none,
|
||||
_30,
|
||||
_50,
|
||||
_59_94,
|
||||
_50,
|
||||
_60,
|
||||
_30,
|
||||
_auto,
|
||||
};
|
||||
|
||||
@@ -291,7 +291,7 @@ struct cfg_root : cfg::node
|
||||
cfg::_int<0, 16> spu_delay_penalty{this, "SPU delay penalty", 3}; //Number of milliseconds to block a thread if a virtual 'core' isn't free
|
||||
cfg::_bool spu_loop_detection{this, "SPU loop detection", true}; //Try to detect wait loops and trigger thread yield
|
||||
|
||||
cfg::_enum<lib_loading_type> lib_loading{this, "Lib loader", lib_loading_type::liblv2only};
|
||||
cfg::_enum<lib_loading_type> lib_loading{this, "Lib Loader", lib_loading_type::liblv2only};
|
||||
cfg::_bool hook_functions{this, "Hook static functions"};
|
||||
cfg::set_entry load_libraries{this, "Load libraries"};
|
||||
|
||||
@@ -350,7 +350,7 @@ struct cfg_root : cfg::node
|
||||
|
||||
struct node_d3d12 : cfg::node
|
||||
{
|
||||
node_d3d12(cfg::node* _this) : cfg::node(_this, "DirectX 12") {}
|
||||
node_d3d12(cfg::node* _this) : cfg::node(_this, "D3D12") {}
|
||||
|
||||
cfg::string adapter{this, "Adapter"};
|
||||
|
||||
@@ -375,7 +375,7 @@ struct cfg_root : cfg::node
|
||||
cfg::_enum<audio_renderer> renderer{this, "Renderer", static_cast<audio_renderer>(1)};
|
||||
|
||||
cfg::_bool dump_to_file{this, "Dump to file"};
|
||||
cfg::_bool convert_to_u16{this, "Convert to 16-bit"};
|
||||
cfg::_bool convert_to_u16{this, "Convert to 16 bit"};
|
||||
cfg::_bool downmix_to_2ch{this, "Downmix to Stereo", true};
|
||||
cfg::_int<2, 128> frames{this, "Buffer Count", 32};
|
||||
cfg::_int<1, 128> startt{this, "Start Threshold", 1};
|
||||
@@ -388,7 +388,7 @@ struct cfg_root : cfg::node
|
||||
|
||||
cfg::_enum<keyboard_handler> keyboard{this, "Keyboard", keyboard_handler::null};
|
||||
cfg::_enum<mouse_handler> mouse{this, "Mouse", mouse_handler::basic};
|
||||
cfg::_enum<pad_handler> pad{this, "Controller", pad_handler::keyboard};
|
||||
cfg::_enum<pad_handler> pad{this, "Pad", pad_handler::keyboard};
|
||||
cfg::_enum<camera_handler> camera{this, "Camera", camera_handler::null};
|
||||
cfg::_enum<fake_camera_type> camera_type{this, "Camera type", fake_camera_type::unknown};
|
||||
|
||||
|
||||
@@ -31,7 +31,7 @@
|
||||
<PropertyGroup Label="Configuration">
|
||||
<ConfigurationType>StaticLibrary</ConfigurationType>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
<PlatformToolset>v141</PlatformToolset>
|
||||
<PlatformToolset>v140</PlatformToolset>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
|
||||
<ImportGroup Label="ExtensionSettings">
|
||||
|
||||
@@ -31,7 +31,7 @@
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
|
||||
<PropertyGroup Label="Configuration">
|
||||
<ConfigurationType>StaticLibrary</ConfigurationType>
|
||||
<PlatformToolset>v141</PlatformToolset>
|
||||
<PlatformToolset>v140</PlatformToolset>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
|
||||
|
||||
@@ -62,7 +62,7 @@
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
|
||||
<PropertyGroup Label="Configuration">
|
||||
<ConfigurationType>StaticLibrary</ConfigurationType>
|
||||
<PlatformToolset>v141</PlatformToolset>
|
||||
<PlatformToolset>v140</PlatformToolset>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
|
||||
|
||||
@@ -31,7 +31,7 @@
|
||||
<PropertyGroup Label="Configuration">
|
||||
<ConfigurationType>StaticLibrary</ConfigurationType>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
<PlatformToolset>v141</PlatformToolset>
|
||||
<PlatformToolset>v140</PlatformToolset>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
|
||||
<ImportGroup Label="ExtensionSettings">
|
||||
|
||||
@@ -30,7 +30,7 @@
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
|
||||
<PropertyGroup Label="Configuration">
|
||||
<ConfigurationType>StaticLibrary</ConfigurationType>
|
||||
<PlatformToolset>v141</PlatformToolset>
|
||||
<PlatformToolset>v140</PlatformToolset>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
|
||||
@@ -61,7 +61,7 @@
|
||||
<ItemDefinitionGroup>
|
||||
<ClCompile>
|
||||
<PrecompiledHeader>Use</PrecompiledHeader>
|
||||
<AdditionalIncludeDirectories>..\3rdparty\zlib;..\llvm\include;..\polly\include;..\llvm_build\include;</AdditionalIncludeDirectories>
|
||||
<AdditionalIncludeDirectories>..\3rdparty\zlib;..\llvm\include;..\llvm_build\include;</AdditionalIncludeDirectories>
|
||||
</ClCompile>
|
||||
<PreBuildEvent>
|
||||
<Command>%windir%\sysnative\cmd.exe /c "$(SolutionDir)\Utilities\git-version-gen.cmd"</Command>
|
||||
|
||||
+4
-4
@@ -26,7 +26,7 @@
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
|
||||
<PlatformToolSet>v141</PlatformToolSet>
|
||||
<PlatformToolSet>v140</PlatformToolSet>
|
||||
<OutputDirectory>release\</OutputDirectory>
|
||||
<ATLMinimizesCRunTimeLibraryUsage>false</ATLMinimizesCRunTimeLibraryUsage>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
@@ -35,7 +35,7 @@
|
||||
<PrimaryOutput>rpcs3</PrimaryOutput>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release - LLVM|x64'" Label="Configuration">
|
||||
<PlatformToolSet>v141</PlatformToolSet>
|
||||
<PlatformToolSet>v140</PlatformToolSet>
|
||||
<OutputDirectory>release\</OutputDirectory>
|
||||
<ATLMinimizesCRunTimeLibraryUsage>false</ATLMinimizesCRunTimeLibraryUsage>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
@@ -44,7 +44,7 @@
|
||||
<PrimaryOutput>rpcs3</PrimaryOutput>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
|
||||
<PlatformToolSet>v141</PlatformToolSet>
|
||||
<PlatformToolSet>v140</PlatformToolSet>
|
||||
<OutputDirectory>debug\</OutputDirectory>
|
||||
<ATLMinimizesCRunTimeLibraryUsage>false</ATLMinimizesCRunTimeLibraryUsage>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
@@ -53,7 +53,7 @@
|
||||
<PrimaryOutput>rpcs3</PrimaryOutput>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug - LLVM|x64'" Label="Configuration">
|
||||
<PlatformToolSet>v141</PlatformToolSet>
|
||||
<PlatformToolSet>v140</PlatformToolSet>
|
||||
<OutputDirectory>debug\</OutputDirectory>
|
||||
<ATLMinimizesCRunTimeLibraryUsage>false</ATLMinimizesCRunTimeLibraryUsage>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
|
||||
@@ -5,7 +5,7 @@ constexpr auto qstr = QString::fromStdString;
|
||||
|
||||
auto_pause_settings_dialog::auto_pause_settings_dialog(QWidget *parent) : QDialog(parent)
|
||||
{
|
||||
QLabel *description = new QLabel(tr("To use automatic pause: enter the ID(s) of a function or a system call. You must restart your emulated game or application for changed settings to take effect. You can enable/disable this in the settings."), this);
|
||||
QLabel *description = new QLabel(tr("To use auto pause: enter the ID(s) of a function or a system call.\nRestart of the game is required to apply. You can enable/disable this in the settings."), this);
|
||||
|
||||
pauseList = new QTableWidget(this);
|
||||
pauseList->setColumnCount(2);
|
||||
@@ -36,7 +36,7 @@ auto_pause_settings_dialog::auto_pause_settings_dialog(QWidget *parent) : QDialo
|
||||
setLayout(mainLayout);
|
||||
|
||||
setMinimumSize(QSize(400, 360));
|
||||
setWindowTitle(tr("Automatic pause settings"));
|
||||
setWindowTitle(tr("Auto Pause Manager"));
|
||||
|
||||
//Events
|
||||
connect(pauseList, &QTableWidget::customContextMenuRequested, this, &auto_pause_settings_dialog::ShowContextMenu);
|
||||
@@ -45,7 +45,7 @@ auto_pause_settings_dialog::auto_pause_settings_dialog(QWidget *parent) : QDialo
|
||||
connect(saveButton, &QAbstractButton::clicked, [=]
|
||||
{
|
||||
SaveEntries();
|
||||
LOG_SUCCESS(HLE, "Automatic pause: file pause.bin was updated.");
|
||||
LOG_SUCCESS(HLE, "Auto Pause: File pause.bin was updated.");
|
||||
});
|
||||
connect(cancelButton, &QAbstractButton::clicked, this, &QWidget::close);
|
||||
|
||||
@@ -124,11 +124,11 @@ void auto_pause_settings_dialog::UpdateList(void)
|
||||
|
||||
if (m_entries[i] < 1024)
|
||||
{
|
||||
typeItem->setData(Qt::DisplayRole, tr("System call"));
|
||||
typeItem->setData(Qt::DisplayRole, tr("System Call"));
|
||||
}
|
||||
else
|
||||
{
|
||||
typeItem->setData(Qt::DisplayRole, tr("Function call"));
|
||||
typeItem->setData(Qt::DisplayRole, tr("Function Call"));
|
||||
}
|
||||
|
||||
pauseList->setItem(i, 0, callItem);
|
||||
@@ -206,7 +206,7 @@ AutoPauseConfigDialog::AutoPauseConfigDialog(QWidget* parent, auto_pause_setting
|
||||
button_ok->setFixedWidth(50);
|
||||
button_cancel->setFixedWidth(50);
|
||||
|
||||
QLabel* description = new QLabel(tr("Specify ID of system call or function call below. You need to use a hexadecimal ID."), this);
|
||||
QLabel* description = new QLabel(tr("Specify ID of System Call or Function Call below. You need to use a Hexadecimal ID."), this);
|
||||
description->setWordWrap(true);
|
||||
|
||||
m_current_converted = new QLabel(tr("Currently it gets an id of \"Unset\"."), this);
|
||||
@@ -218,7 +218,7 @@ AutoPauseConfigDialog::AutoPauseConfigDialog(QWidget* parent, auto_pause_setting
|
||||
m_id->setFont(QFontDatabase::systemFont(QFontDatabase::FixedFont));
|
||||
m_id->setMaxLength(8);
|
||||
m_id->setFixedWidth(65);
|
||||
setWindowTitle("Automatic pause setting: " + m_id->text());
|
||||
setWindowTitle("Auto Pause Setting: " + m_id->text());
|
||||
|
||||
connect(button_cancel, &QAbstractButton::clicked, this, &AutoPauseConfigDialog::OnCancel);
|
||||
connect(button_ok, &QAbstractButton::clicked, this, &AutoPauseConfigDialog::OnOk);
|
||||
|
||||
@@ -22,7 +22,7 @@ inline std::string sstr(const QString& _in) { return _in.toStdString(); }
|
||||
|
||||
cg_disasm_window::cg_disasm_window(std::shared_ptr<gui_settings> xSettings): xgui_settings(xSettings)
|
||||
{
|
||||
setWindowTitle(tr("Cg disassembler"));
|
||||
setWindowTitle(tr("Cg Disasm"));
|
||||
setAttribute(Qt::WA_DeleteOnClose);
|
||||
setAcceptDrops(true);
|
||||
setMinimumSize(QSize(200, 150)); // seems fine on win 10
|
||||
|
||||
@@ -43,8 +43,8 @@ debugger_frame::debugger_frame(std::shared_ptr<gui_settings> settings, QWidget *
|
||||
m_breakpoints_list_delete->setShortcutContext(Qt::WidgetShortcut);
|
||||
m_breakpoints_list->addAction(m_breakpoints_list_delete);
|
||||
|
||||
m_go_to_addr = new QPushButton(tr("Go to address"), this);
|
||||
m_go_to_pc = new QPushButton(tr("Go to PC"), this);
|
||||
m_go_to_addr = new QPushButton(tr("Go To Address"), this);
|
||||
m_go_to_pc = new QPushButton(tr("Go To PC"), this);
|
||||
m_btn_capture = new QPushButton(tr("Capture"), this);
|
||||
m_btn_step = new QPushButton(tr("Step"), this);
|
||||
m_btn_run = new QPushButton(Run, this);
|
||||
|
||||
@@ -126,7 +126,7 @@ public:
|
||||
QStringList vulkanAdapters;
|
||||
QString name_Null = tr("Null");
|
||||
QString name_Vulkan = tr("Vulkan");
|
||||
QString name_D3D12 = tr("DirectX 12");
|
||||
QString name_D3D12 = tr("D3D12[DO NOT USE]");
|
||||
QString name_OpenGL = tr("OpenGL");
|
||||
Render_Info D3D12;
|
||||
Render_Info Vulkan;
|
||||
@@ -186,7 +186,7 @@ private:
|
||||
// Core Tab
|
||||
{ PPUDecoder, { "Core", "PPU Decoder"}},
|
||||
{ SPUDecoder, { "Core", "SPU Decoder"}},
|
||||
{ LibLoadOptions, { "Core", "Lib loader"}},
|
||||
{ LibLoadOptions, { "Core", "Lib Loader"}},
|
||||
{ HookStaticFuncs, { "Core", "Hook static functions"}},
|
||||
{ EnableThreadScheduler, { "Core", "Enable thread scheduler"}},
|
||||
{ LowerSPUThreadPrio, { "Core", "Lower SPU thread priority"}},
|
||||
@@ -221,13 +221,13 @@ private:
|
||||
{ AnisotropicFilterOverride,{ "Video", "Anisotropic Filter Override" }},
|
||||
{ ResolutionScale, { "Video", "Resolution Scale" }},
|
||||
{ MinimumScalableDimension, { "Video", "Minimum Scalable Dimension" }},
|
||||
{ D3D12Adapter, { "Video", "DirectX 12", "Adapter"}},
|
||||
{ D3D12Adapter, { "Video", "D3D12", "Adapter"}},
|
||||
{ VulkanAdapter, { "Video", "Vulkan", "Adapter"}},
|
||||
|
||||
// Audio
|
||||
{ AudioRenderer, { "Audio", "Renderer"}},
|
||||
{ DumpToFile, { "Audio", "Dump to file"}},
|
||||
{ ConvertTo16Bit, { "Audio", "Convert to 16-bit"}},
|
||||
{ ConvertTo16Bit, { "Audio", "Convert to 16 bit"}},
|
||||
{ DownmixStereo, { "Audio", "Downmix to Stereo"}},
|
||||
|
||||
// Input / Output
|
||||
|
||||
@@ -24,7 +24,7 @@ inline std::string sstr(const QString& _in) { return _in.toStdString(); }
|
||||
inline QSize sizeFromSlider(const int& pos) { return gui::gl_icon_size_min + (gui::gl_icon_size_max - gui::gl_icon_size_min) * (pos / (float)gui::gl_max_slider_pos); }
|
||||
|
||||
game_list_frame::game_list_frame(std::shared_ptr<gui_settings> guiSettings, std::shared_ptr<emu_settings> emuSettings, QWidget *parent)
|
||||
: QDockWidget(tr("Game list"), parent), xgui_settings(guiSettings), xemu_settings(emuSettings)
|
||||
: QDockWidget(tr("Game List"), parent), xgui_settings(guiSettings), xemu_settings(emuSettings)
|
||||
{
|
||||
m_isListLayout = xgui_settings->GetValue(gui::gl_listMode).toBool();
|
||||
m_icon_size_index = xgui_settings->GetValue(gui::gl_iconSize).toInt();
|
||||
@@ -87,10 +87,10 @@ game_list_frame::game_list_frame(std::shared_ptr<gui_settings> guiSettings, std:
|
||||
m_categoryActs->setEnabled(m_isListLayout);
|
||||
|
||||
m_modeActList = { new QAction(""), QIcon(":/Icons/list_blue.png"), QIcon(":/Icons/list_gray.png") };
|
||||
m_modeActList.action->setToolTip(tr("Enable list mode"));
|
||||
m_modeActList.action->setToolTip(tr("Enable List Mode"));
|
||||
|
||||
m_modeActGrid = { new QAction(""), QIcon(":/Icons/grid_blue.png"), QIcon(":/Icons/grid_gray.png") };
|
||||
m_modeActGrid.action->setToolTip(tr("Enable grid mode"));
|
||||
m_modeActGrid.action->setToolTip(tr("Enable Grid Mode"));
|
||||
|
||||
m_modeActs = new QActionGroup(m_Tool_Bar);
|
||||
m_modeActs->addAction(m_modeActList.action);
|
||||
@@ -186,17 +186,17 @@ game_list_frame::game_list_frame(std::shared_ptr<gui_settings> guiSettings, std:
|
||||
m_Game_Dock->setCentralWidget(m_Central_Widget);
|
||||
|
||||
// Actions regarding showing/hiding columns
|
||||
QAction* showIconColAct = new QAction(tr("Show icons"), this);
|
||||
QAction* showNameColAct = new QAction(tr("Show names"), this);
|
||||
QAction* showSerialColAct = new QAction(tr("Show serials"), this);
|
||||
QAction* showFWColAct = new QAction(tr("Show firmwares"), this);
|
||||
QAction* showAppVersionColAct = new QAction(tr("Show versions"), this);
|
||||
QAction* showCategoryColAct = new QAction(tr("Show categories"), this);
|
||||
QAction* showPathColAct = new QAction(tr("Show paths"), this);
|
||||
QAction* showResolutionColAct = new QAction(tr("Show supported resolutions"), this);
|
||||
QAction* showSoundFormatColAct = new QAction(tr("Show sound formats"), this);
|
||||
QAction* showParentalLevelColAct = new QAction(tr("Show parental levels"), this);
|
||||
QAction* showCompatibilityAct = new QAction(tr("Show compatibilities"), this);
|
||||
QAction* showIconColAct = new QAction(tr("Show Icons"), this);
|
||||
QAction* showNameColAct = new QAction(tr("Show Names"), this);
|
||||
QAction* showSerialColAct = new QAction(tr("Show Serials"), this);
|
||||
QAction* showFWColAct = new QAction(tr("Show Firmwares"), this);
|
||||
QAction* showAppVersionColAct = new QAction(tr("Show Versions"), this);
|
||||
QAction* showCategoryColAct = new QAction(tr("Show Categories"), this);
|
||||
QAction* showPathColAct = new QAction(tr("Show Paths"), this);
|
||||
QAction* showResolutionColAct = new QAction(tr("Show Supported Resolutions"), this);
|
||||
QAction* showSoundFormatColAct = new QAction(tr("Show Sound Formats"), this);
|
||||
QAction* showParentalLevelColAct = new QAction(tr("Show Parental Levels"), this);
|
||||
QAction* showCompatibilityAct = new QAction(tr("Show Compatibilities"), this);
|
||||
|
||||
m_columnActs = { showIconColAct, showNameColAct, showSerialColAct, showFWColAct, showAppVersionColAct, showCategoryColAct, showPathColAct,
|
||||
showResolutionColAct, showSoundFormatColAct, showParentalLevelColAct, showCompatibilityAct };
|
||||
@@ -670,15 +670,15 @@ void game_list_frame::ShowSpecifiedContextMenu(const QPoint &pos, int row)
|
||||
QAction* configure = myMenu.addAction(tr("&Configure"));
|
||||
myMenu.addSeparator();
|
||||
QAction* removeGame = myMenu.addAction(tr("&Remove"));
|
||||
QAction* removeConfig = myMenu.addAction(tr("&Remove custom configuration"));
|
||||
QAction* deleteShadersCache = myMenu.addAction(tr("&Delete shaders cache"));
|
||||
QAction* deleteLLVMCache = myMenu.addAction(tr("&Delete LLVM cache"));
|
||||
QAction* removeConfig = myMenu.addAction(tr("&Remove Custom Configuration"));
|
||||
QAction* deleteShadersCache = myMenu.addAction(tr("&Delete Shaders Cache"));
|
||||
QAction* deleteLLVMCache = myMenu.addAction(tr("&Delete LLVM Cache"));
|
||||
myMenu.addSeparator();
|
||||
QAction* openGameFolder = myMenu.addAction(tr("&Open install folder"));
|
||||
QAction* openConfig = myMenu.addAction(tr("&Open config folder"));
|
||||
QAction* openGameFolder = myMenu.addAction(tr("&Open Install Folder"));
|
||||
QAction* openConfig = myMenu.addAction(tr("&Open Config Folder"));
|
||||
myMenu.addSeparator();
|
||||
QAction* checkCompat = myMenu.addAction(tr("&Check game compatibility"));
|
||||
QAction* downloadCompat = myMenu.addAction(tr("&Download compatibility database"));
|
||||
QAction* checkCompat = myMenu.addAction(tr("&Check Game Compatibility"));
|
||||
QAction* downloadCompat = myMenu.addAction(tr("&Download Compatibility Database"));
|
||||
|
||||
connect(boot, &QAction::triggered, [=]
|
||||
{
|
||||
@@ -717,7 +717,7 @@ void game_list_frame::ShowSpecifiedContextMenu(const QPoint &pos, int row)
|
||||
|
||||
connect(deleteLLVMCache, &QAction::triggered, [=]()
|
||||
{
|
||||
if (QMessageBox::question(this, tr("Confirm delete"), tr("Delete LLVM cache?")) == QMessageBox::Yes)
|
||||
if (QMessageBox::question(this, tr("Confirm Delete"), tr("Delete LLVM cache?")) == QMessageBox::Yes)
|
||||
{
|
||||
const std::string config_base_dir = fs::get_config_dir() + "data/" + m_game_data[row].info.serial;
|
||||
|
||||
@@ -832,7 +832,7 @@ void game_list_frame::RemoveCustomConfiguration(int row)
|
||||
|
||||
void game_list_frame::DeleteShadersCache(int row)
|
||||
{
|
||||
if (QMessageBox::question(this, tr("Confirm delete"), tr("Delete shaders cache?")) != QMessageBox::Yes)
|
||||
if (QMessageBox::question(this, tr("Confirm Delete"), tr("Delete shaders cache?")) != QMessageBox::Yes)
|
||||
return;
|
||||
|
||||
const std::string config_base_dir = fs::get_config_dir() + "data/" + m_game_data[row].info.serial;
|
||||
|
||||
@@ -69,5 +69,6 @@ void gl_gs_frame::flip(draw_context_t context, bool skip_frame)
|
||||
//Do not swap buffers if frame skip is active
|
||||
if (skip_frame) return;
|
||||
|
||||
((QOpenGLContext*)context)->makeCurrent(this);
|
||||
((QOpenGLContext*)context)->swapBuffers(this);
|
||||
}
|
||||
|
||||
@@ -105,7 +105,7 @@ void gs_frame::keyPressEvent(QKeyEvent *keyEvent)
|
||||
case Qt::Key_R:
|
||||
if (keyEvent->modifiers() == Qt::ControlModifier && (!Emu.GetBoot().empty())) { Emu.Restart(); return; }
|
||||
break;
|
||||
case Qt::Key_F:
|
||||
case Qt::Key_E:
|
||||
if (keyEvent->modifiers() == Qt::ControlModifier)
|
||||
{
|
||||
if (Emu.IsReady()) { Emu.Run(); return; }
|
||||
|
||||
@@ -27,7 +27,7 @@
|
||||
|
||||
kernel_explorer::kernel_explorer(QWidget* parent) : QDialog(parent)
|
||||
{
|
||||
setWindowTitle(tr("Kernel explorer"));
|
||||
setWindowTitle(tr("Kernel Explorer"));
|
||||
setObjectName("kernel_explorer");
|
||||
setAttribute(Qt::WA_DeleteOnClose);
|
||||
setMinimumSize(QSize(700, 450));
|
||||
@@ -74,7 +74,7 @@ void kernel_explorer::Update()
|
||||
const u32 total_memory_usage = vm_block->used();
|
||||
|
||||
QTreeWidgetItem* root = new QTreeWidgetItem();
|
||||
root->setText(0, qstr(fmt::format("Process, ID = 0x00000001, Total memory usage = 0x%x (%0.2f MB)", total_memory_usage, (float)total_memory_usage / (1024 * 1024))));
|
||||
root->setText(0, qstr(fmt::format("Process, ID = 0x00000001, Total Memory Usage = 0x%x (%0.2f MB)", total_memory_usage, (float)total_memory_usage / (1024 * 1024))));
|
||||
m_tree->addTopLevelItem(root);
|
||||
|
||||
union name64
|
||||
@@ -118,21 +118,21 @@ void kernel_explorer::Update()
|
||||
std::vector<lv2_obj_rec> lv2_types(256);
|
||||
lv2_types[SYS_MEM_OBJECT] = l_addTreeChild(root, "Memory");
|
||||
lv2_types[SYS_MUTEX_OBJECT] = l_addTreeChild(root, "Mutexes");
|
||||
lv2_types[SYS_COND_OBJECT] = l_addTreeChild(root, "Condition variables");
|
||||
lv2_types[SYS_RWLOCK_OBJECT] = l_addTreeChild(root, "Reader writer locks");
|
||||
lv2_types[SYS_INTR_TAG_OBJECT] = l_addTreeChild(root, "Interrupt tags");
|
||||
lv2_types[SYS_INTR_SERVICE_HANDLE_OBJECT] = l_addTreeChild(root, "Interrupt service handles");
|
||||
lv2_types[SYS_EVENT_QUEUE_OBJECT] = l_addTreeChild(root, "Event queues");
|
||||
lv2_types[SYS_EVENT_PORT_OBJECT] = l_addTreeChild(root, "Event ports");
|
||||
lv2_types[SYS_COND_OBJECT] = l_addTreeChild(root, "Condition Variables");
|
||||
lv2_types[SYS_RWLOCK_OBJECT] = l_addTreeChild(root, "Reader Writer Locks");
|
||||
lv2_types[SYS_INTR_TAG_OBJECT] = l_addTreeChild(root, "Interrupt Tags");
|
||||
lv2_types[SYS_INTR_SERVICE_HANDLE_OBJECT] = l_addTreeChild(root, "Interrupt Service Handles");
|
||||
lv2_types[SYS_EVENT_QUEUE_OBJECT] = l_addTreeChild(root, "Event Queues");
|
||||
lv2_types[SYS_EVENT_PORT_OBJECT] = l_addTreeChild(root, "Event Ports");
|
||||
lv2_types[SYS_TRACE_OBJECT] = l_addTreeChild(root, "Traces");
|
||||
lv2_types[SYS_SPUIMAGE_OBJECT] = l_addTreeChild(root, "SPU Images");
|
||||
lv2_types[SYS_PRX_OBJECT] = l_addTreeChild(root, "Modules");
|
||||
lv2_types[SYS_SPUPORT_OBJECT] = l_addTreeChild(root, "SPU Ports");
|
||||
lv2_types[SYS_LWMUTEX_OBJECT] = l_addTreeChild(root, "Light weight mutexes");
|
||||
lv2_types[SYS_LWMUTEX_OBJECT] = l_addTreeChild(root, "Light Weight Mutexes");
|
||||
lv2_types[SYS_TIMER_OBJECT] = l_addTreeChild(root, "Timers");
|
||||
lv2_types[SYS_SEMAPHORE_OBJECT] = l_addTreeChild(root, "Semaphores");
|
||||
lv2_types[SYS_LWCOND_OBJECT] = l_addTreeChild(root, "Light weight condition variables");
|
||||
lv2_types[SYS_EVENT_FLAG_OBJECT] = l_addTreeChild(root, "Event flags");
|
||||
lv2_types[SYS_LWCOND_OBJECT] = l_addTreeChild(root, "Light Weight Condition Variables");
|
||||
lv2_types[SYS_EVENT_FLAG_OBJECT] = l_addTreeChild(root, "Event Flags");
|
||||
|
||||
idm::select<lv2_obj>([&](u32 id, lv2_obj& obj)
|
||||
{
|
||||
@@ -170,26 +170,26 @@ void kernel_explorer::Update()
|
||||
case SYS_INTR_TAG_OBJECT:
|
||||
{
|
||||
// auto& tag = static_cast<lv2_int_tag&>(obj);
|
||||
l_addTreeChild(node, qstr(fmt::format("Intr tag: ID = 0x%08x", id)));
|
||||
l_addTreeChild(node, qstr(fmt::format("Intr Tag: ID = 0x%08x", id)));
|
||||
break;
|
||||
}
|
||||
case SYS_INTR_SERVICE_HANDLE_OBJECT:
|
||||
{
|
||||
// auto& serv = static_cast<lv2_int_serv&>(obj);
|
||||
l_addTreeChild(node, qstr(fmt::format("Intr svc: ID = 0x%08x", id)));
|
||||
l_addTreeChild(node, qstr(fmt::format("Intr Svc: ID = 0x%08x", id)));
|
||||
break;
|
||||
}
|
||||
case SYS_EVENT_QUEUE_OBJECT:
|
||||
{
|
||||
auto& eq = static_cast<lv2_event_queue&>(obj);
|
||||
l_addTreeChild(node, qstr(fmt::format("Event queue: ID = 0x%08x \"%s\", %s, Key = %#llx, Events = %zu/%d, Waiters = %zu", id, +name64(eq.name),
|
||||
l_addTreeChild(node, qstr(fmt::format("Event Queue: ID = 0x%08x \"%s\", %s, Key = %#llx, Events = %zu/%d, Waiters = %zu", id, +name64(eq.name),
|
||||
eq.type == SYS_SPU_QUEUE ? "SPU" : "PPU", eq.key, eq.events.size(), eq.size, eq.sq.size())));
|
||||
break;
|
||||
}
|
||||
case SYS_EVENT_PORT_OBJECT:
|
||||
{
|
||||
auto& ep = static_cast<lv2_event_port&>(obj);
|
||||
l_addTreeChild(node, qstr(fmt::format("Event port: ID = 0x%08x, Name = %#llx", id, ep.name)));
|
||||
l_addTreeChild(node, qstr(fmt::format("Event Port: ID = 0x%08x, Name = %#llx", id, ep.name)));
|
||||
break;
|
||||
}
|
||||
case SYS_TRACE_OBJECT:
|
||||
@@ -252,12 +252,12 @@ void kernel_explorer::Update()
|
||||
}
|
||||
});
|
||||
|
||||
lv2_types.emplace_back(l_addTreeChild(root, "Memory containers"));
|
||||
lv2_types.emplace_back(l_addTreeChild(root, "Memory Containers"));
|
||||
|
||||
idm::select<lv2_memory_container>([&](u32 id, lv2_memory_container&)
|
||||
{
|
||||
lv2_types.back().count++;
|
||||
l_addTreeChild(lv2_types.back().node, qstr(fmt::format("Memory container: ID = 0x%08x", id)));
|
||||
l_addTreeChild(lv2_types.back().node, qstr(fmt::format("Memory Container: ID = 0x%08x", id)));
|
||||
});
|
||||
|
||||
lv2_types.emplace_back(l_addTreeChild(root, "PPU Threads"));
|
||||
@@ -276,15 +276,15 @@ void kernel_explorer::Update()
|
||||
l_addTreeChild(lv2_types.back().node, qstr(fmt::format("SPU Thread: ID = 0x%08x '%s'", id, spu.get_name())));
|
||||
});
|
||||
|
||||
lv2_types.emplace_back(l_addTreeChild(root, "SPU Thread groups"));
|
||||
lv2_types.emplace_back(l_addTreeChild(root, "SPU Thread Groups"));
|
||||
|
||||
idm::select<lv2_spu_group>([&](u32 id, lv2_spu_group& tg)
|
||||
{
|
||||
lv2_types.back().count++;
|
||||
l_addTreeChild(lv2_types.back().node, qstr(fmt::format("SPU Thread group: ID = 0x%08x '%s'", id, tg.name)));
|
||||
l_addTreeChild(lv2_types.back().node, qstr(fmt::format("SPU Thread Group: ID = 0x%08x '%s'", id, tg.name)));
|
||||
});
|
||||
|
||||
lv2_types.emplace_back(l_addTreeChild(root, "File descriptors"));
|
||||
lv2_types.emplace_back(l_addTreeChild(root, "File Descriptors"));
|
||||
|
||||
idm::select<lv2_fs_object>([&](u32 id, lv2_fs_object& fo)
|
||||
{
|
||||
|
||||
@@ -290,7 +290,7 @@ void main_window::BootGame()
|
||||
}
|
||||
|
||||
QString path_last_Game = guiSettings->GetValue(gui::fd_boot_game).toString();
|
||||
QString dirPath = QFileDialog::getExistingDirectory(this, tr("Select game folder"), path_last_Game, QFileDialog::ShowDirsOnly);
|
||||
QString dirPath = QFileDialog::getExistingDirectory(this, tr("Select Game Folder"), path_last_Game, QFileDialog::ShowDirsOnly);
|
||||
|
||||
if (dirPath == NULL)
|
||||
{
|
||||
@@ -727,7 +727,7 @@ void main_window::OnEmuPause()
|
||||
m_thumb_playPause->setToolTip(tr("Resume emulation"));
|
||||
m_thumb_playPause->setIcon(m_icon_thumb_play);
|
||||
#endif
|
||||
ui->sysPauseAct->setText(tr("&Resume\tCtrl+F"));
|
||||
ui->sysPauseAct->setText(tr("&Resume\tCtrl+E"));
|
||||
ui->sysPauseAct->setIcon(m_icon_play);
|
||||
ui->toolbar_start->setIcon(m_icon_play);
|
||||
ui->toolbar_start->setToolTip(tr("Resume emulation"));
|
||||
@@ -1099,7 +1099,7 @@ void main_window::CreateConnects()
|
||||
{
|
||||
sysutil_send_system_cmd(m_sys_menu_opened ? 0x0132 /* CELL_SYSUTIL_SYSTEM_MENU_CLOSE */ : 0x0131 /* CELL_SYSUTIL_SYSTEM_MENU_OPEN */, 0);
|
||||
m_sys_menu_opened = !m_sys_menu_opened;
|
||||
ui->sysSendOpenMenuAct->setText(tr("Press &%0 PS button").arg(m_sys_menu_opened ? tr("close") : tr("open")));
|
||||
ui->sysSendOpenMenuAct->setText(tr("Send &%0 system menu cmd").arg(m_sys_menu_opened ? tr("close") : tr("open")));
|
||||
});
|
||||
|
||||
connect(ui->sysSendExitAct, &QAction::triggered, [=]
|
||||
@@ -1512,7 +1512,7 @@ void main_window::keyPressEvent(QKeyEvent *keyEvent)
|
||||
{
|
||||
switch (keyEvent->key())
|
||||
{
|
||||
case Qt::Key_F: if (Emu.IsPaused()) Emu.Resume(); else if (Emu.IsReady()) Emu.Run(); return;
|
||||
case Qt::Key_E: if (Emu.IsPaused()) Emu.Resume(); else if (Emu.IsReady()) Emu.Run(); return;
|
||||
case Qt::Key_P: if (Emu.IsRunning()) Emu.Pause(); return;
|
||||
case Qt::Key_S: if (!Emu.IsStopped()) Emu.Stop(); return;
|
||||
case Qt::Key_R: if (!Emu.GetBoot().empty()) Emu.Restart(); return;
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
memory_string_searcher::memory_string_searcher(QWidget* parent)
|
||||
: QDialog(parent)
|
||||
{
|
||||
setWindowTitle(tr("String searcher"));
|
||||
setWindowTitle(tr("String Searcher"));
|
||||
setAttribute(Qt::WA_DeleteOnClose);
|
||||
|
||||
m_addr_line = new QLineEdit(this);
|
||||
|
||||
@@ -8,7 +8,7 @@ constexpr auto qstr = QString::fromStdString;
|
||||
memory_viewer_panel::memory_viewer_panel(QWidget* parent)
|
||||
: QDialog(parent)
|
||||
{
|
||||
setWindowTitle(tr("Memory viewer"));
|
||||
setWindowTitle(tr("Memory Viewer"));
|
||||
setObjectName("memory_viewer");
|
||||
setAttribute(Qt::WA_DeleteOnClose);
|
||||
exit = false;
|
||||
@@ -29,7 +29,7 @@ memory_viewer_panel::memory_viewer_panel(QWidget* parent)
|
||||
QHBoxLayout* hbox_tools = new QHBoxLayout();
|
||||
|
||||
//Tools: Memory Viewer Options
|
||||
QGroupBox* tools_mem = new QGroupBox(tr("Memory viewer options"));
|
||||
QGroupBox* tools_mem = new QGroupBox(tr("Memory Viewer Options"));
|
||||
QHBoxLayout* hbox_tools_mem = new QHBoxLayout();
|
||||
|
||||
//Tools: Memory Viewer Options: Address
|
||||
@@ -81,7 +81,7 @@ memory_viewer_panel::memory_viewer_panel(QWidget* parent)
|
||||
tools_mem->setLayout(hbox_tools_mem);
|
||||
|
||||
//Tools: Raw Image Preview Options
|
||||
QGroupBox* tools_img = new QGroupBox(tr("Raw image preview options"));
|
||||
QGroupBox* tools_img = new QGroupBox(tr("Raw Image Preview Options"));
|
||||
QHBoxLayout* hbox_tools_img = new QHBoxLayout();;
|
||||
|
||||
//Tools: Raw Image Preview Options : Size
|
||||
@@ -389,7 +389,7 @@ void memory_viewer_panel::ShowImage(QWidget* parent, u32 addr, int mode, u32 wid
|
||||
layout->addWidget(canvas);
|
||||
|
||||
QDialog* f_image_viewer = new QDialog(parent);
|
||||
f_image_viewer->setWindowTitle(qstr(fmt::format("Raw image @ 0x%x", addr)));
|
||||
f_image_viewer->setWindowTitle(qstr(fmt::format("Raw Image @ 0x%x", addr)));
|
||||
f_image_viewer->setFixedSize(QSize(width, height));
|
||||
f_image_viewer->setLayout(layout);
|
||||
f_image_viewer->show();
|
||||
|
||||
@@ -29,7 +29,7 @@ rsx_debugger::rsx_debugger(QWidget* parent)
|
||||
QVBoxLayout* vbox_tools = new QVBoxLayout();
|
||||
|
||||
// Controls
|
||||
QGroupBox* gb_controls = new QGroupBox(tr("RSX Debugger controls"), this);
|
||||
QGroupBox* gb_controls = new QGroupBox(tr("RSX Debugger Controls"), this);
|
||||
QHBoxLayout* hbox_controls = new QHBoxLayout();
|
||||
|
||||
// Controls: Address
|
||||
@@ -110,8 +110,8 @@ rsx_debugger::rsx_debugger(QWidget* parent)
|
||||
};
|
||||
|
||||
m_list_commands = l_addRSXTab(m_list_commands, tr("RSX Commands"), 4);
|
||||
m_list_captured_frame = l_addRSXTab(m_list_captured_frame, tr("Captured frame"), 1);
|
||||
m_list_captured_draw_calls = l_addRSXTab(m_list_captured_draw_calls, tr("Captured draw calls"), 1);
|
||||
m_list_captured_frame = l_addRSXTab(m_list_captured_frame, tr("Captured Frame"), 1);
|
||||
m_list_captured_draw_calls = l_addRSXTab(m_list_captured_draw_calls, tr("Captured Draw Calls"), 1);
|
||||
m_list_flags = l_addRSXTab(m_list_flags, tr("Flags"), 2);
|
||||
m_list_lightning = l_addRSXTab(m_list_lightning, tr("Lightning"), 2);
|
||||
m_list_texture = l_addRSXTab(m_list_texture, tr("Texture"), 9);
|
||||
@@ -193,12 +193,12 @@ rsx_debugger::rsx_debugger(QWidget* parent)
|
||||
//Buffers
|
||||
QVBoxLayout* vbox_buffers1 = new QVBoxLayout();
|
||||
QVBoxLayout* vbox_buffers2 = new QVBoxLayout();
|
||||
QGroupBox* gb_buffers_colorA = new QGroupBox(tr("Color buffer A"), p_buffers);
|
||||
QGroupBox* gb_buffers_colorB = new QGroupBox(tr("Color buffer B"), p_buffers);
|
||||
QGroupBox* gb_buffers_colorC = new QGroupBox(tr("Color buffer C"), p_buffers);
|
||||
QGroupBox* gb_buffers_colorD = new QGroupBox(tr("Color buffer D"), p_buffers);
|
||||
QGroupBox* gb_buffers_depth = new QGroupBox(tr("Depth buffer"), p_buffers);
|
||||
QGroupBox* gb_buffers_stencil = new QGroupBox(tr("Stencil buffer"), p_buffers);
|
||||
QGroupBox* gb_buffers_colorA = new QGroupBox(tr("Color Buffer A"), p_buffers);
|
||||
QGroupBox* gb_buffers_colorB = new QGroupBox(tr("Color Buffer B"), p_buffers);
|
||||
QGroupBox* gb_buffers_colorC = new QGroupBox(tr("Color Buffer C"), p_buffers);
|
||||
QGroupBox* gb_buffers_colorD = new QGroupBox(tr("Color Buffer D"), p_buffers);
|
||||
QGroupBox* gb_buffers_depth = new QGroupBox(tr("Depth Buffer"), p_buffers);
|
||||
QGroupBox* gb_buffers_stencil = new QGroupBox(tr("Stencil Buffer"), p_buffers);
|
||||
QGroupBox* gb_buffers_text = new QGroupBox(tr("Texture"), p_buffers);
|
||||
QHBoxLayout* hbox_buffers_colorA = new QHBoxLayout();
|
||||
QHBoxLayout* hbox_buffers_colorB = new QHBoxLayout();
|
||||
@@ -1062,7 +1062,7 @@ const char* rsx_debugger::ParseGCMEnum(u32 value, u32 type)
|
||||
case 0xF006: return "Add Signed";
|
||||
case 0xF007: return "Reverse Add Signed";
|
||||
|
||||
default: return "Wrong value!";
|
||||
default: return "Wrong Value!";
|
||||
}
|
||||
}
|
||||
case CELL_GCM_PRIMITIVE_ENUM:
|
||||
@@ -1080,7 +1080,7 @@ const char* rsx_debugger::ParseGCMEnum(u32 value, u32 type)
|
||||
case 9: return "QUAD_STRIP";
|
||||
case 10: return "POLYGON";
|
||||
|
||||
default: return "Wrong value!";
|
||||
default: return "Wrong Value!";
|
||||
}
|
||||
}
|
||||
default: return "Unknown!";
|
||||
@@ -1150,7 +1150,7 @@ QString rsx_debugger::DisAsmCommand(u32 cmd, u32 count, u32 currentAddr, u32 ioA
|
||||
break;
|
||||
|
||||
case_16(NV4097_SET_TEXTURE_OFFSET, 0x20):
|
||||
DISASM("Texture offset[%d]: %08x", index, (u32)args[0]);
|
||||
DISASM("Texture Offset[%d]: %08x", index, (u32)args[0]);
|
||||
switch ((args[1] & 0x3) - 1)
|
||||
{
|
||||
case CELL_GCM_LOCATION_LOCAL: DISASM("(Local memory);"); break;
|
||||
@@ -1176,7 +1176,7 @@ QString rsx_debugger::DisAsmCommand(u32 cmd, u32 count, u32 currentAddr, u32 ioA
|
||||
|
||||
if((cmd & RSX_METHOD_NON_INCREMENT_CMD_MASK) == RSX_METHOD_NON_INCREMENT_CMD)
|
||||
{
|
||||
DISASM("Non increment cmd");
|
||||
DISASM("Non Increment cmd");
|
||||
}
|
||||
|
||||
DISASM("[0x%08x(", cmd);
|
||||
|
||||
@@ -9,7 +9,7 @@ constexpr auto qstr = QString::fromStdString;
|
||||
save_data_info_dialog::save_data_info_dialog(const SaveDataEntry& save, QWidget* parent)
|
||||
: QDialog(parent), m_entry(save)
|
||||
{
|
||||
setWindowTitle(tr("Save data information"));
|
||||
setWindowTitle(tr("Save Data Information"));
|
||||
|
||||
// Table
|
||||
m_list = new QTableWidget(this);
|
||||
|
||||
@@ -18,15 +18,15 @@ save_data_list_dialog::save_data_list_dialog(const std::vector<SaveDataEntry>& e
|
||||
{
|
||||
if (op >= 8)
|
||||
{
|
||||
setWindowTitle(tr("Save data interface (Delete)"));
|
||||
setWindowTitle(tr("Save Data Interface (Delete)"));
|
||||
}
|
||||
else if (op & 1)
|
||||
{
|
||||
setWindowTitle(tr("Save data interface (Load)"));
|
||||
setWindowTitle(tr("Save Data Interface (Load)"));
|
||||
}
|
||||
else
|
||||
{
|
||||
setWindowTitle(tr("Save data interface (Save)"));
|
||||
setWindowTitle(tr("Save Data Interface (Save)"));
|
||||
}
|
||||
|
||||
setMinimumSize(QSize(400, 400));
|
||||
@@ -48,7 +48,7 @@ save_data_list_dialog::save_data_list_dialog(const std::vector<SaveDataEntry>& e
|
||||
|
||||
if (entries.size() > 0)
|
||||
{ // If there are no entries, don't add the selection widget or the selection label to the UI.
|
||||
QPushButton *push_select = new QPushButton(tr("&Select entry"), this);
|
||||
QPushButton *push_select = new QPushButton(tr("&Select Entry"), this);
|
||||
connect(push_select, &QAbstractButton::clicked, this, &save_data_list_dialog::accept);
|
||||
push_select->setAutoDefault(true);
|
||||
push_select->setDefault(true);
|
||||
@@ -60,7 +60,7 @@ save_data_list_dialog::save_data_list_dialog(const std::vector<SaveDataEntry>& e
|
||||
|
||||
if (listSet->newData)
|
||||
{
|
||||
QPushButton *saveNewEntry = new QPushButton(tr("Save new entry"), this);
|
||||
QPushButton *saveNewEntry = new QPushButton(tr("Save New Entry"), this);
|
||||
connect(saveNewEntry, &QAbstractButton::clicked, this, [&]()
|
||||
{
|
||||
m_entry = selection_code::new_save;
|
||||
@@ -119,12 +119,12 @@ void save_data_list_dialog::UpdateSelectionLabel()
|
||||
{
|
||||
if (m_list->currentRow() == -1)
|
||||
{
|
||||
m_entry_label->setText(tr("Currently selected: None"));
|
||||
m_entry_label->setText(tr("Currently Selected: None"));
|
||||
}
|
||||
else
|
||||
{
|
||||
int entry = m_list->item(m_list->currentRow(), 0)->data(Qt::UserRole).toInt();
|
||||
m_entry_label->setText(tr("Currently selected: ") + qstr(m_save_entries[entry].dirName));
|
||||
m_entry_label->setText(tr("Currently Selected: ") + qstr(m_save_entries[entry].dirName));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+5
-5
@@ -5,13 +5,13 @@
|
||||
<PropertyGroup />
|
||||
<ItemDefinitionGroup>
|
||||
<ClCompile>
|
||||
<PreprocessorDefinitions>POLLY_AVAILABLE;LLVM_AVAILABLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<PreprocessorDefinitions>LLVM_AVAILABLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
</ClCompile>
|
||||
<Lib>
|
||||
<AdditionalLibraryDirectories Condition="'$(Configuration)'=='Debug - LLVM'">..\llvm_build\Debug\lib;..\llvm_build\lib\Debug</AdditionalLibraryDirectories>
|
||||
<AdditionalLibraryDirectories Condition="'$(Configuration)'=='Release - LLVM'">..\llvm_build\Release\lib;..\llvm_build\lib\Release</AdditionalLibraryDirectories>
|
||||
<AdditionalDependencies>LLVMProfileData.lib;LLVMDebugInfoCodeView.lib;LLVMDebugInfoMSF.lib;LLVMInstrumentation.lib;LLVMMCJIT.lib;LLVMRuntimeDyld.lib;LLVMVectorize.lib;LLVMX86CodeGen.lib;LLVMGlobalISel.lib;LLVMX86Disassembler.lib;LLVMExecutionEngine.lib;LLVMAsmPrinter.lib;LLVMSelectionDAG.lib;LLVMCodeGen.lib;LLVMScalarOpts.lib;LLVMInstCombine.lib;LLVMTransformUtils.lib;LLVMAnalysis.lib;LLVMTarget.lib;LLVMX86Desc.lib;LLVMX86AsmPrinter.lib;LLVMObject.lib;LLVMMCParser.lib;LLVMBitReader.lib;LLVMCore.lib;LLVMX86Utils.lib;LLVMMC.lib;LLVMX86Info.lib;LLVMSupport.lib;LLVMMCDisassembler.lib;LLVMipo.lib;LLVMBinaryFormat.lib;LLVMPasses.lib;LLVMIRReader.lib;LLVMLinker.lib;LLVMAsmParser.lib;Polly.lib;PollyISL.lib;PollyPPCG.lib</AdditionalDependencies>
|
||||
<AdditionalLibraryDirectories Condition="'$(Configuration)'=='Debug - LLVM'">..\llvm_build\Debug\lib</AdditionalLibraryDirectories>
|
||||
<AdditionalLibraryDirectories Condition="'$(Configuration)'=='Release - LLVM'">..\llvm_build\Release\lib</AdditionalLibraryDirectories>
|
||||
<AdditionalDependencies>LLVMProfileData.lib;LLVMDebugInfoCodeView.lib;LLVMDebugInfoMSF.lib;LLVMInstrumentation.lib;LLVMMCJIT.lib;LLVMRuntimeDyld.lib;LLVMVectorize.lib;LLVMX86CodeGen.lib;LLVMGlobalISel.lib;LLVMX86Disassembler.lib;LLVMExecutionEngine.lib;LLVMAsmPrinter.lib;LLVMSelectionDAG.lib;LLVMCodeGen.lib;LLVMScalarOpts.lib;LLVMInstCombine.lib;LLVMTransformUtils.lib;LLVMAnalysis.lib;LLVMTarget.lib;LLVMX86Desc.lib;LLVMX86AsmPrinter.lib;LLVMObject.lib;LLVMMCParser.lib;LLVMBitReader.lib;LLVMCore.lib;LLVMX86Utils.lib;LLVMMC.lib;LLVMX86Info.lib;LLVMSupport.lib;LLVMMCDisassembler.lib;LLVMipo.lib</AdditionalDependencies>
|
||||
</Lib>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemGroup />
|
||||
</Project>
|
||||
</Project>
|
||||
Reference in New Issue
Block a user