Merge branch 'master' into cellAdec

This commit is contained in:
Elad 2024-12-17 19:42:32 +02:00 committed by GitHub
commit 8d4a0537ae
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
45 changed files with 997 additions and 131 deletions

View file

@ -71,13 +71,14 @@ if [ ! -d "/tmp/Qt/$QT_VER" ]; then
git clone https://github.com/engnr/qt-downloader.git
cd qt-downloader
git checkout f52efee0f18668c6d6de2dec0234b8c4bc54c597
# nested Qt 6.8.0 URL workaround
sed -i '' "s/'qt{0}_{0}{1}{2}'.format(major, minor, patch)]))/'qt{0}_{0}{1}{2}'.format(major, minor, patch), 'qt{0}_{0}{1}{2}'.format(major, minor, patch)]))/g" qt-downloader
sed -i '' "s/'{}\/{}\/qt{}_{}\/'/'{0}\/{1}\/qt{2}_{3}\/qt{2}_{3}\/'/g" qt-downloader
# nested Qt 6.8.1 URL workaround
# sed -i '' "s/'qt{0}_{0}{1}{2}'.format(major, minor, patch)]))/'qt{0}_{0}{1}{2}'.format(major, minor, patch), 'qt{0}_{0}{1}{2}'.format(major, minor, patch)]))/g" qt-downloader
# sed -i '' "s/'{}\/{}\/qt{}_{}\/'/'{0}\/{1}\/qt{2}_{3}\/qt{2}_{3}\/'/g" qt-downloader
cd "/tmp/Qt"
"$BREW_X64_PATH/bin/pipenv" run pip3 install py7zr requests semantic_version lxml
mkdir -p "$QT_VER/macos" ; ln -s "macos" "$QT_VER/clang_64"
"$BREW_X64_PATH/bin/pipenv" run "$WORKDIR/qt-downloader/qt-downloader" macos desktop "$QT_VER" clang_64 --opensource --addons qtmultimedia qtimageformats
# sed -i '' 's/args\.version \/ derive_toolchain_dir(args) \/ //g' "$WORKDIR/qt-downloader/qt-downloader" # Qt 6.8.1 workaround
"$BREW_X64_PATH/bin/pipenv" run "$WORKDIR/qt-downloader/qt-downloader" macos desktop "$QT_VER" clang_64 --opensource --addons qtmultimedia qtimageformats # -o "$QT_VER/clang_64"
fi
cd "$WORKDIR"

View file

@ -39,13 +39,14 @@ if [ ! -d "/tmp/Qt/$QT_VER" ]; then
git clone https://github.com/engnr/qt-downloader.git
cd qt-downloader
git checkout f52efee0f18668c6d6de2dec0234b8c4bc54c597
# nested Qt 6.8.0 URL workaround
sed -i '' "s/'qt{0}_{0}{1}{2}'.format(major, minor, patch)]))/'qt{0}_{0}{1}{2}'.format(major, minor, patch), 'qt{0}_{0}{1}{2}'.format(major, minor, patch)]))/g" qt-downloader
sed -i '' "s/'{}\/{}\/qt{}_{}\/'/'{0}\/{1}\/qt{2}_{3}\/qt{2}_{3}\/'/g" qt-downloader
# nested Qt 6.8.1 URL workaround
# sed -i '' "s/'qt{0}_{0}{1}{2}'.format(major, minor, patch)]))/'qt{0}_{0}{1}{2}'.format(major, minor, patch), 'qt{0}_{0}{1}{2}'.format(major, minor, patch)]))/g" qt-downloader
# sed -i '' "s/'{}\/{}\/qt{}_{}\/'/'{0}\/{1}\/qt{2}_{3}\/qt{2}_{3}\/'/g" qt-downloader
cd "/tmp/Qt"
"$BREW_X64_PATH/bin/pipenv" run pip3 install py7zr requests semantic_version lxml
mkdir -p "$QT_VER/macos" ; ln -s "macos" "$QT_VER/clang_64"
"$BREW_X64_PATH/bin/pipenv" run "$WORKDIR/qt-downloader/qt-downloader" macos desktop "$QT_VER" clang_64 --opensource --addons qtmultimedia qtimageformats
# sed -i '' 's/args\.version \/ derive_toolchain_dir(args) \/ //g' "$WORKDIR/qt-downloader/qt-downloader" # Qt 6.8.1 workaround
"$BREW_X64_PATH/bin/pipenv" run "$WORKDIR/qt-downloader/qt-downloader" macos desktop "$QT_VER" clang_64 --opensource --addons qtmultimedia qtimageformats # -o "$QT_VER/clang_64"
fi
cd "$WORKDIR"

View file

@ -77,7 +77,7 @@ for url in $DEP_URLS; do
# shellcheck disable=SC1003
case "$url" in
*qt*) checksum=$(curl -fL "${url}.sha1"); algo="sha1"; outDir='C:\Qt\' ;;
*qt*) checksum=$(curl -fL "${url}.sha1"); algo="sha1"; outDir="$QTDIR/" ;;
*llvm*) checksum=$(curl -fL "${url}.sha256"); algo="sha256"; outDir="./build/lib_ext/Release-x64" ;;
*glslang*) checksum=$(curl -fL "${url}.sha256"); algo="sha256"; outDir="./build/lib_ext/Release-x64" ;;
*Vulkan*)

View file

@ -7,7 +7,7 @@ env:
BUILD_SOURCEBRANCHNAME: $CIRRUS_BRANCH
RPCS3_TOKEN: ENCRYPTED[100ebb8e3552bf2021d0ef55dccda3e58d27be5b6cab0b0b92843ef490195d3c4edaefa087e4a3b425caa6392300b9b1]
QT_VER_MAIN: '6'
QT_VER: '6.8.0'
QT_VER: '6.8.1'
# windows_task:
# matrix:
@ -21,7 +21,7 @@ env:
# COMPILER: msvc
# BUILD_ARTIFACTSTAGINGDIRECTORY: ${CIRRUS_WORKING_DIR}\artifacts\
# QT_VER_MSVC: 'msvc2022'
# QT_DATE: '202410030750'
# QT_DATE: '202411221531'
# QTDIR: C:\Qt\${QT_VER}\${QT_VER_MSVC}_64
# VULKAN_VER: '1.3.268.0'
# VULKAN_SDK_SHA: '8459ef49bd06b697115ddd3d97c9aec729e849cd775f5be70897718a9b3b9db5'

4
.gitmodules vendored
View file

@ -100,3 +100,7 @@
path = 3rdparty/opencv/opencv
url = ../../Megamouse/opencv_minimal.git
ignore = dirty
[submodule "3rdparty/fusion/fusion"]
path = 3rdparty/fusion/fusion
url = ../../xioTechnologies/Fusion.git
ignore = dirty

View file

@ -346,6 +346,9 @@ add_subdirectory(rtmidi EXCLUDE_FROM_ALL)
# OPENCV
add_subdirectory(opencv EXCLUDE_FROM_ALL)
# FUSION
add_subdirectory(fusion EXCLUDE_FROM_ALL)
# add nice ALIAS targets for ease of use
if(USE_SYSTEM_LIBUSB)
add_library(3rdparty::libusb ALIAS usb-1.0-shared)
@ -377,3 +380,4 @@ add_library(3rdparty::sdl2 ALIAS ${SDL2_TARGET})
add_library(3rdparty::miniupnpc ALIAS libminiupnpc-static)
add_library(3rdparty::rtmidi ALIAS rtmidi)
add_library(3rdparty::opencv ALIAS ${OPENCV_TARGET})
add_library(3rdparty::fusion ALIAS Fusion)

1
3rdparty/fusion/CMakeLists.txt vendored Normal file
View file

@ -0,0 +1 @@
add_subdirectory(fusion EXCLUDE_FROM_ALL)

1
3rdparty/fusion/fusion vendored Submodule

@ -0,0 +1 @@
Subproject commit fecf2f0af3bd23cbba553ceedc2bc6c1cd410fc1

75
3rdparty/fusion/fusion.vcxproj vendored Normal file
View file

@ -0,0 +1,75 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|x64">
<Configuration>Debug</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|x64">
<Configuration>Release</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
</ItemGroup>
<ItemGroup>
<ClInclude Include="fusion\Fusion\Fusion.h" />
<ClInclude Include="fusion\Fusion\FusionAhrs.h" />
<ClInclude Include="fusion\Fusion\FusionAxes.h" />
<ClInclude Include="fusion\Fusion\FusionCalibration.h" />
<ClInclude Include="fusion\Fusion\FusionCompass.h" />
<ClInclude Include="fusion\Fusion\FusionConvention.h" />
<ClInclude Include="fusion\Fusion\FusionMath.h" />
<ClInclude Include="fusion\Fusion\FusionOffset.h" />
</ItemGroup>
<ItemGroup>
<ClCompile Include="fusion\Fusion\FusionAhrs.c" />
<ClCompile Include="fusion\Fusion\FusionCompass.c" />
<ClCompile Include="fusion\Fusion\FusionOffset.c" />
</ItemGroup>
<PropertyGroup Label="Globals">
<RootNamespace>Fusion</RootNamespace>
<ProjectGuid>{3C67A2FF-4710-402A-BE3E-31B0CB0576DF}</ProjectGuid>
</PropertyGroup>
<Import Project="$(SolutionDir)\buildfiles\msvc\common_default.props" />
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<Import Project="$(SolutionDir)\buildfiles\msvc\common_default_macros.props" />
<PropertyGroup Label="Configuration">
<ConfigurationType>StaticLibrary</ConfigurationType>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<PropertyGroup>
<PreferredToolArchitecture>x64</PreferredToolArchitecture>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<OutDir>$(SolutionDir)build\lib\$(Configuration)-$(Platform)\</OutDir>
<IntDir>$(SolutionDir)build\tmp\$(ProjectName)-$(Configuration)-$(Platform)\</IntDir>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<OutDir>$(SolutionDir)build\lib\$(Configuration)-$(Platform)\</OutDir>
<IntDir>$(SolutionDir)build\tmp\$(ProjectName)-$(Configuration)-$(Platform)\</IntDir>
</PropertyGroup>
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
<ImportGroup Label="Shared">
</ImportGroup>
<ImportGroup Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
<Import Project="$(SolutionDir)\buildfiles\msvc\rpcs3_default.props" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<Import Project="$(SolutionDir)\buildfiles\msvc\rpcs3_debug.props" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<Import Project="$(SolutionDir)\buildfiles\msvc\rpcs3_release.props" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<ItemDefinitionGroup>
<ClCompile>
<ExceptionHandling>Sync</ExceptionHandling>
<Optimization Condition="'$(Configuration)|$(Platform)'=='Release|x64'">MaxSpeed</Optimization>
</ClCompile>
</ItemDefinitionGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>

29
3rdparty/fusion/fusion.vcxproj.filters vendored Normal file
View file

@ -0,0 +1,29 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<Filter Include="Source Files">
<Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
</Filter>
</ItemGroup>
<ItemGroup>
<ClInclude Include="fusion\Fusion\Fusion.h" />
<ClInclude Include="fusion\Fusion\FusionAhrs.h" />
<ClInclude Include="fusion\Fusion\FusionAxes.h" />
<ClInclude Include="fusion\Fusion\FusionCalibration.h" />
<ClInclude Include="fusion\Fusion\FusionCompass.h" />
<ClInclude Include="fusion\Fusion\FusionConvention.h" />
<ClInclude Include="fusion\Fusion\FusionMath.h" />
<ClInclude Include="fusion\Fusion\FusionOffset.h" />
</ItemGroup>
<ItemGroup>
<ClCompile Include="fusion\Fusion\FusionAhrs.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="fusion\Fusion\FusionCompass.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="fusion\Fusion\FusionOffset.c">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>
</Project>

View file

