Merge branch 'master' into master

This commit is contained in:
Ani 2018-02-09 12:34:50 +00:00 committed by GitHub
commit 4bfe3668f0
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
68 changed files with 2310 additions and 673 deletions

5
.gitmodules vendored
View file

@ -7,8 +7,8 @@
ignore = dirty ignore = dirty
[submodule "llvm"] [submodule "llvm"]
path = llvm path = llvm
url = https://github.com/llvm-mirror/llvm url = https://github.com/RPCS3/llvm
branch = release_40 branch = release_60
[submodule "GSL"] [submodule "GSL"]
path = 3rdparty/GSL path = 3rdparty/GSL
url = https://github.com/Microsoft/GSL.git url = https://github.com/Microsoft/GSL.git
@ -35,6 +35,7 @@
path = 3rdparty/hidapi path = 3rdparty/hidapi
url = https://github.com/RPCS3/hidapi url = https://github.com/RPCS3/hidapi
branch = master branch = master
ignore = dirty
[submodule "3rdparty/Optional"] [submodule "3rdparty/Optional"]
path = 3rdparty/Optional path = 3rdparty/Optional
url = https://github.com/akrzemi1/Optional.git url = https://github.com/akrzemi1/Optional.git

View file

@ -26,9 +26,6 @@ git:
submodules: false submodules: false
before_install: before_install:
- if [ "$CC" = "clang" ]; then
export CXX="clang++-4.0" CC="clang-4.0";
fi;
- if [ "$TRAVIS_OS_NAME" = "linux" ] && [ "$CXX" = "g++" ]; then - if [ "$TRAVIS_OS_NAME" = "linux" ] && [ "$CXX" = "g++" ]; then
export CXX="g++-5" CC="gcc-5" CXXFLAGS="-Wno-format-security"; export CXX="g++-5" CC="gcc-5" CXXFLAGS="-Wno-format-security";
fi; fi;
@ -65,7 +62,7 @@ before_script:
- cmake .. -DCMAKE_INSTALL_PREFIX=/usr -G Ninja; - cmake .. -DCMAKE_INSTALL_PREFIX=/usr -G Ninja;
- ninja - ninja
- # AppImage generation - # AppImage generation
- if [ -n "$UPLOAD_URL" ] && [ "$TRAVIS_BRANCH" = "master" ] && [ "$CC" = "clang-4.0" ] && [ "$TRAVIS_PULL_REQUEST" = false ]; then - if [ -n "$UPLOAD_URL" ] && [ "$TRAVIS_BRANCH" = "master" ] && [ "$CC" = "clang" ] && [ "$TRAVIS_PULL_REQUEST" = false ]; then
export LD_LIBRARY_PATH=~/Qt/5.10.0/gcc_64/lib; export LD_LIBRARY_PATH=~/Qt/5.10.0/gcc_64/lib;
DESTDIR=appdir ninja install ; find appdir/ ; DESTDIR=appdir ninja install ; find appdir/ ;
find ../bin ; find ../bin ;
@ -80,6 +77,7 @@ before_script:
cp ~/Qt/5.10.0/gcc_64/plugins/xcbglintegrations/* ./appdir/usr/plugins/xcbglintegrations/ ; cp ~/Qt/5.10.0/gcc_64/plugins/xcbglintegrations/* ./appdir/usr/plugins/xcbglintegrations/ ;
cp ~/Qt/5.10.0/gcc_64/plugins/imageformats/* ./appdir/usr/plugins/imageformats/ ; cp ~/Qt/5.10.0/gcc_64/plugins/imageformats/* ./appdir/usr/plugins/imageformats/ ;
cp ~/Qt/5.10.0/gcc_64/plugins/platforms/* ./appdir/usr/plugins/platforms/ ; cp ~/Qt/5.10.0/gcc_64/plugins/platforms/* ./appdir/usr/plugins/platforms/ ;
rm ./appdir/usr/lib/libfreetype.so.6 ;
export PATH=${TRAVIS_BUILD_DIR}/build/squashfs-root/usr/bin/:${PATH} ; export PATH=${TRAVIS_BUILD_DIR}/build/squashfs-root/usr/bin/:${PATH} ;
./squashfs-root/usr/bin/appimagetool ${TRAVIS_BUILD_DIR}/build/appdir ; ./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 ; find ./appdir -executable -type f -exec ldd {} \; | grep " => /usr" | cut -d " " -f 2-3 | sort | uniq ;
@ -111,7 +109,8 @@ addons:
- libc6-dev - libc6-dev
- llvm-4.0 - llvm-4.0
- llvm-4.0-dev - llvm-4.0-dev
- clang-4.0 # Clang 5.0 is now bundled in travis, so we no longer need the ppa version.
#- clang-4.0
- libedit-dev - libedit-dev
- g++-5 - g++-5
- gcc-5 - gcc-5

View file

@ -1034,7 +1034,7 @@ fs::file::file(const std::string& path, bs_t<open_mode> mode)
(fmt::throw_exception("Invalid whence (0x%x)" HERE, whence), 0); (fmt::throw_exception("Invalid whence (0x%x)" HERE, whence), 0);
const auto result = ::lseek(m_fd, offset, mode); const auto result = ::lseek(m_fd, offset, mode);
if (result == -1) if (result == -1)
{ {
g_tls_error = to_error(errno); g_tls_error = to_error(errno);
@ -1258,7 +1258,12 @@ bool fs::dir::open(const std::string& path)
} }
struct ::stat file_info; struct ::stat file_info;
verify("dir::read" HERE), ::fstatat(::dirfd(m_dd), found->d_name, &file_info, 0) == 0;
if (::fstatat(::dirfd(m_dd), found->d_name, &file_info, 0) != 0)
{
//failed metadata (broken symlink?), ignore and skip to next file
return read(info);
}
info.name = found->d_name; info.name = found->d_name;
info.is_directory = S_ISDIR(file_info.st_mode); info.is_directory = S_ISDIR(file_info.st_mode);
@ -1358,7 +1363,7 @@ std::string fs::get_data_dir(const std::string& prefix, const std::string& locat
continue; continue;
} }
buf.push_back(c); buf.push_back(c);
} }

View file

@ -32,13 +32,23 @@ void patch_engine::append(const std::string& patch)
{ {
if (fs::file f{patch}) if (fs::file f{patch})
{ {
auto root = YAML::Load(f.to_string()); YAML::Node root;
try
{
root = YAML::Load(f.to_string());
}
catch (const std::exception& e)
{
LOG_FATAL(GENERAL, "Failed to load patch file %s\n%s thrown: %s", patch, typeid(e).name(), e.what());
return;
}
for (auto pair : root) for (auto pair : root)
{ {
auto& name = pair.first.Scalar(); auto& name = pair.first.Scalar();
auto& data = m_map[name]; auto& data = m_map[name];
for (auto patch : pair.second) for (auto patch : pair.second)
{ {
u64 type64 = 0; u64 type64 = 0;
@ -91,7 +101,7 @@ void patch_engine::append(const std::string& patch)
break; break;
} }
} }
data.emplace_back(info); data.emplace_back(info);
} }
} }

View file

@ -39,6 +39,12 @@ bool utils::has_512()
return g_value; return g_value;
} }
bool utils::has_xop()
{
static const bool g_value = has_avx() && get_cpuid(0x80000001, 0)[2] & 0x800;
return g_value;
}
std::string utils::get_system_info() std::string utils::get_system_info()
{ {
std::string result; std::string result;
@ -92,6 +98,11 @@ std::string utils::get_system_info()
{ {
result += '+'; result += '+';
} }
if (has_xop())
{
result += 'x';
}
} }
if (has_rtm()) if (has_rtm())

View file

@ -26,6 +26,8 @@ namespace utils
bool has_512(); bool has_512();
bool has_xop();
inline bool transaction_enter() inline bool transaction_enter()
{ {
while (true) while (true)

View file

@ -1,79 +1,100 @@
#---------------------------------#
# general configuration #
#---------------------------------#
# version format version: '{build}'
version: '0.0.4-{build}'
#---------------------------------#
# environment configuration #
#---------------------------------#
# Build worker image (VM template)
image: Visual Studio 2015 image: Visual Studio 2015
# clone directory
clone_folder: c:\projects\rpcs3
# environment variables
environment: environment:
QTDIR: C:\Qt\5.9\msvc2015_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
# build cache to preserve files/folders between builds
cache: cache:
- llvmlibs.7z -> appveyor.yml - llvmlibs.7z -> appveyor.yml
- vulkan.7z -> appveyor.yml - vulkan.7z -> appveyor.yml
- compat_database.dat
# scripts that run after cloning repository
install: install:
- git submodule update --init 3rdparty/cereal 3rdparty/ffmpeg 3rdparty/GSL 3rdparty/hidapi 3rdparty/libpng 3rdparty/Optional 3rdparty/pugixml 3rdparty/zlib asmjit Utilities/yaml-cpp Vulkan/glslang Vulkan/Vulkan-LoaderAndValidationLayers - 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))
$env:AVVER = "{0}-{1}" -f $commTag.TrimStart("v"), $env:APPVEYOR_BUILD_NUMBER
$env:BUILD = "rpcs3-{0}-{1}-{2}_win64.7z" -f $commTag, $commDate, $commSha
#---------------------------------# - ps: | # used for experimental build warnings for pr builds
# build configuration # $env:BRANCH = "{0}/{1}/#{2}" -f $env:APPVEYOR_REPO_NAME, `
#---------------------------------# $env:APPVEYOR_REPO_BRANCH, $env:APPVEYOR_PULL_REQUEST_NUMBER
$env:BRANCH = $env:BRANCH -replace "/#$"
- ps: | # misc global settings
$env:PATH += $env:QTDIR
[net.servicepointmanager]::securityprotocol = "tls12, tls11, tls"
- ps: | # update and init submodules
git submodule -q update --init `
3rdparty/cereal `
3rdparty/ffmpeg `
3rdparty/GSL `
3rdparty/hidapi `
3rdparty/libpng `
3rdparty/Optional `
3rdparty/pugixml `
3rdparty/zlib `
asmjit `
Utilities/yaml-cpp `
Vulkan/glslang `
Vulkan/Vulkan-LoaderAndValidationLayers
# build platform, i.e. x86, x64, Any CPU. This setting is optional.
platform: x64 platform: x64
# build Configuration, i.e. Debug, Release, etc.
configuration: Release - LLVM configuration: Release - LLVM
build: build:
parallel: true # enable MSBuild parallel builds parallel: true
project: rpcs3.sln # path to Visual Studio solution or project project: rpcs3.sln
# MSBuild verbosity level
verbosity: normal verbosity: normal
# scripts to run before build
before_build: before_build:
- set BRANCH=%APPVEYOR_REPO_NAME%/%APPVEYOR_REPO_BRANCH%/#%APPVEYOR_PULL_REQUEST_NUMBER% - ps: | # fetch precompiled build dependencies
- if "%APPVEYOR_PULL_REQUEST_NUMBER%"=="" (set BRANCH=%APPVEYOR_REPO_NAME%/%APPVEYOR_REPO_BRANCH%) if (!(test-path llvmlibs.7z)) { irm $env:LLVMLIBS -outfile llvmlibs.7z }
- set PATH=%PATH%;%QTDIR% if (!(test-path vulkan.7z)) { irm $env:VULKAN -outfile vulkan.7z }
- if not exist llvmlibs.7z appveyor DownloadFile "https://drive.google.com/uc?export=download&id=0B8A6NaxhQAGRY2k3Q2Yya05lcm8" -FileName llvmlibs.7z 7z x llvmlibs.7z -aos -o"." | out-null
- 7z x llvmlibs.7z -aos -o%APPVEYOR_BUILD_FOLDER% > null 7z x vulkan.7z -aos -o".\lib\$env:CONFIGURATION-$env:PLATFORM" | out-null
- if not exist vulkan.7z appveyor DownloadFile "https://drive.google.com/uc?export=download&id=1A2eOMmCO714i0U7J0qI4aEMKnuWl8l_R" -FileName vulkan.7z
- 7z x vulkan.7z -aos -o"%APPVEYOR_BUILD_FOLDER%\lib\%CONFIGURATION%-%PLATFORM%" > null
# scripts to run *after* solution is built and *before* automatic packaging occurs (web apps, NuGet packages, Azure Cloud Services) after_build:
before_package: - ps: | # remove unnecessary files
- rm %APPVEYOR_BUILD_FOLDER%\bin\rpcs3.exp rm .\bin\rpcs3.exp, .\bin\rpcs3.lib, .\bin\rpcs3.pdb
- rm %APPVEYOR_BUILD_FOLDER%\bin\rpcs3.lib
- rm %APPVEYOR_BUILD_FOLDER%\bin\rpcs3.pdb
- set COMMIT_DATE=%APPVEYOR_REPO_COMMIT_TIMESTAMP:~0,10%
- set COMMIT_SHA=%APPVEYOR_REPO_COMMIT:~0,8%
#---------------------------------# - ps: | # prepare compatibility database for packaging
# tests configuration # $db = irm $env:COMPATDB -erroraction silentlycontinue
#---------------------------------# if ($db -and $db.return_code -eq 0) {
$db | convertto-json -compress | out-file compat_database.dat -encoding utf8
}
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 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"
# to disable automatic tests
test: off test: off
#---------------------------------#
# artifacts configuration #
#---------------------------------#
# pushing entire folder as a zip archive
artifacts: artifacts:
- path: bin - path: $(BUILD)
name: 'rpcs3-v0.0.4-$(COMMIT_DATE)-$(COMMIT_SHA)_win64' name: rpcs3
- path: $(BUILD).sha256
name: rpcs3 sha256 hash
- path: openssl_win64.7z
name: openssl
- path: openssl_win64.7z.sha256
name: openssl sha256 hash
on_finish:
- ps: | # update appveyor build version, done last to prevent webhook breakage
update-appveyorbuild -version $env:AVVER

View file

@ -457,6 +457,13 @@ endif()
cotire(rpcs3) cotire(rpcs3)
if (UNIX)
# Copy icons to executable directory
add_custom_command(TARGET rpcs3 POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy_directory
${CMAKE_SOURCE_DIR}/bin/Icons $<TARGET_FILE_DIR:rpcs3>/Icons)
endif()
# Unix installation # Unix installation
if(UNIX AND NOT APPLE) if(UNIX AND NOT APPLE)
# Install the binary # Install the binary

View file

@ -1 +1,13 @@
#ifdef LLVM_AVAILABLE
#include "CPUTranslator.h" #include "CPUTranslator.h"
cpu_translator::cpu_translator(llvm::LLVMContext& context, llvm::Module* module, bool is_be)
: m_context(context)
, m_module(module)
, m_is_be(is_be)
{
}
#endif

View file

@ -1 +1,750 @@
#pragma once #pragma once
#ifdef LLVM_AVAILABLE
#include "restore_new.h"
#ifdef _MSC_VER
#pragma warning(push, 0)
#endif
#include "llvm/IR/LLVMContext.h"
#include "llvm/IR/IRBuilder.h"
#include "llvm/IR/Module.h"
#ifdef _MSC_VER
#pragma warning(pop)
#endif
#include "define_new_memleakdetect.h"
#include "../Utilities/types.h"
#include "../Utilities/StrFmt.h"
#include "../Utilities/BEType.h"
#include "../Utilities/BitField.h"
#include <unordered_map>
#include <map>
#include <unordered_set>
#include <set>
#include <array>
#include <vector>
template <typename T = void>
struct llvm_value_t
{
static_assert(std::is_same<T, void>::value, "llvm_value_t<> error: unknown type");
using type = void;
static constexpr uint esize = 0;
static constexpr bool is_int = false;
static constexpr bool is_sint = false;
static constexpr bool is_uint = false;
static constexpr bool is_float = false;
static constexpr uint is_vector = false;
static constexpr uint is_pointer = false;
static llvm::Type* get_type(llvm::LLVMContext& context)
{
return llvm::Type::getVoidTy(context);
}
llvm::Value* eval(llvm::IRBuilder<>* ir) const
{
return value;
}
llvm::Value* value;
// llvm_value_t() = default;
// llvm_value_t(llvm::Value* value)
// : value(value)
// {
// }
};
template <>
struct llvm_value_t<bool> : llvm_value_t<void>
{
using type = bool;
using base = llvm_value_t<void>;
using base::base;
static constexpr uint esize = 1;
static constexpr uint is_int = true;
static llvm::Type* get_type(llvm::LLVMContext& context)
{
return llvm::Type::getInt1Ty(context);
}
};
template <>
struct llvm_value_t<char> : llvm_value_t<void>
{
using type = char;
using base = llvm_value_t<void>;
using base::base;
static constexpr uint esize = 8;
static constexpr bool is_int = true;
static llvm::Type* get_type(llvm::LLVMContext& context)
{
return llvm::Type::getInt8Ty(context);
}
};
template <>
struct llvm_value_t<s8> : llvm_value_t<char>
{
using type = s8;
using base = llvm_value_t<char>;
using base::base;
static constexpr bool is_sint = true;
};
template <>
struct llvm_value_t<u8> : llvm_value_t<char>
{
using type = u8;
using base = llvm_value_t<char>;
using base::base;
static constexpr bool is_uint = true;
};
template <>
struct llvm_value_t<s16> : llvm_value_t<s8>
{
using type = s16;
using base = llvm_value_t<s8>;
using base::base;
static constexpr uint esize = 16;
static llvm::Type* get_type(llvm::LLVMContext& context)
{
return llvm::Type::getInt16Ty(context);
}
};
template <>
struct llvm_value_t<u16> : llvm_value_t<s16>
{
using type = u16;
using base = llvm_value_t<s16>;
using base::base;
static constexpr bool is_sint = false;
static constexpr bool is_uint = true;
};
template <>
struct llvm_value_t<s32> : llvm_value_t<s8>
{
using type = s32;
using base = llvm_value_t<s8>;
using base::base;
static constexpr uint esize = 32;
static llvm::Type* get_type(llvm::LLVMContext& context)
{
return llvm::Type::getInt32Ty(context);
}
};
template <>
struct llvm_value_t<u32> : llvm_value_t<s32>
{
using type = u32;
using base = llvm_value_t<s32>;
using base::base;
static constexpr bool is_sint = false;
static constexpr bool is_uint = true;
};
template <>
struct llvm_value_t<s64> : llvm_value_t<s8>
{
using type = s64;
using base = llvm_value_t<s8>;
using base::base;
static constexpr uint esize = 64;
static llvm::Type* get_type(llvm::LLVMContext& context)
{
return llvm::Type::getInt64Ty(context);
}
};
template <>
struct llvm_value_t<u64> : llvm_value_t<s64>
{
using type = u64;
using base = llvm_value_t<s64>;
using base::base;
static constexpr bool is_sint = false;
static constexpr bool is_uint = true;
};
template <>
struct llvm_value_t<s128> : llvm_value_t<s8>
{
using type = s128;
using base = llvm_value_t<s8>;
using base::base;
static constexpr uint esize = 128;
static llvm::Type* get_type(llvm::LLVMContext& context)
{
return llvm::Type::getIntNTy(context, 128);
}
};
template <>
struct llvm_value_t<u128> : llvm_value_t<s128>
{
using type = u128;
using base = llvm_value_t<s128>;
using base::base;
static constexpr bool is_sint = false;
static constexpr bool is_uint = true;
};
template <>
struct llvm_value_t<f32> : llvm_value_t<void>
{
using type = f32;
using base = llvm_value_t<void>;
using base::base;
static constexpr uint esize = 32;
static constexpr bool is_float = true;
static llvm::Type* get_type(llvm::LLVMContext& context)
{
return llvm::Type::getFloatTy(context);
}
};
template <>
struct llvm_value_t<f64> : llvm_value_t<void>
{
using type = f64;
using base = llvm_value_t<void>;
using base::base;
static constexpr uint esize = 64;
static constexpr bool is_float = true;
static llvm::Type* get_type(llvm::LLVMContext& context)
{
return llvm::Type::getDoubleTy(context);
}
};
template <typename T>
struct llvm_value_t<T*> : llvm_value_t<T>
{
static_assert(!std::is_void<T>::value, "llvm_value_t<> error: invalid pointer to void type");
using type = T*;
using base = llvm_value_t<T>;
using base::base;
static constexpr uint is_pointer = llvm_value_t<T>::is_pointer + 1;
static llvm::Type* get_type(llvm::LLVMContext& context)
{
return llvm_value_t<T>::get_type(context)->getPointerTo();
}
};
template <typename T, uint N>
struct llvm_value_t<T[N]> : llvm_value_t<T>
{
static_assert(!llvm_value_t<T>::is_vector, "llvm_value_t<> error: invalid multidimensional vector");
static_assert(!llvm_value_t<T>::is_pointer, "llvm_value_t<>: vector of pointers is not allowed");
using type = T[N];
using base = llvm_value_t<T>;
using base::base;
static constexpr uint is_vector = N;
static constexpr uint is_pointer = 0;
static llvm::Type* get_type(llvm::LLVMContext& context)
{
return llvm::VectorType::get(llvm_value_t<T>::get_type(context), N);
}
};
template <typename T, typename A1, typename A2>
struct llvm_add_t
{
using type = T;
A1 a1;
A2 a2;
static_assert(llvm_value_t<T>::is_sint || llvm_value_t<T>::is_uint || llvm_value_t<T>::is_float, "llvm_add_t<>: invalid type");
llvm::Value* eval(llvm::IRBuilder<>* ir) const
{
const auto v1 = a1.eval(ir);
const auto v2 = a2.eval(ir);
if (llvm_value_t<T>::is_int)
{
return ir->CreateAdd(v1, v2);
}
if (llvm_value_t<T>::is_float)
{
return ir->CreateFAdd(v1, v2);
}
}
};
template <typename T1, typename T2, typename = decltype(std::declval<T1>().eval(0)), typename = std::enable_if_t<std::is_same<typename T1::type, typename T2::type>::value>>
inline llvm_add_t<typename T1::type, T1, T2> operator +(T1 a1, T2 a2)
{
return {a1, a2};
}
template <typename T, typename A1, typename A2>
struct llvm_sub_t
{
using type = T;
A1 a1;
A2 a2;
static_assert(llvm_value_t<T>::is_sint || llvm_value_t<T>::is_uint || llvm_value_t<T>::is_float, "llvm_sub_t<>: invalid type");
llvm::Value* eval(llvm::IRBuilder<>* ir) const
{
const auto v1 = a1.eval(ir);
const auto v2 = a2.eval(ir);
if (llvm_value_t<T>::is_int)
{
return ir->CreateSub(v1, v2);
}
if (llvm_value_t<T>::is_float)
{
return ir->CreateFSub(v1, v2);
}
}
};
template <typename T1, typename T2, typename = decltype(std::declval<T1>().eval(0)), typename = std::enable_if_t<std::is_same<typename T1::type, typename T2::type>::value>>
inline llvm_sub_t<typename T1::type, T1, T2> operator -(T1 a1, T2 a2)
{
return {a1, a2};
}
template <typename T, typename A1, typename A2>
struct llvm_mul_t
{
using type = T;
A1 a1;
A2 a2;
static_assert(llvm_value_t<T>::is_sint || llvm_value_t<T>::is_uint || llvm_value_t<T>::is_float, "llvm_mul_t<>: invalid type");
llvm::Value* eval(llvm::IRBuilder<>* ir) const
{
const auto v1 = a1.eval(ir);
const auto v2 = a2.eval(ir);
if (llvm_value_t<T>::is_int)
{
return ir->CreateMul(v1, v2);
}
if (llvm_value_t<T>::is_float)
{
return ir->CreateFMul(v1, v2);
}
}
};
template <typename T1, typename T2, typename = decltype(std::declval<T1>().eval(0)), typename = std::enable_if_t<std::is_same<typename T1::type, typename T2::type>::value>>
inline llvm_mul_t<typename T1::type, T1, T2> operator *(T1 a1, T2 a2)
{
return {a1, a2};
}
template <typename T, typename A1, typename A2>
struct llvm_div_t
{
using type = T;
A1 a1;
A2 a2;
static_assert(llvm_value_t<T>::is_sint || llvm_value_t<T>::is_uint || llvm_value_t<T>::is_float, "llvm_div_t<>: invalid type");
llvm::Value* eval(llvm::IRBuilder<>* ir) const
{
const auto v1 = a1.eval(ir);
const auto v2 = a2.eval(ir);
if (llvm_value_t<T>::is_sint)
{
return ir->CreateSDiv(v1, v2);
}
if (llvm_value_t<T>::is_uint)
{
return ir->CreateUDiv(v1, v2);
}
if (llvm_value_t<T>::is_float)
{
return ir->CreateFDiv(v1, v2);
}
}
};
template <typename T1, typename T2, typename = decltype(std::declval<T1>().eval(0)), typename = std::enable_if_t<std::is_same<typename T1::type, typename T2::type>::value>>
inline llvm_div_t<typename T1::type, T1, T2> operator /(T1 a1, T2 a2)
{
return {a1, a2};
}
template <typename T, typename A1>
struct llvm_neg_t
{
using type = T;
A1 a1;
static_assert(llvm_value_t<T>::is_sint || llvm_value_t<T>::is_uint || llvm_value_t<T>::is_float, "llvm_neg_t<>: invalid type");
llvm::Value* eval(llvm::IRBuilder<>* ir) const
{
const auto v1 = a1.eval(ir);
if (llvm_value_t<T>::is_int)
{
return ir->CreateNeg(v1);
}
if (llvm_value_t<T>::is_float)
{
return ir->CreateFNeg(v1);
}
}
};
template <typename T1, typename = decltype(std::declval<T1>().eval(0)), typename = std::enable_if_t<llvm_value_t<typename T1::type>::esize>>
inline llvm_neg_t<typename T1::type, T1> operator -(T1 a1)
{
return {a1};
}
// Constant int helper
struct llvm_int_t
{
u64 value;
u64 eval(llvm::IRBuilder<>*) const
{
return value;
}
};
template <typename T, typename A1, typename A2>
struct llvm_shl_t
{
using type = T;
A1 a1;
A2 a2;
static_assert(llvm_value_t<T>::is_sint || llvm_value_t<T>::is_uint, "llvm_shl_t<>: invalid type");
llvm::Value* eval(llvm::IRBuilder<>* ir) const
{
const auto v1 = a1.eval(ir);
const auto v2 = a2.eval(ir);
if (llvm_value_t<T>::is_sint)
{
return ir->CreateShl(v1, v2);
}
if (llvm_value_t<T>::is_uint)
{
return ir->CreateShl(v1, v2);
}
}
};
template <typename T1, typename T2, typename = decltype(std::declval<T1>().eval(0)), typename = std::enable_if_t<std::is_same<typename T1::type, typename T2::type>::value>>
inline llvm_shl_t<typename T1::type, T1, T2> operator <<(T1 a1, T2 a2)
{
return {a1, a2};
}
template <typename T1, typename = decltype(std::declval<T1>().eval(0)), typename = std::enable_if_t<llvm_value_t<typename T1::type>::is_int>>
inline llvm_shl_t<typename T1::type, T1, llvm_int_t> operator <<(T1 a1, u64 a2)
{
return {a1, llvm_int_t{a2}};
}
template <typename T, typename A1, typename A2>
struct llvm_shr_t
{
using type = T;
A1 a1;
A2 a2;
static_assert(llvm_value_t<T>::is_sint || llvm_value_t<T>::is_uint, "llvm_shr_t<>: invalid type");
llvm::Value* eval(llvm::IRBuilder<>* ir) const
{
const auto v1 = a1.eval(ir);
const auto v2 = a2.eval(ir);
if (llvm_value_t<T>::is_sint)
{
return ir->CreateAShr(v1, v2);
}
if (llvm_value_t<T>::is_uint)
{
return ir->CreateLShr(v1, v2);
}
}
};
template <typename T1, typename T2, typename = decltype(std::declval<T1>().eval(0)), typename = std::enable_if_t<std::is_same<typename T1::type, typename T2::type>::value>>
inline llvm_shr_t<typename T1::type, T1, T2> operator >>(T1 a1, T2 a2)
{
return {a1, a2};
}
template <typename T1, typename = decltype(std::declval<T1>().eval(0)), typename = std::enable_if_t<llvm_value_t<typename T1::type>::is_int>>
inline llvm_shr_t<typename T1::type, T1, llvm_int_t> operator >>(T1 a1, u64 a2)
{
return {a1, llvm_int_t{a2}};
}
template <typename T, typename A1, typename A2>
struct llvm_and_t
{
using type = T;
A1 a1;
A2 a2;
static_assert(llvm_value_t<T>::is_int, "llvm_and_t<>: invalid type");
llvm::Value* eval(llvm::IRBuilder<>* ir) const
{
const auto v1 = a1.eval(ir);
const auto v2 = a2.eval(ir);
if (llvm_value_t<T>::is_int)
{
return ir->CreateAnd(v1, v2);
}
}
};
template <typename T1, typename T2, typename = decltype(std::declval<T1>().eval(0)), typename = std::enable_if_t<std::is_same<typename T1::type, typename T2::type>::value>>
inline llvm_and_t<typename T1::type, T1, T2> operator &(T1 a1, T2 a2)
{
return {a1, a2};
}
template <typename T1, typename = decltype(std::declval<T1>().eval(0)), typename = std::enable_if_t<llvm_value_t<typename T1::type>::is_int>>
inline llvm_and_t<typename T1::type, T1, llvm_int_t> operator &(T1 a1, u64 a2)
{
return {a1, llvm_int_t{a2}};
}
template <typename T, typename A1, typename A2>
struct llvm_or_t
{
using type = T;
A1 a1;
A2 a2;
static_assert(llvm_value_t<T>::is_int, "llvm_or_t<>: invalid type");
llvm::Value* eval(llvm::IRBuilder<>* ir) const
{
const auto v1 = a1.eval(ir);
const auto v2 = a2.eval(ir);
if (llvm_value_t<T>::is_int)
{
return ir->CreateOr(v1, v2);
}
}
};
template <typename T1, typename T2, typename = decltype(std::declval<T1>().eval(0)), typename = std::enable_if_t<std::is_same<typename T1::type, typename T2::type>::value>>
inline llvm_or_t<typename T1::type, T1, T2> operator |(T1 a1, T2 a2)
{
return {a1, a2};
}
template <typename T1, typename = decltype(std::declval<T1>().eval(0)), typename = std::enable_if_t<llvm_value_t<typename T1::type>::is_int>>
inline llvm_or_t<typename T1::type, T1, llvm_int_t> operator |(T1 a1, u64 a2)
{
return {a1, llvm_int_t{a2}};
}
template <typename T, typename A1, typename A2>
struct llvm_xor_t
{
using type = T;
A1 a1;
A2 a2;
static_assert(llvm_value_t<T>::is_int, "llvm_xor_t<>: invalid type");
llvm::Value* eval(llvm::IRBuilder<>* ir) const
{
const auto v1 = a1.eval(ir);
const auto v2 = a2.eval(ir);
if (llvm_value_t<T>::is_int)
{
return ir->CreateXor(v1, v2);
}
}
};
template <typename T1, typename T2, typename = decltype(std::declval<T1>().eval(0)), typename = std::enable_if_t<std::is_same<typename T1::type, typename T2::type>::value>>
inline llvm_xor_t<typename T1::type, T1, T2> operator ^(T1 a1, T2 a2)
{
return {a1, a2};
}
template <typename T1, typename = decltype(std::declval<T1>().eval(0)), typename = std::enable_if_t<llvm_value_t<typename T1::type>::is_int>>
inline llvm_xor_t<typename T1::type, T1, llvm_int_t> operator ^(T1 a1, u64 a2)
{
return {a1, llvm_int_t{a2}};
}
template <typename T, typename A1>
struct llvm_not_t
{
using type = T;
A1 a1;
static_assert(llvm_value_t<T>::is_int, "llvm_not_t<>: invalid type");
llvm::Value* eval(llvm::IRBuilder<>* ir) const
{
const auto v1 = a1.eval(ir);
if (llvm_value_t<T>::is_int)
{
return ir->CreateNot(v1);
}
}
};
template <typename T1, typename = decltype(std::declval<T1>().eval(0)), typename = std::enable_if_t<llvm_value_t<typename T1::type>::is_int>>
inline llvm_not_t<typename T1::type, T1> operator ~(T1 a1)
{
return {a1};
}
class cpu_translator
{
protected:
cpu_translator(llvm::LLVMContext& context, llvm::Module* module, bool is_be);
// LLVM context
llvm::LLVMContext& m_context;
// Module to which all generated code is output to
llvm::Module* const m_module;
// Endianness, affects vector element numbering (TODO)
const bool m_is_be;
// IR builder
llvm::IRBuilder<>* m_ir;
public:
// Convert a C++ type to an LLVM type (TODO: remove)
template <typename T>
llvm::Type* GetType()
{
return llvm_value_t<T>::get_type(m_context);
}
template <typename T>
llvm::Type* get_type()
{
return llvm_value_t<T>::get_type(m_context);
}
template <typename T>
using value_t = llvm_value_t<T>;
template <typename T>
auto eval(T expr)
{
value_t<typename T::type> result;
result.value = expr.eval(m_ir);
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)
{
return ((a ^ b) & ~s) | (a & b);
}
// Get signed addition overflow into the sign bit (s = a + b)
template <typename T>
static inline auto scarry(T a, T b, T s)
{
return (b ^ s) & ~(a ^ b);
}
// Get signed subtraction overflow into the sign bit (d = a - b)
template <typename T>
static inline auto sborrow(T a, T b, T d)
{
return (a ^ b) & (a ^ d);
}
// Bitwise select (c ? a : b)
template <typename T>
static inline auto merge(T c, T a, T b)
{
return (a & c) | (b & ~c);
}
// Average: (a + b + 1) >> 1
template <typename T>
static inline auto avg(T a, T b)
{
return (a >> 1) + (b >> 1) + ((a | b) & 1);
}
};
#endif

View file

@ -302,7 +302,7 @@ void mfc_thread::cpu_task()
spu.ch_tag_stat.push(spu, completed); spu.ch_tag_stat.push(spu, completed);
no_updates = 0; no_updates = 0;
} }
else if (completed && spu.ch_tag_mask == completed && spu.ch_tag_upd.compare_and_swap_test(2, 0)) else if (spu.ch_tag_mask == completed && spu.ch_tag_upd.compare_and_swap_test(2, 0))
{ {
spu.ch_tag_stat.push(spu, completed); spu.ch_tag_stat.push(spu, completed);
no_updates = 0; no_updates = 0;

View file

@ -100,7 +100,7 @@ u16 cellKbCnvRawCode(u32 arrange, u32 mkey, u32 led, u16 rawcode)
((led&(CELL_KB_LED_CAPS_LOCK)) ? 0 : 0x20) : ((led&(CELL_KB_LED_CAPS_LOCK)) ? 0 : 0x20) :
((led&(CELL_KB_LED_CAPS_LOCK)) ? 0x20 : 0); ((led&(CELL_KB_LED_CAPS_LOCK)) ? 0x20 : 0);
return rawcode + 0x5D; return rawcode + 0x5D;
} }
if (rawcode >= 0x1E && rawcode <= 0x26) return rawcode + 0x13; // '1' - '9' if (rawcode >= 0x1E && rawcode <= 0x26) return rawcode + 0x13; // '1' - '9'
if (rawcode == 0x27) return 0x30; // '0' if (rawcode == 0x27) return 0x30; // '0'
if (rawcode == 0x28) return 0x0A; // '\n' if (rawcode == 0x28) return 0x0A; // '\n'
@ -136,7 +136,7 @@ error_code cellKbGetInfo(vm::ptr<CellKbInfo> info)
{ {
info->status[i] = current_info.status[i]; info->status[i] = current_info.status[i];
} }
return CELL_OK; return CELL_OK;
} }
@ -165,7 +165,7 @@ error_code cellKbRead(u32 port_no, vm::ptr<CellKbData> data)
} }
current_data.len = 0; current_data.len = 0;
return CELL_OK; return CELL_OK;
} }
@ -180,7 +180,7 @@ error_code cellKbSetCodeType(u32 port_no, u32 type)
if (port_no >= handler->GetKeyboards().size()) if (port_no >= handler->GetKeyboards().size())
return CELL_KB_ERROR_INVALID_PARAMETER; return CELL_KB_ERROR_INVALID_PARAMETER;
KbConfig& current_config = handler->GetConfig(port_no); KbConfig& current_config = handler->GetConfig(port_no);
current_config.code_type = type; current_config.code_type = type;
return CELL_OK; return CELL_OK;
@ -203,7 +203,7 @@ error_code cellKbSetReadMode(u32 port_no, u32 rmode)
if (port_no >= handler->GetKeyboards().size()) if (port_no >= handler->GetKeyboards().size())
return CELL_KB_ERROR_INVALID_PARAMETER; return CELL_KB_ERROR_INVALID_PARAMETER;
KbConfig& current_config = handler->GetConfig(port_no); KbConfig& current_config = handler->GetConfig(port_no);
current_config.read_mode = rmode; current_config.read_mode = rmode;

View file

@ -315,6 +315,11 @@ s32 cellMsgDialogProgressBarSetMsg(u32 progressBarIndex, vm::cptr<char> msgStrin
{ {
cellSysutil.warning("cellMsgDialogProgressBarSetMsg(progressBarIndex=%d, msgString=%s)", progressBarIndex, msgString); cellSysutil.warning("cellMsgDialogProgressBarSetMsg(progressBarIndex=%d, msgString=%s)", progressBarIndex, msgString);
if (!msgString)
{
return CELL_MSGDIALOG_ERROR_PARAM;
}
if (auto rsxthr = fxm::get<GSRender>()) if (auto rsxthr = fxm::get<GSRender>())
{ {
if (auto dlg2 = rsxthr->shell_get_current_dialog()) if (auto dlg2 = rsxthr->shell_get_current_dialog())
@ -331,7 +336,7 @@ s32 cellMsgDialogProgressBarSetMsg(u32 progressBarIndex, vm::cptr<char> msgStrin
return CELL_MSGDIALOG_ERROR_DIALOG_NOT_OPENED; return CELL_MSGDIALOG_ERROR_DIALOG_NOT_OPENED;
} }
if (progressBarIndex >= dlg->type.progress_bar_count || !msgString) if (progressBarIndex >= dlg->type.progress_bar_count)
{ {
return CELL_MSGDIALOG_ERROR_PARAM; return CELL_MSGDIALOG_ERROR_PARAM;
} }

View file

@ -1,5 +1,6 @@
#include "stdafx.h" #include "stdafx.h"
#include "Emu/Cell/PPUModule.h" #include "Emu/Cell/PPUModule.h"
#include "cellSysutil.h"
namespace vm { using namespace ps3; } namespace vm { using namespace ps3; }
@ -20,6 +21,16 @@ enum
CELL_PHOTO_EXPORT_UTIL_ERROR_INITIALIZE = 0x8002c20a, CELL_PHOTO_EXPORT_UTIL_ERROR_INITIALIZE = 0x8002c20a,
}; };
struct CellPhotoExportSetParam
{
vm::bptr<char> photo_title;
vm::bptr<char> game_title;
vm::bptr<char> game_comment;
vm::bptr<void> reserved;
};
using CellPhotoExportUtilFinishCallback = void(s32 result, vm::ptr<void> userdata);
s32 cellPhotoInitialize() s32 cellPhotoInitialize()
{ {
UNIMPLEMENTED_FUNC(cellPhotoExport); UNIMPLEMENTED_FUNC(cellPhotoExport);
@ -38,39 +49,81 @@ s32 cellPhotoRegistFromFile()
return CELL_OK; return CELL_OK;
} }
s32 cellPhotoExportInitialize() error_code cellPhotoExportInitialize(u32 version, u32 container, vm::ptr<CellPhotoExportUtilFinishCallback> funcFinish, vm::ptr<void> userdata)
{ {
UNIMPLEMENTED_FUNC(cellPhotoExport); cellPhotoExport.todo("cellPhotoExportInitialize(version=0x%x, container=0x%x, funcFinish=*0x%x, userdata=*0x%x)", version, container, funcFinish, userdata);
sysutil_register_cb([=](ppu_thread& ppu) -> s32
{
funcFinish(ppu, CELL_OK, userdata);
return CELL_OK;
});
return CELL_OK; return CELL_OK;
} }
s32 cellPhotoExportInitialize2() error_code cellPhotoExportInitialize2(u32 version, vm::ptr<CellPhotoExportUtilFinishCallback> funcFinish, vm::ptr<void> userdata)
{ {
UNIMPLEMENTED_FUNC(cellPhotoExport); cellPhotoExport.todo("cellPhotoExportInitialize2(version=0x%x, funcFinish=*0x%x, userdata=*0x%x)", version, funcFinish, userdata);
sysutil_register_cb([=](ppu_thread& ppu) -> s32
{
funcFinish(ppu, CELL_OK, userdata);
return CELL_OK;
});
return CELL_OK; return CELL_OK;
} }
s32 cellPhotoExportFinalize() error_code cellPhotoExportFinalize(vm::ptr<CellPhotoExportUtilFinishCallback> funcFinish, vm::ptr<void> userdata)
{ {
UNIMPLEMENTED_FUNC(cellPhotoExport); cellPhotoExport.todo("cellPhotoExportFinalize(funcFinish=*0x%x, userdata=*0x%x)", funcFinish, userdata);
sysutil_register_cb([=](ppu_thread& ppu) -> s32
{
funcFinish(ppu, CELL_OK, userdata);
return CELL_OK;
});
return CELL_OK; return CELL_OK;
} }
s32 cellPhotoExportFromFile() error_code cellPhotoExportFromFile(vm::cptr<char> srcHddDir, vm::cptr<char> srcHddFile, vm::ptr<CellPhotoExportSetParam> param, vm::ptr<CellPhotoExportUtilFinishCallback> funcFinish, vm::ptr<void> userdata)
{ {
UNIMPLEMENTED_FUNC(cellPhotoExport); cellPhotoExport.todo("cellPhotoExportFromFile(srcHddDir=%s, srcHddFile=%s, param=*0x%x, funcFinish=*0x%x, userdata=*0x%x)", srcHddDir, srcHddFile, param, funcFinish, userdata);
sysutil_register_cb([=](ppu_thread& ppu) -> s32
{
funcFinish(ppu, CELL_OK, userdata);
return CELL_OK;
});
return CELL_OK; return CELL_OK;
} }
s32 cellPhotoExportFromFileWithCopy() error_code cellPhotoExportFromFileWithCopy(vm::cptr<char> srcHddDir, vm::cptr<char> srcHddFile, vm::ptr<CellPhotoExportSetParam> param, vm::ptr<CellPhotoExportUtilFinishCallback> funcFinish, vm::ptr<void> userdata)
{ {
UNIMPLEMENTED_FUNC(cellPhotoExport); cellPhotoExport.todo("cellPhotoExportFromFileWithCopy(srcHddDir=%s, srcHddFile=%s, param=*0x%x, funcFinish=*0x%x, userdata=*0x%x)", srcHddDir, srcHddFile, param, funcFinish, userdata);
sysutil_register_cb([=](ppu_thread& ppu) -> s32
{
funcFinish(ppu, CELL_OK, userdata);
return CELL_OK;
});
return CELL_OK; return CELL_OK;
} }
s32 cellPhotoExportProgress() error_code cellPhotoExportProgress(vm::ptr<CellPhotoExportUtilFinishCallback> funcFinish, vm::ptr<void> userdata)
{ {
UNIMPLEMENTED_FUNC(cellPhotoExport); cellPhotoExport.todo("cellPhotoExportProgress(funcFinish=*0x%x, userdata=*0x%x)", funcFinish, userdata);
sysutil_register_cb([=](ppu_thread& ppu) -> s32
{
funcFinish(ppu, 0xFFFF, userdata); // 0-0xFFFF where 0xFFFF = 100%
return CELL_OK;
});
return CELL_OK; return CELL_OK;
} }

View file

@ -1,10 +1,22 @@
#include "stdafx.h" #include "stdafx.h"
#include "Emu/Cell/PPUModule.h" #include "Emu/Cell/PPUModule.h"
#include "Emu/IdManager.h"
#include "cellSysutil.h"
namespace vm { using namespace ps3; } namespace vm { using namespace ps3; }
logs::channel cellRec("cellRec"); logs::channel cellRec("cellRec");
enum
{
CELL_REC_STATUS_UNLOAD = 0,
CELL_REC_STATUS_OPEN = 1,
CELL_REC_STATUS_START = 2,
CELL_REC_STATUS_STOP = 3,
CELL_REC_STATUS_CLOSE = 4,
CELL_REC_STATUS_ERR = 10
};
struct CellRecSpursParam struct CellRecSpursParam
{ {
vm::bptr<struct CellSpurs> pSpurs; vm::bptr<struct CellSpurs> pSpurs;
@ -46,15 +58,40 @@ struct CellRecParam
using CellRecCallback = void(s32 recStatus, s32 recError, vm::ptr<void> userdata); using CellRecCallback = void(s32 recStatus, s32 recError, vm::ptr<void> userdata);
s32 cellRecOpen(vm::cptr<char> pDirName, vm::cptr<char> pFileName, vm::cptr<CellRecParam> pParam, u32 container, vm::ptr<CellRecCallback> cb, vm::ptr<void> cbUserData) struct rec_t
{
vm::ptr<CellRecCallback> cb;
vm::ptr<void> cbUserData;
};
error_code cellRecOpen(vm::cptr<char> pDirName, vm::cptr<char> pFileName, vm::cptr<CellRecParam> pParam, u32 container, vm::ptr<CellRecCallback> cb, vm::ptr<void> cbUserData)
{ {
cellRec.todo("cellRecOpen(pDirName=%s, pFileName=%s, pParam=*0x%x, container=0x%x, cb=*0x%x, cbUserData=*0x%x)", pDirName, pFileName, pParam, container, cb, cbUserData); cellRec.todo("cellRecOpen(pDirName=%s, pFileName=%s, pParam=*0x%x, container=0x%x, cb=*0x%x, cbUserData=*0x%x)", pDirName, pFileName, pParam, container, cb, cbUserData);
const auto rec = fxm::make_always<rec_t>();
rec->cb = cb;
rec->cbUserData = cbUserData;
sysutil_register_cb([=](ppu_thread& ppu) -> s32
{
cb(ppu, CELL_REC_STATUS_OPEN, CELL_OK, cbUserData);
return CELL_OK;
});
return CELL_OK; return CELL_OK;
} }
s32 cellRecClose(s32 isDiscard) error_code cellRecClose(s32 isDiscard)
{ {
cellRec.todo("cellRecClose(isDiscard=0x%x)", isDiscard); cellRec.todo("cellRecClose(isDiscard=0x%x)", isDiscard);
sysutil_register_cb([=](ppu_thread& ppu) -> s32
{
const auto rec = fxm::get_always<rec_t>();
rec->cb(ppu, CELL_REC_STATUS_CLOSE, CELL_OK, rec->cbUserData);
return CELL_OK;
});
return CELL_OK; return CELL_OK;
} }
@ -63,15 +100,31 @@ void cellRecGetInfo(s32 info, vm::ptr<u64> pValue)
cellRec.todo("cellRecGetInfo(info=0x%x, pValue=*0x%x)", info, pValue); cellRec.todo("cellRecGetInfo(info=0x%x, pValue=*0x%x)", info, pValue);
} }
s32 cellRecStop() error_code cellRecStop()
{ {
cellRec.todo("cellRecStop()"); cellRec.todo("cellRecStop()");
sysutil_register_cb([=](ppu_thread& ppu) -> s32
{
const auto rec = fxm::get_always<rec_t>();
rec->cb(ppu, CELL_REC_STATUS_STOP, CELL_OK, rec->cbUserData);
return CELL_OK;
});
return CELL_OK; return CELL_OK;
} }
s32 cellRecStart() error_code cellRecStart()
{ {
cellRec.todo("cellRecStart()"); cellRec.todo("cellRecStart()");
sysutil_register_cb([=](ppu_thread& ppu) -> s32
{
const auto rec = fxm::get_always<rec_t>();
rec->cb(ppu, CELL_REC_STATUS_START, CELL_OK, rec->cbUserData);
return CELL_OK;
});
return CELL_OK; return CELL_OK;
} }
@ -81,7 +134,7 @@ u32 cellRecQueryMemSize(vm::cptr<CellRecParam> pParam)
return 1 * 1024 * 1024; // dummy memory size return 1 * 1024 * 1024; // dummy memory size
} }
s32 cellRecSetInfo(s32 setInfo, u64 value) error_code cellRecSetInfo(s32 setInfo, u64 value)
{ {
cellRec.todo("cellRecSetInfo(setInfo=0x%x, value=0x%x)", setInfo, value); cellRec.todo("cellRecSetInfo(setInfo=0x%x, value=0x%x)", setInfo, value);
return CELL_OK; return CELL_OK;

View file

@ -1,36 +1,99 @@
#include "stdafx.h" #include "stdafx.h"
#include "Emu/Cell/PPUModule.h" #include "Emu/Cell/PPUModule.h"
#include "cellSysutil.h"
namespace vm { using namespace ps3; }
logs::channel cellVideoExport("cellVideoExport"); logs::channel cellVideoExport("cellVideoExport");
s32 cellVideoExportProgress() struct CellVideoExportSetParam
{ {
fmt::throw_exception("Unimplemented" HERE); vm::bptr<char> title;
vm::bptr<char> game_title;
vm::bptr<char> game_comment;
be_t<s32> editable;
vm::bptr<void> reserved2;
};
using CellVideoExportUtilFinishCallback = void(s32 result, vm::ptr<void> userdata);
error_code cellVideoExportProgress(vm::ptr<CellVideoExportUtilFinishCallback> funcFinish, vm::ptr<void> userdata)
{
cellVideoExport.todo("cellVideoExportProgress(funcFinish=*0x%x, userdata=*0x%x)", funcFinish, userdata);
sysutil_register_cb([=](ppu_thread& ppu) -> s32
{
funcFinish(ppu, 0xFFFF, userdata); // 0-0xFFFF where 0xFFFF = 100%
return CELL_OK;
});
return CELL_OK;
} }
s32 cellVideoExportInitialize2() error_code cellVideoExportInitialize2(u32 version, vm::ptr<CellVideoExportUtilFinishCallback> funcFinish, vm::ptr<void> userdata)
{ {
fmt::throw_exception("Unimplemented" HERE); cellVideoExport.todo("cellVideoExportInitialize2(version=0x%x, funcFinish=*0x%x, userdata=*0x%x)", version, funcFinish, userdata);
sysutil_register_cb([=](ppu_thread& ppu) -> s32
{
funcFinish(ppu, CELL_OK, userdata);
return CELL_OK;
});
return CELL_OK;
} }
s32 cellVideoExportInitialize() error_code cellVideoExportInitialize(u32 version, u32 container, vm::ptr<CellVideoExportUtilFinishCallback> funcFinish, vm::ptr<void> userdata)
{ {
fmt::throw_exception("Unimplemented" HERE); cellVideoExport.todo("cellVideoExportInitialize(version=0x%x, container=0x%x, funcFinish=*0x%x, userdata=*0x%x)", version, container, funcFinish, userdata);
sysutil_register_cb([=](ppu_thread& ppu) -> s32
{
funcFinish(ppu, CELL_OK, userdata);
return CELL_OK;
});
return CELL_OK;
} }
s32 cellVideoExportFromFileWithCopy() error_code cellVideoExportFromFileWithCopy(vm::cptr<char> srcHddDir, vm::cptr<char> srcHddFile, vm::ptr<CellVideoExportSetParam> param, vm::ptr<CellVideoExportUtilFinishCallback> funcFinish, vm::ptr<void> userdata)
{ {
fmt::throw_exception("Unimplemented" HERE); cellVideoExport.todo("cellVideoExportFromFileWithCopy(srcHddDir=%s, srcHddFile=%s, param=*0x%x, funcFinish=*0x%x, userdata=*0x%x)", srcHddDir, srcHddFile, param, funcFinish, userdata);
sysutil_register_cb([=](ppu_thread& ppu) -> s32
{
funcFinish(ppu, CELL_OK, userdata);
return CELL_OK;
});
return CELL_OK;
} }
s32 cellVideoExportFromFile() error_code cellVideoExportFromFile(vm::cptr<char> srcHddDir, vm::cptr<char> srcHddFile, vm::ptr<CellVideoExportSetParam> param, vm::ptr<CellVideoExportUtilFinishCallback> funcFinish, vm::ptr<void> userdata)
{ {
fmt::throw_exception("Unimplemented" HERE); cellVideoExport.todo("cellVideoExportFromFile(srcHddDir=%s, srcHddFile=%s, param=*0x%x, funcFinish=*0x%x, userdata=*0x%x)", srcHddDir, srcHddFile, param, funcFinish, userdata);
sysutil_register_cb([=](ppu_thread& ppu) -> s32
{
funcFinish(ppu, CELL_OK, userdata);
return CELL_OK;
});
return CELL_OK;
} }
s32 cellVideoExportFinalize() error_code cellVideoExportFinalize(vm::ptr<CellVideoExportUtilFinishCallback> funcFinish, vm::ptr<void> userdata)
{ {
fmt::throw_exception("Unimplemented" HERE); cellVideoExport.todo("cellVideoExportFinalize(funcFinish=*0x%x, userdata=*0x%x)", funcFinish, userdata);
sysutil_register_cb([=](ppu_thread& ppu) -> s32
{
funcFinish(ppu, CELL_OK, userdata);
return CELL_OK;
});
return CELL_OK;
} }

View file

@ -2,13 +2,24 @@
#include "Emu/Cell/PPUModule.h" #include "Emu/Cell/PPUModule.h"
#include "cellVideoUpload.h" #include "cellVideoUpload.h"
#include "cellSysutil.h"
logs::channel cellVideoUpload("cellVideoUpload"); logs::channel cellVideoUpload("cellVideoUpload");
s32 cellVideoUploadInitialize(vm::cptr<CellVideoUploadParam> pParam, vm::ptr<CellVideoUploadCallback> cb, vm::ptr<void> userdata) error_code cellVideoUploadInitialize(vm::cptr<CellVideoUploadParam> pParam, vm::ptr<CellVideoUploadCallback> cb, vm::ptr<void> userdata)
{ {
cellVideoUpload.todo("cellVideoUploadInitialize(pParam=*0x%x, cb=*0x%x, userdata=*0x%x)", pParam, cb, userdata); cellVideoUpload.todo("cellVideoUploadInitialize(pParam=*0x%x, cb=*0x%x, userdata=*0x%x)", pParam, cb, userdata);
sysutil_register_cb([=](ppu_thread& ppu) -> s32
{
vm::var<char[]> pResultURL(128);
cb(ppu, CELL_VIDEO_UPLOAD_STATUS_INITIALIZED, CELL_OK, pResultURL, userdata);
cb(ppu, CELL_VIDEO_UPLOAD_STATUS_FINALIZED, CELL_OK, pResultURL, userdata);
return CELL_OK;
});
return CELL_OK; return CELL_OK;
} }

View file

@ -1,7 +1,5 @@
#pragma once #pragma once
namespace vm { using namespace ps3; }
struct CellVideoUploadOption struct CellVideoUploadOption
{ {
be_t<s32> type; be_t<s32> type;
@ -11,27 +9,27 @@ struct CellVideoUploadOption
struct CellVideoUploadParam struct CellVideoUploadParam
{ {
be_t<s32> siteID; be_t<s32> siteID;
vm::bcptr<char> pFilePath; vm::ps3::bcptr<char> pFilePath;
union union
{ {
struct struct
{ {
vm::bcptr<char> pClientId; vm::ps3::bcptr<char> pClientId;
vm::bcptr<char> pDeveloperKey; vm::ps3::bcptr<char> pDeveloperKey;
vm::bcptr<char> pTitle_UTF8; vm::ps3::bcptr<char> pTitle_UTF8;
vm::bcptr<char> pDescription_UTF8; vm::ps3::bcptr<char> pDescription_UTF8;
vm::bcptr<char> pKeyword_1_UTF8; vm::ps3::bcptr<char> pKeyword_1_UTF8;
vm::bcptr<char> pKeyword_2_UTF8; vm::ps3::bcptr<char> pKeyword_2_UTF8;
vm::bcptr<char> pKeyword_3_UTF8; vm::ps3::bcptr<char> pKeyword_3_UTF8;
u8 isPrivate; u8 isPrivate;
u8 rating; u8 rating;
} youtube; } youtube;
} u; } u;
be_t<s32> numOfOption; be_t<s32> numOfOption;
vm::bptr<CellVideoUploadOption> pOption; vm::ps3::bptr<CellVideoUploadOption> pOption;
}; };
typedef void(CellVideoUploadCallback)(s32 status, s32 errorCode, vm::cptr<char> pResultURL, vm::ptr<void> userdata); using CellVideoUploadCallback = void(s32 status, s32 errorCode, vm::ps3::cptr<char> pResultURL, vm::ps3::ptr<void> userdata);
enum enum
{ {
@ -59,3 +57,9 @@ enum
CELL_VIDEO_UPLOAD_ERROR_FILE_OPEN = 0x8002d023, CELL_VIDEO_UPLOAD_ERROR_FILE_OPEN = 0x8002d023,
CELL_VIDEO_UPLOAD_ERROR_INVALID_STATE = 0x8002d024 CELL_VIDEO_UPLOAD_ERROR_INVALID_STATE = 0x8002d024
}; };
enum
{
CELL_VIDEO_UPLOAD_STATUS_INITIALIZED = 1,
CELL_VIDEO_UPLOAD_STATUS_FINALIZED = 2
};

View file

@ -2,9 +2,16 @@
#include "Emu/Cell/PPUModule.h" #include "Emu/Cell/PPUModule.h"
#include "cellWebBrowser.h" #include "cellWebBrowser.h"
#include "Emu/IdManager.h"
extern logs::channel cellSysutil; extern logs::channel cellSysutil;
struct browser_t
{
vm::ptr<CellWebBrowserSystemCallback> system_cb;
vm::ptr<void> userData;
};
s32 cellWebBrowserActivate() s32 cellWebBrowserActivate()
{ {
fmt::throw_exception("Unimplemented" HERE); fmt::throw_exception("Unimplemented" HERE);
@ -15,9 +22,10 @@ s32 cellWebBrowserConfig()
fmt::throw_exception("Unimplemented" HERE); fmt::throw_exception("Unimplemented" HERE);
} }
s32 cellWebBrowserConfig2() error_code cellWebBrowserConfig2(vm::cptr<CellWebBrowserConfig2> config, u32 version)
{ {
fmt::throw_exception("Unimplemented" HERE); cellSysutil.todo("cellWebBrowserConfig2(config=*0x%x, version=%d)", config, version);
return CELL_OK;
} }
s32 cellWebBrowserConfigGetHeapSize() s32 cellWebBrowserConfigGetHeapSize()
@ -45,9 +53,10 @@ s32 cellWebBrowserConfigSetErrorHook2()
fmt::throw_exception("Unimplemented" HERE); fmt::throw_exception("Unimplemented" HERE);
} }
s32 cellWebBrowserConfigSetFullScreen2() error_code cellWebBrowserConfigSetFullScreen2(vm::cptr<CellWebBrowserConfig2> config, u32 full)
{ {
fmt::throw_exception("Unimplemented" HERE); cellSysutil.todo("cellWebBrowserConfigSetFullScreen2(config=*0x%x, full=%d)", config, full);
return CELL_OK;
} }
s32 cellWebBrowserConfigSetFullVersion2() s32 cellWebBrowserConfigSetFullVersion2()
@ -60,9 +69,10 @@ s32 cellWebBrowserConfigSetFunction()
fmt::throw_exception("Unimplemented" HERE); fmt::throw_exception("Unimplemented" HERE);
} }
s32 cellWebBrowserConfigSetFunction2() error_code cellWebBrowserConfigSetFunction2(vm::ptr<CellWebBrowserConfig2> config, u32 funcset)
{ {
fmt::throw_exception("Unimplemented" HERE); cellSysutil.todo("cellWebBrowserConfigSetFunction2(config=*0x%x, funcset=0x%x)", config, funcset);
return CELL_OK;
} }
s32 cellWebBrowserConfigSetHeapSize() s32 cellWebBrowserConfigSetHeapSize()
@ -70,9 +80,10 @@ s32 cellWebBrowserConfigSetHeapSize()
fmt::throw_exception("Unimplemented" HERE); fmt::throw_exception("Unimplemented" HERE);
} }
s32 cellWebBrowserConfigSetHeapSize2() error_code cellWebBrowserConfigSetHeapSize2(vm::ptr<CellWebBrowserConfig2> config, u32 size)
{ {
fmt::throw_exception("Unimplemented" HERE); cellSysutil.todo("cellWebBrowserConfigSetHeapSize(config=*0x%x, size=0x%x)", config, size);
return CELL_OK;
} }
s32 cellWebBrowserConfigSetMimeSet() s32 cellWebBrowserConfigSetMimeSet()
@ -80,9 +91,10 @@ s32 cellWebBrowserConfigSetMimeSet()
fmt::throw_exception("Unimplemented" HERE); fmt::throw_exception("Unimplemented" HERE);
} }
s32 cellWebBrowserConfigSetNotifyHook2() error_code cellWebBrowserConfigSetNotifyHook2(vm::cptr<CellWebBrowserConfig2> config, vm::ptr<CellWebBrowserNotify> cb, vm::ptr<void> userdata)
{ {
fmt::throw_exception("Unimplemented" HERE); cellSysutil.todo("cellWebBrowserConfigSetNotifyHook2(config=*0x%x, cb=*0x%x, userdata=*0x%x)", config, cb, userdata);
return CELL_OK;
} }
s32 cellWebBrowserConfigSetRequestHook2() s32 cellWebBrowserConfigSetRequestHook2()
@ -95,14 +107,16 @@ s32 cellWebBrowserConfigSetStatusHook2()
fmt::throw_exception("Unimplemented" HERE); fmt::throw_exception("Unimplemented" HERE);
} }
s32 cellWebBrowserConfigSetTabCount2() error_code cellWebBrowserConfigSetTabCount2(vm::cptr<CellWebBrowserConfig2> config, u32 tab_count)
{ {
fmt::throw_exception("Unimplemented" HERE); cellSysutil.todo("cellWebBrowserConfigSetTabCount2(config=*0x%x, tab_count=%d)", config, tab_count);
return CELL_OK;
} }
s32 cellWebBrowserConfigSetUnknownMIMETypeHook2() error_code cellWebBrowserConfigSetUnknownMIMETypeHook2(vm::cptr<CellWebBrowserConfig2> config, vm::ptr<CellWebBrowserMIMETypeCallback> cb, vm::ptr<void> userdata)
{ {
fmt::throw_exception("Unimplemented" HERE); cellSysutil.todo("cellWebBrowserConfigSetUnknownMIMETypeHook2(config=*0x%x, cb=*0x%x, userdata=*0x%x)", config, cb, userdata);
return CELL_OK;
} }
s32 cellWebBrowserConfigSetVersion() s32 cellWebBrowserConfigSetVersion()
@ -110,9 +124,10 @@ s32 cellWebBrowserConfigSetVersion()
fmt::throw_exception("Unimplemented" HERE); fmt::throw_exception("Unimplemented" HERE);
} }
s32 cellWebBrowserConfigSetViewCondition2() error_code cellWebBrowserConfigSetViewCondition2(vm::ptr<CellWebBrowserConfig2> config, u32 cond)
{ {
fmt::throw_exception("Unimplemented" HERE); cellSysutil.todo("cellWebBrowserConfigSetViewCondition2(config=*0x%x, cond=0x%x)", config, cond);
return CELL_OK;
} }
s32 cellWebBrowserConfigSetViewRect2() s32 cellWebBrowserConfigSetViewRect2()
@ -180,7 +195,7 @@ s32 cellWebBrowserEstimate()
fmt::throw_exception("Unimplemented" HERE); fmt::throw_exception("Unimplemented" HERE);
} }
s32 cellWebBrowserEstimate2(vm::cptr<CellWebBrowserConfig2> config, vm::ptr<u32> memSize) error_code cellWebBrowserEstimate2(vm::cptr<CellWebBrowserConfig2> config, vm::ptr<u32> memSize)
{ {
cellSysutil.warning("cellWebBrowserEstimate2(config=*0x%x, memSize=*0x%x)", config, memSize); cellSysutil.warning("cellWebBrowserEstimate2(config=*0x%x, memSize=*0x%x)", config, memSize);
@ -190,15 +205,26 @@ s32 cellWebBrowserEstimate2(vm::cptr<CellWebBrowserConfig2> config, vm::ptr<u32>
return CELL_OK; return CELL_OK;
} }
s32 cellWebBrowserGetUsrdataOnGameExit(vm::ptr<CellWebBrowserUsrdata> ptr) error_code cellWebBrowserGetUsrdataOnGameExit(vm::ptr<CellWebBrowserUsrdata> ptr)
{ {
cellSysutil.todo("cellWebBrowserGetUsrdataOnGameExit(ptr=*0x%x", ptr); cellSysutil.todo("cellWebBrowserGetUsrdataOnGameExit(ptr=*0x%x)", ptr);
return CELL_OK; return CELL_OK;
} }
s32 cellWebBrowserInitialize() error_code cellWebBrowserInitialize(vm::ptr<CellWebBrowserSystemCallback> system_cb, u32 container)
{ {
fmt::throw_exception("Unimplemented" HERE); cellSysutil.todo("cellWebBrowserInitialize(system_cb=*0x%x, container=0x%x)", system_cb, container);
const auto browser = fxm::make_always<browser_t>();
browser->system_cb = system_cb;
sysutil_register_cb([=](ppu_thread& ppu) -> s32
{
system_cb(ppu, CELL_SYSUTIL_WEBBROWSER_INITIALIZING_FINISHED, browser->userData);
return CELL_OK;
});
return CELL_OK;
} }
s32 cellWebBrowserNavigate2() s32 cellWebBrowserNavigate2()
@ -216,9 +242,17 @@ s32 cellWebBrowserSetSystemCallbackUsrdata()
fmt::throw_exception("Unimplemented" HERE); fmt::throw_exception("Unimplemented" HERE);
} }
s32 cellWebBrowserShutdown() void cellWebBrowserShutdown()
{ {
fmt::throw_exception("Unimplemented" HERE); cellSysutil.todo("cellWebBrowserShutdown()");
sysutil_register_cb([=](ppu_thread& ppu) -> s32
{
const auto browser = fxm::get_always<browser_t>();
browser->system_cb(ppu, CELL_SYSUTIL_WEBBROWSER_SHUTDOWN_FINISHED, browser->userData);
return CELL_OK;
});
} }
s32 cellWebBrowserUpdatePointerDisplayPos2() s32 cellWebBrowserUpdatePointerDisplayPos2()

View file

@ -2,6 +2,17 @@
#include "cellSysutil.h" #include "cellSysutil.h"
//events
enum CellWebBrowserEvent : s32
{
CELL_SYSUTIL_WEBBROWSER_INITIALIZING_FINISHED = 1,
CELL_SYSUTIL_WEBBROWSER_SHUTDOWN_FINISHED = 4,
CELL_SYSUTIL_WEBBROWSER_LOADING_FINISHED = 5,
CELL_SYSUTIL_WEBBROWSER_UNLOADING_FINISHED = 7,
CELL_SYSUTIL_WEBBROWSER_RELEASED = 9,
CELL_SYSUTIL_WEBBROWSER_GRABBED = 11,
};
using CellWebBrowserCallback = void(s32 cb_type, vm::ptr<void> client_session, vm::ptr<void> usrdata); using CellWebBrowserCallback = void(s32 cb_type, vm::ptr<void> client_session, vm::ptr<void> usrdata);
using CellWebComponentCallback = void(s32 web_browser_id, s32 cb_type, vm::ptr<void> client_session, vm::ptr<void> usrdata); using CellWebComponentCallback = void(s32 web_browser_id, s32 cb_type, vm::ptr<void> client_session, vm::ptr<void> usrdata);
using CellWebBrowserSystemCallback = void(s32 cb_type, vm::ptr<void> usrdata); using CellWebBrowserSystemCallback = void(s32 cb_type, vm::ptr<void> usrdata);

View file

@ -0,0 +1,41 @@
#include "stdafx.h"
#include "Emu/System.h"
#include "Emu/Cell/PPUModule.h"
namespace vm { using namespace ps3; }
logs::channel sceNpMatchingInt("sceNpMatchingInt");
s32 sceNpMatchingGetRoomMemberList()
{
UNIMPLEMENTED_FUNC(sceNpMatchingInt);
return CELL_OK;
}
// Parameter "unknown" added to distinguish this function
// from the one in sceNp.cpp which has the same name
s32 sceNpMatchingJoinRoomGUI(vm::ptr<void> unknown)
{
UNIMPLEMENTED_FUNC(sceNpMatchingInt);
return CELL_OK;
}
s32 sceNpMatchingGetRoomListGUI()
{
UNIMPLEMENTED_FUNC(sceNpMatchingInt);
return CELL_OK;
}
s32 sceNpMatchingSendRoomMessage()
{
UNIMPLEMENTED_FUNC(sceNpMatchingInt);
return CELL_OK;
}
DECLARE(ppu_module_manager::sceNpMatchingInt)("sceNpMatchingInt", []()
{
REG_FUNC(sceNpMatchingInt, sceNpMatchingGetRoomMemberList);
REG_FUNC(sceNpMatchingInt, sceNpMatchingJoinRoomGUI);
REG_FUNC(sceNpMatchingInt, sceNpMatchingGetRoomListGUI);
REG_FUNC(sceNpMatchingInt, sceNpMatchingSendRoomMessage);
});

View file

@ -244,6 +244,7 @@ static void ppu_initialize_modules(const std::shared_ptr<ppu_linkage_info>& link
&ppu_module_manager::sceNp2, &ppu_module_manager::sceNp2,
&ppu_module_manager::sceNpClans, &ppu_module_manager::sceNpClans,
&ppu_module_manager::sceNpCommerce2, &ppu_module_manager::sceNpCommerce2,
&ppu_module_manager::sceNpMatchingInt,
&ppu_module_manager::sceNpSns, &ppu_module_manager::sceNpSns,
&ppu_module_manager::sceNpTrophy, &ppu_module_manager::sceNpTrophy,
&ppu_module_manager::sceNpTus, &ppu_module_manager::sceNpTus,

View file

@ -255,6 +255,7 @@ public:
static const ppu_static_module sceNp2; static const ppu_static_module sceNp2;
static const ppu_static_module sceNpClans; static const ppu_static_module sceNpClans;
static const ppu_static_module sceNpCommerce2; static const ppu_static_module sceNpCommerce2;
static const ppu_static_module sceNpMatchingInt;
static const ppu_static_module sceNpSns; static const ppu_static_module sceNpSns;
static const ppu_static_module sceNpTrophy; static const ppu_static_module sceNpTrophy;
static const ppu_static_module sceNpTus; static const ppu_static_module sceNpTus;

View file

@ -12,9 +12,7 @@ using namespace llvm;
const ppu_decoder<PPUTranslator> s_ppu_decoder; const ppu_decoder<PPUTranslator> s_ppu_decoder;
PPUTranslator::PPUTranslator(LLVMContext& context, Module* module, const ppu_module& info) PPUTranslator::PPUTranslator(LLVMContext& context, Module* module, const ppu_module& info)
: m_context(context) : cpu_translator(context, module, false)
, m_module(module)
, m_is_be(false)
, m_info(info) , m_info(info)
, m_pure_attr(AttributeSet::get(m_context, AttributeSet::FunctionIndex, {Attribute::NoUnwind, Attribute::ReadNone})) , m_pure_attr(AttributeSet::get(m_context, AttributeSet::FunctionIndex, {Attribute::NoUnwind, Attribute::ReadNone}))
{ {
@ -564,136 +562,156 @@ void PPUTranslator::MTVSCR(ppu_opcode_t op)
void PPUTranslator::VADDCUW(ppu_opcode_t op) void PPUTranslator::VADDCUW(ppu_opcode_t op)
{ {
const auto ab = GetVrs(VrType::vi32, op.va, op.vb); const auto a = get_vr<u32[4]>(op.va);
SetVr(op.vd, ZExt(m_ir->CreateICmpULT(m_ir->CreateAdd(ab[0], ab[1]), ab[0]), GetType<u32[4]>())); const auto b = get_vr<u32[4]>(op.vb);
set_vr(op.vd, eval(ucarry(a, b, eval(a + b)) >> 31));
} }
void PPUTranslator::VADDFP(ppu_opcode_t op) void PPUTranslator::VADDFP(ppu_opcode_t op)
{ {
const auto ab = GetVrs(VrType::vf, op.va, op.vb); const auto a = get_vr<f32[4]>(op.va);
SetVr(op.vd, m_ir->CreateFAdd(ab[0], ab[1])); const auto b = get_vr<f32[4]>(op.vb);
set_vr(op.vd, eval(a + b));
} }
void PPUTranslator::VADDSBS(ppu_opcode_t op) void PPUTranslator::VADDSBS(ppu_opcode_t op)
{ {
const auto ab = SExt(GetVrs(VrType::vi8, op.va, op.vb)); const auto a = get_vr<s8[16]>(op.va);
const auto result = m_ir->CreateAdd(ab[0], ab[1]); const auto b = get_vr<s8[16]>(op.vb);
const auto saturated = SaturateSigned(result, -0x80, 0x7f); const auto s = eval(a + b);
SetVr(op.vd, saturated.first); const auto z = eval((a >> 7) ^ 0x7f);
SetSat(IsNotZero(saturated.second)); const auto x = eval(scarry(a, b, s) >> 7);
set_vr(op.vd, eval(merge(x, z, s)));
SetSat(IsNotZero(x.value));
} }
void PPUTranslator::VADDSHS(ppu_opcode_t op) void PPUTranslator::VADDSHS(ppu_opcode_t op)
{ {
const auto ab = SExt(GetVrs(VrType::vi16, op.va, op.vb)); const auto a = get_vr<s16[8]>(op.va);
const auto result = m_ir->CreateAdd(ab[0], ab[1]); const auto b = get_vr<s16[8]>(op.vb);
const auto saturated = SaturateSigned(result, -0x8000, 0x7fff); const auto s = eval(a + b);
SetVr(op.vd, saturated.first); const auto z = eval((a >> 15) ^ 0x7fff);
SetSat(IsNotZero(saturated.second)); const auto x = eval(scarry(a, b, s) >> 15);
set_vr(op.vd, eval(merge(x, z, s)));
SetSat(IsNotZero(x.value));
} }
void PPUTranslator::VADDSWS(ppu_opcode_t op) void PPUTranslator::VADDSWS(ppu_opcode_t op)
{ {
const auto ab = SExt(GetVrs(VrType::vi32, op.va, op.vb)); const auto a = get_vr<s32[4]>(op.va);
const auto result = m_ir->CreateAdd(ab[0], ab[1]); const auto b = get_vr<s32[4]>(op.vb);
const auto saturated = SaturateSigned(result, -0x80000000ll, 0x7fffffff); const auto s = eval(a + b);
SetVr(op.vd, saturated.first); const auto z = eval((a >> 31) ^ 0x7fffffff);
SetSat(IsNotZero(saturated.second)); const auto x = eval(scarry(a, b, s) >> 31);
set_vr(op.vd, eval(merge(x, z, s)));
SetSat(IsNotZero(x.value));
} }
void PPUTranslator::VADDUBM(ppu_opcode_t op) void PPUTranslator::VADDUBM(ppu_opcode_t op)
{ {
const auto ab = GetVrs(VrType::vi8, op.va, op.vb); const auto a = get_vr<u8[16]>(op.va);
SetVr(op.vd, m_ir->CreateAdd(ab[0], ab[1])); const auto b = get_vr<u8[16]>(op.vb);
set_vr(op.vd, eval(a + b));
} }
void PPUTranslator::VADDUBS(ppu_opcode_t op) void PPUTranslator::VADDUBS(ppu_opcode_t op)
{ {
const auto ab = ZExt(GetVrs(VrType::vi8, op.va, op.vb)); const auto a = get_vr<s8[16]>(op.va);
const auto result = m_ir->CreateAdd(ab[0], ab[1]); const auto b = get_vr<s8[16]>(op.vb);
const auto saturated = Saturate(result, ICmpInst::ICMP_UGT, m_ir->getInt16(0xff)); const auto s = eval(a + b);
SetVr(op.vd, saturated.first); const auto x = eval(ucarry(a, b, s) >> 7);
SetSat(IsNotZero(saturated.second)); set_vr(op.vd, eval(s | x));
SetSat(IsNotZero(x.value));
} }
void PPUTranslator::VADDUHM(ppu_opcode_t op) void PPUTranslator::VADDUHM(ppu_opcode_t op)
{ {
const auto ab = GetVrs(VrType::vi16, op.va, op.vb); const auto a = get_vr<u16[8]>(op.va);
SetVr(op.vd, m_ir->CreateAdd(ab[0], ab[1])); const auto b = get_vr<u16[8]>(op.vb);
set_vr(op.vd, eval(a + b));
} }
void PPUTranslator::VADDUHS(ppu_opcode_t op) void PPUTranslator::VADDUHS(ppu_opcode_t op)
{ {
const auto ab = ZExt(GetVrs(VrType::vi16, op.va, op.vb)); const auto a = get_vr<s16[8]>(op.va);
const auto result = m_ir->CreateAdd(ab[0], ab[1]); const auto b = get_vr<s16[8]>(op.vb);
const auto saturated = Saturate(result, ICmpInst::ICMP_UGT, m_ir->getInt32(0xffff)); const auto s = eval(a + b);
SetVr(op.vd, saturated.first); const auto x = eval(ucarry(a, b, s) >> 15);
SetSat(IsNotZero(saturated.second)); set_vr(op.vd, eval(s | x));
SetSat(IsNotZero(x.value));
} }
void PPUTranslator::VADDUWM(ppu_opcode_t op) void PPUTranslator::VADDUWM(ppu_opcode_t op)
{ {
const auto ab = GetVrs(VrType::vi32, op.va, op.vb); const auto a = get_vr<u32[4]>(op.va);
SetVr(op.vd, m_ir->CreateAdd(ab[0], ab[1])); const auto b = get_vr<u32[4]>(op.vb);
set_vr(op.vd, eval(a + b));
} }
void PPUTranslator::VADDUWS(ppu_opcode_t op) void PPUTranslator::VADDUWS(ppu_opcode_t op)
{ {
const auto ab = ZExt(GetVrs(VrType::vi32, op.va, op.vb)); const auto a = get_vr<s32[4]>(op.va);
const auto result = m_ir->CreateAdd(ab[0], ab[1]); const auto b = get_vr<s32[4]>(op.vb);
const auto saturated = Saturate(result, ICmpInst::ICMP_UGT, m_ir->getInt64(0xffffffff)); const auto s = eval(a + b);
SetVr(op.vd, saturated.first); const auto x = eval(ucarry(a, b, s) >> 31);
SetSat(IsNotZero(saturated.second)); set_vr(op.vd, eval(s | x));
SetSat(IsNotZero(x.value));
} }
void PPUTranslator::VAND(ppu_opcode_t op) void PPUTranslator::VAND(ppu_opcode_t op)
{ {
const auto ab = GetVrs(VrType::vi32, op.va, op.vb); const auto a = get_vr<u32[4]>(op.va);
SetVr(op.vd, m_ir->CreateAnd(ab[0], ab[1])); const auto b = get_vr<u32[4]>(op.vb);
set_vr(op.vd, eval(a & b));
} }
void PPUTranslator::VANDC(ppu_opcode_t op) void PPUTranslator::VANDC(ppu_opcode_t op)
{ {
const auto ab = GetVrs(VrType::vi32, op.va, op.vb); const auto a = get_vr<u32[4]>(op.va);
SetVr(op.vd, m_ir->CreateAnd(ab[0], m_ir->CreateNot(ab[1]))); const auto b = get_vr<u32[4]>(op.vb);
set_vr(op.vd, eval(a & ~b));
} }
#define AVG_OP(a, b) m_ir->CreateLShr(m_ir->CreateSub(a, m_ir->CreateNot(b)), 1) /* (a + b + 1) >> 1 */
void PPUTranslator::VAVGSB(ppu_opcode_t op) void PPUTranslator::VAVGSB(ppu_opcode_t op)
{ {
const auto ab = SExt(GetVrs(VrType::vi8, op.va, op.vb)); const auto a = get_vr<s8[16]>(op.va);
SetVr(op.vd, AVG_OP(ab[0], ab[1])); const auto b = get_vr<s8[16]>(op.vb);
set_vr(op.vd, eval(avg(a, b)));
} }
void PPUTranslator::VAVGSH(ppu_opcode_t op) void PPUTranslator::VAVGSH(ppu_opcode_t op)
{ {
const auto ab = SExt(GetVrs(VrType::vi16, op.va, op.vb)); const auto a = get_vr<s16[8]>(op.va);
SetVr(op.vd, AVG_OP(ab[0], ab[1])); const auto b = get_vr<s16[8]>(op.vb);
set_vr(op.vd, eval(avg(a, b)));
} }
void PPUTranslator::VAVGSW(ppu_opcode_t op) void PPUTranslator::VAVGSW(ppu_opcode_t op)
{ {
const auto ab = SExt(GetVrs(VrType::vi32, op.va, op.vb)); const auto a = get_vr<s32[4]>(op.va);
SetVr(op.vd, AVG_OP(ab[0], ab[1])); const auto b = get_vr<s32[4]>(op.vb);
set_vr(op.vd, eval(avg(a, b)));
} }
void PPUTranslator::VAVGUB(ppu_opcode_t op) void PPUTranslator::VAVGUB(ppu_opcode_t op)
{ {
const auto ab = ZExt(GetVrs(VrType::vi8, op.va, op.vb)); const auto a = get_vr<u8[16]>(op.va);
SetVr(op.vd, AVG_OP(ab[0], ab[1])); const auto b = get_vr<u8[16]>(op.vb);
set_vr(op.vd, eval(avg(a, b)));
} }
void PPUTranslator::VAVGUH(ppu_opcode_t op) void PPUTranslator::VAVGUH(ppu_opcode_t op)
{ {
const auto ab = ZExt(GetVrs(VrType::vi16, op.va, op.vb)); const auto a = get_vr<u16[8]>(op.va);
SetVr(op.vd, AVG_OP(ab[0], ab[1])); const auto b = get_vr<u16[8]>(op.vb);
set_vr(op.vd, eval(avg(a, b)));
} }
void PPUTranslator::VAVGUW(ppu_opcode_t op) void PPUTranslator::VAVGUW(ppu_opcode_t op)
{ {
const auto ab = ZExt(GetVrs(VrType::vi32, op.va, op.vb)); const auto a = get_vr<u32[4]>(op.va);
SetVr(op.vd, AVG_OP(ab[0], ab[1])); const auto b = get_vr<u32[4]>(op.vb);
set_vr(op.vd, eval(avg(a, b)));
} }
void PPUTranslator::VCFSX(ppu_opcode_t op) void PPUTranslator::VCFSX(ppu_opcode_t op)
@ -1134,14 +1152,16 @@ void PPUTranslator::VNMSUBFP(ppu_opcode_t op)
void PPUTranslator::VNOR(ppu_opcode_t op) void PPUTranslator::VNOR(ppu_opcode_t op)
{ {
const auto ab = GetVrs(VrType::vi32, op.va, op.vb); const auto a = get_vr<u32[4]>(op.va);
SetVr(op.vd, m_ir->CreateNot(m_ir->CreateOr(ab[0], ab[1]))); const auto b = get_vr<u32[4]>(op.vb);
set_vr(op.vd, eval(~(a | b)));
} }
void PPUTranslator::VOR(ppu_opcode_t op) void PPUTranslator::VOR(ppu_opcode_t op)
{ {
const auto ab = GetVrs(VrType::vi32, op.va, op.vb); const auto a = get_vr<u32[4]>(op.va);
SetVr(op.vd, m_ir->CreateOr(ab[0], ab[1])); const auto b = get_vr<u32[4]>(op.vb);
set_vr(op.vd, eval(a | b));
} }
void PPUTranslator::VPERM(ppu_opcode_t op) void PPUTranslator::VPERM(ppu_opcode_t op)
@ -1424,86 +1444,100 @@ void PPUTranslator::VSRW(ppu_opcode_t op)
void PPUTranslator::VSUBCUW(ppu_opcode_t op) void PPUTranslator::VSUBCUW(ppu_opcode_t op)
{ {
const auto ab = GetVrs(VrType::vi32, op.va, op.vb); const auto a = get_vr<u32[4]>(op.va);
SetVr(op.vd, ZExt(m_ir->CreateICmpUGE(ab[0], ab[1]), GetType<u32[4]>())); const auto b = get_vr<u32[4]>(op.vb);
set_vr(op.vd, eval(~ucarry(b, eval(a - b), a) >> 31));
} }
void PPUTranslator::VSUBFP(ppu_opcode_t op) void PPUTranslator::VSUBFP(ppu_opcode_t op)
{ {
const auto ab = GetVrs(VrType::vf, op.va, op.vb); const auto a = get_vr<f32[4]>(op.va);
SetVr(op.vd, m_ir->CreateFSub(ab[0], ab[1])); const auto b = get_vr<f32[4]>(op.vb);
set_vr(op.vd, eval(a - b));
} }
void PPUTranslator::VSUBSBS(ppu_opcode_t op) void PPUTranslator::VSUBSBS(ppu_opcode_t op)
{ {
const auto ab = SExt(GetVrs(VrType::vi8, op.va, op.vb)); const auto a = get_vr<s8[16]>(op.va);
const auto result = m_ir->CreateSub(ab[0], ab[1]); const auto b = get_vr<s8[16]>(op.vb);
const auto saturated = SaturateSigned(result, -0x80, 0x7f); const auto d = eval(a - b);
SetVr(op.vd, saturated.first); const auto z = eval((a >> 7) ^ 0x7f);
SetSat(IsNotZero(saturated.second)); const auto x = eval(sborrow(a, b, d) >> 7);
set_vr(op.vd, eval(merge(x, z, d)));
SetSat(IsNotZero(x.value));
} }
void PPUTranslator::VSUBSHS(ppu_opcode_t op) void PPUTranslator::VSUBSHS(ppu_opcode_t op)
{ {
const auto ab = SExt(GetVrs(VrType::vi16, op.va, op.vb)); const auto a = get_vr<s16[8]>(op.va);
const auto result = m_ir->CreateSub(ab[0], ab[1]); const auto b = get_vr<s16[8]>(op.vb);
const auto saturated = SaturateSigned(result, -0x8000, 0x7fff); const auto d = eval(a - b);
SetVr(op.vd, saturated.first); const auto z = eval((a >> 15) ^ 0x7fff);
SetSat(IsNotZero(saturated.second)); const auto x = eval(sborrow(a, b, d) >> 15);
set_vr(op.vd, eval(merge(x, z, d)));
SetSat(IsNotZero(x.value));
} }
void PPUTranslator::VSUBSWS(ppu_opcode_t op) void PPUTranslator::VSUBSWS(ppu_opcode_t op)
{ {
const auto ab = SExt(GetVrs(VrType::vi32, op.va, op.vb)); const auto a = get_vr<s32[4]>(op.va);
const auto result = m_ir->CreateSub(ab[0], ab[1]); const auto b = get_vr<s32[4]>(op.vb);
const auto saturated = SaturateSigned(result, -0x80000000ll, 0x7fffffff); const auto d = eval(a - b);
SetVr(op.vd, saturated.first); const auto z = eval((a >> 31) ^ 0x7fffffff);
SetSat(IsNotZero(saturated.second)); const auto x = eval(sborrow(a, b, d) >> 31);
set_vr(op.vd, eval(merge(x, z, d)));
SetSat(IsNotZero(x.value));
} }
void PPUTranslator::VSUBUBM(ppu_opcode_t op) void PPUTranslator::VSUBUBM(ppu_opcode_t op)
{ {
const auto ab = GetVrs(VrType::vi8, op.va, op.vb); const auto a = get_vr<u8[16]>(op.va);
SetVr(op.vd, m_ir->CreateSub(ab[0], ab[1])); const auto b = get_vr<u8[16]>(op.vb);
set_vr(op.vd, eval(a - b));
} }
void PPUTranslator::VSUBUBS(ppu_opcode_t op) void PPUTranslator::VSUBUBS(ppu_opcode_t op)
{ {
const auto ab = ZExt(GetVrs(VrType::vi8, op.va, op.vb)); const auto a = get_vr<s8[16]>(op.va);
const auto result = m_ir->CreateSub(ab[0], ab[1]); const auto b = get_vr<s8[16]>(op.vb);
const auto saturated = Saturate(result, ICmpInst::ICMP_SLT, m_ir->getInt16(0)); const auto d = eval(a - b);
SetVr(op.vd, saturated.first); const auto x = eval(ucarry(b, d, a) >> 7);
SetSat(IsNotZero(saturated.second)); set_vr(op.vd, eval(d & ~x));
SetSat(IsNotZero(x.value));
} }
void PPUTranslator::VSUBUHM(ppu_opcode_t op) void PPUTranslator::VSUBUHM(ppu_opcode_t op)
{ {
const auto ab = GetVrs(VrType::vi16, op.va, op.vb); const auto a = get_vr<u16[8]>(op.va);
SetVr(op.vd, m_ir->CreateSub(ab[0], ab[1])); const auto b = get_vr<u16[8]>(op.vb);
set_vr(op.vd, eval(a - b));
} }
void PPUTranslator::VSUBUHS(ppu_opcode_t op) void PPUTranslator::VSUBUHS(ppu_opcode_t op)
{ {
const auto ab = ZExt(GetVrs(VrType::vi16, op.va, op.vb)); const auto a = get_vr<s16[8]>(op.va);
const auto result = m_ir->CreateSub(ab[0], ab[1]); const auto b = get_vr<s16[8]>(op.vb);
const auto saturated = Saturate(result, ICmpInst::ICMP_SLT, m_ir->getInt32(0)); const auto d = eval(a - b);
SetVr(op.vd, saturated.first); const auto x = eval(ucarry(b, d, a) >> 15);
SetSat(IsNotZero(saturated.second)); set_vr(op.vd, eval(d & ~x));
SetSat(IsNotZero(x.value));
} }
void PPUTranslator::VSUBUWM(ppu_opcode_t op) void PPUTranslator::VSUBUWM(ppu_opcode_t op)
{ {
const auto ab = GetVrs(VrType::vi32, op.va, op.vb); const auto a = get_vr<u32[4]>(op.va);
SetVr(op.vd, m_ir->CreateSub(ab[0], ab[1])); const auto b = get_vr<u32[4]>(op.vb);
set_vr(op.vd, eval(a - b));
} }
void PPUTranslator::VSUBUWS(ppu_opcode_t op) void PPUTranslator::VSUBUWS(ppu_opcode_t op)
{ {
const auto ab = ZExt(GetVrs(VrType::vi32, op.va, op.vb)); const auto a = get_vr<s32[4]>(op.va);
const auto result = m_ir->CreateSub(ab[0], ab[1]); const auto b = get_vr<s32[4]>(op.vb);
const auto saturated = Saturate(result, ICmpInst::ICMP_SLT, m_ir->getInt64(0)); const auto d = eval(a - b);
SetVr(op.vd, saturated.first); const auto x = eval(ucarry(b, d, a) >> 31);
SetSat(IsNotZero(saturated.second)); set_vr(op.vd, eval(d & ~x));
SetSat(IsNotZero(x.value));
} }
void PPUTranslator::VSUMSWS(ppu_opcode_t op) void PPUTranslator::VSUMSWS(ppu_opcode_t op)