@ -19,26 +19,26 @@ The following tools are required to build RPCS3 on Windows 10 or later:
with standalone **CMake** tool.
- [Python 3.6+](https://www.python.org/downloads/) (add to PATH)
- [Qt 6.8.0](https://www.qt.io/download-qt-installer) In case you can't download from the official installer, you can use [Another Qt installer](https://github.com/miurahr/aqtinstall) (In that case you will need to manually add the "qtmultimedia" module when installing Qt)
- [Qt 6.8.1](https://www.qt.io/download-qt-installer) In case you can't download from the official installer, you can use [Another Qt installer](https://github.com/miurahr/aqtinstall) (In that case you will need to manually add the "qtmultimedia" module when installing Qt)
- [Vulkan SDK 1.3.268.0](https://vulkan.lunarg.com/sdk/home) (see "Install the SDK" [here](https://vulkan.lunarg.com/doc/sdk/latest/windows/getting_started.html)) for now future SDKs don't work. You need precisely 1.3.268.0.
The `sln` solution available only on **Visual Studio** is the preferred building solution. It easily allows to build the **RPCS3** application in `Release` and `Debug` mode.
In order to build **RPCS3** with the `sln` solution (with **Visual Studio**), **Qt** libs need to be detected. To detect the libs:
- add and set the `QTDIR` environment variable, e.g. `<QtInstallFolder>\6.8.0\msvc2022_64\`
- add and set the `QTDIR` environment variable, e.g. `<QtInstallFolder>\6.8.1\msvc2022_64\`
- or use the [Visual Studio Qt Plugin](https://marketplace.visualstudio.com/items?itemName=TheQtCompany.QtVisualStudioTools2022)
**NOTE:** If you have issues with the **Visual Studio Qt Plugin**, you may want to uninstall it and install the [Legacy Qt Plugin](https://marketplace.visualstudio.com/items?itemName=TheQtCompany.LEGACYQtVisualStudioTools2022) instead.
In order to build **RPCS3** with the `CMake` solution (with both **Visual Studio** and standalone **CMake** tool):
- add and set the `CMAKE_PREFIX_PATH` environment variable to the **Qt** libs path, e.g. `<QtInstallFolder>\6.8.0\msvc2022_64\`
- add and set the `CMAKE_PREFIX_PATH` environment variable to the **Qt** libs path, e.g. `<QtInstallFolder>\6.8.1\msvc2022_64\`
### Linux
These are the essentials tools to build RPCS3 on Linux. Some of them can be installed through your favorite package manager:
- Clang 17+ or GCC 13+
- [CMake 3.28.0+](https://www.cmake.org/download/)
- [Qt 6.8.0](https://www.qt.io/download-qt-installer)
- [Qt 6.8.1](https://www.qt.io/download-qt-installer)
- [Vulkan SDK 1.3.268.0](https://vulkan.lunarg.com/sdk/home) (See "Install the SDK" [here](https://vulkan.lunarg.com/doc/sdk/latest/linux/getting_started.html)) for now future SDKs don't work. You need precisely 1.3.268.0.
- [SDL2](https://github.com/libsdl-org/SDL/releases) (for the FAudio backend)
@ -119,7 +119,7 @@ Start **Visual Studio**, click on `Open a project or solution` and select the `r
##### Configuring the Qt Plugin (if used)
1) go to `Extensions->Qt VS Tools->Qt Versions`
2) add the path to your Qt installation with compiler e.g. `<QtInstallFolder>\6.8.0\msvc2022_64`, version will fill in automatically
2) add the path to your Qt installation with compiler e.g. `<QtInstallFolder>\6.8.1\msvc2022_64`, version will fill in automatically
3) go to `Extensions->Qt VS Tools->Options->Legacy Project Format`. (Only available in the **Legacy Qt Plugin**)
4) set `Build: Run pre-build setup` to `true`. (Only available in the **Legacy Qt Plugin**)

View file

@ -69,9 +69,9 @@ jobs:
variables:
COMPILER: msvc
QT_VER_MAIN: '6'
QT_VER: '6.8.0'
QT_VER: '6.8.1'
QT_VER_MSVC: 'msvc2022'
QT_DATE: '202410030750'
QT_DATE: '202411221531'
QTDIR: C:\Qt\$(QT_VER)\$(QT_VER_MSVC)_64
VULKAN_VER: '1.3.268.0'
VULKAN_SDK_SHA: '8459ef49bd06b697115ddd3d97c9aec729e849cd775f5be70897718a9b3b9db5'
@ -132,7 +132,7 @@ jobs:
UPLOAD_REPO_FULL_NAME: "RPCS3/rpcs3-binaries-mac"
RELEASE_MESSAGE: "../GitHubReleaseMessage.txt"
ARTDIR: $(Build.ArtifactStagingDirectory)
QT_VER: '6.8.0'
QT_VER: '6.7.3'
QT_VER_MAIN: '6'
LLVM_COMPILER_VER: '16'
@ -193,7 +193,7 @@ jobs:
UPLOAD_REPO_FULL_NAME: "RPCS3/rpcs3-binaries-mac-arm64"
RELEASE_MESSAGE: "../GitHubReleaseMessage.txt"
ARTDIR: $(Build.ArtifactStagingDirectory)
QT_VER: '6.8.0'
QT_VER: '6.7.3'
QT_VER_MAIN: '6'
LLVM_COMPILER_VER: '16'

View file

@ -7,6 +7,7 @@ EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "emucore", "rpcs3\emucore.vcxproj", "{C4A10229-4712-4BD2-B63E-50D93C67A038}"
ProjectSection(ProjectDependencies) = postProject
{2C902C67-985C-4BE0-94A3-E0FE2EB929A3} = {2C902C67-985C-4BE0-94A3-E0FE2EB929A3}
{3C67A2FF-4710-402A-BE3E-31B0CB0576DF} = {3C67A2FF-4710-402A-BE3E-31B0CB0576DF}
{5228F863-E0DD-4DE7-AA7B-5C52B14CD4D0} = {5228F863-E0DD-4DE7-AA7B-5C52B14CD4D0}
{8846A9AA-5539-4C91-8301-F54260E1A07A} = {8846A9AA-5539-4C91-8301-F54260E1A07A}
{939FE206-1182-ABC3-1234-FEAB88E98404} = {939FE206-1182-ABC3-1234-FEAB88E98404}
@ -46,6 +47,7 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "rpcs3", "rpcs3\rpcs3.vcxpro
{2C902C67-985C-4BE0-94A3-E0FE2EB929A3} = {2C902C67-985C-4BE0-94A3-E0FE2EB929A3}
{3384223A-6D97-4799-9862-359F85312892} = {3384223A-6D97-4799-9862-359F85312892}
{349EE8F9-7D25-4909-AAF5-FF3FADE72187} = {349EE8F9-7D25-4909-AAF5-FF3FADE72187}
{3C67A2FF-4710-402A-BE3E-31B0CB0576DF} = {3C67A2FF-4710-402A-BE3E-31B0CB0576DF}
{3EE5F075-B546-42C4-B6A8-E3CCEF38B78D} = {3EE5F075-B546-42C4-B6A8-E3CCEF38B78D}
{508C291A-3D18-49F5-B25D-F7C8DB92CB21} = {508C291A-3D18-49F5-B25D-F7C8DB92CB21}
{5B146DEA-9ACE-4D32-A7FD-3F42464DD69C} = {5B146DEA-9ACE-4D32-A7FD-3F42464DD69C}
@ -103,6 +105,8 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "7zip", "3rdparty\7zip\7zip.
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "openal-soft", "3rdparty\openal\openal-soft.vcxproj", "{8846A9AA-5539-4C91-8301-F54260E1A07A}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "fusion", "3rdparty\fusion\fusion.vcxproj", "{3C67A2FF-4710-402A-BE3E-31B0CB0576DF}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|x64 = Debug|x64
@ -211,6 +215,10 @@ Global
{8846A9AA-5539-4C91-8301-F54260E1A07A}.Debug|x64.Build.0 = Debug|x64
{8846A9AA-5539-4C91-8301-F54260E1A07A}.Release|x64.ActiveCfg = Release|x64
{8846A9AA-5539-4C91-8301-F54260E1A07A}.Release|x64.Build.0 = Release|x64
{3C67A2FF-4710-402A-BE3E-31B0CB0576DF}.Debug|x64.ActiveCfg = Debug|x64
{3C67A2FF-4710-402A-BE3E-31B0CB0576DF}.Debug|x64.Build.0 = Debug|x64
{3C67A2FF-4710-402A-BE3E-31B0CB0576DF}.Release|x64.ActiveCfg = Release|x64
{3C67A2FF-4710-402A-BE3E-31B0CB0576DF}.Release|x64.Build.0 = Release|x64
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@ -243,6 +251,7 @@ Global
{4E52A41A-F33B-4C7A-8C36-A1A6B4F4277C} = {6C3B64A0-8F8A-4DC4-8C0B-D71EBEED7FA8}
{5B146DEA-9ACE-4D32-A7FD-3F42464DD69C} = {6C3B64A0-8F8A-4DC4-8C0B-D71EBEED7FA8}
{8846A9AA-5539-4C91-8301-F54260E1A07A} = {6C3B64A0-8F8A-4DC4-8C0B-D71EBEED7FA8}
{3C67A2FF-4710-402A-BE3E-31B0CB0576DF} = {6C3B64A0-8F8A-4DC4-8C0B-D71EBEED7FA8}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {06CC7920-E085-4B81-9582-8DE8AAD42510}

View file

@ -82,6 +82,7 @@ target_sources(rpcs3
Input/mm_joystick_handler.cpp
Input/pad_thread.cpp
Input/product_info.cpp
Input/ps_move_calibration.cpp
Input/ps_move_config.cpp
Input/ps_move_handler.cpp
Input/ps_move_tracker.cpp
@ -110,6 +111,7 @@ target_link_libraries(rpcs3
3rdparty::libcurl
3rdparty::zlib
3rdparty::opencv
3rdparty::fusion
${ADDITIONAL_LIBS})
# Unix display manager

View file

@ -506,6 +506,7 @@ target_sources(rpcs3_emu PRIVATE
RSX/GL/OpenGL.cpp
RSX/GL/upscalers/fsr1/fsr_pass.cpp
RSX/GSRender.cpp
RSX/Host/MM.cpp
RSX/Host/RSXDMAWriter.cpp
RSX/Null/NullGSRender.cpp
RSX/NV47/FW/draw_call.cpp

View file

@ -232,8 +232,8 @@ public:
u8 rumble = 0; // Rumble intensity
gem_color sphere_rgb = {}; // RGB color of the sphere LED
u32 hue = 0; // Tracking hue of the motion controller
f32 distance_mm{1500.0f}; // Distance from the camera in mm
f32 radius{10.0f}; // Radius of the sphere in camera pixels
f32 distance_mm{3000.0f}; // Distance from the camera in mm
f32 radius{5.0f}; // Radius of the sphere in camera pixels
bool radius_valid = true; // If the radius and distance of the sphere was computed.
bool is_calibrating{false}; // Whether or not we are currently calibrating
@ -716,8 +716,9 @@ public:
return hue < m_hues.size() && m_hues[hue] < 20; // potentially true if less than 20 pixels have the hue
}
ps_move_info& get_info(u32 gem_num)
ps_move_info get_info(u32 gem_num)
{
std::lock_guard lock(mutex);
return ::at32(m_info, gem_num);
}
@ -903,7 +904,7 @@ static inline void pos_to_gem_image_state(u32 gem_num, const gem_config::gem_con
}
}
static inline void pos_to_gem_state(u32 gem_num, const gem_config::gem_controller& controller, vm::ptr<CellGemState>& gem_state, s32 x_pos, s32 y_pos, s32 x_max, s32 y_max)
static inline void pos_to_gem_state(u32 gem_num, gem_config::gem_controller& controller, vm::ptr<CellGemState>& gem_state, s32 x_pos, s32 y_pos, s32 x_max, s32 y_max, const ps_move_data& move_data)
{
const auto& shared_data = g_fxo->get<gem_camera_shared>();
@ -918,9 +919,13 @@ static inline void pos_to_gem_state(u32 gem_num, const gem_config::gem_controlle
const f32 image_x = static_cast<f32>(x_pos) / scaling_width;
const f32 image_y = static_cast<f32>(y_pos) / scaling_height;
// Half of the camera image
const f32 half_width = shared_data.width / 2.f;
const f32 half_height = shared_data.height / 2.f;
// Centered image coordinates in pixels
const f32 centered_x = image_x - (shared_data.width / 2.f);
const f32 centered_y = (shared_data.height / 2.f) - image_y; // Image coordinates increase downwards, so we have to invert this
const f32 centered_x = image_x - half_width;
const f32 centered_y = half_height - image_y; // Image coordinates increase downwards, so we have to invert this
// Camera coordinates in mm (centered, so it's the same as world coordinates)
const f32 camera_x = centered_x * mmPerPixel;
@ -932,16 +937,47 @@ static inline void pos_to_gem_state(u32 gem_num, const gem_config::gem_controlle
gem_state->pos[2] = controller.distance_mm;
gem_state->pos[3] = 0.f;
gem_state->quat[0] = 320.f - image_x;
gem_state->quat[1] = (y_pos / scaling_width) - 180.f;
gem_state->quat[2] = 1200.f;
// TODO: calculate handle position based on our world coordinate and the angles
gem_state->handle_pos[0] = camera_x;
gem_state->handle_pos[1] = camera_y;
gem_state->handle_pos[2] = controller.distance_mm + 10.0f;
gem_state->handle_pos[3] = 0.f;
// Calculate orientation
if (g_cfg.io.move == move_handler::real)
{
gem_state->quat[0] = move_data.quaternion[1]; // x
gem_state->quat[1] = move_data.quaternion[2]; // y
gem_state->quat[2] = move_data.quaternion[3]; // z
gem_state->quat[3] = move_data.quaternion[0]; // w
}
else
{
static constexpr f32 PI = 3.14159265f;
const auto degree_to_rad = [](f32 degree) -> f32 { return degree * PI / 180.0f; };
static constexpr f32 CONE = 10.0f / 2.0f;
const f32 roll = -degree_to_rad((image_y - half_height) / half_height * CONE); // This is actually the pitch
const f32 pitch = -degree_to_rad((image_x - half_width) / half_width * CONE); // This is actually the yaw
const f32 yaw = degree_to_rad(0.0f);
const f32 cr = std::cos(roll * 0.5f);
const f32 sr = std::sin(roll * 0.5f);
const f32 cp = std::cos(pitch * 0.5f);
const f32 sp = std::sin(pitch * 0.5f);
const f32 cy = std::cos(yaw * 0.5f);
const f32 sy = std::sin(yaw * 0.5f);
const f32 q_x = sr * cp * cy - cr * sp * sy;
const f32 q_y = cr * sp * cy + sr * cp * sy;
const f32 q_z = cr * cp * sy - sr * sp * cy;
const f32 q_w = cr * cp * cy + sr * sp * sy;
gem_state->quat[0] = q_x;
gem_state->quat[1] = q_y;
gem_state->quat[2] = q_z;
gem_state->quat[3] = q_w;
}
if (g_cfg.io.show_move_cursor)
{
draw_overlay_cursor(gem_num, controller, x_pos, y_pos, x_max, y_max);
@ -1056,7 +1092,7 @@ static inline void ds3_get_stick_values(u32 gem_num, const std::shared_ptr<Pad>&
}
template <typename T>
static void ds3_pos_to_gem_state(u32 gem_num, const gem_config::gem_controller& controller, T& gem_state)
static void ds3_pos_to_gem_state(u32 gem_num, gem_config::gem_controller& controller, T& gem_state)
{
if (!gem_state || !is_input_allowed())
{
@ -1078,7 +1114,7 @@ static void ds3_pos_to_gem_state(u32 gem_num, const gem_config::gem_controller&
if constexpr (std::is_same_v<T, vm::ptr<CellGemState>>)
{
pos_to_gem_state(gem_num, controller, gem_state, ds3_pos_x, ds3_pos_y, ds3_max_x, ds3_max_y);
pos_to_gem_state(gem_num, controller, gem_state, ds3_pos_x, ds3_pos_y, ds3_max_x, ds3_max_y, {});
}
else if constexpr (std::is_same_v<T, vm::ptr<CellGemImageState>>)
{
@ -1087,7 +1123,7 @@ static void ds3_pos_to_gem_state(u32 gem_num, const gem_config::gem_controller&
}
template <typename T>
static void ps_move_pos_to_gem_state(u32 gem_num, const gem_config::gem_controller& controller, T& gem_state)
static void ps_move_pos_to_gem_state(u32 gem_num, gem_config::gem_controller& controller, T& gem_state)
{
if (!gem_state || !is_input_allowed())
{
@ -1104,12 +1140,17 @@ static void ps_move_pos_to_gem_state(u32 gem_num, const gem_config::gem_controll
return;
}
auto& tracker = g_fxo->get<named_thread<gem_tracker>>(); // Let's not lock the mutex. This not really important here
const ps_move_info& info = tracker.get_info(gem_num);
auto& tracker = g_fxo->get<named_thread<gem_tracker>>();
const ps_move_info info = tracker.get_info(gem_num);
if constexpr (std::is_same_v<T, vm::ptr<CellGemState>>)
{
pos_to_gem_state(gem_num, controller, gem_state, info.x_pos, info.y_pos, info.x_max, info.y_max);
gem_state->temperature = pad->move_data.temperature;
gem_state->accel[0] = pad->move_data.accelerometer_x * 1000; // linear velocity in mm/s²
gem_state->accel[1] = pad->move_data.accelerometer_y * 1000; // linear velocity in mm/s²
gem_state->accel[2] = pad->move_data.accelerometer_z * 1000; // linear velocity in mm/s²
pos_to_gem_state(gem_num, controller, gem_state, info.x_pos, info.y_pos, info.x_max, info.y_max, pad->move_data);
}
else if constexpr (std::is_same_v<T, vm::ptr<CellGemImageState>>)
{
@ -1267,7 +1308,7 @@ static bool mouse_input_to_pad(u32 mouse_no, be_t<u16>& digital_buttons, be_t<u1
}
template <typename T>
static void mouse_pos_to_gem_state(u32 mouse_no, const gem_config::gem_controller& controller, T& gem_state)
static void mouse_pos_to_gem_state(u32 mouse_no, gem_config::gem_controller& controller, T& gem_state)
{
if (!gem_state || !is_input_allowed())
{
@ -1290,7 +1331,7 @@ static void mouse_pos_to_gem_state(u32 mouse_no, const gem_config::gem_controlle
if constexpr (std::is_same_v<T, vm::ptr<CellGemState>>)
{
pos_to_gem_state(mouse_no, controller, gem_state, mouse.x_pos, mouse.y_pos, mouse.x_max, mouse.y_max);
pos_to_gem_state(mouse_no, controller, gem_state, mouse.x_pos, mouse.y_pos, mouse.x_max, mouse.y_max, {});
}
else if constexpr (std::is_same_v<T, vm::ptr<CellGemImageState>>)
{
@ -1340,7 +1381,7 @@ static bool gun_input_to_pad(u32 gem_no, be_t<u16>& digital_buttons, be_t<u16>&
}
template <typename T>
static void gun_pos_to_gem_state(u32 gem_no, const gem_config::gem_controller& controller, T& gem_state)
static void gun_pos_to_gem_state(u32 gem_no, gem_config::gem_controller& controller, T& gem_state)
{
if (!gem_state || !is_input_allowed())
return;
@ -1358,7 +1399,7 @@ static void gun_pos_to_gem_state(u32 gem_no, const gem_config::gem_controller& c
if constexpr (std::is_same_v<T, vm::ptr<CellGemState>>)
{
pos_to_gem_state(gem_no, controller, gem_state, x_pos, y_pos, x_max, y_max);
pos_to_gem_state(gem_no, controller, gem_state, x_pos, y_pos, x_max, y_max, {});
}
else if constexpr (std::is_same_v<T, vm::ptr<CellGemImageState>>)
{
@ -1795,7 +1836,7 @@ error_code cellGemGetImageState(u32 gem_num, vm::ptr<CellGemImageState> gem_imag
if (g_cfg.io.move != move_handler::null)
{
auto& shared_data = g_fxo->get<gem_camera_shared>();
const auto& controller = gem.controllers[gem_num];
auto& controller = gem.controllers[gem_num];
gem_image_state->frame_timestamp = shared_data.frame_timestamp_us.load();
gem_image_state->timestamp = gem_image_state->frame_timestamp + 10;
@ -1866,7 +1907,7 @@ error_code cellGemGetInertialState(u32 gem_num, u32 state_flag, u64 timestamp, v
{
case move_handler::real:
{
// Get temperature
// Get temperature and sensor data
{
std::lock_guard lock(pad::g_pad_mutex);
@ -1876,6 +1917,12 @@ error_code cellGemGetInertialState(u32 gem_num, u32 state_flag, u64 timestamp, v
if (pad && pad->m_pad_handler == pad_handler::move && (pad->m_port_status & CELL_PAD_STATUS_CONNECTED))
{
inertial_state->temperature = pad->move_data.temperature;
inertial_state->accelerometer[0] = pad->move_data.accelerometer_x;
inertial_state->accelerometer[1] = pad->move_data.accelerometer_y;
inertial_state->accelerometer[2] = pad->move_data.accelerometer_z;
inertial_state->gyro[0] = pad->move_data.gyro_x;
inertial_state->gyro[1] = pad->move_data.gyro_y;
inertial_state->gyro[2] = pad->move_data.gyro_z;
}
}
@ -2119,14 +2166,13 @@ error_code cellGemGetState(u32 gem_num, u32 flag, u64 time_parameter, vm::ptr<Ce
gem_state->timestamp = (get_guest_system_time() - gem.start_timestamp_us);
gem_state->camera_pitch_angle = 0.f;
gem_state->quat[3] = 1.f;
switch (g_cfg.io.move)
{
case move_handler::real:
{
auto& tracker = g_fxo->get<named_thread<gem_tracker>>(); // Let's not lock the mutex. This not really important here
const ps_move_info& info = tracker.get_info(gem_num);
auto& tracker = g_fxo->get<named_thread<gem_tracker>>();
const ps_move_info info = tracker.get_info(gem_num);
ds3_input_to_pad(gem_num, gem_state->pad.digitalbuttons, gem_state->pad.analog_T);
ps_move_pos_to_gem_state(gem_num, controller, gem_state);

View file

@ -333,6 +333,10 @@ void lv2_socket_p2p::close()
auto& nc = g_fxo->get<p2p_context>();
{
std::lock_guard lock(nc.list_p2p_ports_mutex);
if (!nc.list_p2p_ports.contains(port))
return;
auto& p2p_port = ::at32(nc.list_p2p_ports, port);
{
std::lock_guard lock(p2p_port.bound_p2p_vports_mutex);

View file

@ -516,9 +516,14 @@ error_code sys_rsx_context_attribute(u32 context_id, u32 package_id, u64 a3, u64
const auto render = rsx::get_current_renderer();
if (!render->dma_address || context_id != 0x55555555)
if (!render->dma_address)
{
return CELL_EINVAL;
return { CELL_EINVAL, "dma_address is 0" };
}
if (context_id != 0x55555555)
{
return { CELL_EINVAL, "context_id is 0x%x", context_id };
}
auto &driverInfo = vm::_ref<RsxDriverInfo>(render->driver_info);
@ -534,7 +539,6 @@ error_code sys_rsx_context_attribute(u32 context_id, u32 package_id, u64 a3, u64
set_rsx_dmactl(render, get_put);
break;
}
case 0x100: // Display mode set
break;
case 0x101: // Display sync set, cellGcmSetFlipMode
@ -594,9 +598,8 @@ error_code sys_rsx_context_attribute(u32 context_id, u32 package_id, u64 a3, u64
return {};
}
break;
}
break;
case 0x103: // Display Queue
{
// NOTE: There currently seem to only be 2 active heads on PS3
@ -615,9 +618,8 @@ error_code sys_rsx_context_attribute(u32 context_id, u32 package_id, u64 a3, u64
{
render->post_vblank_event(get_system_time());
}
break;
}
break;
case 0x104: // Display buffer
{
const u8 id = a3 & 0xFF;
@ -641,9 +643,8 @@ error_code sys_rsx_context_attribute(u32 context_id, u32 package_id, u64 a3, u64
render->display_buffers[id].offset = offset;
render->display_buffers_count = std::max<u32>(id + 1, render->display_buffers_count);
break;
}
break;
case 0x105: // destroy buffer?
break;
@ -684,9 +685,8 @@ error_code sys_rsx_context_attribute(u32 context_id, u32 package_id, u64 a3, u64
{
flipStatus = (flipStatus & static_cast<u32>(a4)) | static_cast<u32>(a5);
});
break;
}
break;
case 0x10D: // Called by cellGcmInitCursor
break;
@ -721,7 +721,7 @@ error_code sys_rsx_context_attribute(u32 context_id, u32 package_id, u64 a3, u64
{
if (!size || !pitch)
{
return CELL_EINVAL;
return { CELL_EINVAL, "size or pitch are 0 (size=%d, pitch=%d)", size, pitch };
}
u32 limit = -1;
@ -735,7 +735,7 @@ error_code sys_rsx_context_attribute(u32 context_id, u32 package_id, u64 a3, u64
if (!range.valid() || range.end >= limit)
{
return CELL_EINVAL;
return { CELL_EINVAL, "range invalid (valid=%d, end=%d, limit=%d)", range.valid(), range.end, limit };
}
// Hardcoded value in gcm
@ -757,7 +757,7 @@ error_code sys_rsx_context_attribute(u32 context_id, u32 package_id, u64 a3, u64
{
if (render->iomap_table.ea[io] == umax)
{
return CELL_EINVAL;
return { CELL_EINVAL, "iomap_table ea is umax" };
}
}
}
@ -770,9 +770,8 @@ error_code sys_rsx_context_attribute(u32 context_id, u32 package_id, u64 a3, u64
tile.base = base;
tile.bank = base;
tile.bound = bound;
break;
}
break;
case 0x301: // Depth-buffer (Z-cull)
{
//a4 high = region = (1 << 0) | (zFormat << 4) | (aaFormat << 8);
@ -806,7 +805,7 @@ error_code sys_rsx_context_attribute(u32 context_id, u32 package_id, u64 a3, u64
// width and height are not allowed to be zero (checked by range.valid())
if (!cull_range.valid() || cull_range.end >= 3u << 20 || offset >= render->local_mem_size)
{
return CELL_EINVAL;
return { CELL_EINVAL, "cull_range invalid (valid=%d, end=%d, offset=%d, local_mem_size=%d)", cull_range.valid(), cull_range.end, offset, render->local_mem_size };
}
if (a5 & 0xF0000000)
@ -835,8 +834,8 @@ error_code sys_rsx_context_attribute(u32 context_id, u32 package_id, u64 a3, u64
zcull.sRef = ((a6 >> 32) >> 16) & 0xFF;
zcull.sMask = ((a6 >> 32) >> 24) & 0xFF;
zcull.bound = bound;
break;
}
break;
case 0x302: // something with zcull
break;
@ -867,13 +866,12 @@ error_code sys_rsx_context_attribute(u32 context_id, u32 package_id, u64 a3, u64
render->send_event(0, SYS_RSX_EVENT_FLIP_BASE << 1, 0);
break;
}
case 0xFED: // hack: vblank command
{
if (cpu_thread::get_current<ppu_thread>())
{
// VBLANK/RSX thread only
return CELL_EINVAL;
return { CELL_EINVAL, "wrong thread" };
}
// NOTE: There currently seem to only be 2 active heads on PS3
@ -916,7 +914,7 @@ error_code sys_rsx_context_attribute(u32 context_id, u32 package_id, u64 a3, u64
}
default:
return CELL_EINVAL;
return { CELL_EINVAL, "unsupported package id %d", package_id };
}
return CELL_OK;

View file

@ -466,12 +466,13 @@ struct ps_move_data
bool external_device_read_requested = false;
bool external_device_write_requested = false;
s16 accelerometer_x = 0;
s16 accelerometer_y = 0;
s16 accelerometer_z = 0;
s16 gyro_x = 0;
s16 gyro_y = 0;
s16 gyro_z = 0;
std::array<f32, 4> quaternion { 1.0f, 0.0f, 0.0f, 0.0f }; // quaternion orientation (x,y,z,w) of controller relative to default (facing the camera with buttons up)
f32 accelerometer_x = 0; // linear velocity in m/s²
f32 accelerometer_y = 0; // linear velocity in m/s²
f32 accelerometer_z = 0; // linear velocity in m/s²
f32 gyro_x = 0; // angular velocity in rad/s
f32 gyro_y = 0; // angular velocity in rad/s
f32 gyro_z = 0; // angular velocity in rad/s
s16 temperature = 0;
};

View file

@ -5,6 +5,7 @@
#include "TextureUtils.h"
#include "Emu/Memory/vm.h"
#include "Emu/RSX/Host/MM.h"
#include "util/vm.hpp"
#include <list>
@ -29,8 +30,7 @@ namespace rsx
{
ensure(range.is_page_range());
//rsx_log.error("memory_protect(0x%x, 0x%x, %x)", static_cast<u32>(range.start), static_cast<u32>(range.length()), static_cast<u32>(prot));
utils::memory_protect(vm::base(range.start), range.length(), prot);
rsx::mm_protect(vm::base(range.start), range.length(), prot);
#ifdef TEXTURE_CACHE_DEBUG
tex_cache_checker.set_protection(range, prot);

View file

@ -7,6 +7,7 @@
#include "Emu/Memory/vm_locking.h"
#include "Emu/RSX/rsx_methods.h"
#include "Emu/RSX/Host/MM.h"
#include "Emu/RSX/Host/RSXDMAWriter.h"
#include "Emu/RSX/NV47/HW/context_accessors.define.h"
@ -1082,6 +1083,8 @@ void GLGSRender::patch_transform_constants(rsx::context* ctx, u32 index, u32 cou
bool GLGSRender::on_access_violation(u32 address, bool is_writing)
{
rsx::mm_flush(address);
const bool can_flush = is_current_thread();
const rsx::invalidation_cause cause = is_writing
? (can_flush ? rsx::invalidation_cause::write : rsx::invalidation_cause::deferred_write)

110
rpcs3/Emu/RSX/Host/MM.cpp Normal file
View file

@ -0,0 +1,110 @@
#include "stdafx.h"
#include "MM.h"
#include <Emu/RSX/Common/simple_array.hpp>
#include <Emu/RSX/RSXOffload.h>
#include <Emu/Memory/vm.h>
#include <Emu/IdManager.h>
#include <Emu/system_config.h>
#include <Utilities/address_range.h>
#include <Utilities/mutex.h>
namespace rsx
{
rsx::simple_array<MM_block> g_deferred_mprotect_queue;
shared_mutex g_mprotect_queue_lock;
void mm_flush_mprotect_queue_internal()
{
for (const auto& block : g_deferred_mprotect_queue)
{
utils::memory_protect(reinterpret_cast<void*>(block.start), block.length, block.prot);
}
g_deferred_mprotect_queue.clear();
}
void mm_defer_mprotect_internal(u64 start, u64 length, utils::protection prot)
{
// We could stack and merge requests here, but that is more trouble than it is truly worth.
// A fresh call to memory_protect only takes a few nanoseconds of setup overhead, it is not worth the risk of hanging because of conflicts.
g_deferred_mprotect_queue.push_back({ start, length, prot });
}
void mm_protect(void* ptr, u64 length, utils::protection prot)
{
if (g_cfg.video.disable_async_host_memory_manager)
{
utils::memory_protect(ptr, length, prot);
return;
}
// Naive merge. Eventually it makes more sense to do conflict resolution, but it's not as important.
const auto start = reinterpret_cast<u64>(ptr);
const auto end = start + length;
std::lock_guard lock(g_mprotect_queue_lock);
if (prot == utils::protection::rw || prot == utils::protection::wx)
{
// Basically an unlock op. Flush if any overlap is detected
for (const auto& block : g_deferred_mprotect_queue)
{
if (block.overlaps(start, end))
{
mm_flush_mprotect_queue_internal();
break;
}
}
utils::memory_protect(ptr, length, prot);
return;
}
// No, Ro, etc.
mm_defer_mprotect_internal(start, length, prot);
}
void mm_flush()
{
std::lock_guard lock(g_mprotect_queue_lock);
mm_flush_mprotect_queue_internal();
}
void mm_flush(u32 vm_address)
{
std::lock_guard lock(g_mprotect_queue_lock);
if (g_deferred_mprotect_queue.empty())
{
return;
}
const auto addr = reinterpret_cast<u64>(vm::base(vm_address));
for (const auto& block : g_deferred_mprotect_queue)
{
if (block.overlaps(addr))
{
mm_flush_mprotect_queue_internal();
return;
}
}
}
void mm_flush_lazy()
{
if (!g_cfg.video.multithreaded_rsx)
{
mm_flush();
return;
}
std::lock_guard lock(g_mprotect_queue_lock);
if (g_deferred_mprotect_queue.empty())
{
return;
}
auto& rsxdma = g_fxo->get<rsx::dma_manager>();
rsxdma.backend_ctrl(mm_backend_ctrl::cmd_mm_flush, nullptr);
}
}

40
rpcs3/Emu/RSX/Host/MM.h Normal file
View file

@ -0,0 +1,40 @@
#pragma once
#include <util/types.hpp>
#include <util/vm.hpp>
namespace rsx
{
struct MM_block
{
u64 start;
u64 length;
utils::protection prot;
inline bool overlaps(u64 start, u64 end) const
{
// [Start, End] is not a proper closed range, there is an off-by-one by design.
// FIXME: Use address_range64
const u64 this_end = this->start + this->length;
return (this->start < end && start < this_end);
}
inline bool overlaps(u64 addr) const
{
// [Start, End] is not a proper closed range, there is an off-by-one by design.
// FIXME: Use address_range64
const u64 this_end = this->start + this->length;
return (addr >= start && addr < this_end);
}
};
enum mm_backend_ctrl : u32
{
cmd_mm_flush = 0x81000000,
};
void mm_protect(void* start, u64 length, utils::protection prot);
void mm_flush_lazy();
void mm_flush(u32 vm_address);
void mm_flush();
}

View file

@ -7,6 +7,9 @@
namespace rsx
{
void mm_flush_lazy();
void mm_flush();
namespace util
{
template <bool FlushDMA, bool FlushPipe>
@ -24,17 +27,24 @@ namespace rsx
return;
}
if constexpr (FlushDMA)
if constexpr (FlushDMA || FlushPipe)
{
// If the backend handled the request, this call will basically be a NOP
g_fxo->get<rsx::dma_manager>().sync();
}
// Release op must be acoompanied by MM flush.
// FlushPipe implicitly does a MM flush but FlushDMA does not. Trigger the flush here
rsx::mm_flush();
if constexpr (FlushPipe)
{
// Manually flush the pipeline.
// It is possible to stream report writes using the host GPU, but that generates too much submit traffic.
RSX(ctx)->sync();
if constexpr (FlushDMA)
{
// If the backend handled the request, this call will basically be a NOP
g_fxo->get<rsx::dma_manager>().sync();
}
if constexpr (FlushPipe)
{
// Manually flush the pipeline.
// It is possible to stream report writes using the host GPU, but that generates too much submit traffic.
RSX(ctx)->sync();
}
}
if (handled)

View file

@ -9,6 +9,7 @@
#include "Common/time.hpp"
#include "Core/RSXReservationLock.hpp"
#include "Core/RSXEngLock.hpp"
#include "Host/MM.h"
#include "Host/RSXDMAWriter.h"
#include "NV47/HW/context.h"
#include "Program/GLSLCommon.h"
@ -2603,8 +2604,14 @@ namespace rsx
rsx_log.error("Depth texture bound to pipeline with unexpected format 0x%X", format);
}
}
else if (!backend_config.supports_hw_renormalization)
else if (!backend_config.supports_hw_renormalization /* &&
tex.min_filter() == rsx::texture_minify_filter::nearest &&
tex.mag_filter() == rsx::texture_magnify_filter::nearest*/)
{
// FIXME: This check should only apply to point-sampled textures. However, it severely regresses some games (id tech 5).
// This is because even when filtering is active, the error from the PS3 texture expansion still applies.
// A proper fix is to expand these formats into BGRA8 when high texture precision is required. That requires different GUI settings and inflation shaders, so it will be handled separately.
switch (format)
{
case CELL_GCM_TEXTURE_A1R5G5B5:
@ -3175,6 +3182,8 @@ namespace rsx
{
m_eng_interrupt_mask.clear(rsx::pipe_flush_interrupt);
mm_flush();
if (zcull_ctrl->has_pending())
{
zcull_ctrl->sync(this);
@ -3627,10 +3636,25 @@ namespace rsx
on_invalidate_memory_range(m_invalidated_memory_range, rsx::invalidation_cause::read);
}
// Host sync
rsx::mm_flush();
on_invalidate_memory_range(m_invalidated_memory_range, rsx::invalidation_cause::unmap);
m_invalidated_memory_range.invalidate();
}
void thread::renderctl(u32 request_code, void* args)
{
switch (request_code)
{
case rsx::mm_backend_ctrl::cmd_mm_flush:
rsx::mm_flush();
break;
default:
fmt::throw_exception("Unknown backend request: 0x%x", request_code);
}
}
//Pause/cont wrappers for FIFO ctrl. Never call this from rsx thread itself!
void thread::pause()
{
@ -3696,6 +3720,9 @@ namespace rsx
{
bool pause_emulator = false;
// MM sync. This is a pre-emptive operation, so we can use a deferred request.
rsx::mm_flush_lazy();
// Marks the end of a frame scope GPU-side
if (g_user_asked_for_frame_capture.exchange(false) && !capture_current_frame)
{

View file

@ -404,7 +404,7 @@ namespace rsx
virtual void notify_tile_unbound(u32 /*tile*/) {}
// control
virtual void renderctl(u32 /*request_code*/, void* /*args*/) {}
virtual void renderctl(u32 request_code, void* args);
// zcull
void notify_zcull_info_changed();

View file

@ -9,7 +9,7 @@ namespace vk
enum // callback commands
{
rctrl_queue_submit = 0x80000000,
rctrl_run_gc = 0x80000001
rctrl_run_gc = 0x80000001,
};
struct submit_packet

View file

@ -15,6 +15,7 @@
#include "vkutils/scratch.h"
#include "Emu/RSX/rsx_methods.h"
#include "Emu/RSX/Host/MM.h"
#include "Emu/RSX/Host/RSXDMAWriter.h"
#include "Emu/RSX/NV47/HW/context_accessors.define.h"
#include "Emu/Memory/vm_locking.h"
@ -1010,6 +1011,8 @@ VKGSRender::~VKGSRender()
bool VKGSRender::on_access_violation(u32 address, bool is_writing)
{
rsx::mm_flush(address);
vk::texture_cache::thrashed_set result;
{
const rsx::invalidation_cause cause = is_writing ? rsx::invalidation_cause::deferred_write : rsx::invalidation_cause::deferred_read;
@ -2460,6 +2463,9 @@ void VKGSRender::close_and_submit_command_buffer(vk::fence* pFence, VkSemaphore
{
ensure(!m_queue_status.test_and_set(flush_queue_state::flushing));
// Host MM sync before executing anything on the GPU
rsx::mm_flush();
// Workaround for deadlock occuring during RSX offloader fault
// TODO: Restructure command submission infrastructure to avoid this condition
const bool sync_success = g_fxo->get<rsx::dma_manager>().sync();
@ -2824,7 +2830,7 @@ void VKGSRender::renderctl(u32 request_code, void* args)
break;
}
default:
fmt::throw_exception("Unhandled request code 0x%x", request_code);
rsx::thread::renderctl(request_code, args);
}
}

View file

@ -178,6 +178,7 @@ struct cfg_root : cfg::node
cfg::_bool decr_memory_layout{ this, "DECR memory layout", false}; // Force enable increased allowed main memory range as DECR console
cfg::_bool host_label_synchronization{ this, "Allow Host GPU Labels", false };
cfg::_bool disable_msl_fast_math{ this, "Disable MSL Fast Math", false };
cfg::_bool disable_async_host_memory_manager{ this, "Disable Asynchronous Memory Manager", false, true };
cfg::_enum<output_scaling_mode> output_scaling{ this, "Output Scaling Mode", output_scaling_mode::bilinear, true };
struct node_vk : cfg::node

View file

@ -25,7 +25,7 @@ public:
void operator()();
PadInfo& GetInfo() { return m_info; }
auto& GetPads() { return m_pads; }
std::array<std::shared_ptr<Pad>, CELL_PAD_MAX_PORT_NUM>& GetPads() { return m_pads; }
void SetRumble(const u32 pad, u8 large_motor, bool small_motor);
void SetIntercepted(bool intercepted);

View file

@ -0,0 +1,244 @@
#include "stdafx.h"
#include "ps_move_calibration.h"
LOG_CHANNEL(move_log, "Move");
// This is basically the same as in ps move api
static inline s32 psmove_calibration_decode_16bit_unsigned(const u8* data, u32 offset)
{
const u8 low = data[offset] & 0xFF;
const u8 high = (data[offset + 1]) & 0xFF;
return (low | (high << 8)) - zero_shift;
}
static inline s16 psmove_calibration_decode_16bit_signed(const u8* data, u32 offset)
{
const u16 low = data[offset] & 0xFF;
const u16 high = (data[offset + 1]) & 0xFF;
return static_cast<s16>(low | (high << 8));
}
static inline u32 psmove_calibration_decode_12bits(const u8* data, u32 offset)
{
const u8 low = data[offset] & 0xFF;
const u8 high = (data[offset + 1]) & 0xFF;
return low | (high << 8);
}
static inline f32 psmove_calibration_decode_float(const u8* data, u32 offset)
{
union
{
uint32_t u32;
float f;
} v {
.u32 = static_cast<u32>( (data[offset] & 0xFF) |
((data[offset + 1] & 0xFF) << 8) |
((data[offset + 2] & 0xFF) << 16) |
((data[offset + 3] & 0xFF) << 24))
};
return v.f;
}
static void psmove_dump_calibration(const reports::ps_move_calibration_blob& calibration, const ps_move_device& device)
{
int t, x, y, z;
float fx, fy, fz;
const u8* data = calibration.data.data();
std::string msg;
switch (device.model)
{
case ps_move_model::ZCM1:
t = psmove_calibration_decode_12bits(data, 0x02);
fmt::append(msg, "Temperature: 0x%04X\n", t);
for (int orientation = 0; orientation < 6; orientation++)
{
x = psmove_calibration_decode_16bit_unsigned(data, 0x04 + 6 * orientation);
y = psmove_calibration_decode_16bit_unsigned(data, 0x04 + 6 * orientation + 2);
z = psmove_calibration_decode_16bit_unsigned(data, 0x04 + 6 * orientation + 4);
fmt::append(msg, "Orientation #%d: (%5d | %5d | %5d)\n", orientation, x, y, z);
}
t = psmove_calibration_decode_12bits(data, 0x42);
fmt::append(msg, "Temperature: 0x%04X\n", t);
for (int orientation = 0; orientation < 3; orientation++)
{
x = psmove_calibration_decode_16bit_unsigned(data, 0x46 + 8 * orientation);
y = psmove_calibration_decode_16bit_unsigned(data, 0x46 + 8 * orientation + 2);
z = psmove_calibration_decode_16bit_unsigned(data, 0x46 + 8 * orientation + 4);
fmt::append(msg, "Gyro %c, 80 rpm: (%5d | %5d | %5d)\n", "XYZ"[orientation], x, y, z);
}
t = psmove_calibration_decode_12bits(data, 0x28);
x = psmove_calibration_decode_16bit_unsigned(data, 0x2a);
y = psmove_calibration_decode_16bit_unsigned(data, 0x2a + 2);
z = psmove_calibration_decode_16bit_unsigned(data, 0x2a + 4);
fmt::append(msg, "Temperature: 0x%04X\n", t);
fmt::append(msg, "Gyro, 0 rpm (@0x2a): (%5d | %5d | %5d)\n", x, y, z);
t = psmove_calibration_decode_12bits(data, 0x30);
x = psmove_calibration_decode_16bit_unsigned(data, 0x32);
y = psmove_calibration_decode_16bit_unsigned(data, 0x32 + 2);
z = psmove_calibration_decode_16bit_unsigned(data, 0x32 + 4);
fmt::append(msg, "Temperature: 0x%04X\n", t);
fmt::append(msg, "Gyro, 0 rpm (@0x32): (%5d | %5d | %5d)\n", x, y, z);
t = psmove_calibration_decode_12bits(data, 0x5c);
fx = psmove_calibration_decode_float(data, 0x5e);
fy = psmove_calibration_decode_float(data, 0x5e + 4);
fz = psmove_calibration_decode_float(data, 0x5e + 8);
fmt::append(msg, "Temperature: 0x%04X\n", t);
fmt::append(msg, "Vector @0x5e: (%f | %f | %f)\n", fx, fy, fz);
fx = psmove_calibration_decode_float(data, 0x6a);
fy = psmove_calibration_decode_float(data, 0x6a + 4);
fz = psmove_calibration_decode_float(data, 0x6a + 8);
fmt::append(msg, "Vector @0x6a: (%f | %f | %f)\n", fx, fy, fz);
fmt::append(msg, "byte @0x3f: 0x%02x\n", static_cast<u8>(data[0x3f]));
fmt::append(msg, "float @0x76: %f\n", psmove_calibration_decode_float(data, 0x76));
fmt::append(msg, "float @0x7a: %f\n", psmove_calibration_decode_float(data, 0x7a));
break;
case ps_move_model::ZCM2:
for (int orientation = 0; orientation < 6; orientation++)
{
x = psmove_calibration_decode_16bit_signed(data, 0x04 + 6 * orientation);
y = psmove_calibration_decode_16bit_signed(data, 0x04 + 6 * orientation + 2);
z = psmove_calibration_decode_16bit_signed(data, 0x04 + 6 * orientation + 4);
fmt::append(msg, "Orientation #%d: (%5d | %5d | %5d)\n", orientation, x, y, z);
}
x = psmove_calibration_decode_16bit_signed(data, 0x26);
y = psmove_calibration_decode_16bit_signed(data, 0x26 + 2);
z = psmove_calibration_decode_16bit_signed(data, 0x26 + 4);
fmt::append(msg, "Gyro Bias?, 0 rpm (@0x26): (%5d | %5d | %5d)\n", x, y, z);
for (int orientation = 0; orientation < 6; orientation++)
{
x = psmove_calibration_decode_16bit_signed(data, 0x30 + 6 * orientation);
y = psmove_calibration_decode_16bit_signed(data, 0x30 + 6 * orientation + 2);
z = psmove_calibration_decode_16bit_signed(data, 0x30 + 6 * orientation + 4);
fmt::append(msg, "Gyro %c, 90 rpm: (%5d | %5d | %5d)\n", "XYZXYZ"[orientation], x, y, z);
}
break;
}
move_log.notice("Calibration:\n%s", msg);
}
void psmove_calibration_get_usb_accel_values(const reports::ps_move_calibration_blob& calibration, ps_move_device& device)
{
const u8* data = calibration.data.data();
int x1 = 0, x2 = 0, y1 = 0, y2 = 0, z1 = 0, z2 = 0;
switch (device.model)
{
case ps_move_model::ZCM1:
// Minimum (negative) value of each axis
x1 = psmove_calibration_decode_16bit_unsigned(data, 0x04 + 6 * 1);
y1 = psmove_calibration_decode_16bit_unsigned(data, 0x04 + 6 * 5 + 2);
z1 = psmove_calibration_decode_16bit_unsigned(data, 0x04 + 6 * 2 + 4);
// Maximum (positive) value of each axis
x2 = psmove_calibration_decode_16bit_unsigned(data, 0x04 + 6 * 3);
y2 = psmove_calibration_decode_16bit_unsigned(data, 0x04 + 6 * 4 + 2);
z2 = psmove_calibration_decode_16bit_unsigned(data, 0x04 + 6 * 0 + 4);
break;
case ps_move_model::ZCM2:
// Minimum (negative) value of each axis
x1 = psmove_calibration_decode_16bit_signed(data, 0x02 + 6 * 1);
y1 = psmove_calibration_decode_16bit_signed(data, 0x02 + 6 * 3 + 2);
z1 = psmove_calibration_decode_16bit_signed(data, 0x02 + 6 * 5 + 4);
// Maximum (positive) value of each axis
x2 = psmove_calibration_decode_16bit_signed(data, 0x02 + 6 * 0);
y2 = psmove_calibration_decode_16bit_signed(data, 0x02 + 6 * 2 + 2);
z2 = psmove_calibration_decode_16bit_signed(data, 0x02 + 6 * 4 + 4);
break;
}
device.calibration.accel_x_factor = 2.0f / static_cast<float>(x2 - x1);
device.calibration.accel_y_factor = 2.0f / static_cast<float>(y2 - y1);
device.calibration.accel_z_factor = 2.0f / static_cast<float>(z2 - z1);
device.calibration.accel_x_offset = -(device.calibration.accel_x_factor * static_cast<float>(x1)) - 1.0f;
device.calibration.accel_y_offset = -(device.calibration.accel_y_factor * static_cast<float>(x1)) - 1.0f;
device.calibration.accel_z_offset = -(device.calibration.accel_z_factor * static_cast<float>(x1)) - 1.0f;
}
void psmove_calibration_get_usb_gyro_values(const reports::ps_move_calibration_blob& calibration, ps_move_device& device)
{
const u8* data = calibration.data.data();
constexpr f32 PI = 3.14159265f;
constexpr f32 rpm_to_rad_per_sec = (2.0f * PI) / 60.0f;
switch (device.model)
{
case ps_move_model::ZCM1:
{
const int bx = psmove_calibration_decode_16bit_unsigned(data, 0x2a);
const int by = psmove_calibration_decode_16bit_unsigned(data, 0x2a + 2);
const int bz = psmove_calibration_decode_16bit_unsigned(data, 0x2a + 4);
const int x = psmove_calibration_decode_16bit_unsigned(data, 0x46 + 8 * 0) - bx;
const int y = psmove_calibration_decode_16bit_unsigned(data, 0x46 + 8 * 1 + 2) - by;
const int z = psmove_calibration_decode_16bit_unsigned(data, 0x46 + 8 * 2 + 4) - bz;
constexpr f32 calibration_rpm = 80.0f;
constexpr f32 factor = calibration_rpm * rpm_to_rad_per_sec;
// Per frame drift taken into account using adjusted gain values
device.calibration.gyro_x_gain = factor / static_cast<float>(x);
device.calibration.gyro_y_gain = factor / static_cast<float>(y);
device.calibration.gyro_z_gain = factor / static_cast<float>(z);
device.calibration.gyro_x_offset = 0;
device.calibration.gyro_y_offset = 0;
device.calibration.gyro_z_offset = 0;
break;
}
case ps_move_model::ZCM2:
{
// Minimum (negative) value of each axis
const int x1 = psmove_calibration_decode_16bit_signed(data, 0x30 + 6 * 3);
const int y1 = psmove_calibration_decode_16bit_signed(data, 0x30 + 6 * 4 + 2);
const int z1 = psmove_calibration_decode_16bit_signed(data, 0x30 + 6 * 5 + 4);
// Maximum (positive) values of each axis
const int x2 = psmove_calibration_decode_16bit_signed(data, 0x30 + 6 * 0);
const int y2 = psmove_calibration_decode_16bit_signed(data, 0x30 + 6 * 1 + 2);
const int z2 = psmove_calibration_decode_16bit_signed(data, 0x30 + 6 * 2 + 4);
const int dx = psmove_calibration_decode_16bit_signed(data, 0x26);
const int dy = psmove_calibration_decode_16bit_signed(data, 0x26 + 2);
const int dz = psmove_calibration_decode_16bit_signed(data, 0x26 + 4);
constexpr f32 calibration_rpm = 90.0f;
constexpr f32 calibration_hi = calibration_rpm * rpm_to_rad_per_sec;
constexpr f32 calibration_low = -calibration_rpm * rpm_to_rad_per_sec;
constexpr f32 factor = calibration_hi - calibration_low;
// Compute the gain value (the slope of the gyro reading/angular speed line)
device.calibration.gyro_x_gain = factor / static_cast<f32>(x2 - x1);
device.calibration.gyro_y_gain = factor / static_cast<f32>(y2 - y1);
device.calibration.gyro_z_gain = factor / static_cast<f32>(z2 - z1);
device.calibration.gyro_x_offset = static_cast<f32>(dx);
device.calibration.gyro_y_offset = static_cast<f32>(dy);
device.calibration.gyro_z_offset = static_cast<f32>(dz);
break;
}
}
}
void psmove_parse_calibration(const reports::ps_move_calibration_blob& calibration, ps_move_device& device)
{
psmove_dump_calibration(calibration, device);
psmove_calibration_get_usb_accel_values(calibration, device);
psmove_calibration_get_usb_gyro_values(calibration, device);
}

View file

@ -0,0 +1,5 @@
#pragma once
#include "ps_move_handler.h"
void psmove_parse_calibration(const reports::ps_move_calibration_blob& calibration, ps_move_device& device);

View file

@ -1,5 +1,6 @@
#include "stdafx.h"
#include "ps_move_handler.h"
#include "ps_move_calibration.h"
#include "Emu/Io/pad_config.h"
#include "Emu/System.h"
#include "Emu/system_config.h"
@ -57,11 +58,6 @@ namespace
usb_charging = 0xEE,
usb_charged = 0xEF,
};
enum
{
zero_shift = 0x8000,
};
}
const ps_move_input_report_common& ps_move_device::input_report_common() const
@ -223,7 +219,7 @@ hid_device* ps_move_handler::connect_move_device(ps_move_device* device, std::st
if (hid_set_nonblocking(device->bt_device, 1) == -1)
{
move_log.error("check_add_device: hid_set_nonblocking failed! Reason: %s", hid_error(device->bt_device));
move_log.error("connect_move_device: hid_set_nonblocking failed! Reason: %s", hid_error(device->bt_device));
device->close();
return nullptr;
}
@ -239,7 +235,7 @@ hid_device* ps_move_handler::connect_move_device(ps_move_device* device, std::st
if (hid_set_nonblocking(device->hidDevice, 1) == -1)
{
move_log.error("check_add_device: hid_set_nonblocking failed! Reason: %s", hid_error(device->hidDevice));
move_log.error("connect_move_device: hid_set_nonblocking failed! Reason: %s", hid_error(device->hidDevice));
device->close();
return nullptr;
}
@ -315,6 +311,61 @@ void ps_move_handler::check_add_device(hid_device* hidDevice, std::string_view p
device->hidDevice = hidDevice;
device->path = path;
// Get calibration
device->calibration.is_valid = true;
ps_move_calibration_blob calibration {};
for (int i = 0; i < 2; i++)
{
std::array<u8, PSMOVE_CALIBRATION_SIZE> cal {};
cal[0] = 0x10;
const int res = hid_get_feature_report(device->hidDevice, cal.data(), cal.size());
if (res < 0)
{
move_log.error("connect_move_device: hid_get_feature_report 0x10 (calibration) failed! result=%d, error=%s", res, hid_error(device->hidDevice));
device->calibration.is_valid = false;
break;
}
int src_offset = 0;
int dest_offset = 0;
if ((cal[1] == 0x01 && device->model == ps_move_model::ZCM1) ||
(cal[1] == 0x81 && device->model == ps_move_model::ZCM2))
{
// This is the second block
dest_offset = PSMOVE_CALIBRATION_SIZE;
src_offset = 2;
}
else if (cal[1] == 0x82 && device->model == ps_move_model::ZCM1)
{
// This is the third block
dest_offset = 2 * PSMOVE_CALIBRATION_SIZE - 2;
src_offset = 2;
}
else if (cal[1] != 0x00) // Check if this is the first block (offsets stay 0)
{
move_log.error("connect_move_device: Failed to read calibration: cal=0x%x'", cal[1]);
device->calibration.is_valid = false;
break;
}
std::memcpy(&calibration.data[dest_offset], &cal[src_offset], cal.size() - src_offset);
}
if (device->calibration.is_valid)
{
psmove_parse_calibration(calibration, *device);
}
// Initialize Fusion
FusionAhrsInitialise(&device->ahrs);
device->ahrs.settings.convention = FusionConvention::FusionConventionEnu;
device->ahrs.settings.gain = 0.0f; // If gain is set, the algorithm tries to adjust the orientation over time.
FusionAhrsSetSettings(&device->ahrs, &device->ahrs.settings);
FusionAhrsReset(&device->ahrs);
// Activate
if (send_output_report(device) == -1)
{
@ -620,41 +671,107 @@ void ps_move_handler::get_extended_info(const pad_ensemble& binding)
const ps_move_input_report_common& input = dev->input_report_common();
constexpr f32 MOVE_ONE_G = 4096.0f; // This is just a rough estimate and probably depends on the device
// The default position is flat on the ground, pointing forward.
// The accelerometers constantly measure G forces.
// The gyros measure changes in orientation and will reset when the device isn't moved anymore.
s16 accel_x = input.accel_x_2; // Increases if the device is rolled to the left
s16 accel_y = input.accel_y_2; // Increases if the device is pitched upwards
s16 accel_z = input.accel_z_2; // Increases if the device is moved upwards
s16 gyro_x = input.gyro_x_2; // Increases if the device is pitched upwards
s16 gyro_y = input.gyro_y_2; // Increases if the device is rolled to the right
s16 gyro_z = input.gyro_z_2; // Increases if the device is yawed to the left
s16 accel_x = input.accel_x_1; // Increases if the device is rolled to the left
s16 accel_y = input.accel_y_1; // Increases if the device is pitched upwards
s16 accel_z = input.accel_z_1; // Increases if the device is moved upwards
s16 gyro_x = input.gyro_x_1; // Increases if the device is pitched upwards
s16 gyro_y = input.gyro_y_1; // Increases if the device is rolled to the right
s16 gyro_z = input.gyro_z_1; // Increases if the device is yawed to the left
if (dev->model == ps_move_model::ZCM1)
{
accel_x -= zero_shift;
accel_y -= zero_shift;
accel_z -= zero_shift;
gyro_x -= zero_shift;
gyro_y -= zero_shift;
gyro_z -= zero_shift;
accel_x = (input.accel_x_1 + input.accel_x_2) / 2 - zero_shift;
accel_y = (input.accel_y_1 + input.accel_y_2) / 2 - zero_shift;
accel_z = (input.accel_z_1 + input.accel_z_2) / 2 - zero_shift;
gyro_x = (input.gyro_x_1 + input.gyro_x_2) / 2 - zero_shift;
gyro_y = (input.gyro_y_1 + input.gyro_y_2) / 2 - zero_shift;
gyro_z = (input.gyro_z_1 + input.gyro_z_2) / 2 - zero_shift;
}
pad->m_sensors[0].m_value = Clamp0To1023(512.0f + (MOTION_ONE_G * (accel_x / MOVE_ONE_G) * -1.0f));
pad->m_sensors[1].m_value = Clamp0To1023(512.0f + (MOTION_ONE_G * (accel_z / MOVE_ONE_G) * -1.0f));
pad->m_sensors[2].m_value = Clamp0To1023(512.0f + (MOTION_ONE_G * (accel_y / MOVE_ONE_G)));
pad->m_sensors[3].m_value = Clamp0To1023(512.0f + (MOTION_ONE_G * (gyro_z / MOVE_ONE_G) * -1.0f));
// Apply calibration
if (dev->calibration.is_valid)
{
pad->move_data.accelerometer_x = accel_x * dev->calibration.accel_x_factor + dev->calibration.accel_x_offset;
pad->move_data.accelerometer_y = accel_y * dev->calibration.accel_y_factor + dev->calibration.accel_y_offset;
pad->move_data.accelerometer_z = accel_z * dev->calibration.accel_z_factor + dev->calibration.accel_z_offset;
pad->move_data.gyro_x = (gyro_x - dev->calibration.gyro_x_offset) * dev->calibration.gyro_x_gain;
pad->move_data.gyro_y = (gyro_y - dev->calibration.gyro_y_offset) * dev->calibration.gyro_y_gain;
pad->move_data.gyro_z = (gyro_z - dev->calibration.gyro_z_offset) * dev->calibration.gyro_z_gain;
}
else
{
constexpr f32 MOVE_ONE_G = 4096.0f; // This is just a rough estimate and probably depends on the device
pad->move_data.accelerometer_x = accel_x / MOVE_ONE_G;
pad->move_data.accelerometer_y = accel_y / MOVE_ONE_G;
pad->move_data.accelerometer_z = accel_z / MOVE_ONE_G;
pad->move_data.gyro_x = gyro_x / MOVE_ONE_G;
pad->move_data.gyro_y = gyro_y / MOVE_ONE_G;
pad->move_data.gyro_z = gyro_z / MOVE_ONE_G;
}
pad->move_data.accelerometer_x = accel_x;
pad->move_data.accelerometer_y = accel_y;
pad->move_data.accelerometer_z = accel_z;
pad->move_data.gyro_x = gyro_x;
pad->move_data.gyro_y = gyro_y;
pad->move_data.gyro_z = gyro_z;
pad->move_data.temperature = ((input.temperature << 4) | ((input.magnetometer_x & 0xF0) >> 4));
pad->m_sensors[0].m_value = Clamp0To1023(512.0f + (MOTION_ONE_G * pad->move_data.accelerometer_x * -1.0f));
pad->m_sensors[1].m_value = Clamp0To1023(512.0f + (MOTION_ONE_G * pad->move_data.accelerometer_y * -1.0f));
pad->m_sensors[2].m_value = Clamp0To1023(512.0f + (MOTION_ONE_G * pad->move_data.accelerometer_z));
pad->m_sensors[3].m_value = Clamp0To1023(512.0f + (MOTION_ONE_G * pad->move_data.gyro_z * -1.0f));
// Get elapsed time since last update
const u64 now_us = get_system_time();
const float elapsed_sec = (dev->last_ahrs_update_time_us == 0) ? 0.0f : ((now_us - dev->last_ahrs_update_time_us) / 1'000'000.0f);
dev->last_ahrs_update_time_us = now_us;
// The ps move handler's axis may differ from the Fusion axis, so we have to map them correctly.
// Don't ask how the axis work. It's basically been trial and error.
ensure(dev->ahrs.settings.convention == FusionConvention::FusionConventionEnu); // East-North-Up
const FusionVector accelerometer{
.axis {
.x = -pad->move_data.accelerometer_x,
.y = +pad->move_data.accelerometer_y,
.z = +pad->move_data.accelerometer_z
}
};
static constexpr f32 PI = 3.14159265f;
const auto rad_to_degree = [](f32 radians) -> f32 { return radians * 180.0f / PI; };
const FusionVector gyroscope{
.axis {
.x = +rad_to_degree(pad->move_data.gyro_x),
.y = +rad_to_degree(pad->move_data.gyro_z),
.z = -rad_to_degree(pad->move_data.gyro_y)
}
};
FusionVector magnetometer {};
// TODO: use magnetometer if possible
//if (dev->model == ps_move_model::ZCM1)
//{
// const ps_move_input_report_ZCM1& input = dev->input_report_ZCM1;
// magnetometer = FusionVector{
// .axis {
// .x = input.magnetometer_x2,
// .y = input.magnetometer_y,
// .z = input.magnetometer_z
// }
// };
//}
// Update Fusion
FusionAhrsUpdate(&dev->ahrs, gyroscope, accelerometer, magnetometer, elapsed_sec);
// Get quaternion
const FusionQuaternion quaternion = FusionAhrsGetQuaternion(&dev->ahrs);
pad->move_data.quaternion[0] = quaternion.array[0];
pad->move_data.quaternion[1] = quaternion.array[1];
pad->move_data.quaternion[2] = quaternion.array[2];
pad->move_data.quaternion[3] = quaternion.array[3];
handle_external_device(binding);
}

View file

@ -2,6 +2,15 @@
#include "hid_pad_handler.h"
#ifndef _MSC_VER
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wold-style-cast"
#endif
#include "3rdparty/fusion/fusion/Fusion/Fusion.h"
#ifndef _MSC_VER
#pragma GCC diagnostic pop
#endif
#include <unordered_map>
namespace reports
@ -80,14 +89,50 @@ namespace reports
{
std::array<u8, 4> data{}; // TODO
};
// Buffer size for calibration data
constexpr u32 PSMOVE_CALIBRATION_SIZE = 49;
// Three blocks, minus header (2 bytes) for blocks 2,3
constexpr u32 PSMOVE_ZCM1_CALIBRATION_BLOB_SIZE = PSMOVE_CALIBRATION_SIZE * 3 - 2 * 2;
// Three blocks, minus header (2 bytes) for block 2
constexpr u32 PSMOVE_ZCM2_CALIBRATION_BLOB_SIZE = PSMOVE_CALIBRATION_SIZE * 2 - 2 * 1;
struct ps_move_calibration_blob
{
std::array<u8, std::max(PSMOVE_ZCM1_CALIBRATION_BLOB_SIZE, PSMOVE_ZCM2_CALIBRATION_BLOB_SIZE)> data{};
};
}
enum
{
zero_shift = 0x8000,
};
enum class ps_move_model
{
ZCM1, // PS3
ZCM2, // PS4
};
struct ps_move_calibration
{
bool is_valid = false;
f32 accel_x_factor = 1.0f;
f32 accel_y_factor = 1.0f;
f32 accel_z_factor = 1.0f;
f32 accel_x_offset = 0.0f;
f32 accel_y_offset = 0.0f;
f32 accel_z_offset = 0.0f;
f32 gyro_x_gain = 1.0f;
f32 gyro_y_gain = 1.0f;
f32 gyro_z_gain = 1.0f;
f32 gyro_x_offset = 0.0f;
f32 gyro_y_offset = 0.0f;
f32 gyro_z_offset = 0.0f;
};
class ps_move_device : public HidDevice
{
public:
@ -98,6 +143,10 @@ public:
reports::ps_move_output_report last_output_report{};
steady_clock::time_point last_output_report_time;
u32 external_device_id = 0;
ps_move_calibration calibration{};
FusionAhrs ahrs {}; // Used to calculate quaternions from sensor data
u64 last_ahrs_update_time_us = 0; // Last ahrs update
const reports::ps_move_input_report_common& input_report_common() const;
};

View file

@ -40,6 +40,26 @@ ps_move_tracker<DiagnosticsEnabled>::~ps_move_tracker()
}
}
template <bool DiagnosticsEnabled>
void ps_move_tracker<DiagnosticsEnabled>::set_valid(ps_move_info& info, u32 index, bool valid)
{
u32& fail_count = ::at32(m_fail_count, index);
if (info.valid && !valid)
{
// Ignore a couple of untracked frames. This reduces noise.
if (++fail_count >= 3)
{
info.valid = valid;
}
return;
}
info.valid = valid;
fail_count = 0; // Reset fail count
};
template <bool DiagnosticsEnabled>
void ps_move_tracker<DiagnosticsEnabled>::set_image_data(const void* buf, u64 size, u32 width, u32 height, s32 format)
{
@ -136,7 +156,7 @@ void ps_move_tracker<DiagnosticsEnabled>::init_workers()
// Find contours
ps_move_info& info = m_info[index];
ps_move_info new_info{};
ps_move_info new_info = info;
process_contours(new_info, index);
if (new_info.valid)
@ -179,6 +199,7 @@ void ps_move_tracker<DiagnosticsEnabled>::process_image()
{
ps_move_info& info = m_info[index];
info.valid = false;
m_fail_count[index] = 0;
}
}
@ -303,7 +324,6 @@ void ps_move_tracker<DiagnosticsEnabled>::process_contours(ps_move_info& info, u
const u32 height = m_height;
const bool wrapped_hue = config.min_hue > config.max_hue; // e.g. min=355, max=5 (red)
info.valid = false;
info.x_max = width;
info.y_max = height;
@ -362,7 +382,10 @@ void ps_move_tracker<DiagnosticsEnabled>::process_contours(ps_move_info& info, u
cv::findContours(binary, all_contours, cv::RETR_EXTERNAL, cv::CHAIN_APPROX_SIMPLE);
if (all_contours.empty())
{
set_valid(info, index, false);
return;
}
std::vector<std::vector<cv::Point>> contours;
contours.reserve(all_contours.size());
@ -406,7 +429,10 @@ void ps_move_tracker<DiagnosticsEnabled>::process_contours(ps_move_info& info, u
}
if (best_index == umax)
{
set_valid(info, index, false);
return;
}
// Calculate distance from sphere to camera
const f32 sphere_radius_pixels = radii[best_index];
@ -417,11 +443,28 @@ void ps_move_tracker<DiagnosticsEnabled>::process_contours(ps_move_info& info, u
const f32 distance_mm = (focal_length_pixels * CELL_GEM_SPHERE_RADIUS_MM) / sphere_radius_pixels;
// Set results
info.valid = true;
info.distance_mm = distance_mm;
info.radius = sphere_radius_pixels;
info.x_pos = std::clamp(static_cast<u32>(centers[best_index].x), 0u, width);
info.y_pos = std::clamp(static_cast<u32>(centers[best_index].y), 0u, height);
set_valid(info, index, true);
const u32 x_pos = std::clamp(static_cast<u32>(centers[best_index].x), 0u, width);
const u32 y_pos = std::clamp(static_cast<u32>(centers[best_index].y), 0u, height);
// Only set new values if the new shape and position are relatively similar to the old ones.
const auto distance_travelled = [](int x1, int y1, int x2, int y2)
{
return std::sqrt(std::pow(x2 - x1, 2) + pow(y2 - y1, 2));
};
const bool shape_matches = std::abs(info.radius - sphere_radius_pixels) < (info.radius * 2) &&
distance_travelled(info.x_pos, info.y_pos, x_pos, y_pos) < (info.radius * 8);
if (shape_matches || ++m_shape_fail_count[index] >= 3)
{
info.distance_mm = distance_mm;
info.radius = sphere_radius_pixels;
info.x_pos = x_pos;
info.y_pos = y_pos;
m_shape_fail_count[index] = 0; // Reset fail count
}
if constexpr (!DiagnosticsEnabled)
return;

View file

@ -71,6 +71,8 @@ private:
void calculate_values();
};
void set_valid(ps_move_info& info, u32 index, bool valid);
u32 m_width = 0;
u32 m_height = 0;
s32 m_format = 0;
@ -90,6 +92,8 @@ private:
std::array<std::vector<u8>, CELL_GEM_MAX_NUM> m_image_hue_filtered{};
std::array<std::vector<u8>, CELL_GEM_MAX_NUM> m_image_binary{};
std::array<u32, CELL_GEM_MAX_NUM> m_fail_count{};
std::array<u32, CELL_GEM_MAX_NUM> m_shape_fail_count{};
std::array<u32, 360> m_hues{};
std::array<ps_move_info, CELL_GEM_MAX_NUM> m_info{};

View file

@ -40,7 +40,7 @@
<ItemDefinitionGroup>
<ClCompile>
<PrecompiledHeader>Use</PrecompiledHeader>
<AdditionalIncludeDirectories>..\3rdparty\miniupnp\miniupnp\miniupnpc\include;..\3rdparty\wolfssl\wolfssl;..\3rdparty\flatbuffers\include;..\3rdparty\libusb\libusb\libusb;..\3rdparty\yaml-cpp\yaml-cpp\include;..\3rdparty\SoundTouch\soundtouch\include;..\3rdparty\rtmidi\rtmidi;..\3rdparty\zlib\zlib;$(SolutionDir)build\lib\$(Configuration)-$(Platform)\llvm_build\include;$(SolutionDir)build\lib_ext\$(Configuration)-$(Platform)\llvm_build\include;$(SolutionDir)build\lib_ext\$(Configuration)-$(Platform)\llvm\include;$(VULKAN_SDK)\Include;..\3rdparty\zstd\zstd\lib</AdditionalIncludeDirectories>
<AdditionalIncludeDirectories>..\3rdparty\miniupnp\miniupnp\miniupnpc\include;..\3rdparty\wolfssl\wolfssl;..\3rdparty\flatbuffers\include;..\3rdparty\libusb\libusb\libusb;..\3rdparty\yaml-cpp\yaml-cpp\include;..\3rdparty\SoundTouch\soundtouch\include;..\3rdparty\rtmidi\rtmidi;..\3rdparty\zlib\zlib;$(SolutionDir)build\lib\$(Configuration)-$(Platform)\llvm_build\include;$(SolutionDir)build\lib_ext\$(Configuration)-$(Platform)\llvm_build\include;$(SolutionDir)build\lib_ext\$(Configuration)-$(Platform)\llvm\include;$(VULKAN_SDK)\Include;..\3rdparty\zstd\zstd\lib;$(SolutionDir)3rdparty\fusion\fusion\Fusion</AdditionalIncludeDirectories>
<Optimization Condition="'$(Configuration)|$(Platform)'=='Release|x64'">MaxSpeed</Optimization>
<PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">AL_LIBTYPE_STATIC;MINIUPNP_STATICLIB;HAVE_VULKAN;HAVE_SDL2;ZLIB_CONST;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Release|x64'">AL_LIBTYPE_STATIC;MINIUPNP_STATICLIB;HAVE_VULKAN;HAVE_SDL2;ZLIB_CONST;%(PreprocessorDefinitions)</PreprocessorDefinitions>
@ -104,6 +104,7 @@
<ClCompile Include="Emu\perf_monitor.cpp" />
<ClCompile Include="Emu\RSX\Common\texture_cache.cpp" />
<ClCompile Include="Emu\RSX\Core\RSXContext.cpp" />
<ClCompile Include="Emu\RSX\Host\MM.cpp" />
<ClCompile Include="Emu\RSX\Host\RSXDMAWriter.cpp" />
<ClCompile Include="Emu\RSX\NV47\FW\draw_call.cpp" />
<ClCompile Include="Emu\RSX\NV47\FW\reg_context.cpp" />
@ -621,6 +622,7 @@
<ClInclude Include="Emu\RSX\Core\RSXDisplay.h" />
<ClInclude Include="Emu\RSX\Core\RSXReservationLock.hpp" />
<ClInclude Include="Emu\RSX\Core\RSXVertexTypes.h" />
<ClInclude Include="Emu\RSX\Host\MM.h" />
<ClInclude Include="Emu\RSX\Host\RSXDMAWriter.h" />
<ClInclude Include="Emu\RSX\NV47\FW\draw_call.hpp" />
<ClInclude Include="Emu\RSX\NV47\FW\draw_call.inc.h" />

View file

@ -1312,6 +1312,9 @@
<ClCompile Include="Emu\RSX\Host\RSXDMAWriter.cpp">
<Filter>Emu\GPU\RSX\Host Mini-Driver</Filter>
</ClCompile>
<ClCompile Include="Emu\RSX\Host\MM.cpp">
<Filter>Emu\GPU\RSX\Host Mini-Driver</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="Crypto\aes.h">
@ -2644,6 +2647,9 @@
<ClInclude Include="Emu\RSX\Host\RSXDMAWriter.h">
<Filter>Emu\GPU\RSX\Host Mini-Driver</Filter>
</ClInclude>
<ClInclude Include="Emu\RSX\Host\MM.h">
<Filter>Emu\GPU\RSX\Host Mini-Driver</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<None Include="Emu\RSX\Program\GLSLSnippets\GPUDeswizzle.glsl">

View file

@ -62,12 +62,12 @@
<IgnoreImportLibrary Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</IgnoreImportLibrary>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<IncludePath>$(SolutionDir)3rdparty\7zip\7zip\C;$(SolutionDir)3rdparty\hidapi\hidapi\hidapi;.\;$(SolutionDir);$(SolutionDir)3rdparty\asmjit\asmjit\src;$(SolutionDir)3rdparty\yaml-cpp\yaml-cpp\include;$(SolutionDir)3rdparty\ffmpeg\include;$(VC_IncludePath);$(WindowsSDK_IncludePath);$(UniversalCRT_IncludePath);$(SolutionDir)3rdparty\libpng\libpng;$(SolutionDir)3rdparty\GL;$(SolutionDir)3rdparty\stblib\stb;$(SolutionDir)3rdparty\openal\openal-soft\include\AL;$(SolutionDir)3rdparty\pugixml\src;$(SolutionDir)3rdparty\Optional;$(SolutionDir)3rdparty\discord-rpc\include;$(SolutionDir)3rdparty\zlib\zlib;$(SolutionDir)3rdparty\libsdl-org\SDL\include</IncludePath>
<IncludePath>$(SolutionDir)3rdparty\7zip\7zip\C;$(SolutionDir)3rdparty\hidapi\hidapi\hidapi;.\;$(SolutionDir);$(SolutionDir)3rdparty\asmjit\asmjit\src;$(SolutionDir)3rdparty\yaml-cpp\yaml-cpp\include;$(SolutionDir)3rdparty\ffmpeg\include;$(VC_IncludePath);$(WindowsSDK_IncludePath);$(UniversalCRT_IncludePath);$(SolutionDir)3rdparty\libpng\libpng;$(SolutionDir)3rdparty\GL;$(SolutionDir)3rdparty\stblib\stb;$(SolutionDir)3rdparty\openal\openal-soft\include\AL;$(SolutionDir)3rdparty\pugixml\src;$(SolutionDir)3rdparty\Optional;$(SolutionDir)3rdparty\discord-rpc\include;$(SolutionDir)3rdparty\zlib\zlib;$(SolutionDir)3rdparty\libsdl-org\SDL\include;$(SolutionDir)3rdparty\fusion\fusion\Fusion</IncludePath>
<LibraryPath>$(SolutionDir)build\lib\$(Configuration)-$(Platform)\;$(UniversalCRT_LibraryPath_x64);$(LibraryPath)</LibraryPath>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<LibraryPath>$(SolutionDir)build\lib\$(Configuration)-$(Platform)\;$(UniversalCRT_LibraryPath_x64);$(LibraryPath)</LibraryPath>
<IncludePath>$(SolutionDir)3rdparty\7zip\7zip\C;$(SolutionDir)3rdparty\hidapi\hidapi\hidapi;.\;$(SolutionDir);$(SolutionDir)3rdparty\asmjit\asmjit\src;$(SolutionDir)3rdparty\yaml-cpp\yaml-cpp\include;$(SolutionDir)3rdparty\ffmpeg\include;$(VC_IncludePath);$(WindowsSDK_IncludePath);$(UniversalCRT_IncludePath);$(SolutionDir)3rdparty\libpng\libpng;$(SolutionDir)3rdparty\GL;$(SolutionDir)3rdparty\stblib\stb;$(SolutionDir)3rdparty\openal\openal-soft\include\AL;$(SolutionDir)3rdparty\pugixml\src;$(SolutionDir)3rdparty\Optional;$(SolutionDir)3rdparty\discord-rpc\include;$(SolutionDir)3rdparty\zlib\zlib;$(SolutionDir)3rdparty\libsdl-org\SDL\include</IncludePath>
<IncludePath>$(SolutionDir)3rdparty\7zip\7zip\C;$(SolutionDir)3rdparty\hidapi\hidapi\hidapi;.\;$(SolutionDir);$(SolutionDir)3rdparty\asmjit\asmjit\src;$(SolutionDir)3rdparty\yaml-cpp\yaml-cpp\include;$(SolutionDir)3rdparty\ffmpeg\include;$(VC_IncludePath);$(WindowsSDK_IncludePath);$(UniversalCRT_IncludePath);$(SolutionDir)3rdparty\libpng\libpng;$(SolutionDir)3rdparty\GL;$(SolutionDir)3rdparty\stblib\stb;$(SolutionDir)3rdparty\openal\openal-soft\include\AL;$(SolutionDir)3rdparty\pugixml\src;$(SolutionDir)3rdparty\Optional;$(SolutionDir)3rdparty\discord-rpc\include;$(SolutionDir)3rdparty\zlib\zlib;$(SolutionDir)3rdparty\libsdl-org\SDL\include;$(SolutionDir)3rdparty\fusion\fusion\Fusion</IncludePath>
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<ClCompile>
@ -89,7 +89,7 @@
<ExternalWarningLevel>TurnOffAllWarnings</ExternalWarningLevel>
</ClCompile>
<Link>
<AdditionalDependencies>opencv_world4100.lib;DbgHelp.lib;Ole32.lib;gdi32.lib;hidapi.lib;libusb-1.0.lib;winmm.lib;miniupnpc_static.lib;rtmidi.lib;imm32.lib;ksuser.lib;version.lib;OpenAL32.lib;XAudio.lib;GLGSRender.lib;shlwapi.lib;VKGSRender.lib;vulkan-1.lib;wolfssl.lib;libcurl.lib;Wldap32.lib;glslang.lib;OSDependent.lib;OGLCompiler.lib;SPIRV.lib;MachineIndependent.lib;GenericCodeGen.lib;Advapi32.lib;user32.lib;zlib.lib;zstd.lib;libpng16.lib;asmjit.lib;yaml-cpp.lib;discord-rpc.lib;emucore.lib;dxgi.lib;shell32.lib;Qt6Core.lib;Qt6Gui.lib;Qt6Widgets.lib;Qt6Concurrent.lib;Qt6Multimedia.lib;Qt6MultimediaWidgets.lib;Qt6Svg.lib;Qt6SvgWidgets.lib;7zip.lib;libcubeb.lib;cubeb.lib;soundtouch.lib;Avrt.lib;SDL.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalDependencies>opencv_world4100.lib;DbgHelp.lib;Ole32.lib;gdi32.lib;hidapi.lib;libusb-1.0.lib;winmm.lib;miniupnpc_static.lib;rtmidi.lib;imm32.lib;ksuser.lib;version.lib;OpenAL32.lib;XAudio.lib;GLGSRender.lib;shlwapi.lib;VKGSRender.lib;vulkan-1.lib;wolfssl.lib;libcurl.lib;Wldap32.lib;glslang.lib;OSDependent.lib;OGLCompiler.lib;SPIRV.lib;MachineIndependent.lib;GenericCodeGen.lib;Advapi32.lib;user32.lib;zlib.lib;zstd.lib;libpng16.lib;asmjit.lib;yaml-cpp.lib;discord-rpc.lib;emucore.lib;dxgi.lib;shell32.lib;Qt6Core.lib;Qt6Gui.lib;Qt6Widgets.lib;Qt6Concurrent.lib;Qt6Multimedia.lib;Qt6MultimediaWidgets.lib;Qt6Svg.lib;Qt6SvgWidgets.lib;7zip.lib;libcubeb.lib;cubeb.lib;soundtouch.lib;Avrt.lib;SDL.lib;fusion.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalLibraryDirectories>$(SolutionDir)3rdparty\opencv\opencv\opencv410\build\x64\lib;$(SolutionDir)build\lib\$(Configuration)-$(Platform)\glslang;$(SolutionDir)build\lib_ext\$(CONFIGURATION)-$(PLATFORM);$(SolutionDir)3rdparty\discord-rpc\lib;$(QTDIR)\lib;$(VULKAN_SDK)\Lib;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
<AdditionalOptions>"/MANIFESTDEPENDENCY:type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' publicKeyToken='6595b64144ccf1df' language='*' processorArchitecture='*'" %(AdditionalOptions)</AdditionalOptions>
<DataExecutionPrevention>true</DataExecutionPrevention>
@ -141,7 +141,7 @@
<ProgramDataBaseFileName>$(IntDir)vc$(PlatformToolsetVersion).pdb</ProgramDataBaseFileName>
</ClCompile>
<Link>
<AdditionalDependencies>opencv_world4100.lib;DbgHelp.lib;Ole32.lib;gdi32.lib;hidapi.lib;libusb-1.0.lib;winmm.lib;miniupnpc_static.lib;rtmidi.lib;imm32.lib;ksuser.lib;version.lib;OpenAL32.lib;XAudio.lib;GLGSRender.lib;shlwapi.lib;VKGSRender.lib;vulkan-1.lib;wolfssl.lib;libcurl.lib;Wldap32.lib;glslangd.lib;OSDependentd.lib;OGLCompilerd.lib;SPIRVd.lib;MachineIndependentd.lib;GenericCodeGend.lib;Advapi32.lib;user32.lib;zlib.lib;zstd.lib;libpng16.lib;asmjit.lib;yaml-cpp.lib;discord-rpc.lib;emucore.lib;dxgi.lib;shell32.lib;Qt6Cored.lib;Qt6Guid.lib;Qt6Widgetsd.lib;Qt6Concurrentd.lib;Qt6Multimediad.lib;Qt6MultimediaWidgetsd.lib;Qt6Svgd.lib;Qt6SvgWidgetsd.lib;7zip.lib;libcubeb.lib;cubeb.lib;soundtouch.lib;Avrt.lib;SDL.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalDependencies>opencv_world4100.lib;DbgHelp.lib;Ole32.lib;gdi32.lib;hidapi.lib;libusb-1.0.lib;winmm.lib;miniupnpc_static.lib;rtmidi.lib;imm32.lib;ksuser.lib;version.lib;OpenAL32.lib;XAudio.lib;GLGSRender.lib;shlwapi.lib;VKGSRender.lib;vulkan-1.lib;wolfssl.lib;libcurl.lib;Wldap32.lib;glslangd.lib;OSDependentd.lib;OGLCompilerd.lib;SPIRVd.lib;MachineIndependentd.lib;GenericCodeGend.lib;Advapi32.lib;user32.lib;zlib.lib;zstd.lib;libpng16.lib;asmjit.lib;yaml-cpp.lib;discord-rpc.lib;emucore.lib;dxgi.lib;shell32.lib;Qt6Cored.lib;Qt6Guid.lib;Qt6Widgetsd.lib;Qt6Concurrentd.lib;Qt6Multimediad.lib;Qt6MultimediaWidgetsd.lib;Qt6Svgd.lib;Qt6SvgWidgetsd.lib;7zip.lib;libcubeb.lib;cubeb.lib;soundtouch.lib;Avrt.lib;SDL.lib;fusion.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalLibraryDirectories>$(SolutionDir)3rdparty\opencv\opencv\opencv410\build\x64\lib;$(SolutionDir)build\lib\$(Configuration)-$(Platform)\glslang;$(SolutionDir)3rdparty\discord-rpc\lib;$(SolutionDir)build\lib\$(CONFIGURATION)-$(PLATFORM);$(QTDIR)\lib;$(VULKAN_SDK)\Lib;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
<AdditionalOptions>"/MANIFESTDEPENDENCY:type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' publicKeyToken='6595b64144ccf1df' language='*' processorArchitecture='*'" /VERBOSE %(AdditionalOptions)</AdditionalOptions>
<DataExecutionPrevention>true</DataExecutionPrevention>
@ -179,6 +179,7 @@
<ClCompile Include="Input\evdev_gun_handler.cpp" />
<ClCompile Include="Input\gui_pad_thread.cpp" />
<ClCompile Include="Input\hid_pad_handler.cpp" />
<ClCompile Include="Input\ps_move_calibration.cpp" />
<ClCompile Include="Input\ps_move_config.cpp" />
<ClCompile Include="Input\ps_move_tracker.cpp" />
<ClCompile Include="Input\raw_mouse_config.cpp" />
@ -971,6 +972,7 @@
<AdditionalInputs Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">$(QTDIR)\bin\moc.exe;%(FullPath);$(QTDIR)\bin\moc.exe;%(FullPath)</AdditionalInputs>
<AdditionalInputs Condition="'$(Configuration)|$(Platform)'=='Release|x64'">$(QTDIR)\bin\moc.exe;%(FullPath);$(QTDIR)\bin\moc.exe;%(FullPath)</AdditionalInputs>
</CustomBuild>
<ClInclude Include="Input\ps_move_calibration.h" />
<ClInclude Include="Input\ps_move_config.h" />
<ClInclude Include="Input\ps_move_tracker.h" />
<ClInclude Include="Input\raw_mouse_config.h" />

View file

@ -1143,6 +1143,9 @@
<ClCompile Include="Input\ps_move_config.cpp">
<Filter>Io\Move</Filter>
</ClCompile>
<ClCompile Include="Input\ps_move_calibration.cpp">
<Filter>Io\Move</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="Input\ds4_pad_handler.h">
@ -1343,6 +1346,9 @@
<ClInclude Include="Input\ps_move_config.h">
<Filter>Io\Move</Filter>
</ClInclude>
<ClInclude Include="Input\ps_move_calibration.h">
<Filter>Io\Move</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<CustomBuild Include="debug\moc_predefs.h.cbt">

View file

@ -160,4 +160,5 @@ target_link_libraries(rpcs3_ui
3rdparty::wolfssl
3rdparty::libcurl
3rdparty::opencv
3rdparty::fusion
3rdparty::rtmidi)

View file

@ -103,6 +103,7 @@ enum class emu_settings_type
DisableMSLFastMath,
OutputScalingMode,
ForceHwMSAAResolve,
DisableAsyncHostMM,
// Performance Overlay
PerfOverlayEnabled,
@ -294,6 +295,7 @@ inline static const std::map<emu_settings_type, cfg_location> settings_location
{ emu_settings_type::DisableMSLFastMath, { "Video", "Disable MSL Fast Math"}},
{ emu_settings_type::OutputScalingMode, { "Video", "Output Scaling Mode"}},
{ emu_settings_type::ForceHwMSAAResolve, { "Video", "Force Hardware MSAA Resolve"}},
{ emu_settings_type::DisableAsyncHostMM, { "Video", "Disable Asynchronous Memory Manager"}},
// Vulkan
{ emu_settings_type::VulkanAsyncTextureUploads, { "Video", "Vulkan", "Asynchronous Texture Streaming 2"}},

View file

@ -1593,6 +1593,9 @@ settings_dialog::settings_dialog(std::shared_ptr<gui_settings> gui_settings, std
ui->disableMslFastMath->setVisible(false);
#endif
m_emu_settings->EnhanceCheckBox(ui->disableAsyncHostMM, emu_settings_type::DisableAsyncHostMM);
SubscribeTooltip(ui->disableAsyncHostMM, tooltips.settings.disable_async_host_mm);
// Comboboxes
m_emu_settings->EnhanceComboBox(ui->maxSPURSThreads, emu_settings_type::MaxSPURSThreads, true);

View file

@ -2695,6 +2695,13 @@
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="disableAsyncHostMM">
<property name="text">
<string>Disable Asynchronous Memory Manager</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>

View file

@ -40,6 +40,7 @@ public:
const QString allow_host_labels = tr("Allows the host GPU to synchronize with CELL directly. This incurs a performance penalty, but exposes the true state of GPU objects to the guest CPU. Can help eliminate visual noise and glitching at the cost of performance. Use with caution.");
const QString force_hw_MSAA = tr("Forces MSAA to use the host GPU's resolve capabilities for all sampling operations.\nThis option incurs a performance penalty as well as the risk of visual artifacts but can yield crisper visuals when MSAA is enabled.");
const QString disable_vertex_cache = tr("Disables the vertex cache.\nMight resolve missing or flickering graphics output.\nMay degrade performance.");
const QString disable_async_host_mm = tr("Force host memory management calls to be inlined instead of handled asynchronously.\nThis can cause severe performance degradation and stuttering in some games.\nThis option is only needed by developers to debug problems with texture cache memory protection.");
const QString zcull_operation_mode = tr("Changes ZCULL report synchronization behaviour. Experiment to find the best option for your game. Approximate mode is recommended for most games.\n· Precise is the most accurate to PS3 behaviour. Required for accurate visuals in some titles such as Demon's Souls and The Darkness.\n· Approximate is a much faster way to generate occlusion data which may not always match what the PS3 would generate. Works well with most PS3 games.\n· Relaxed changes the synchronization method completely and can greatly improve performance in some games or completely break others.");
const QString max_spurs_threads = tr("Limits the maximum number of SPURS threads in each thread group.\nMay improve performance in some cases, especially on systems with limited number of hardware threads.\nLimiting the number of threads is likely to cause crashes; it's recommended to keep this at the default value.");
const QString sleep_timers_accuracy = tr("Changes the sleep period accuracy.\n'As Host' uses default accuracy of the underlying operating system, while 'All Timers' attempts to improve it.\n'Usleep Only' limits the adjustments to usleep syscall only.\nCan affect performance in unexpected ways.");