View file

@ -2,117 +2,12 @@
#ifdef LLVM_AVAILABLE #ifdef LLVM_AVAILABLE
#include <unordered_map> #include "../rpcs3/Emu/CPU/CPUTranslator.h"
#include <map>
#include <unordered_set>
#include <set>
#include <array>
#include <vector>
#include "../rpcs3/Emu/Cell/PPUOpcodes.h" #include "../rpcs3/Emu/Cell/PPUOpcodes.h"
#include "../rpcs3/Emu/Cell/PPUAnalyser.h" #include "../rpcs3/Emu/Cell/PPUAnalyser.h"
#include "restore_new.h" class PPUTranslator final : public cpu_translator
#ifdef _MSC_VER
#pragma warning(push, 0)
#endif
#include "llvm/IR/LLVMContext.h"
#include "llvm/IR/IRBuilder.h"
#include "llvm/IR/Module.h"
#ifdef _MSC_VER
#pragma warning(pop)
#endif
#include "define_new_memleakdetect.h"
#include "../Utilities/types.h"
#include "../Utilities/StrFmt.h"
#include "../Utilities/BEType.h"
template<typename T, typename = void>
struct TypeGen
{ {
static_assert(!sizeof(T), "GetType<>() error: unknown type");
};
template<typename T>
struct TypeGen<T, std::enable_if_t<std::is_void<T>::value>>
{
static llvm::Type* get(llvm::LLVMContext& context) { return llvm::Type::getVoidTy(context); }
};
template<typename T>
struct TypeGen<T, std::enable_if_t<std::is_same<T, s64>::value || std::is_same<T, u64>::value || std::is_same<T, uptr>::value>>
{
static llvm::Type* get(llvm::LLVMContext& context) { return llvm::Type::getInt64Ty(context); }
};
template<typename T>
struct TypeGen<T, std::enable_if_t<std::is_same<T, s32>::value || std::is_same<T, u32>::value>>
{
static llvm::Type* get(llvm::LLVMContext& context) { return llvm::Type::getInt32Ty(context); }
};
template<typename T>
struct TypeGen<T, std::enable_if_t<std::is_same<T, s16>::value || std::is_same<T, u16>::value>>
{
static llvm::Type* get(llvm::LLVMContext& context) { return llvm::Type::getInt16Ty(context); }
};
template<typename T>
struct TypeGen<T, std::enable_if_t<std::is_same<T, s8>::value || std::is_same<T, u8>::value || std::is_same<T, char>::value>>
{
static llvm::Type* get(llvm::LLVMContext& context) { return llvm::Type::getInt8Ty(context); }
};
template<>
struct TypeGen<f32, void>
{
static llvm::Type* get(llvm::LLVMContext& context) { return llvm::Type::getFloatTy(context); }
};
template<>
struct TypeGen<f64, void>
{
static llvm::Type* get(llvm::LLVMContext& context) { return llvm::Type::getDoubleTy(context); }
};
template<>
struct TypeGen<bool, void>
{
static llvm::Type* get(llvm::LLVMContext& context) { return llvm::Type::getInt1Ty(context); }
};
template<>
struct TypeGen<u128, void>
{
static llvm::Type* get(llvm::LLVMContext& context) { return llvm::Type::getIntNTy(context, 128); }
};
// Pointer type
template<typename T>
struct TypeGen<T*, void>
{
static llvm::Type* get(llvm::LLVMContext& context) { return TypeGen<T>::get(context)->getPointerTo(); }
};
// Vector type
template<typename T, int N>
struct TypeGen<T[N], void>
{
static llvm::Type* get(llvm::LLVMContext& context) { return llvm::VectorType::get(TypeGen<T>::get(context), N); }
};
class PPUTranslator final //: public CPUTranslator
{
// LLVM context
llvm::LLVMContext& m_context;
// Module to which all generated code is output to
llvm::Module* const m_module;
// Endianness, affects vector element numbering (TODO)
const bool m_is_be;
// PPU Module // PPU Module
const ppu_module& m_info; const ppu_module& m_info;
@ -122,9 +17,6 @@ class PPUTranslator final //: public CPUTranslator
// Attributes for function calls which are "pure" and may be optimized away if their results are unused // Attributes for function calls which are "pure" and may be optimized away if their results are unused
const llvm::AttributeSet m_pure_attr; const llvm::AttributeSet m_pure_attr;
// IR builder
llvm::IRBuilder<>* m_ir;
// LLVM function // LLVM function
llvm::Function* m_function; llvm::Function* m_function;
@ -191,6 +83,20 @@ class PPUTranslator final //: public CPUTranslator
#undef DEF_VALUE #undef DEF_VALUE
public: public:
template <typename T>
value_t<T> get_vr(u32 vr)
{
value_t<T> result;
result.value = m_ir->CreateBitCast(GetVr(vr, VrType::vi32), value_t<T>::get_type(m_context));
return result;
}
template <typename T>
void set_vr(u32 vr, value_t<T> v)
{
return SetVr(vr, v.value);
}
// Get current instruction address // Get current instruction address
llvm::Value* GetAddr(u64 _add = 0); llvm::Value* GetAddr(u64 _add = 0);
@ -382,19 +288,6 @@ public:
// Write to memory // Write to memory
void WriteMemory(llvm::Value* addr, llvm::Value* value, bool is_be = true, u32 align = 1); void WriteMemory(llvm::Value* addr, llvm::Value* value, bool is_be = true, u32 align = 1);
// Convert a C++ type to an LLVM type
template<typename T>
llvm::Type* GetType()
{
return TypeGen<T>::get(m_context);
}
template<typename T>
llvm::PointerType* GetPtrType()
{
return TypeGen<T>::get(m_context)->getPointerTo();
}
// Get an undefined value with specified type // Get an undefined value with specified type
template<typename T> template<typename T>
llvm::Value* GetUndef() llvm::Value* GetUndef()

View file

@ -157,6 +157,14 @@ void spu_recompiler::compile(spu_function_t& f)
// Start compilation // Start compilation
m_pos = f.addr; m_pos = f.addr;
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) for (const u32 op : f.data)
{ {
// Bind label if initialized // Bind label if initialized
@ -615,6 +623,16 @@ void spu_recompiler::ROT(spu_opcode_t op)
return; 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 auto body = [](u32* t, const u32* a, const s32* b) noexcept
{ {
for (u32 i = 0; i < 4; i++) for (u32 i = 0; i < 4; i++)
@ -654,6 +672,22 @@ void spu_recompiler::ROTM(spu_opcode_t op)
return; 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 auto body = [](u32* t, const u32* a, const u32* b) noexcept
{ {
for (u32 i = 0; i < 4; i++) for (u32 i = 0; i < 4; i++)
@ -694,6 +728,21 @@ void spu_recompiler::ROTMA(spu_opcode_t op)
return; 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 auto body = [](s32* t, const s32* a, const u32* b) noexcept
{ {
for (u32 i = 0; i < 4; i++) for (u32 i = 0; i < 4; i++)
@ -733,6 +782,19 @@ void spu_recompiler::SHL(spu_opcode_t op)
return; 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 auto body = [](u32* t, const u32* a, const u32* b) noexcept
{ {
for (u32 i = 0; i < 4; i++) for (u32 i = 0; i < 4; i++)
@ -766,13 +828,24 @@ void spu_recompiler::ROTH(spu_opcode_t op) //nf
const XmmLink& vb = XmmGet(op.rb, XmmType::Int); const XmmLink& vb = XmmGet(op.rb, XmmType::Int);
const XmmLink& vt = XmmAlloc(); const XmmLink& vt = XmmAlloc();
const XmmLink& v4 = XmmAlloc(); const XmmLink& v4 = XmmAlloc();
c->movdqa(v4, XmmConst(_mm_set1_epi16(0xf))); c->vmovdqa(v4, XmmConst(_mm_set_epi32(0x0d0c0d0c, 0x09080908, 0x05040504, 0x01000100)));
c->pand(vb, v4); c->vpshufb(vt, va, v4); // duplicate low word
c->vpsllvw(vt, va, vb); c->vpsrld(va, va, 16);
c->psubw(vb, XmmConst(_mm_set1_epi16(1))); c->vpshufb(va, va, v4);
c->pandn(vb, v4); c->vpsrld(v4, vb, 16);
c->vpsrlvw(va, va, vb); c->vprolvd(va, va, v4);
c->por(vt, va); 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); c->movdqa(SPU_OFF_128(gpr, op.rt), vt);
return; return;
} }
@ -816,6 +889,42 @@ void spu_recompiler::ROTHM(spu_opcode_t op)
return; 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 auto body = [](u16* t, const u16* a, const u16* b) noexcept
{ {
for (u32 i = 0; i < 8; i++) for (u32 i = 0; i < 8; i++)
@ -856,6 +965,43 @@ void spu_recompiler::ROTMAH(spu_opcode_t op)
return; 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 auto body = [](s16* t, const s16* a, const u16* b) noexcept
{ {
for (u32 i = 0; i < 8; i++) for (u32 i = 0; i < 8; i++)
@ -895,6 +1041,38 @@ void spu_recompiler::SHLH(spu_opcode_t op)
return; 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 auto body = [](u16* t, const u16* a, const u16* b) noexcept
{ {
for (u32 i = 0; i < 8; i++) for (u32 i = 0; i < 8; i++)
@ -933,6 +1111,14 @@ void spu_recompiler::ROTI(spu_opcode_t op)
return; 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& va = XmmGet(op.ra, XmmType::Int);
const XmmLink& v1 = XmmAlloc(); const XmmLink& v1 = XmmAlloc();
c->movdqa(v1, va); c->movdqa(v1, va);
@ -1530,50 +1716,57 @@ void spu_recompiler::CDX(spu_opcode_t op)
void spu_recompiler::ROTQBI(spu_opcode_t op) void spu_recompiler::ROTQBI(spu_opcode_t op)
{ {
c->mov(*qw0, SPU_OFF_64(gpr, op.ra, &v128::_u64, 0)); const XmmLink& va = XmmGet(op.ra, XmmType::Int);
c->mov(*qw1, SPU_OFF_64(gpr, op.ra, &v128::_u64, 1)); const XmmLink& vb = XmmGet(op.rb, XmmType::Int);
c->mov(*qw2, *qw0); const XmmLink& vt = XmmAlloc();
c->mov(*addr, SPU_OFF_32(gpr, op.rb, &v128::_u32, 3)); const XmmLink& v4 = XmmAlloc();
c->and_(*addr, 7); c->psrldq(vb, 12);
c->shld(*qw0, *qw1, *addr); c->pand(vb, XmmConst(_mm_set_epi64x(0, 7)));
c->shld(*qw1, *qw2, *addr); c->movdqa(v4, XmmConst(_mm_set_epi64x(0, 64)));
c->mov(SPU_OFF_64(gpr, op.rt, &v128::_u64, 0), *qw0); c->pshufd(vt, va, 0x4e);
c->mov(SPU_OFF_64(gpr, op.rt, &v128::_u64, 1), *qw1); c->psubq(v4, vb);
c->unuse(*addr); c->psllq(va, vb);
c->unuse(*qw0); c->psrlq(vt, v4);
c->unuse(*qw1); c->por(vt, va);
c->unuse(*qw2); c->movdqa(SPU_OFF_128(gpr, op.rt), vt);
} }
void spu_recompiler::ROTQMBI(spu_opcode_t op) void spu_recompiler::ROTQMBI(spu_opcode_t op)
{ {
c->mov(*qw0, SPU_OFF_64(gpr, op.ra, &v128::_u64, 0)); const XmmLink& va = XmmGet(op.ra, XmmType::Int);
c->mov(*qw1, SPU_OFF_64(gpr, op.ra, &v128::_u64, 1)); const XmmLink& vb = XmmAlloc();
c->mov(*addr, SPU_OFF_32(gpr, op.rb, &v128::_u32, 3)); const XmmLink& vt = XmmGet(op.rb, XmmType::Int);
c->neg(*addr); const XmmLink& v4 = XmmAlloc();
c->and_(*addr, 7); c->psrldq(vt, 12);
c->shrd(*qw0, *qw1, *addr); c->pxor(vb, vb);
c->shr(*qw1, *addr); c->psubq(vb, vt);
c->mov(SPU_OFF_64(gpr, op.rt, &v128::_u64, 0), *qw0); c->pand(vb, XmmConst(_mm_set_epi64x(0, 7)));
c->mov(SPU_OFF_64(gpr, op.rt, &v128::_u64, 1), *qw1); c->movdqa(v4, XmmConst(_mm_set_epi64x(0, 64)));
c->unuse(*addr); c->movdqa(vt, va);
c->unuse(*qw0); c->psrldq(vt, 8);
c->unuse(*qw1); 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) void spu_recompiler::SHLQBI(spu_opcode_t op)
{ {
c->mov(*qw0, SPU_OFF_64(gpr, op.ra, &v128::_u64, 0)); const XmmLink& va = XmmGet(op.ra, XmmType::Int);
c->mov(*qw1, SPU_OFF_64(gpr, op.ra, &v128::_u64, 1)); const XmmLink& vb = XmmGet(op.rb, XmmType::Int);
c->mov(*addr, SPU_OFF_32(gpr, op.rb, &v128::_u32, 3)); const XmmLink& vt = XmmAlloc();
c->and_(*addr, 7); const XmmLink& v4 = XmmAlloc();
c->shld(*qw1, *qw0, *addr); c->psrldq(vb, 12);
c->shl(*qw0, *addr); c->pand(vb, XmmConst(_mm_set_epi64x(0, 7)));
c->mov(SPU_OFF_64(gpr, op.rt, &v128::_u64, 0), *qw0); c->movdqa(v4, XmmConst(_mm_set_epi64x(0, 64)));
c->mov(SPU_OFF_64(gpr, op.rt, &v128::_u64, 1), *qw1); c->movdqa(vt, va);
c->unuse(*addr); c->pslldq(vt, 8);
c->unuse(*qw0); c->psubq(v4, vb);
c->unuse(*qw1); 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) void spu_recompiler::ROTQBY(spu_opcode_t op)
@ -1674,16 +1867,14 @@ void spu_recompiler::SHLQBY(spu_opcode_t op)
void spu_recompiler::ORX(spu_opcode_t op) void spu_recompiler::ORX(spu_opcode_t op)
{ {
c->mov(*addr, SPU_OFF_32(gpr, op.ra, &v128::_u32, 0)); const XmmLink& va = XmmGet(op.ra, XmmType::Int);
c->or_(*addr, SPU_OFF_32(gpr, op.ra, &v128::_u32, 1)); const XmmLink& v1 = XmmAlloc();
c->or_(*addr, SPU_OFF_32(gpr, op.ra, &v128::_u32, 2)); c->pshufd(v1, va, 0xb1);
c->or_(*addr, SPU_OFF_32(gpr, op.ra, &v128::_u32, 3)); c->por(va, v1);
c->mov(SPU_OFF_32(gpr, op.rt, &v128::_u32, 3), *addr); c->pshufd(v1, va, 0x4e);
c->xor_(*addr, *addr); c->por(va, v1);
c->mov(SPU_OFF_32(gpr, op.rt, &v128::_u32, 0), *addr); c->pslldq(va, 12);
c->mov(SPU_OFF_32(gpr, op.rt, &v128::_u32, 1), *addr); c->movdqa(SPU_OFF_128(gpr, op.rt), va);
c->mov(SPU_OFF_32(gpr, op.rt, &v128::_u32, 2), *addr);
c->unuse(*addr);
} }
void spu_recompiler::CBD(spu_opcode_t op) void spu_recompiler::CBD(spu_opcode_t op)
@ -1790,40 +1981,37 @@ void spu_recompiler::CDD(spu_opcode_t op)
void spu_recompiler::ROTQBII(spu_opcode_t op) void spu_recompiler::ROTQBII(spu_opcode_t op)
{ {
c->mov(*qw0, SPU_OFF_64(gpr, op.ra, &v128::_u64, 0)); const XmmLink& va = XmmGet(op.ra, XmmType::Int);
c->mov(*qw1, SPU_OFF_64(gpr, op.ra, &v128::_u64, 1)); const XmmLink& vt = XmmAlloc();
c->mov(*qw2, *qw0); c->pshufd(vt, va, 0x4e); // swap 64-bit parts
c->shld(*qw0, *qw1, op.i7 & 0x7); c->psllq(va, (op.i7 & 0x7));
c->shld(*qw1, *qw2, op.i7 & 0x7); c->psrlq(vt, 64 - (op.i7 & 0x7));
c->mov(SPU_OFF_64(gpr, op.rt, &v128::_u64, 0), *qw0); c->por(vt, va);
c->mov(SPU_OFF_64(gpr, op.rt, &v128::_u64, 1), *qw1); c->movdqa(SPU_OFF_128(gpr, op.rt), vt);
c->unuse(*qw0);
c->unuse(*qw1);
c->unuse(*qw2);
} }
void spu_recompiler::ROTQMBII(spu_opcode_t op) void spu_recompiler::ROTQMBII(spu_opcode_t op)
{ {
c->mov(*qw0, SPU_OFF_64(gpr, op.ra, &v128::_u64, 0)); const XmmLink& va = XmmGet(op.ra, XmmType::Int);
c->mov(*qw1, SPU_OFF_64(gpr, op.ra, &v128::_u64, 1)); const XmmLink& vt = XmmAlloc();
c->shrd(*qw0, *qw1, 0-op.i7 & 0x7); c->movdqa(vt, va);
c->shr(*qw1, 0-op.i7 & 0x7); c->psrldq(vt, 8);
c->mov(SPU_OFF_64(gpr, op.rt, &v128::_u64, 0), *qw0); c->psrlq(va, ((0 - op.i7) & 0x7));
c->mov(SPU_OFF_64(gpr, op.rt, &v128::_u64, 1), *qw1); c->psllq(vt, 64 - ((0 - op.i7) & 0x7));
c->unuse(*qw0); c->por(vt, va);
c->unuse(*qw1); c->movdqa(SPU_OFF_128(gpr, op.rt), vt);
} }
void spu_recompiler::SHLQBII(spu_opcode_t op) void spu_recompiler::SHLQBII(spu_opcode_t op)
{ {
c->mov(*qw0, SPU_OFF_64(gpr, op.ra, &v128::_u64, 0)); const XmmLink& va = XmmGet(op.ra, XmmType::Int);
c->mov(*qw1, SPU_OFF_64(gpr, op.ra, &v128::_u64, 1)); const XmmLink& vt = XmmAlloc();
c->shld(*qw1, *qw0, op.i7 & 0x7); c->movdqa(vt, va);
c->shl(*qw0, op.i7 & 0x7); c->pslldq(vt, 8);
c->mov(SPU_OFF_64(gpr, op.rt, &v128::_u64, 0), *qw0); c->psllq(va, (op.i7 & 0x7));
c->mov(SPU_OFF_64(gpr, op.rt, &v128::_u64, 1), *qw1); c->psrlq(vt, 64 - (op.i7 & 0x7));
c->unuse(*qw0); c->por(vt, va);
c->unuse(*qw1); c->movdqa(SPU_OFF_128(gpr, op.rt), vt);
} }
void spu_recompiler::ROTQBYI(spu_opcode_t op) void spu_recompiler::ROTQBYI(spu_opcode_t op)
@ -3290,6 +3478,13 @@ void spu_recompiler::SELB(spu_opcode_t op)
return; 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->pand(vb, vc);
c->pandn(vc, SPU_OFF_128(gpr, op.ra)); c->pandn(vc, SPU_OFF_128(gpr, op.ra));
c->por(vb, vc); c->por(vb, vc);
@ -3414,6 +3609,10 @@ void spu_recompiler::SHUFB(spu_opcode_t op)
{ {
c->vpternlogd(vc, va, vb, 0xca /* A?B:C */); c->vpternlogd(vc, va, vb, 0xca /* A?B:C */);
} }
else if (utils::has_xop())
{
c->vpcmov(vc, va, vb, vc);
}
else else
{ {
c->pand(va, vc); c->pand(va, vc);

View file

@ -1767,6 +1767,17 @@ bool SPUThread::stop_and_signal(u32 code)
return true; return true;
} }
case 0x100:
{
if (ch_out_mbox.get_count())
{
fmt::throw_exception("STOP code 0x100: Out_MBox is not empty" HERE);
}
_mm_mfence();
return true;
}
case 0x101: case 0x101:
{ {
/* ===== sys_spu_thread_group_exit ===== */ /* ===== sys_spu_thread_group_exit ===== */

View file

@ -278,16 +278,18 @@ error_code sys_spu_thread_get_exit_status(u32 id, vm::ptr<u32> status)
const auto thread = idm::get<SPUThread>(id); const auto thread = idm::get<SPUThread>(id);
if (!thread) if (UNLIKELY(!thread))
{ {
return CELL_ESRCH; return CELL_ESRCH;
} }
// TODO: check CELL_ESTAT condition if (thread->status & SPU_STATUS_STOPPED_BY_STOP)
{
*status = thread->ch_out_mbox.get_value();
return CELL_OK;
}
*status = thread->ch_out_mbox.pop(*thread); return CELL_ESTAT;
return CELL_OK;
} }
error_code sys_spu_thread_group_create(vm::ptr<u32> id, u32 num, s32 prio, vm::ptr<sys_spu_thread_group_attribute> attr) error_code sys_spu_thread_group_create(vm::ptr<u32> id, u32 num, s32 prio, vm::ptr<sys_spu_thread_group_attribute> attr)

View file

@ -248,6 +248,7 @@ struct KbButton
struct Keyboard struct Keyboard
{ {
bool m_key_repeat; // for future use
KbData m_data; KbData m_data;
KbConfig m_config; KbConfig m_config;
std::vector<KbButton> m_buttons; std::vector<KbButton> m_buttons;
@ -255,6 +256,7 @@ struct Keyboard
Keyboard() Keyboard()
: m_data() : m_data()
, m_config() , m_config()
, m_key_repeat(false)
{ {
} }
}; };
@ -274,19 +276,20 @@ public:
{ {
for(Keyboard& keyboard : m_keyboards) for(Keyboard& keyboard : m_keyboards)
{ {
KbData& data = keyboard.m_data;
KbConfig& config = keyboard.m_config;
// TODO: handle read modes
for(KbButton& button : keyboard.m_buttons) for(KbButton& button : keyboard.m_buttons)
{ {
if(button.m_keyCode != code) if(button.m_keyCode != code)
continue; continue;
KbData& data = keyboard.m_data;
KbConfig& config = keyboard.m_config;
if (pressed) if (pressed)
{ {
// Meta Keys // Meta Keys
if (code == 308 || code == 307 || code == 306 || if (code == 308 || code == 307 || code == 306 || code == 393 || code == 396 || code == 394)
code == 393 || code == 396 || code == 394)
{ {
data.mkey |= button.m_outKeyCode; data.mkey |= button.m_outKeyCode;
} }
@ -310,17 +313,17 @@ public:
data.len++; data.len++;
} }
} }
else
if (!pressed)
{ {
// Meta Keys // Meta Keys
if (code == 308 || code == 307 || code == 306 || if (code == 308 || code == 307 || code == 306 || code == 393 || code == 396 || code == 394)
code == 393 || code == 396 || code == 394)
{ {
data.mkey &= ~button.m_outKeyCode; data.mkey &= ~button.m_outKeyCode;
} }
// Needed to indicate key releases. Without this you have to tap another key before using the same key again
data.keycode[0] = CELL_KEYC_NO_EVENT;
data.len = 1;
} }
} }
} }
} }

View file

@ -40,15 +40,48 @@ void FragmentProgramDecompiler::SetDst(std::string code, bool append_mask)
{ {
if (dst.exp_tex) if (dst.exp_tex)
{ {
//If dst.exp_tex really is _bx2 postfix, we need to unpack dynamic range //Expand [0,1] to [-1, 1]. Confirmed by Castlevania: LOS
AddCode("//exp tex flag is set"); AddCode("//exp tex flag is set");
code = "((" + code + "- 0.5) * 2.)"; code = "((" + code + "- 0.5) * 2.)";
} }
if (dst.saturate) if (dst.saturate)
{
code = saturate(code); code = saturate(code);
else }
code = ClampValue(code, dst.prec); else if (dst.prec)
{
switch (dst.opcode)
{
case RSX_FP_OPCODE_NRM:
case RSX_FP_OPCODE_MAX:
case RSX_FP_OPCODE_MIN:
case RSX_FP_OPCODE_COS:
case RSX_FP_OPCODE_SIN:
case RSX_FP_OPCODE_REFL:
case RSX_FP_OPCODE_EX2:
case RSX_FP_OPCODE_FRC:
case RSX_FP_OPCODE_LIT:
case RSX_FP_OPCODE_LIF:
case RSX_FP_OPCODE_LRP:
case RSX_FP_OPCODE_LG2:
break;
case RSX_FP_OPCODE_MOV:
//NOTE: Sometimes varying inputs from VS are out of range so do not exempt any input types, unless fp16 (Naruto UNS)
if (dst.fp16 && src0.fp16 && src0.reg_type == RSX_FP_REGISTER_TYPE_TEMP)
break;
default:
{
//fp16 precsion flag on f32 register; ignore
if (dst.prec == 1 && !dst.fp16)
break;
//clamp value to allowed range
code = ClampValue(code, dst.prec);
break;
}
}
}
} }
code += (append_mask ? "$m" : ""); code += (append_mask ? "$m" : "");
@ -195,12 +228,12 @@ std::string FragmentProgramDecompiler::AddX2d()
//Failure to catch causes infinite values since theres alot of rcp(0) //Failure to catch causes infinite values since theres alot of rcp(0)
std::string FragmentProgramDecompiler::NotZero(const std::string& code) std::string FragmentProgramDecompiler::NotZero(const std::string& code)
{ {
return "(max(abs(" + code + "), 0.000001) * sign(" + code + "))"; return "(max(abs(" + code + "), 0.0000000001) * sign(" + code + "))";
} }
std::string FragmentProgramDecompiler::NotZeroPositive(const std::string& code) std::string FragmentProgramDecompiler::NotZeroPositive(const std::string& code)
{ {
return "max(abs(" + code + "), 0.000001)"; return "max(abs(" + code + "), 0.0000000001)";
} }
std::string FragmentProgramDecompiler::ClampValue(const std::string& code, u32 precision) std::string FragmentProgramDecompiler::ClampValue(const std::string& code, u32 precision)
@ -385,7 +418,10 @@ template<typename T> std::string FragmentProgramDecompiler::GetSRC(T src)
auto &reg = temp_registers[src.tmp_reg_index]; auto &reg = temp_registers[src.tmp_reg_index];
if (reg.requires_gather(xy_read, zw_read)) if (reg.requires_gather(xy_read, zw_read))
{
properties.has_gather_op = true;
AddCode(reg.gather_r()); AddCode(reg.gather_r());
}
} }
} }
@ -407,7 +443,10 @@ template<typename T> std::string FragmentProgramDecompiler::GetSRC(T src)
switch (dst.src_attr_reg_num) switch (dst.src_attr_reg_num)
{ {
case 0x00: ret += reg_table[0]; break; case 0x00:
ret += reg_table[0];
properties.has_wpos_input = true;
break;
default: default:
if (dst.src_attr_reg_num < sizeof(reg_table) / sizeof(reg_table[0])) if (dst.src_attr_reg_num < sizeof(reg_table) / sizeof(reg_table[0]))
{ {
@ -478,24 +517,28 @@ std::string FragmentProgramDecompiler::BuildCode()
//Insert global function definitions //Insert global function definitions
insertGlobalFunctions(OS); insertGlobalFunctions(OS);
std::string float2 = getFloatTypeName(2); //Declare register gather/merge if needed
std::string float4 = getFloatTypeName(4); if (properties.has_gather_op)
{
std::string float2 = getFloatTypeName(2);
std::string float4 = getFloatTypeName(4);
OS << float4 << " gather(" << float4 << " _h0, " << float4 << " _h1)\n"; OS << float4 << " gather(" << float4 << " _h0, " << float4 << " _h1)\n";
OS << "{\n"; OS << "{\n";
OS << " float x = uintBitsToFloat(packHalf2x16(_h0.xy));\n"; OS << " float x = uintBitsToFloat(packHalf2x16(_h0.xy));\n";
OS << " float y = uintBitsToFloat(packHalf2x16(_h0.zw));\n"; OS << " float y = uintBitsToFloat(packHalf2x16(_h0.zw));\n";
OS << " float z = uintBitsToFloat(packHalf2x16(_h1.xy));\n"; OS << " float z = uintBitsToFloat(packHalf2x16(_h1.xy));\n";
OS << " float w = uintBitsToFloat(packHalf2x16(_h1.zw));\n"; OS << " float w = uintBitsToFloat(packHalf2x16(_h1.zw));\n";
OS << " return " << float4 << "(x, y, z, w);\n"; OS << " return " << float4 << "(x, y, z, w);\n";
OS << "}\n\n"; OS << "}\n\n";
OS << float2 << " gather(" << float4 << " _h)\n"; OS << float2 << " gather(" << float4 << " _h)\n";
OS << "{\n"; OS << "{\n";
OS << " float x = uintBitsToFloat(packHalf2x16(_h.xy));\n"; OS << " float x = uintBitsToFloat(packHalf2x16(_h.xy));\n";
OS << " float y = uintBitsToFloat(packHalf2x16(_h.zw));\n"; OS << " float y = uintBitsToFloat(packHalf2x16(_h.zw));\n";
OS << " return " << float2 << "(x, y);\n"; OS << " return " << float2 << "(x, y);\n";
OS << "}\n\n"; OS << "}\n\n";
}
insertMainStart(OS); insertMainStart(OS);
OS << main << std::endl; OS << main << std::endl;
@ -558,7 +601,10 @@ bool FragmentProgramDecompiler::handle_scb(u32 opcode)
case RSX_FP_OPCODE_EX2: SetDst("exp2($0.xxxx)"); return true; case RSX_FP_OPCODE_EX2: SetDst("exp2($0.xxxx)"); return true;
case RSX_FP_OPCODE_FLR: SetDst("floor($0)"); return true; case RSX_FP_OPCODE_FLR: SetDst("floor($0)"); return true;
case RSX_FP_OPCODE_FRC: SetDst(getFunction(FUNCTION::FUNCTION_FRACT)); return true; case RSX_FP_OPCODE_FRC: SetDst(getFunction(FUNCTION::FUNCTION_FRACT)); return true;
case RSX_FP_OPCODE_LIT: SetDst("lit_legacy($0)"); return true; case RSX_FP_OPCODE_LIT:
SetDst("lit_legacy($0)");
properties.has_lit_op = true;
return true;
case RSX_FP_OPCODE_LIF: SetDst(getFloatTypeName(4) + "(1.0, $0.y, ($0.y > 0 ? pow(2.0, $0.w) : 0.0), 1.0)"); return true; case RSX_FP_OPCODE_LIF: SetDst(getFloatTypeName(4) + "(1.0, $0.y, ($0.y > 0 ? pow(2.0, $0.w) : 0.0), 1.0)"); return true;
case RSX_FP_OPCODE_LRP: SetDst(getFloatTypeName(4) + "($2 * (1 - $0) + $1 * $0)"); return true; case RSX_FP_OPCODE_LRP: SetDst(getFloatTypeName(4) + "($2 * (1 - $0) + $1 * $0)"); return true;
case RSX_FP_OPCODE_LG2: SetDst("log2(" + NotZeroPositive("$0.x") + ").xxxx"); return true; case RSX_FP_OPCODE_LG2: SetDst("log2(" + NotZeroPositive("$0.x") + ").xxxx"); return true;

View file

@ -219,7 +219,16 @@ protected:
/** insert end of main function (return value, output copy...) /** insert end of main function (return value, output copy...)
*/ */
virtual void insertMainEnd(std::stringstream &OS) = 0; virtual void insertMainEnd(std::stringstream &OS) = 0;
public: public:
struct
{
bool has_lit_op = false;
bool has_gather_op = false;
bool has_wpos_input = false;
}
properties;
ParamArray m_parr; ParamArray m_parr;
FragmentProgramDecompiler(const RSXFragmentProgram &prog, u32& size); FragmentProgramDecompiler(const RSXFragmentProgram &prog, u32& size);
FragmentProgramDecompiler(const FragmentProgramDecompiler&) = delete; FragmentProgramDecompiler(const FragmentProgramDecompiler&) = delete;

View file

@ -281,31 +281,18 @@ namespace glsl
OS << " if (desc.attribute_size == 0)\n"; OS << " if (desc.attribute_size == 0)\n";
OS << " {\n"; OS << " {\n";
OS << " //default values\n"; OS << " //default values\n";
OS << " switch (location)\n"; OS << " const vec4 defaults[] = \n";
OS << " {\n"; OS << " { vec4(0., 0., 0., 1.), //position\n";
OS << " case 0:\n"; OS << " vec4(0.), vec4(0.), //weight, normals\n";
OS << " //position\n"; OS << " vec4(1.), //diffuse\n";
OS << " return vec4(0., 0., 0., 1.);\n"; OS << " vec4(0.), vec4(0.), //specular, fog\n";
OS << " case 1:\n"; OS << " vec4(1.), //point size\n";
OS << " case 2:\n"; OS << " vec4(0.), //in_7\n";
OS << " //weight, normals\n"; OS << " //in_tc registers\n";
OS << " return vec4(0.);\n"; OS << " vec4(0.), vec4(0.), vec4(0.), vec4(0.),\n";
OS << " case 3:\n"; OS << " vec4(0.), vec4(0.), vec4(0.), vec4(0.)\n";
OS << " //diffuse\n"; OS << " };\n";
OS << " return vec4(1.);\n"; OS << " return defaults[location];\n";
OS << " case 4:\n";
OS << " //specular\n";
OS << " return vec4(0.);\n";
OS << " case 5:\n";
OS << " //fog\n";
OS << " return vec4(0.);\n";
OS << " case 6:\n";
OS << " //point size\n";
OS << " return vec4(1.);\n";
OS << " default:\n";
OS << " //mostly just texture coordinates\n";
OS << " return vec4(0.);\n";
OS << " }\n";
OS << " }\n\n"; OS << " }\n\n";
OS << " int vertex_id = " << vertex_id_name << " - int(vertex_base_index);\n"; OS << " int vertex_id = " << vertex_id_name << " - int(vertex_base_index);\n";
OS << " if (desc.frequency == 0)\n"; OS << " if (desc.frequency == 0)\n";
@ -326,84 +313,95 @@ namespace glsl
OS << "}\n\n"; OS << "}\n\n";
} }
static void insert_glsl_legacy_function(std::ostream& OS, glsl::program_domain domain) static void insert_glsl_legacy_function(std::ostream& OS, glsl::program_domain domain, bool require_lit_emulation, bool require_depth_conversion = false, bool require_wpos = false)
{ {
OS << "vec4 lit_legacy(vec4 val)"; if (require_lit_emulation)
OS << "{\n"; {
OS << " vec4 clamped_val = val;\n"; OS << "vec4 lit_legacy(vec4 val)";
OS << " clamped_val.x = max(val.x, 0.);\n"; OS << "{\n";
OS << " clamped_val.y = max(val.y, 0.);\n"; OS << " vec4 clamped_val = val;\n";
OS << " vec4 result;\n"; OS << " clamped_val.x = max(val.x, 0.);\n";
OS << " result.x = 1.;\n"; OS << " clamped_val.y = max(val.y, 0.);\n";
OS << " result.w = 1.;\n"; OS << " vec4 result;\n";
OS << " result.y = clamped_val.x;\n"; OS << " result.x = 1.;\n";
OS << " result.z = clamped_val.x > 0. ? exp(clamped_val.w * log(max(clamped_val.y, 0.000001))) : 0.;\n"; OS << " result.w = 1.;\n";
OS << " return result;\n"; OS << " result.y = clamped_val.x;\n";
OS << "}\n\n"; OS << " result.z = clamped_val.x > 0. ? exp(clamped_val.w * log(max(clamped_val.y, 0.0000000001))) : 0.;\n";
OS << " return result;\n";
OS << "vec4 apply_zclip_xform(vec4 pos, float near_plane, float far_plane)\n"; OS << "}\n\n";
OS << "{\n"; }
OS << " float d = pos.z / pos.w;\n";
OS << " if (d < 0.f && d >= near_plane)\n";
OS << " d = 0.f;\n"; //force clamp negative values
OS << " else if (d > 1.f && d <= far_plane)\n";
OS << " d = min(1., 0.99 + (0.01 * (pos.z - near_plane) / (far_plane - near_plane)));\n";
OS << " else\n";
OS << " return pos; //d = (0.99 * d);\n"; //range compression for normal values is disabled until a solution to ops comparing z is found
OS << "\n";
OS << " pos.z = d * pos.w;\n";
OS << " return pos;\n";
OS << "}\n\n";
if (domain == glsl::program_domain::glsl_vertex_program) if (domain == glsl::program_domain::glsl_vertex_program)
{
OS << "vec4 apply_zclip_xform(vec4 pos, float near_plane, float far_plane)\n";
OS << "{\n";
OS << " float d = pos.z / pos.w;\n";
OS << " if (d < 0.f && d >= near_plane)\n";
OS << " d = 0.f;\n"; //force clamp negative values
OS << " else if (d > 1.f && d <= far_plane)\n";
OS << " d = min(1., 0.99 + (0.01 * (pos.z - near_plane) / (far_plane - near_plane)));\n";
OS << " else\n";
OS << " return pos; //d = (0.99 * d);\n"; //range compression for normal values is disabled until a solution to ops comparing z is found
OS << "\n";
OS << " pos.z = d * pos.w;\n";
OS << " return pos;\n";
OS << "}\n\n";
return; return;
}
program_common::insert_compare_op(OS); program_common::insert_compare_op(OS);
//NOTE: Memory layout is fetched as byteswapped BGRA [GBAR] (GOW collection, DS2, DeS) if (require_depth_conversion)
//The A component (Z) is useless (should contain stencil8 or just 1) {
OS << "vec4 decodeLinearDepth(float depth_value)\n"; //NOTE: Memory layout is fetched as byteswapped BGRA [GBAR] (GOW collection, DS2, DeS)
OS << "{\n"; //The A component (Z) is useless (should contain stencil8 or just 1)
OS << " uint value = uint(depth_value * 16777215);\n"; OS << "vec4 decodeLinearDepth(float depth_value)\n";
OS << " uint b = (value & 0xff);\n"; OS << "{\n";
OS << " uint g = (value >> 8) & 0xff;\n"; OS << " uint value = uint(depth_value * 16777215);\n";
OS << " uint r = (value >> 16) & 0xff;\n"; OS << " uint b = (value & 0xff);\n";
OS << " return vec4(float(g)/255., float(b)/255., 1., float(r)/255.);\n"; OS << " uint g = (value >> 8) & 0xff;\n";
OS << "}\n\n"; OS << " uint r = (value >> 16) & 0xff;\n";
OS << " return vec4(float(g)/255., float(b)/255., 1., float(r)/255.);\n";
OS << "}\n\n";
OS << "float read_value(vec4 src, uint remap_index)\n"; OS << "float read_value(vec4 src, uint remap_index)\n";
OS << "{\n"; OS << "{\n";
OS << " switch (remap_index)\n"; OS << " switch (remap_index)\n";
OS << " {\n"; OS << " {\n";
OS << " case 0: return src.a;\n"; OS << " case 0: return src.a;\n";
OS << " case 1: return src.r;\n"; OS << " case 1: return src.r;\n";
OS << " case 2: return src.g;\n"; OS << " case 2: return src.g;\n";
OS << " case 3: return src.b;\n"; OS << " case 3: return src.b;\n";
OS << " }\n"; OS << " }\n";
OS << "}\n\n"; OS << "}\n\n";
OS << "vec4 texture2DReconstruct(sampler2D tex, vec2 coord, float remap)\n"; OS << "vec4 texture2DReconstruct(sampler2D tex, vec2 coord, float remap)\n";
OS << "{\n"; OS << "{\n";
OS << " vec4 result = decodeLinearDepth(texture(tex, coord.xy).r);\n"; OS << " vec4 result = decodeLinearDepth(texture(tex, coord.xy).r);\n";
OS << " uint remap_vector = floatBitsToUint(remap) & 0xFF;\n"; OS << " uint remap_vector = floatBitsToUint(remap) & 0xFF;\n";
OS << " if (remap_vector == 0xE4) return result;\n\n"; OS << " if (remap_vector == 0xE4) return result;\n\n";
OS << " vec4 tmp;\n"; OS << " vec4 tmp;\n";
OS << " uint remap_a = remap_vector & 0x3;\n"; OS << " uint remap_a = remap_vector & 0x3;\n";
OS << " uint remap_r = (remap_vector >> 2) & 0x3;\n"; OS << " uint remap_r = (remap_vector >> 2) & 0x3;\n";
OS << " uint remap_g = (remap_vector >> 4) & 0x3;\n"; OS << " uint remap_g = (remap_vector >> 4) & 0x3;\n";
OS << " uint remap_b = (remap_vector >> 6) & 0x3;\n"; OS << " uint remap_b = (remap_vector >> 6) & 0x3;\n";
OS << " tmp.a = read_value(result, remap_a);\n"; OS << " tmp.a = read_value(result, remap_a);\n";
OS << " tmp.r = read_value(result, remap_r);\n"; OS << " tmp.r = read_value(result, remap_r);\n";
OS << " tmp.g = read_value(result, remap_g);\n"; OS << " tmp.g = read_value(result, remap_g);\n";
OS << " tmp.b = read_value(result, remap_b);\n"; OS << " tmp.b = read_value(result, remap_b);\n";
OS << " return tmp;\n"; OS << " return tmp;\n";
OS << "}\n\n"; OS << "}\n\n";
}
OS << "vec4 get_wpos()\n"; if (require_wpos)
OS << "{\n"; {
OS << " float abs_scale = abs(wpos_scale);\n"; OS << "vec4 get_wpos()\n";
OS << " return (gl_FragCoord * vec4(abs_scale, wpos_scale, 1., 1.)) + vec4(0., wpos_bias, 0., 0.);\n"; OS << "{\n";
OS << "}\n\n"; OS << " float abs_scale = abs(wpos_scale);\n";
OS << " return (gl_FragCoord * vec4(abs_scale, wpos_scale, 1., 1.)) + vec4(0., wpos_bias, 0., 0.);\n";
OS << "}\n\n";
}
} }
static void insert_fog_declaration(std::ostream& OS) static void insert_fog_declaration(std::ostream& OS)

View file

@ -376,7 +376,7 @@ void VertexProgramDecompiler::SetDSTSca(const std::string& code)
std::string VertexProgramDecompiler::NotZeroPositive(const std::string& code) std::string VertexProgramDecompiler::NotZeroPositive(const std::string& code)
{ {
return "max(" + code + ", 0.000001)"; return "max(" + code + ", 0.0000000001)";
} }
std::string VertexProgramDecompiler::BuildFuncBody(const FuncInfo& func) std::string VertexProgramDecompiler::BuildFuncBody(const FuncInfo& func)
@ -638,7 +638,10 @@ std::string VertexProgramDecompiler::Decompile()
case RSX_SCA_OPCODE_RSQ: SetDSTSca("1. / sqrt(" + NotZeroPositive("$s.x") +").xxxx"); break; case RSX_SCA_OPCODE_RSQ: SetDSTSca("1. / sqrt(" + NotZeroPositive("$s.x") +").xxxx"); break;
case RSX_SCA_OPCODE_EXP: SetDSTSca("exp($s)"); break; case RSX_SCA_OPCODE_EXP: SetDSTSca("exp($s)"); break;
case RSX_SCA_OPCODE_LOG: SetDSTSca("log($s)"); break; case RSX_SCA_OPCODE_LOG: SetDSTSca("log($s)"); break;
case RSX_SCA_OPCODE_LIT: SetDSTSca("lit_legacy($s)"); break; case RSX_SCA_OPCODE_LIT:
SetDSTSca("lit_legacy($s)");
properties.has_lit_op = true;
break;
case RSX_SCA_OPCODE_BRA: case RSX_SCA_OPCODE_BRA:
{ {
AddCode("$if ($cond) //BRA"); AddCode("$if ($cond) //BRA");

View file

@ -126,7 +126,14 @@ protected:
/** insert end of main function (return value, output copy...) /** insert end of main function (return value, output copy...)
*/ */
virtual void insertMainEnd(std::stringstream &OS) = 0; virtual void insertMainEnd(std::stringstream &OS) = 0;
public: public:
struct
{
bool has_lit_op = false;
}
properties;
VertexProgramDecompiler(const RSXVertexProgram& prog); VertexProgramDecompiler(const RSXVertexProgram& prog);
std::string Decompile(); std::string Decompile();
}; };

View file

@ -274,6 +274,9 @@ namespace rsx
//Set when a hw blit engine incompatibility is detected //Set when a hw blit engine incompatibility is detected
bool blit_engine_incompatibility_warning_raised = false; bool blit_engine_incompatibility_warning_raised = false;
//Set when a shader read-only texture data suddenly becomes contested, usually by fbo memory
bool read_only_tex_invalidate = false;
//Memory usage //Memory usage
const s32 m_max_zombie_objects = 64; //Limit on how many texture objects to keep around for reuse after they are invalidated const s32 m_max_zombie_objects = 64; //Limit on how many texture objects to keep around for reuse after they are invalidated
std::atomic<s32> m_unreleased_texture_objects = { 0 }; //Number of invalidated objects not yet freed from memory std::atomic<s32> m_unreleased_texture_objects = { 0 }; //Number of invalidated objects not yet freed from memory
@ -289,7 +292,7 @@ namespace rsx
const std::vector<rsx_subresource_layout>& subresource_layout, rsx::texture_dimension_extended type, bool swizzled, const std::pair<std::array<u8, 4>, std::array<u8, 4>>& remap_vector) = 0; const std::vector<rsx_subresource_layout>& subresource_layout, rsx::texture_dimension_extended type, bool swizzled, const std::pair<std::array<u8, 4>, std::array<u8, 4>>& remap_vector) = 0;
virtual void enforce_surface_creation_type(section_storage_type& section, u32 gcm_format, texture_create_flags expected) = 0; virtual void enforce_surface_creation_type(section_storage_type& section, u32 gcm_format, texture_create_flags expected) = 0;
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 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() = 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 image_view_type generate_cubemap_from_images(commandbuffer_type&, u32 gcm_format, u16 size, const std::array<image_resource_type, 6>& sources) = 0;
constexpr u32 get_block_size() const { return 0x1000000; } constexpr u32 get_block_size() const { return 0x1000000; }
@ -782,6 +785,7 @@ namespace rsx
{ {
//This space was being used for other purposes other than framebuffer storage //This space was being used for other purposes other than framebuffer storage
//Delete used resources before attaching it to framebuffer memory //Delete used resources before attaching it to framebuffer memory
read_only_tex_invalidate = true;
free_texture_section(region); free_texture_section(region);
m_texture_memory_in_use -= region.get_section_size(); m_texture_memory_in_use -= region.get_section_size();
} }
@ -1116,7 +1120,7 @@ namespace rsx
} }
template <typename render_target_type, typename surface_store_type> template <typename render_target_type, typename surface_store_type>
sampled_image_descriptor process_framebuffer_resource(render_target_type texptr, u32 texaddr, u32 gcm_format, surface_store_type& m_rtts, sampled_image_descriptor process_framebuffer_resource(commandbuffer_type& cmd, render_target_type texptr, u32 texaddr, u32 gcm_format, surface_store_type& m_rtts,
u16 tex_width, u16 tex_height, rsx::texture_dimension_extended extended_dimension, bool is_depth) u16 tex_width, u16 tex_height, rsx::texture_dimension_extended extended_dimension, bool is_depth)
{ {
const u32 format = gcm_format & ~(CELL_GCM_TEXTURE_UN | CELL_GCM_TEXTURE_LN); const u32 format = gcm_format & ~(CELL_GCM_TEXTURE_UN | CELL_GCM_TEXTURE_LN);
@ -1240,7 +1244,7 @@ namespace rsx
else else
{ {
//issue a texture barrier to ensure previous writes are visible //issue a texture barrier to ensure previous writes are visible
insert_texture_barrier(); insert_texture_barrier(cmd, texptr);
break; break;
} }
} }
@ -1258,7 +1262,7 @@ namespace rsx
else else
{ {
//issue a texture barrier to ensure previous writes are visible //issue a texture barrier to ensure previous writes are visible
insert_texture_barrier(); insert_texture_barrier(cmd, texptr);
} }
} }
} }
@ -1320,7 +1324,7 @@ namespace rsx
{ {
if (test_framebuffer(texaddr + texptr->raster_address_offset)) if (test_framebuffer(texaddr + texptr->raster_address_offset))
{ {
return process_framebuffer_resource(texptr, texaddr, tex.format(), m_rtts, tex_width, tex_height, extended_dimension, false); return process_framebuffer_resource(cmd, texptr, texaddr, tex.format(), m_rtts, tex_width, tex_height, extended_dimension, false);
} }
else else
{ {
@ -1333,7 +1337,7 @@ namespace rsx
{ {
if (test_framebuffer(texaddr + texptr->raster_address_offset)) if (test_framebuffer(texaddr + texptr->raster_address_offset))
{ {
return process_framebuffer_resource(texptr, texaddr, tex.format(), m_rtts, tex_width, tex_height, extended_dimension, true); return process_framebuffer_resource(cmd, texptr, texaddr, tex.format(), m_rtts, tex_width, tex_height, extended_dimension, true);
} }
else else
{ {
@ -1391,7 +1395,7 @@ namespace rsx
if (rsc.is_bound) if (rsc.is_bound)
{ {
LOG_WARNING(RSX, "Sampling from a currently bound render target @ 0x%x", texaddr); LOG_WARNING(RSX, "Sampling from a currently bound render target @ 0x%x", texaddr);
insert_texture_barrier(); insert_texture_barrier(cmd, rsc.surface);
} }
return{ rsc.surface->get_view(), texture_upload_context::framebuffer_storage, rsc.is_depth_surface, return{ rsc.surface->get_view(), texture_upload_context::framebuffer_storage, rsc.is_depth_surface,
@ -1875,6 +1879,20 @@ namespace rsx
return m_texture_memory_in_use; return m_texture_memory_in_use;
} }
/**
* The read only texture invalidate flag is set if a read only texture is trampled by framebuffer memory
* If set, all cached read only textures are considered invalid and should be re-fetched from the texture cache
*/
virtual void clear_ro_tex_invalidate_intr()
{
read_only_tex_invalidate = false;
}
virtual bool get_ro_tex_invalidate_intr() const
{
return read_only_tex_invalidate;
}
void tag_framebuffer(u32 texaddr) void tag_framebuffer(u32 texaddr)
{ {
if (!g_cfg.video.strict_rendering_mode) if (!g_cfg.video.strict_rendering_mode)

View file

@ -194,7 +194,7 @@ namespace
void GLFragmentDecompilerThread::insertGlobalFunctions(std::stringstream &OS) void GLFragmentDecompilerThread::insertGlobalFunctions(std::stringstream &OS)
{ {
glsl::insert_glsl_legacy_function(OS, glsl::glsl_fragment_program); glsl::insert_glsl_legacy_function(OS, glsl::glsl_fragment_program, properties.has_lit_op, m_prog.redirected_textures != 0, properties.has_wpos_input);
} }
void GLFragmentDecompilerThread::insertMainStart(std::stringstream & OS) void GLFragmentDecompilerThread::insertMainStart(std::stringstream & OS)
@ -248,8 +248,11 @@ void GLFragmentDecompilerThread::insertMainStart(std::stringstream & OS)
} }
} }
OS << " vec4 ssa = gl_FrontFacing ? vec4(1.) : vec4(-1.);\n"; if (m_parr.HasParam(PF_PARAM_IN, "vec4", "ssa"))
OS << " vec4 wpos = get_wpos();\n"; OS << " vec4 ssa = gl_FrontFacing ? vec4(1.) : vec4(-1.);\n";
if (properties.has_wpos_input)
OS << " vec4 wpos = get_wpos();\n";
for (const ParamType& PT : m_parr.params[PF_PARAM_UNIFORM]) for (const ParamType& PT : m_parr.params[PF_PARAM_UNIFORM])
{ {

View file

@ -176,21 +176,6 @@ void GLGSRender::begin()
init_buffers(rsx::framebuffer_creation_context::context_draw); init_buffers(rsx::framebuffer_creation_context::context_draw);
} }
namespace
{
GLenum get_gl_target_for_texture(const rsx::texture_dimension_extended type)
{
switch (type)
{
case rsx::texture_dimension_extended::texture_dimension_1d: return GL_TEXTURE_1D;
case rsx::texture_dimension_extended::texture_dimension_2d: return GL_TEXTURE_2D;
case rsx::texture_dimension_extended::texture_dimension_cubemap: return GL_TEXTURE_CUBE_MAP;
case rsx::texture_dimension_extended::texture_dimension_3d: return GL_TEXTURE_3D;
}
fmt::throw_exception("Unknown texture target" HERE);
}
}
void GLGSRender::end() void GLGSRender::end()
{ {
std::chrono::time_point<steady_clock> state_check_start = steady_clock::now(); std::chrono::time_point<steady_clock> state_check_start = steady_clock::now();
@ -321,7 +306,7 @@ void GLGSRender::end()
if (tex.enabled()) if (tex.enabled())
{ {
GLenum target = get_gl_target_for_texture(sampler_state->image_type); GLenum target = gl::get_target(sampler_state->image_type);
if (sampler_state->image_handle) if (sampler_state->image_handle)
{ {
glBindTexture(target, sampler_state->image_handle); glBindTexture(target, sampler_state->image_handle);

View file

@ -31,7 +31,8 @@ color_format rsx::internals::surface_color_format_to_gl(rsx::surface_color_forma
return{ ::gl::texture::type::f32, ::gl::texture::format::rgba, true, 4, 4 }; return{ ::gl::texture::type::f32, ::gl::texture::format::rgba, true, 4, 4 };
case rsx::surface_color_format::b8: case rsx::surface_color_format::b8:
return{ ::gl::texture::type::ubyte, ::gl::texture::format::r, false, 1, 1 }; return{ ::gl::texture::type::ubyte, ::gl::texture::format::r, false, 1, 1,
{ ::gl::texture::channel::one, ::gl::texture::channel::r, ::gl::texture::channel::r, ::gl::texture::channel::r } };
case rsx::surface_color_format::g8b8: case rsx::surface_color_format::g8b8:
return{ ::gl::texture::type::ubyte, ::gl::texture::format::rg, false, 2, 1 }; return{ ::gl::texture::type::ubyte, ::gl::texture::format::rg, false, 2, 1 };
@ -188,10 +189,14 @@ void GLGSRender::init_buffers(rsx::framebuffer_creation_context context, bool sk
//NOTE: Its is possible that some renders are done on a swizzled context. Pitch is meaningless in that case //NOTE: Its is possible that some renders are done on a swizzled context. Pitch is meaningless in that case
//Seen in Nier (color) and GT HD concept (z buffer) //Seen in Nier (color) and GT HD concept (z buffer)
//Restriction is that the RTT is always a square region for that dimensions are powers of 2 //Restriction is that the dimensions are powers of 2. Also, dimensions are passed via log2w and log2h entries
const auto required_zeta_pitch = std::max<u32>((u32)(depth_format == rsx::surface_depth_format::z16 ? clip_horizontal * 2 : clip_horizontal * 4), 64u); const auto required_zeta_pitch = std::max<u32>((u32)(depth_format == rsx::surface_depth_format::z16 ? clip_horizontal * 2 : clip_horizontal * 4), 64u);
const auto required_color_pitch = std::max<u32>((u32)rsx::utility::get_packed_pitch(surface_format, clip_horizontal), 64u); const auto required_color_pitch = std::max<u32>((u32)rsx::utility::get_packed_pitch(surface_format, clip_horizontal), 64u);
const bool stencil_test_enabled = depth_format == rsx::surface_depth_format::z24s8 && rsx::method_registers.stencil_test_enabled(); const bool stencil_test_enabled = depth_format == rsx::surface_depth_format::z24s8 && rsx::method_registers.stencil_test_enabled();
const auto lg2w = rsx::method_registers.surface_log2_width();
const auto lg2h = rsx::method_registers.surface_log2_height();
const auto clipw_log2 = (u32)floor(log2(clip_horizontal));
const auto cliph_log2 = (u32)floor(log2(clip_vertical));
if (depth_address) if (depth_address)
{ {
@ -210,8 +215,21 @@ void GLGSRender::init_buffers(rsx::framebuffer_creation_context context, bool sk
if (depth_address && zeta_pitch < required_zeta_pitch) if (depth_address && zeta_pitch < required_zeta_pitch)
{ {
if (zeta_pitch < 64 || clip_vertical != clip_horizontal) if (lg2w < clipw_log2 || lg2h < cliph_log2)
{
//Cannot fit
depth_address = 0; depth_address = 0;
if (lg2w > 0 || lg2h > 0)
{
//Something was actually declared for the swizzle context dimensions
LOG_ERROR(RSX, "Invalid swizzled context depth surface dims, LG2W=%d, LG2H=%d, clip_w=%d, clip_h=%d", lg2w, lg2h, clip_horizontal, clip_vertical);
}
}
else
{
LOG_TRACE(RSX, "Swizzled context depth surface, LG2W=%d, LG2H=%d, clip_w=%d, clip_h=%d", lg2w, lg2h, clip_horizontal, clip_vertical);
}
} }
} }
@ -219,8 +237,20 @@ void GLGSRender::init_buffers(rsx::framebuffer_creation_context context, bool sk
{ {
if (pitchs[index] < required_color_pitch) if (pitchs[index] < required_color_pitch)
{ {
if (pitchs[index] < 64 || clip_vertical != clip_horizontal) if (lg2w < clipw_log2 || lg2h < cliph_log2)
{
surface_addresses[index] = 0; surface_addresses[index] = 0;
if (lg2w > 0 || lg2h > 0)
{
//Something was actually declared for the swizzle context dimensions
LOG_ERROR(RSX, "Invalid swizzled context color surface dims, LG2W=%d, LG2H=%d, clip_w=%d, clip_h=%d", lg2w, lg2h, clip_horizontal, clip_vertical);
}
}
else
{
LOG_TRACE(RSX, "Swizzled context color surface, LG2W=%d, LG2H=%d, clip_w=%d, clip_h=%d", lg2w, lg2h, clip_horizontal, clip_vertical);
}
} }
if (surface_addresses[index] == depth_address) if (surface_addresses[index] == depth_address)
@ -364,6 +394,8 @@ void GLGSRender::init_buffers(rsx::framebuffer_creation_context context, bool sk
break; break;
} }
m_gl_texture_cache.clear_ro_tex_invalidate_intr();
//Mark buffer regions as NO_ACCESS on Cell visible side //Mark buffer regions as NO_ACCESS on Cell visible side
if (g_cfg.video.write_color_buffers) if (g_cfg.video.write_color_buffers)
{ {
@ -393,6 +425,12 @@ void GLGSRender::init_buffers(rsx::framebuffer_creation_context context, bool sk
depth_format_gl.format, depth_format_gl.type, true); depth_format_gl.format, depth_format_gl.type, true);
} }
} }
if (m_gl_texture_cache.get_ro_tex_invalidate_intr())
{
//Invalidate cached sampler state
m_samplers_dirty.store(true);
}
} }
std::array<std::vector<gsl::byte>, 4> GLGSRender::copy_render_targets_to_memory() std::array<std::vector<gsl::byte>, 4> GLGSRender::copy_render_targets_to_memory()

View file

@ -8,6 +8,18 @@
namespace gl namespace gl
{ {
GLenum get_target(rsx::texture_dimension_extended type)
{
switch (type)
{
case rsx::texture_dimension_extended::texture_dimension_1d: return GL_TEXTURE_1D;
case rsx::texture_dimension_extended::texture_dimension_2d: return GL_TEXTURE_2D;
case rsx::texture_dimension_extended::texture_dimension_cubemap: return GL_TEXTURE_CUBE_MAP;
case rsx::texture_dimension_extended::texture_dimension_3d: return GL_TEXTURE_3D;
}
fmt::throw_exception("Unknown texture target" HERE);
}
GLenum get_sized_internal_format(u32 texture_format) GLenum get_sized_internal_format(u32 texture_format)
{ {
switch (texture_format) switch (texture_format)

View file

@ -10,6 +10,7 @@ namespace rsx
namespace gl namespace gl
{ {
GLenum get_target(rsx::texture_dimension_extended type);
GLenum get_sized_internal_format(u32 gcm_format); GLenum get_sized_internal_format(u32 gcm_format);
std::tuple<GLenum, GLenum> get_format_type(u32 texture_format); std::tuple<GLenum, GLenum> get_format_type(u32 texture_format);
GLenum wrap_mode(rsx::texture_wrap_mode wrap); GLenum wrap_mode(rsx::texture_wrap_mode wrap);

View file

@ -765,8 +765,9 @@ namespace gl
break; break;
} }
glBindTexture(GL_TEXTURE_2D, vram_texture); auto target = gl::get_target(type);
apply_component_mapping_flags(GL_TEXTURE_2D, gcm_format, flags); glBindTexture(target, vram_texture);
apply_component_mapping_flags(target, gcm_format, flags);
auto& cached = create_texture(vram_texture, rsx_address, rsx_size, width, height, depth, mipmaps); auto& cached = create_texture(vram_texture, rsx_address, rsx_size, width, height, depth, mipmaps);
cached.set_dirty(false); cached.set_dirty(false);
@ -836,7 +837,7 @@ namespace gl
section.set_sampler_status(rsx::texture_sampler_status::status_ready); section.set_sampler_status(rsx::texture_sampler_status::status_ready);
} }
void insert_texture_barrier() override void insert_texture_barrier(void*&, gl::texture*) override
{ {
auto &caps = gl::get_driver_caps(); auto &caps = gl::get_driver_caps();

View file

@ -149,7 +149,7 @@ void GLVertexDecompilerThread::insertOutputs(std::stringstream & OS, const std::
void GLVertexDecompilerThread::insertMainStart(std::stringstream & OS) void GLVertexDecompilerThread::insertMainStart(std::stringstream & OS)
{ {
insert_glsl_legacy_function(OS, glsl::glsl_vertex_program); insert_glsl_legacy_function(OS, glsl::glsl_vertex_program, properties.has_lit_op);
glsl::insert_vertex_input_fetch(OS, glsl::glsl_rules_opengl4, gl::get_driver_caps().vendor_INTEL==false); glsl::insert_vertex_input_fetch(OS, glsl::glsl_rules_opengl4, gl::get_driver_caps().vendor_INTEL==false);
std::string parameters = ""; std::string parameters = "";

View file

@ -34,6 +34,9 @@ void gl::init()
#ifdef __unix__ #ifdef __unix__
glewExperimental = true; glewExperimental = true;
glewInit(); glewInit();
#ifndef __APPLE__
glxewInit();
#endif
#endif #endif
} }
@ -41,5 +44,19 @@ void gl::set_swapinterval(int interval)
{ {
#ifdef _WIN32 #ifdef _WIN32
wglSwapIntervalEXT(interval); wglSwapIntervalEXT(interval);
#elif !defined(__APPLE__)
if (glXSwapIntervalEXT)
{
if (auto window = glXGetCurrentDrawable())
{
glXSwapIntervalEXT(glXGetCurrentDisplay(), window, interval);
return;
}
}
//No existing drawable or missing swap extension, EGL?
LOG_ERROR(RSX, "Failed to set swap interval");
#else
LOG_UNIMPLEMENTED(RSX, "Swap control not implemented for this platform. Vsync options not available.");
#endif #endif
} }

View file

@ -22,6 +22,7 @@ typedef BOOL (WINAPI* PFNWGLSWAPINTERVALEXTPROC) (int interval);
#include <OpenGL/glu.h> #include <OpenGL/glu.h>
#else #else
#include <GL/glxew.h>
#include <GL/gl.h> #include <GL/gl.h>
#include <GL/glx.h> #include <GL/glx.h>
#include <GL/glxext.h> #include <GL/glxext.h>

View file

@ -144,6 +144,10 @@ namespace vk
glslang::TProgram program; glslang::TProgram program;
glslang::TShader shader_object(lang); glslang::TShader shader_object(lang);
shader_object.setEnvInput(glslang::EShSourceGlsl, lang, glslang::EShClientVulkan, 100);
shader_object.setEnvClient(glslang::EShClientVulkan, 100);
shader_object.setEnvTarget(glslang::EshTargetSpv, 0x00001000);
bool success = false; bool success = false;
const char *shader_text = shader.data(); const char *shader_text = shader.data();
@ -154,11 +158,13 @@ namespace vk
if (shader_object.parse(&g_default_config, 400, EProfile::ECoreProfile, false, true, msg)) if (shader_object.parse(&g_default_config, 400, EProfile::ECoreProfile, false, true, msg))
{ {
program.addShader(&shader_object); program.addShader(&shader_object);
success = program.link(EShMsgVulkanRules); success = program.link(msg);
if (success) if (success)
{ {
glslang::TIntermediate* bytes = program.getIntermediate(lang); glslang::SpvOptions options;
glslang::GlslangToSpv(*bytes, spv); options.disableOptimizer = false;
options.optimizeSize = true;
glslang::GlslangToSpv(*program.getIntermediate(lang), spv, &options);
} }
} }
else else

View file

@ -197,7 +197,7 @@ namespace vk
void VKFragmentDecompilerThread::insertGlobalFunctions(std::stringstream &OS) void VKFragmentDecompilerThread::insertGlobalFunctions(std::stringstream &OS)
{ {
glsl::insert_glsl_legacy_function(OS, glsl::glsl_fragment_program); glsl::insert_glsl_legacy_function(OS, glsl::glsl_fragment_program, properties.has_lit_op, m_prog.redirected_textures != 0, properties.has_wpos_input);
} }
void VKFragmentDecompilerThread::insertMainStart(std::stringstream & OS) void VKFragmentDecompilerThread::insertMainStart(std::stringstream & OS)
@ -251,8 +251,11 @@ void VKFragmentDecompilerThread::insertMainStart(std::stringstream & OS)
} }
} }
OS << " vec4 ssa = gl_FrontFacing ? vec4(1.) : vec4(-1.);\n"; if (m_parr.HasParam(PF_PARAM_IN, "vec4", "ssa"))
OS << " vec4 wpos = get_wpos();\n"; OS << " vec4 ssa = gl_FrontFacing ? vec4(1.) : vec4(-1.);\n";
if (properties.has_wpos_input)
OS << " vec4 wpos = get_wpos();\n";
bool two_sided_enabled = m_prog.front_back_color_enabled && (m_prog.back_color_diffuse_output || m_prog.back_color_specular_output); bool two_sided_enabled = m_prog.front_back_color_enabled && (m_prog.back_color_diffuse_output || m_prog.back_color_specular_output);

View file

@ -84,7 +84,10 @@ namespace vk
} }
case rsx::surface_color_format::b8: case rsx::surface_color_format::b8:
return std::make_pair(VK_FORMAT_R8_UNORM, vk::default_component_map()); {
VkComponentMapping no_alpha = { VK_COMPONENT_SWIZZLE_R, VK_COMPONENT_SWIZZLE_R, VK_COMPONENT_SWIZZLE_R, VK_COMPONENT_SWIZZLE_ONE };
return std::make_pair(VK_FORMAT_R8_UNORM, no_alpha);
}
case rsx::surface_color_format::g8b8: case rsx::surface_color_format::g8b8:
return std::make_pair(VK_FORMAT_R8G8_UNORM, vk::default_component_map()); return std::make_pair(VK_FORMAT_R8G8_UNORM, vk::default_component_map());
@ -360,23 +363,14 @@ namespace
subpass.pColorAttachments = number_of_color_surface > 0 ? attachment_references.data() : nullptr; subpass.pColorAttachments = number_of_color_surface > 0 ? attachment_references.data() : nullptr;
subpass.pDepthStencilAttachment = depth_format != VK_FORMAT_UNDEFINED ? &attachment_references.back() : nullptr; subpass.pDepthStencilAttachment = depth_format != VK_FORMAT_UNDEFINED ? &attachment_references.back() : nullptr;
VkSubpassDependency dependency = {};
dependency.srcSubpass = VK_SUBPASS_EXTERNAL;
dependency.srcAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT;
dependency.srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
dependency.dstSubpass = 0;
dependency.dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT;
dependency.dstStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
dependency.dependencyFlags = VK_DEPENDENCY_BY_REGION_BIT;
VkRenderPassCreateInfo rp_info = {}; VkRenderPassCreateInfo rp_info = {};
rp_info.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO; rp_info.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO;
rp_info.attachmentCount = static_cast<uint32_t>(attachments.size()); rp_info.attachmentCount = static_cast<uint32_t>(attachments.size());
rp_info.pAttachments = attachments.data(); rp_info.pAttachments = attachments.data();
rp_info.subpassCount = 1; rp_info.subpassCount = 1;
rp_info.pSubpasses = &subpass; rp_info.pSubpasses = &subpass;
rp_info.pDependencies = &dependency; rp_info.pDependencies = nullptr;
rp_info.dependencyCount = 1; rp_info.dependencyCount = 0;
VkRenderPass result; VkRenderPass result;
CHECK_RESULT(vkCreateRenderPass(dev, &rp_info, NULL, &result)); CHECK_RESULT(vkCreateRenderPass(dev, &rp_info, NULL, &result));
@ -1143,8 +1137,22 @@ void VKGSRender::end()
if (replace) 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, for (auto &sampler : m_current_frame->samplers_to_clean)
min_filter, mag_filter, mip_mode, border_color, compare_enabled, depth_compare_mode); {
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 else
@ -1188,6 +1196,7 @@ void VKGSRender::end()
if (replace) if (replace)
{ {
//This is unlikely, there is no need to check the dirty pool
vs_sampler_handles[i] = std::make_unique<vk::sampler>( vs_sampler_handles[i] = std::make_unique<vk::sampler>(
*m_device, *m_device,
VK_SAMPLER_ADDRESS_MODE_REPEAT, VK_SAMPLER_ADDRESS_MODE_REPEAT, VK_SAMPLER_ADDRESS_MODE_REPEAT, VK_SAMPLER_ADDRESS_MODE_REPEAT, VK_SAMPLER_ADDRESS_MODE_REPEAT, VK_SAMPLER_ADDRESS_MODE_REPEAT,
@ -2478,10 +2487,14 @@ void VKGSRender::prepare_rtts(rsx::framebuffer_creation_context context)
//NOTE: Its is possible that some renders are done on a swizzled context. Pitch is meaningless in that case //NOTE: Its is possible that some renders are done on a swizzled context. Pitch is meaningless in that case
//Seen in Nier (color) and GT HD concept (z buffer) //Seen in Nier (color) and GT HD concept (z buffer)
//Restriction is that the RTT is always a square region for that dimensions are powers of 2 //Restriction is that the dimensions are powers of 2. Also, dimensions are passed via log2w and log2h entries
const auto required_zeta_pitch = std::max<u32>((u32)(depth_fmt == rsx::surface_depth_format::z16 ? clip_width * 2 : clip_width * 4), 64u); const auto required_zeta_pitch = std::max<u32>((u32)(depth_fmt == rsx::surface_depth_format::z16 ? clip_width * 2 : clip_width * 4), 64u);
const auto required_color_pitch = std::max<u32>((u32)rsx::utility::get_packed_pitch(color_fmt, clip_width), 64u); const auto required_color_pitch = std::max<u32>((u32)rsx::utility::get_packed_pitch(color_fmt, clip_width), 64u);
const bool stencil_test_enabled = depth_fmt == rsx::surface_depth_format::z24s8 && rsx::method_registers.stencil_test_enabled(); const bool stencil_test_enabled = depth_fmt == rsx::surface_depth_format::z24s8 && rsx::method_registers.stencil_test_enabled();
const auto lg2w = rsx::method_registers.surface_log2_width();
const auto lg2h = rsx::method_registers.surface_log2_height();
const auto clipw_log2 = (u32)floor(log2(clip_width));
const auto cliph_log2 = (u32)floor(log2(clip_height));
if (zeta_address) if (zeta_address)
{ {
@ -2500,8 +2513,21 @@ void VKGSRender::prepare_rtts(rsx::framebuffer_creation_context context)
if (zeta_address && zeta_pitch < required_zeta_pitch) if (zeta_address && zeta_pitch < required_zeta_pitch)
{ {
if (zeta_pitch < 64 || clip_width != clip_height) if (lg2w < clipw_log2 || lg2h < cliph_log2)
{
//Cannot fit
zeta_address = 0; zeta_address = 0;
if (lg2w > 0 || lg2h > 0)
{
//Something was actually declared for the swizzle context dimensions
LOG_ERROR(RSX, "Invalid swizzled context depth surface dims, LG2W=%d, LG2H=%d, clip_w=%d, clip_h=%d", lg2w, lg2h, clip_width, clip_height);
}
}
else
{
LOG_TRACE(RSX, "Swizzled context depth surface, LG2W=%d, LG2H=%d, clip_w=%d, clip_h=%d", lg2w, lg2h, clip_width, clip_height);
}
} }
} }
@ -2509,8 +2535,20 @@ void VKGSRender::prepare_rtts(rsx::framebuffer_creation_context context)
{ {
if (surface_pitchs[index] < required_color_pitch) if (surface_pitchs[index] < required_color_pitch)
{ {
if (surface_pitchs[index] < 64 || clip_width != clip_height) if (lg2w < clipw_log2 || lg2h < cliph_log2)
{
surface_addresses[index] = 0; surface_addresses[index] = 0;
if (lg2w > 0 || lg2h > 0)
{
//Something was actually declared for the swizzle context dimensions
LOG_ERROR(RSX, "Invalid swizzled context color surface dims, LG2W=%d, LG2H=%d, clip_w=%d, clip_h=%d", lg2w, lg2h, clip_width, clip_height);
}
}
else
{
LOG_TRACE(RSX, "Swizzled context color surface, LG2W=%d, LG2H=%d, clip_w=%d, clip_h=%d", lg2w, lg2h, clip_width, clip_height);
}
} }
if (surface_addresses[index] == zeta_address) if (surface_addresses[index] == zeta_address)
@ -2990,7 +3028,7 @@ void VKGSRender::flip(int buffer)
VkImageLayout target_layout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR; VkImageLayout target_layout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR;
VkImageSubresourceRange range = { VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1 }; VkImageSubresourceRange range = { VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1 };
if (aspect_ratio.x) if (aspect_ratio.x || aspect_ratio.y)
{ {
VkClearColorValue clear_black {}; VkClearColorValue clear_black {};
vk::change_image_layout(*m_current_command_buffer, target_image, VK_IMAGE_LAYOUT_PRESENT_SRC_KHR, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, range); vk::change_image_layout(*m_current_command_buffer, target_image, VK_IMAGE_LAYOUT_PRESENT_SRC_KHR, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, range);
@ -3194,4 +3232,4 @@ void VKGSRender::shell_do_cleanup()
{ {
//TODO: Guard this //TODO: Guard this
m_overlay_cleanup_requests.push_back(0); m_overlay_cleanup_requests.push_back(0);
} }

View file

@ -388,6 +388,45 @@ namespace vk
image->current_layout = new_layout; image->current_layout = new_layout;
} }
void insert_texture_barrier(VkCommandBuffer cmd, VkImage image, VkImageLayout layout, VkImageSubresourceRange range)
{
VkImageMemoryBarrier barrier = {};
barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
barrier.newLayout = layout;
barrier.oldLayout = layout;
barrier.image = image;
barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
barrier.subresourceRange = range;
barrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT;
VkPipelineStageFlags src_stage;
if (range.aspectMask == VK_IMAGE_ASPECT_COLOR_BIT)
{
barrier.srcAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
src_stage = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
}
else
{
barrier.srcAccessMask = VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT;
src_stage = VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT;
}
vkCmdPipelineBarrier(cmd, src_stage, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT | VK_PIPELINE_STAGE_VERTEX_SHADER_BIT, 0, 0, nullptr, 0, nullptr, 1, &barrier);
}
void insert_texture_barrier(VkCommandBuffer cmd, vk::image *image)
{
if (image->info.usage & VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT)
{
insert_texture_barrier(cmd, image->value, image->current_layout, { VK_IMAGE_ASPECT_DEPTH_BIT, 0, 1, 0, 1 });
}
else
{
insert_texture_barrier(cmd, image->value, image->current_layout, { VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1 });
}
}
void enter_uninterruptible() void enter_uninterruptible()
{ {
g_cb_no_interrupt_flag = true; g_cb_no_interrupt_flag = true;

View file

@ -90,6 +90,10 @@ namespace vk
std::pair<VkFormat, VkComponentMapping> get_compatible_surface_format(rsx::surface_color_format color_format); std::pair<VkFormat, VkComponentMapping> get_compatible_surface_format(rsx::surface_color_format color_format);
size_t get_render_pass_location(VkFormat color_surface_format, VkFormat depth_stencil_format, u8 color_surface_count); size_t get_render_pass_location(VkFormat color_surface_format, VkFormat depth_stencil_format, u8 color_surface_count);
//Texture barrier applies to a texture to ensure writes to it are finished before any reads are attempted to avoid RAW hazards
void insert_texture_barrier(VkCommandBuffer cmd, VkImage image, VkImageLayout layout, VkImageSubresourceRange range);
void insert_texture_barrier(VkCommandBuffer cmd, vk::image *image);
void enter_uninterruptible(); void enter_uninterruptible();
void leave_uninterruptible(); void leave_uninterruptible();
bool is_uninterruptible(); bool is_uninterruptible();

View file

@ -831,8 +831,10 @@ namespace vk
section.set_sampler_status(rsx::texture_sampler_status::status_ready); section.set_sampler_status(rsx::texture_sampler_status::status_ready);
} }
void insert_texture_barrier() override void insert_texture_barrier(vk::command_buffer& cmd, vk::image* tex) override
{} {
vk::insert_texture_barrier(cmd, tex);
}
public: public:

View file

@ -185,7 +185,7 @@ void VKVertexDecompilerThread::insertOutputs(std::stringstream & OS, const std::
void VKVertexDecompilerThread::insertMainStart(std::stringstream & OS) void VKVertexDecompilerThread::insertMainStart(std::stringstream & OS)
{ {
glsl::insert_glsl_legacy_function(OS, glsl::glsl_vertex_program); glsl::insert_glsl_legacy_function(OS, glsl::glsl_vertex_program, properties.has_lit_op);
glsl::insert_vertex_input_fetch(OS, glsl::glsl_rules_rpirv); glsl::insert_vertex_input_fetch(OS, glsl::glsl_rules_rpirv);
std::string parameters = ""; std::string parameters = "";

View file

@ -472,6 +472,7 @@ namespace rsx
//Resource was not found in config dir, try and grab from relative path (linux) //Resource was not found in config dir, try and grab from relative path (linux)
info = std::make_unique<image_info>(("Icons/ui/" + res).c_str()); info = std::make_unique<image_info>(("Icons/ui/" + res).c_str());
#ifndef _WIN32 #ifndef _WIN32
// Check for Icons in ../share/rpcs3 for AppImages and /usr/bin/
if (info->data == nullptr) if (info->data == nullptr)
{ {
char result[ PATH_MAX ]; char result[ PATH_MAX ];
@ -483,6 +484,11 @@ namespace rsx
std::string executablePath = dirname(result); std::string executablePath = dirname(result);
info = std::make_unique<image_info>((executablePath + "/../share/rpcs3/Icons/ui/" + res).c_str()); info = std::make_unique<image_info>((executablePath + "/../share/rpcs3/Icons/ui/" + res).c_str());
// Check if the icons are in the same directory as the executable (local builds)
if (info->data == nullptr)
{
info = std::make_unique<image_info>((executablePath + "/Icons/ui/" + res).c_str());
}
} }
#endif #endif
if (info->data != nullptr) if (info->data != nullptr)
@ -1331,6 +1337,8 @@ namespace rsx
s16 m_selected_entry = -1; s16 m_selected_entry = -1;
u16 m_elements_count = 0; u16 m_elements_count = 0;
bool m_cancel_only = false;
public: public:
list_view(u16 width, u16 height) list_view(u16 width, u16 height)
{ {
@ -1461,6 +1469,17 @@ namespace rsx
return m_items[m_selected_entry]->text; return m_items[m_selected_entry]->text;
} }
void set_cancel_only(bool cancel_only)
{
if (cancel_only)
m_cancel_btn->set_pos(x + 30, y + h + 20);
else
m_cancel_btn->set_pos(x + 180, y + h + 20);
m_cancel_only = cancel_only;
is_compiled = false;
}
void translate(s16 _x, s16 _y) override void translate(s16 _x, s16 _y) override
{ {
layout_container::translate(_x, _y); layout_container::translate(_x, _y);
@ -1478,9 +1497,11 @@ namespace rsx
compiled.add(m_highlight_box->get_compiled()); compiled.add(m_highlight_box->get_compiled());
compiled.add(m_scroll_indicator_top->get_compiled()); compiled.add(m_scroll_indicator_top->get_compiled());
compiled.add(m_scroll_indicator_bottom->get_compiled()); compiled.add(m_scroll_indicator_bottom->get_compiled());
compiled.add(m_accept_btn->get_compiled());
compiled.add(m_cancel_btn->get_compiled()); compiled.add(m_cancel_btn->get_compiled());
if (!m_cancel_only)
compiled.add(m_accept_btn->get_compiled());
compiled_resources = compiled; compiled_resources = compiled;
} }

View file

@ -254,6 +254,7 @@ namespace rsx
std::unique_ptr<list_view> m_list; std::unique_ptr<list_view> m_list;
std::unique_ptr<label> m_description; std::unique_ptr<label> m_description;
std::unique_ptr<label> m_time_thingy; std::unique_ptr<label> m_time_thingy;
std::unique_ptr<label> m_no_saves_text;
std::string current_time() std::string current_time()
{ {
@ -264,6 +265,8 @@ namespace rsx
return buf; return buf;
} }
bool m_no_saves = false;
public: public:
save_dialog() save_dialog()
{ {
@ -297,6 +300,8 @@ namespace rsx
switch (button_press) switch (button_press)
{ {
case pad_button::cross: case pad_button::cross:
if (m_no_saves)
break;
return_code = m_list->get_selected_index(); return_code = m_list->get_selected_index();
//Fall through //Fall through
case pad_button::circle: case pad_button::circle:
@ -320,6 +325,10 @@ namespace rsx
result.add(m_list->get_compiled()); result.add(m_list->get_compiled());
result.add(m_description->get_compiled()); result.add(m_description->get_compiled());
result.add(m_time_thingy->get_compiled()); result.add(m_time_thingy->get_compiled());
if (m_no_saves)
result.add(m_no_saves_text->get_compiled());
return result; return result;
} }
@ -349,6 +358,20 @@ namespace rsx
m_list->add_entry(new_stub); m_list->add_entry(new_stub);
} }
if (!m_list->m_items.size())
{
m_no_saves_text = std::make_unique<label>();
m_no_saves_text->set_font("Arial", 20);
m_no_saves_text->align_text(overlay_element::text_align::center);
m_no_saves_text->set_pos(m_list->x, m_list->y + m_list->h / 2);
m_no_saves_text->set_size(m_list->w, 30);
m_no_saves_text->set_text("There is no saved data.");
m_no_saves_text->back_color.a = 0;
m_no_saves = true;
m_list->set_cancel_only(true);
}
static_cast<label*>(m_description.get())->auto_resize(); static_cast<label*>(m_description.get())->auto_resize();
if (auto err = run_input_loop()) if (auto err = run_input_loop())

View file

@ -282,6 +282,7 @@ namespace rsx
struct progress_dialog_helper struct progress_dialog_helper
{ {
std::shared_ptr<MsgDialogBase> dlg; std::shared_ptr<MsgDialogBase> dlg;
atomic_t<bool> initialized{ false };
virtual void create() virtual void create()
{ {
@ -300,7 +301,13 @@ namespace rsx
Emu.CallAfter([&]() Emu.CallAfter([&]()
{ {
dlg->Create("Preloading cached shaders from disk.\nPlease wait..."); dlg->Create("Preloading cached shaders from disk.\nPlease wait...");
initialized.store(true);
}); });
while (!initialized.load() && !Emu.IsStopped())
{
_mm_pause();
}
} }
virtual void update_msg(u32 processed, u32 entry_count) virtual void update_msg(u32 processed, u32 entry_count)

View file

@ -60,11 +60,21 @@ bool basic_keyboard_handler::eventFilter(QObject* target, QEvent* ev)
void basic_keyboard_handler::keyPressEvent(QKeyEvent* keyEvent) void basic_keyboard_handler::keyPressEvent(QKeyEvent* keyEvent)
{ {
if (keyEvent->isAutoRepeat() && !m_keyboards[0].m_key_repeat)
{
keyEvent->ignore();
return;
}
Key(keyEvent->key(), 1); Key(keyEvent->key(), 1);
} }
void basic_keyboard_handler::keyReleaseEvent(QKeyEvent* keyEvent) void basic_keyboard_handler::keyReleaseEvent(QKeyEvent* keyEvent)
{ {
if (keyEvent->isAutoRepeat() && !m_keyboards[0].m_key_repeat)
{
keyEvent->ignore();
return;
}
Key(keyEvent->key(), 0); Key(keyEvent->key(), 0);
} }

View file

@ -250,6 +250,7 @@
<ClCompile Include="Emu\Cell\Modules\sceNp2.cpp" /> <ClCompile Include="Emu\Cell\Modules\sceNp2.cpp" />
<ClCompile Include="Emu\Cell\Modules\sceNpClans.cpp" /> <ClCompile Include="Emu\Cell\Modules\sceNpClans.cpp" />
<ClCompile Include="Emu\Cell\Modules\sceNpCommerce2.cpp" /> <ClCompile Include="Emu\Cell\Modules\sceNpCommerce2.cpp" />
<ClCompile Include="Emu\Cell\Modules\sceNpMatchingInt.cpp" />
<ClCompile Include="Emu\Cell\Modules\sceNpSns.cpp" /> <ClCompile Include="Emu\Cell\Modules\sceNpSns.cpp" />
<ClCompile Include="Emu\Cell\Modules\sceNpTrophy.cpp" /> <ClCompile Include="Emu\Cell\Modules\sceNpTrophy.cpp" />
<ClCompile Include="Emu\Cell\Modules\sceNpTus.cpp" /> <ClCompile Include="Emu\Cell\Modules\sceNpTus.cpp" />

View file

@ -587,6 +587,9 @@
<ClCompile Include="Emu\Cell\Modules\sceNpCommerce2.cpp"> <ClCompile Include="Emu\Cell\Modules\sceNpCommerce2.cpp">
<Filter>Emu\Cell\Modules</Filter> <Filter>Emu\Cell\Modules</Filter>
</ClCompile> </ClCompile>
<ClCompile Include="Emu\Cell\Modules\sceNpMatchingInt.cpp">
<Filter>Emu\Cell\Modules</Filter>
</ClCompile>
<ClCompile Include="Emu\Cell\Modules\sceNpSns.cpp"> <ClCompile Include="Emu\Cell\Modules\sceNpSns.cpp">
<Filter>Emu\Cell\Modules</Filter> <Filter>Emu\Cell\Modules</Filter>
</ClCompile> </ClCompile>
@ -934,12 +937,12 @@
</ClCompile> </ClCompile>
<ClCompile Include="Emu\Cell\lv2\sys_net.cpp"> <ClCompile Include="Emu\Cell\lv2\sys_net.cpp">
<Filter>Emu\Cell\lv2</Filter> <Filter>Emu\Cell\lv2</Filter>
</ClCompile> </ClCompile>
<ClCompile Include="Emu\Io\PadHandler.cpp"> <ClCompile Include="Emu\Io\PadHandler.cpp">
<Filter>Emu\Io</Filter> <Filter>Emu\Io</Filter>
</ClCompile> </ClCompile>
<ClCompile Include="Emu\RSX\overlays.cpp"> <ClCompile Include="Emu\RSX\overlays.cpp">
<Filter>Emu\GPU\RSX</Filter> <Filter>Emu\GPU\RSX</Filter>
</ClCompile> </ClCompile>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>

View file

@ -938,6 +938,7 @@
<ClCompile Include="rpcs3qt\game_list_grid.cpp" /> <ClCompile Include="rpcs3qt\game_list_grid.cpp" />
<ClCompile Include="rpcs3qt\game_list_grid_delegate.cpp" /> <ClCompile Include="rpcs3qt\game_list_grid_delegate.cpp" />
<ClCompile Include="rpcs3qt\progress_dialog.cpp" /> <ClCompile Include="rpcs3qt\progress_dialog.cpp" />
<ClCompile Include="rpcs3qt\qt_utils.cpp" />
<ClCompile Include="rpcs3qt\syntax_highlighter.cpp" /> <ClCompile Include="rpcs3qt\syntax_highlighter.cpp" />
<ClCompile Include="rpcs3qt\save_data_info_dialog.cpp" /> <ClCompile Include="rpcs3qt\save_data_info_dialog.cpp" />
<ClCompile Include="rpcs3qt\save_manager_dialog.cpp" /> <ClCompile Include="rpcs3qt\save_manager_dialog.cpp" />
@ -1432,6 +1433,7 @@
<Command Condition="'$(Configuration)|$(Platform)'=='Debug - LLVM|x64'"> <Command Condition="'$(Configuration)|$(Platform)'=='Debug - LLVM|x64'">
</Command> </Command>
</CustomBuild> </CustomBuild>
<ClInclude Include="rpcs3qt\qt_utils.h" />
<ClInclude Include="rpcs3qt\save_data_dialog.h" /> <ClInclude Include="rpcs3qt\save_data_dialog.h" />
<CustomBuild Include="rpcs3qt\register_editor_dialog.h"> <CustomBuild Include="rpcs3qt\register_editor_dialog.h">
<AdditionalInputs Condition="'$(Configuration)|$(Platform)'=='Release - LLVM|x64'">$(QTDIR)\bin\moc.exe;%(FullPath)</AdditionalInputs> <AdditionalInputs Condition="'$(Configuration)|$(Platform)'=='Release - LLVM|x64'">$(QTDIR)\bin\moc.exe;%(FullPath)</AdditionalInputs>

View file

@ -99,6 +99,9 @@
<Filter Include="Io\evdev"> <Filter Include="Io\evdev">
<UniqueIdentifier>{6992629a-48f1-43ec-8070-d1dba81bcbf9}</UniqueIdentifier> <UniqueIdentifier>{6992629a-48f1-43ec-8070-d1dba81bcbf9}</UniqueIdentifier>
</Filter> </Filter>
<Filter Include="Gui\utils">
<UniqueIdentifier>{77ca7382-c296-43af-adb4-fb32f5ab4571}</UniqueIdentifier>
</Filter>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ClCompile Include="\rpcs3qt\*.cpp"> <ClCompile Include="\rpcs3qt\*.cpp">
@ -587,6 +590,9 @@
<ClCompile Include="rpcs3qt\find_dialog.cpp"> <ClCompile Include="rpcs3qt\find_dialog.cpp">
<Filter>Gui\misc dialogs</Filter> <Filter>Gui\misc dialogs</Filter>
</ClCompile> </ClCompile>
<ClCompile Include="rpcs3qt\qt_utils.cpp">
<Filter>Gui\utils</Filter>
</ClCompile>
<ClCompile Include="QTGeneratedFiles\Release - LLVM\moc_register_editor_dialog.cpp"> <ClCompile Include="QTGeneratedFiles\Release - LLVM\moc_register_editor_dialog.cpp">
<Filter>Generated Files\Release - LLVM</Filter> <Filter>Generated Files\Release - LLVM</Filter>
</ClCompile> </ClCompile>
@ -679,6 +685,9 @@
<ClInclude Include="rpcs3qt\custom_table_widget_item.h"> <ClInclude Include="rpcs3qt\custom_table_widget_item.h">
<Filter>Gui\game list</Filter> <Filter>Gui\game list</Filter>
</ClInclude> </ClInclude>
<ClInclude Include="rpcs3qt\qt_utils.h">
<Filter>Gui\utils</Filter>
</ClInclude>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<CustomBuild Include="debug\moc_predefs.h.cbt"> <CustomBuild Include="debug\moc_predefs.h.cbt">
@ -808,4 +817,4 @@
<ItemGroup> <ItemGroup>
<ResourceCompile Include="rpcs3.rc" /> <ResourceCompile Include="rpcs3.rc" />
</ItemGroup> </ItemGroup>
</Project> </Project>

View file

@ -1,5 +1,7 @@
#include "rpcs3_app.h" #include "rpcs3_app.h"
#include "rpcs3qt/qt_utils.h"
#include "rpcs3qt/welcome_dialog.h" #include "rpcs3qt/welcome_dialog.h"
#include "Emu/System.h" #include "Emu/System.h"
@ -167,37 +169,40 @@ void rpcs3_app::InitializeCallbacks()
} }
bool disableMouse = guiSettings->GetValue(gui::gs_disableMouse).toBool(); bool disableMouse = guiSettings->GetValue(gui::gs_disableMouse).toBool();
auto frame_geometry = gui::utils::create_centered_window_geometry(RPCS3MainWin->geometry(), w, h);
gs_frame* frame;
switch (video_renderer type = g_cfg.video.renderer) switch (video_renderer type = g_cfg.video.renderer)
{ {
case video_renderer::null: case video_renderer::null:
{ {
gs_frame* ret = new gs_frame("Null", w, h, RPCS3MainWin->GetAppIcon(), disableMouse); frame = new gs_frame("Null", frame_geometry, RPCS3MainWin->GetAppIcon(), disableMouse);
gameWindow = ret; break;
return std::unique_ptr<gs_frame>(ret);
} }
case video_renderer::opengl: case video_renderer::opengl:
{ {
gl_gs_frame* ret = new gl_gs_frame(w, h, RPCS3MainWin->GetAppIcon(), disableMouse); frame = new gl_gs_frame(frame_geometry, RPCS3MainWin->GetAppIcon(), disableMouse);
gameWindow = ret; break;
return std::unique_ptr<gl_gs_frame>(ret);
} }
case video_renderer::vulkan: case video_renderer::vulkan:
{ {
gs_frame* ret = new gs_frame("Vulkan", w, h, RPCS3MainWin->GetAppIcon(), disableMouse); frame = new gs_frame("Vulkan", frame_geometry, RPCS3MainWin->GetAppIcon(), disableMouse);
gameWindow = ret; break;
return std::unique_ptr<gs_frame>(ret);
} }
#ifdef _MSC_VER #ifdef _MSC_VER
case video_renderer::dx12: case video_renderer::dx12:
{ {
gs_frame* ret = new gs_frame("DirectX 12", w, h, RPCS3MainWin->GetAppIcon(), disableMouse); frame = new gs_frame("DirectX 12", frame_geometry, RPCS3MainWin->GetAppIcon(), disableMouse);
gameWindow = ret; break;
return std::unique_ptr<gs_frame>(ret);
} }
#endif #endif
default: fmt::throw_exception("Invalid video renderer: %s" HERE, type); default:
fmt::throw_exception("Invalid video renderer: %s" HERE, type);
} }
gameWindow = frame;
return std::unique_ptr<gs_frame>(frame);
}; };
callbacks.get_gs_render = []() -> std::shared_ptr<GSRender> callbacks.get_gs_render = []() -> std::shared_ptr<GSRender>

View file

@ -144,7 +144,7 @@ game_list_frame::game_list_frame(std::shared_ptr<gui_settings> guiSettings, std:
m_gameList->verticalScrollBar()->installEventFilter(this); m_gameList->verticalScrollBar()->installEventFilter(this);
m_gameList->verticalScrollBar()->setSingleStep(20); m_gameList->verticalScrollBar()->setSingleStep(20);
m_gameList->horizontalScrollBar()->setSingleStep(20); m_gameList->horizontalScrollBar()->setSingleStep(20);
m_gameList->verticalHeader()->setSectionResizeMode(QHeaderView::Fixed); m_gameList->verticalHeader()->setSectionResizeMode(QHeaderView::Fixed);
m_gameList->verticalHeader()->setMinimumSectionSize(m_Icon_Size.height()); m_gameList->verticalHeader()->setMinimumSectionSize(m_Icon_Size.height());
m_gameList->verticalHeader()->setMaximumSectionSize(m_Icon_Size.height()); m_gameList->verticalHeader()->setMaximumSectionSize(m_Icon_Size.height());
m_gameList->verticalHeader()->setVisible(false); m_gameList->verticalHeader()->setVisible(false);
@ -170,7 +170,7 @@ game_list_frame::game_list_frame(std::shared_ptr<gui_settings> guiSettings, std:
m_gameList->setHorizontalHeaderItem(gui::column_parental, new QTableWidgetItem(tr("Parental Level"))); m_gameList->setHorizontalHeaderItem(gui::column_parental, new QTableWidgetItem(tr("Parental Level")));
m_gameList->setHorizontalHeaderItem(gui::column_compat, new QTableWidgetItem(tr("Compatibility"))); m_gameList->setHorizontalHeaderItem(gui::column_compat, new QTableWidgetItem(tr("Compatibility")));
// since this won't work somehow: gameList->horizontalHeader()->setDefaultAlignment(Qt::AlignLeft); // since this won't work somehow: gameList->horizontalHeader()->setDefaultAlignment(Qt::AlignLeft);
for (int i = 0; i < m_gameList->horizontalHeader()->count(); i++) for (int i = 0; i < m_gameList->horizontalHeader()->count(); i++)
{ {
m_gameList->horizontalHeaderItem(i)->setTextAlignment(Qt::AlignLeft); m_gameList->horizontalHeaderItem(i)->setTextAlignment(Qt::AlignLeft);
@ -423,8 +423,10 @@ void game_list_frame::Refresh(const bool fromDrive, const bool scrollAfter)
path_list.back().resize(path_list.back().find_last_not_of('/') + 1); path_list.back().resize(path_list.back().find_last_not_of('/') + 1);
} }
// std::set is used to remove duplicates from the list // Used to remove duplications from the list (serial -> set of cats)
for (const auto& dir : std::set<std::string>(std::make_move_iterator(path_list.begin()), std::make_move_iterator(path_list.end()))) std::map<std::string, std::set<std::string>> serial_cat;
for (const auto& dir : path_list) { try
{ {
const std::string sfb = dir + "/PS3_DISC.SFB"; const std::string sfb = dir + "/PS3_DISC.SFB";
const std::string sfo = dir + (fs::is_file(sfb) ? "/PS3_GAME/PARAM.SFO" : "/PARAM.SFO"); const std::string sfo = dir + (fs::is_file(sfb) ? "/PS3_GAME/PARAM.SFO" : "/PARAM.SFO");
@ -435,7 +437,7 @@ void game_list_frame::Refresh(const bool fromDrive, const bool scrollAfter)
continue; continue;
} }
const auto& psf = psf::load_object(sfo_file); const auto psf = psf::load_object(sfo_file);
GameInfo game; GameInfo game;
game.path = dir; game.path = dir;
@ -448,6 +450,12 @@ void game_list_frame::Refresh(const bool fromDrive, const bool scrollAfter)
game.resolution = psf::get_integer(psf, "RESOLUTION"); game.resolution = psf::get_integer(psf, "RESOLUTION");
game.sound_format = psf::get_integer(psf, "SOUND_FORMAT"); game.sound_format = psf::get_integer(psf, "SOUND_FORMAT");
// Detect duplication
if (!serial_cat[game.serial].emplace(game.category).second)
{
continue;
}
bool bootable = false; bool bootable = false;
auto cat = category::cat_boot.find(game.category); auto cat = category::cat_boot.find(game.category);
if (cat != category::cat_boot.end()) if (cat != category::cat_boot.end())
@ -493,6 +501,12 @@ void game_list_frame::Refresh(const bool fromDrive, const bool scrollAfter)
m_game_data.push_back({ game, m_game_compat->GetCompatibility(game.serial), img, pxmap, true, bootable, hasCustomConfig }); m_game_data.push_back({ game, m_game_compat->GetCompatibility(game.serial), img, pxmap, true, bootable, hasCustomConfig });
} }
catch (const std::exception& e)
{
LOG_FATAL(GENERAL, "Failed to update game list at %s\n%s thrown: %s", dir, typeid(e).name(), e.what());
continue;
// Blame MSVC for double }}
}}
auto op = [](const GUI_GameInfo& game1, const GUI_GameInfo& game2) auto op = [](const GUI_GameInfo& game1, const GUI_GameInfo& game2)
{ {
@ -597,7 +611,7 @@ void game_list_frame::doubleClickedSlot(const QModelIndex& index)
{ {
i = m_xgrid->item(index.row(), index.column())->data(Qt::ItemDataRole::UserRole).toInt(); i = m_xgrid->item(index.row(), index.column())->data(Qt::ItemDataRole::UserRole).toInt();
} }
if (1) if (1)
{ {
if (Boot(m_game_data[i].info)) if (Boot(m_game_data[i].info))

View file

@ -5,8 +5,8 @@
#include <QOpenGLContext> #include <QOpenGLContext>
#include <QWindow> #include <QWindow>
gl_gs_frame::gl_gs_frame(int w, int h, QIcon appIcon, bool disableMouse) gl_gs_frame::gl_gs_frame(const QRect& geometry, QIcon appIcon, bool disableMouse)
: gs_frame("OpenGL", w, h, appIcon, disableMouse) : gs_frame("OpenGL", geometry, appIcon, disableMouse)
{ {
setSurfaceType(QSurface::OpenGLSurface); setSurfaceType(QSurface::OpenGLSurface);

View file

@ -9,7 +9,7 @@ private:
QSurfaceFormat m_format; QSurfaceFormat m_format;
public: public:
gl_gs_frame(int w, int h, QIcon appIcon, bool disableMouse); gl_gs_frame(const QRect& geometry, QIcon appIcon, bool disableMouse);
draw_context_t make_context() override; draw_context_t make_context() override;
void set_current(draw_context_t context) override; void set_current(draw_context_t context) override;

View file

@ -23,7 +23,7 @@
constexpr auto qstr = QString::fromStdString; constexpr auto qstr = QString::fromStdString;
gs_frame::gs_frame(const QString& title, int w, int h, QIcon appIcon, bool disableMouse) gs_frame::gs_frame(const QString& title, const QRect& geometry, QIcon appIcon, bool disableMouse)
: QWindow(), m_windowTitle(title), m_disable_mouse(disableMouse) : QWindow(), m_windowTitle(title), m_disable_mouse(disableMouse)
{ {
//Get version by substringing VersionNumber-buildnumber-commithash to get just the part before the dash //Get version by substringing VersionNumber-buildnumber-commithash to get just the part before the dash
@ -55,8 +55,7 @@ gs_frame::gs_frame(const QString& title, int w, int h, QIcon appIcon, bool disab
m_show_fps = static_cast<bool>(g_cfg.misc.show_fps_in_title); m_show_fps = static_cast<bool>(g_cfg.misc.show_fps_in_title);
resize(w, h); setGeometry(geometry);
setTitle(m_windowTitle); setTitle(m_windowTitle);
setVisibility(Hidden); setVisibility(Hidden);
create(); create();
@ -70,6 +69,18 @@ void gs_frame::paintEvent(QPaintEvent *event)
Q_UNUSED(event); Q_UNUSED(event);
} }
void gs_frame::showEvent(QShowEvent *event)
{
// we have to calculate new window positions, since the frame is only known once the window was created
// the left and right margins are too big on my setup for some reason yet unknown, so we'll have to ignore them
int x = geometry().left(); //std::max(geometry().left(), frameMargins().left());
int y = std::max(geometry().top(), frameMargins().top());
setPosition(x, y);
QWindow::showEvent(event);
}
void gs_frame::keyPressEvent(QKeyEvent *keyEvent) void gs_frame::keyPressEvent(QKeyEvent *keyEvent)
{ {
auto l_handleKeyEvent = [this ,keyEvent]() auto l_handleKeyEvent = [this ,keyEvent]()

View file

@ -9,6 +9,7 @@
class gs_frame : public QWindow, public GSFrameBase class gs_frame : public QWindow, public GSFrameBase
{ {
Q_OBJECT Q_OBJECT
u64 m_frames = 0; u64 m_frames = 0;
QString m_windowTitle; QString m_windowTitle;
bool m_show_fps; bool m_show_fps;
@ -20,7 +21,7 @@ class gs_frame : public QWindow, public GSFrameBase
bool m_minimized = false; bool m_minimized = false;
public: public:
gs_frame(const QString& title, int w, int h, QIcon appIcon, bool disableMouse); gs_frame(const QString& title, const QRect& geometry, QIcon appIcon, bool disableMouse);
draw_context_t make_context() override; draw_context_t make_context() override;
void set_current(draw_context_t context) override; void set_current(draw_context_t context) override;
@ -29,6 +30,7 @@ public:
wm_event get_default_wm_event() const override; wm_event get_default_wm_event() const override;
protected: protected:
virtual void paintEvent(QPaintEvent *event); virtual void paintEvent(QPaintEvent *event);
virtual void showEvent(QShowEvent *event);
void keyPressEvent(QKeyEvent *keyEvent) override; void keyPressEvent(QKeyEvent *keyEvent) override;
void OnFullScreen(); void OnFullScreen();

View file

@ -0,0 +1,37 @@
#include "qt_utils.h"
#include <QApplication>
#include <QScreen>
namespace gui
{
namespace utils
{
QRect create_centered_window_geometry(const QRect& origin, s32 width, s32 height)
{
// Get minimum virtual screen x & y for clamping the
// window x & y later while taking the width and height
// into account, so they don't go offscreen
s32 min_screen_x = std::numeric_limits<s32>::max();
s32 max_screen_x = std::numeric_limits<s32>::min();
s32 min_screen_y = std::numeric_limits<s32>::max();
s32 max_screen_y = std::numeric_limits<s32>::min();
for (auto screen : QApplication::screens())
{
auto screen_geometry = screen->availableGeometry();
min_screen_x = std::min(min_screen_x, screen_geometry.x());
max_screen_x = std::max(max_screen_x, screen_geometry.x() + screen_geometry.width() - width);
min_screen_y = std::min(min_screen_y, screen_geometry.y());
max_screen_y = std::max(max_screen_y, screen_geometry.y() + screen_geometry.height() - height);
}
s32 frame_x_raw = origin.left() + ((origin.width() - width) / 2);
s32 frame_y_raw = origin.top() + ((origin.height() - height) / 2);
s32 frame_x = std::clamp(frame_x_raw, min_screen_x, max_screen_x);
s32 frame_y = std::clamp(frame_y_raw, min_screen_y, max_screen_y);
return QRect(frame_x, frame_y, width, height);
}
} // utils
} // gui

14
rpcs3/rpcs3qt/qt_utils.h Normal file
View file

@ -0,0 +1,14 @@
#pragma once
#include "stdafx.h"
#include <QtCore>
namespace gui
{
namespace utils
{
// Creates a frame geometry rectangle with given width height that's centered inside the origin,
// while still considering screen boundaries.
QRect create_centered_window_geometry(const QRect& origin, s32 width, s32 height);
} // utils
} // gui

View file

@ -42,5 +42,16 @@ namespace std { inline namespace literals { inline namespace chrono_literals {}}
#include <array> #include <array>
#include <functional> #include <functional>
#include <unordered_map> #include <unordered_map>
#include <algorithm>
using namespace std::literals; using namespace std::literals;
// Remove once we move to C++17
namespace std
{
template<typename T>
constexpr const T clamp(const T value, const T min, const T max)
{
return value < min ? min : value > max ? max : value;
}
}