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

View File

@ -26,9 +26,6 @@ git:
submodules: false
before_install:
- if [ "$CC" = "clang" ]; then
export CXX="clang++-4.0" CC="clang-4.0";
fi;
- if [ "$TRAVIS_OS_NAME" = "linux" ] && [ "$CXX" = "g++" ]; then
export CXX="g++-5" CC="gcc-5" CXXFLAGS="-Wno-format-security";
fi;
@ -65,7 +62,7 @@ before_script:
- cmake .. -DCMAKE_INSTALL_PREFIX=/usr -G Ninja;
- ninja
- # 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;
DESTDIR=appdir ninja install ; find appdir/ ;
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/imageformats/* ./appdir/usr/plugins/imageformats/ ;
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} ;
./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 ;
@ -111,7 +109,8 @@ addons:
- libc6-dev
- llvm-4.0
- 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
- g++-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);
const auto result = ::lseek(m_fd, offset, mode);
if (result == -1)
{
g_tls_error = to_error(errno);
@ -1258,7 +1258,12 @@ bool fs::dir::open(const std::string& path)
}
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.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;
}
buf.push_back(c);
}

View File

@ -32,13 +32,23 @@ void patch_engine::append(const std::string& 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)
{
auto& name = pair.first.Scalar();
auto& data = m_map[name];
for (auto patch : pair.second)
{
u64 type64 = 0;
@ -91,7 +101,7 @@ void patch_engine::append(const std::string& patch)
break;
}
}
data.emplace_back(info);
}
}

View File

@ -39,6 +39,12 @@ bool utils::has_512()
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 result;
@ -92,6 +98,11 @@ std::string utils::get_system_info()
{
result += '+';
}
if (has_xop())
{
result += 'x';
}
}
if (has_rtm())

View File

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

View File

@ -1,79 +1,100 @@
#---------------------------------#
# general configuration #
#---------------------------------#
# version format
version: '0.0.4-{build}'
version: '{build}'
#---------------------------------#
# environment configuration #
#---------------------------------#
# Build worker image (VM template)
image: Visual Studio 2015
# clone directory
clone_folder: c:\projects\rpcs3
# environment variables
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:
- llvmlibs.7z -> appveyor.yml
- vulkan.7z -> appveyor.yml
- llvmlibs.7z -> appveyor.yml
- vulkan.7z -> appveyor.yml
- compat_database.dat
# scripts that run after cloning repository
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
#---------------------------------#
# build configuration #
#---------------------------------#
- ps: | # used for experimental build warnings for pr builds
$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
# build Configuration, i.e. Debug, Release, etc.
configuration: Release - LLVM
build:
parallel: true # enable MSBuild parallel builds
project: rpcs3.sln # path to Visual Studio solution or project
# MSBuild verbosity level
parallel: true
project: rpcs3.sln
verbosity: normal
# scripts to run before build
before_build:
- set BRANCH=%APPVEYOR_REPO_NAME%/%APPVEYOR_REPO_BRANCH%/#%APPVEYOR_PULL_REQUEST_NUMBER%
- if "%APPVEYOR_PULL_REQUEST_NUMBER%"=="" (set BRANCH=%APPVEYOR_REPO_NAME%/%APPVEYOR_REPO_BRANCH%)
- set PATH=%PATH%;%QTDIR%
- 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%APPVEYOR_BUILD_FOLDER% > 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
- ps: | # fetch precompiled build dependencies
if (!(test-path llvmlibs.7z)) { irm $env:LLVMLIBS -outfile llvmlibs.7z }
if (!(test-path vulkan.7z)) { irm $env:VULKAN -outfile vulkan.7z }
7z x llvmlibs.7z -aos -o"." | out-null
7z x vulkan.7z -aos -o".\lib\$env:CONFIGURATION-$env:PLATFORM" | out-null
# scripts to run *after* solution is built and *before* automatic packaging occurs (web apps, NuGet packages, Azure Cloud Services)
before_package:
- rm %APPVEYOR_BUILD_FOLDER%\bin\rpcs3.exp
- 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%
after_build:
- ps: | # remove unnecessary files
rm .\bin\rpcs3.exp, .\bin\rpcs3.lib, .\bin\rpcs3.pdb
#---------------------------------#
# tests configuration #
#---------------------------------#
- ps: | # prepare compatibility database for packaging
$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
#---------------------------------#
# artifacts configuration #
#---------------------------------#
# pushing entire folder as a zip archive
artifacts:
- path: bin
name: 'rpcs3-v0.0.4-$(COMMIT_DATE)-$(COMMIT_SHA)_win64'
- path: $(BUILD)
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)
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
if(UNIX AND NOT APPLE)
# Install the binary

View File

@ -1 +1,13 @@
#ifdef LLVM_AVAILABLE
#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
#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);
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);
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)) ? 0x20 : 0);
return rawcode + 0x5D;
}
}
if (rawcode >= 0x1E && rawcode <= 0x26) return rawcode + 0x13; // '1' - '9'
if (rawcode == 0x27) return 0x30; // '0'
if (rawcode == 0x28) return 0x0A; // '\n'
@ -136,7 +136,7 @@ error_code cellKbGetInfo(vm::ptr<CellKbInfo> info)
{
info->status[i] = current_info.status[i];
}
return CELL_OK;
}
@ -165,7 +165,7 @@ error_code cellKbRead(u32 port_no, vm::ptr<CellKbData> data)
}
current_data.len = 0;
return CELL_OK;
}
@ -180,7 +180,7 @@ error_code cellKbSetCodeType(u32 port_no, u32 type)
if (port_no >= handler->GetKeyboards().size())
return CELL_KB_ERROR_INVALID_PARAMETER;
KbConfig& current_config = handler->GetConfig(port_no);
current_config.code_type = type;
return CELL_OK;
@ -203,7 +203,7 @@ error_code cellKbSetReadMode(u32 port_no, u32 rmode)
if (port_no >= handler->GetKeyboards().size())
return CELL_KB_ERROR_INVALID_PARAMETER;
KbConfig& current_config = handler->GetConfig(port_no);
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);
if (!msgString)
{
return CELL_MSGDIALOG_ERROR_PARAM;
}
if (auto rsxthr = fxm::get<GSRender>())
{
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;
}
if (progressBarIndex >= dlg->type.progress_bar_count || !msgString)
if (progressBarIndex >= dlg->type.progress_bar_count)
{
return CELL_MSGDIALOG_ERROR_PARAM;
}

View File

@ -1,5 +1,6 @@
#include "stdafx.h"
#include "Emu/Cell/PPUModule.h"
#include "cellSysutil.h"
namespace vm { using namespace ps3; }
@ -20,6 +21,16 @@ enum
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()
{
UNIMPLEMENTED_FUNC(cellPhotoExport);
@ -38,39 +49,81 @@ s32 cellPhotoRegistFromFile()
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;
}
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;
}
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;
}
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;
}
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;
}
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;
}

View File

@ -1,10 +1,22 @@
#include "stdafx.h"
#include "Emu/Cell/PPUModule.h"
#include "Emu/IdManager.h"
#include "cellSysutil.h"
namespace vm { using namespace ps3; }
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
{
vm::bptr<struct CellSpurs> pSpurs;
@ -46,15 +58,40 @@ struct CellRecParam
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);
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;
}
s32 cellRecClose(s32 isDiscard)
error_code cellRecClose(s32 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;
}
@ -63,15 +100,31 @@ void cellRecGetInfo(s32 info, vm::ptr<u64> pValue)
cellRec.todo("cellRecGetInfo(info=0x%x, pValue=*0x%x)", info, pValue);
}
s32 cellRecStop()
error_code 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;
}
s32 cellRecStart()
error_code 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;
}
@ -81,7 +134,7 @@ u32 cellRecQueryMemSize(vm::cptr<CellRecParam> pParam)
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);
return CELL_OK;

View File

@ -1,36 +1,99 @@
#include "stdafx.h"
#include "Emu/Cell/PPUModule.h"
#include "cellSysutil.h"
namespace vm { using namespace ps3; }
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 "cellVideoUpload.h"
#include "cellSysutil.h"
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);
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;
}

View File

@ -1,7 +1,5 @@
#pragma once
namespace vm { using namespace ps3; }
struct CellVideoUploadOption
{
be_t<s32> type;
@ -11,27 +9,27 @@ struct CellVideoUploadOption
struct CellVideoUploadParam
{
be_t<s32> siteID;
vm::bcptr<char> pFilePath;
vm::ps3::bcptr<char> pFilePath;
union
{
struct
{
vm::bcptr<char> pClientId;
vm::bcptr<char> pDeveloperKey;
vm::bcptr<char> pTitle_UTF8;
vm::bcptr<char> pDescription_UTF8;
vm::bcptr<char> pKeyword_1_UTF8;
vm::bcptr<char> pKeyword_2_UTF8;
vm::bcptr<char> pKeyword_3_UTF8;
vm::ps3::bcptr<char> pClientId;
vm::ps3::bcptr<char> pDeveloperKey;
vm::ps3::bcptr<char> pTitle_UTF8;
vm::ps3::bcptr<char> pDescription_UTF8;
vm::ps3::bcptr<char> pKeyword_1_UTF8;
vm::ps3::bcptr<char> pKeyword_2_UTF8;
vm::ps3::bcptr<char> pKeyword_3_UTF8;
u8 isPrivate;
u8 rating;
} youtube;
} u;
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
{
@ -59,3 +57,9 @@ enum
CELL_VIDEO_UPLOAD_ERROR_FILE_OPEN = 0x8002d023,
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 "cellWebBrowser.h"
#include "Emu/IdManager.h"
extern logs::channel cellSysutil;
struct browser_t
{
vm::ptr<CellWebBrowserSystemCallback> system_cb;
vm::ptr<void> userData;
};
s32 cellWebBrowserActivate()
{
fmt::throw_exception("Unimplemented" HERE);
@ -15,9 +22,10 @@ s32 cellWebBrowserConfig()
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()
@ -45,9 +53,10 @@ s32 cellWebBrowserConfigSetErrorHook2()
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()
@ -60,9 +69,10 @@ s32 cellWebBrowserConfigSetFunction()
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()
@ -70,9 +80,10 @@ s32 cellWebBrowserConfigSetHeapSize()
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()
@ -80,9 +91,10 @@ s32 cellWebBrowserConfigSetMimeSet()
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()
@ -95,14 +107,16 @@ s32 cellWebBrowserConfigSetStatusHook2()
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()
@ -110,9 +124,10 @@ s32 cellWebBrowserConfigSetVersion()
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()
@ -180,7 +195,7 @@ s32 cellWebBrowserEstimate()
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);
@ -190,15 +205,26 @@ s32 cellWebBrowserEstimate2(vm::cptr<CellWebBrowserConfig2> config, vm::ptr<u32>
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;
}
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()
@ -216,9 +242,17 @@ s32 cellWebBrowserSetSystemCallbackUsrdata()
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()

View File

@ -2,6 +2,17 @@
#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 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);

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::sceNpClans,
&ppu_module_manager::sceNpCommerce2,
&ppu_module_manager::sceNpMatchingInt,
&ppu_module_manager::sceNpSns,
&ppu_module_manager::sceNpTrophy,
&ppu_module_manager::sceNpTus,

View File

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

View File

@ -12,9 +12,7 @@ using namespace llvm;
const ppu_decoder<PPUTranslator> s_ppu_decoder;
PPUTranslator::PPUTranslator(LLVMContext& context, Module* module, const ppu_module& info)
: m_context(context)
, m_module(module)
, m_is_be(false)
: cpu_translator(context, module, false)
, m_info(info)
, 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)
{
const auto ab = GetVrs(VrType::vi32, op.va, op.vb);
SetVr(op.vd, ZExt(m_ir->CreateICmpULT(m_ir->CreateAdd(ab[0], ab[1]), ab[0]), GetType<u32[4]>()));
const auto a = get_vr<u32[4]>(op.va);
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)
{
const auto ab = GetVrs(VrType::vf, op.va, op.vb);
SetVr(op.vd, m_ir->CreateFAdd(ab[0], ab[1]));
const auto a = get_vr<f32[4]>(op.va);
const auto b = get_vr<f32[4]>(op.vb);
set_vr(op.vd, eval(a + b));
}
void PPUTranslator::VADDSBS(ppu_opcode_t op)
{
const auto ab = SExt(GetVrs(VrType::vi8, op.va, op.vb));
const auto result = m_ir->CreateAdd(ab[0], ab[1]);
const auto saturated = SaturateSigned(result, -0x80, 0x7f);
SetVr(op.vd, saturated.first);
SetSat(IsNotZero(saturated.second));
const auto a = get_vr<s8[16]>(op.va);
const auto b = get_vr<s8[16]>(op.vb);
const auto s = eval(a + b);
const auto z = eval((a >> 7) ^ 0x7f);
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)
{
const auto ab = SExt(GetVrs(VrType::vi16, op.va, op.vb));
const auto result = m_ir->CreateAdd(ab[0], ab[1]);
const auto saturated = SaturateSigned(result, -0x8000, 0x7fff);
SetVr(op.vd, saturated.first);
SetSat(IsNotZero(saturated.second));
const auto a = get_vr<s16[8]>(op.va);
const auto b = get_vr<s16[8]>(op.vb);
const auto s = eval(a + b);
const auto z = eval((a >> 15) ^ 0x7fff);
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)
{
const auto ab = SExt(GetVrs(VrType::vi32, op.va, op.vb));
const auto result = m_ir->CreateAdd(ab[0], ab[1]);
const auto saturated = SaturateSigned(result, -0x80000000ll, 0x7fffffff);
SetVr(op.vd, saturated.first);
SetSat(IsNotZero(saturated.second));
const auto a = get_vr<s32[4]>(op.va);
const auto b = get_vr<s32[4]>(op.vb);
const auto s = eval(a + b);
const auto z = eval((a >> 31) ^ 0x7fffffff);
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)
{
const auto ab = GetVrs(VrType::vi8, op.va, op.vb);
SetVr(op.vd, m_ir->CreateAdd(ab[0], ab[1]));
const auto a = get_vr<u8[16]>(op.va);
const auto b = get_vr<u8[16]>(op.vb);
set_vr(op.vd, eval(a + b));
}
void PPUTranslator::VADDUBS(ppu_opcode_t op)
{
const auto ab = ZExt(GetVrs(VrType::vi8, op.va, op.vb));
const auto result = m_ir->CreateAdd(ab[0], ab[1]);
const auto saturated = Saturate(result, ICmpInst::ICMP_UGT, m_ir->getInt16(0xff));
SetVr(op.vd, saturated.first);
SetSat(IsNotZero(saturated.second));
const auto a = get_vr<s8[16]>(op.va);
const auto b = get_vr<s8[16]>(op.vb);
const auto s = eval(a + b);
const auto x = eval(ucarry(a, b, s) >> 7);
set_vr(op.vd, eval(s | x));
SetSat(IsNotZero(x.value));
}
void PPUTranslator::VADDUHM(ppu_opcode_t op)
{
const auto ab = GetVrs(VrType::vi16, op.va, op.vb);
SetVr(op.vd, m_ir->CreateAdd(ab[0], ab[1]));
const auto a = get_vr<u16[8]>(op.va);
const auto b = get_vr<u16[8]>(op.vb);
set_vr(op.vd, eval(a + b));
}
void PPUTranslator::VADDUHS(ppu_opcode_t op)
{
const auto ab = ZExt(GetVrs(VrType::vi16, op.va, op.vb));
const auto result = m_ir->CreateAdd(ab[0], ab[1]);
const auto saturated = Saturate(result, ICmpInst::ICMP_UGT, m_ir->getInt32(0xffff));
SetVr(op.vd, saturated.first);
SetSat(IsNotZero(saturated.second));
const auto a = get_vr<s16[8]>(op.va);
const auto b = get_vr<s16[8]>(op.vb);
const auto s = eval(a + b);
const auto x = eval(ucarry(a, b, s) >> 15);
set_vr(op.vd, eval(s | x));
SetSat(IsNotZero(x.value));
}
void PPUTranslator::VADDUWM(ppu_opcode_t op)
{
const auto ab = GetVrs(VrType::vi32, op.va, op.vb);
SetVr(op.vd, m_ir->CreateAdd(ab[0], ab[1]));
const auto a = get_vr<u32[4]>(op.va);
const auto b = get_vr<u32[4]>(op.vb);
set_vr(op.vd, eval(a + b));
}
void PPUTranslator::VADDUWS(ppu_opcode_t op)
{
const auto ab = ZExt(GetVrs(VrType::vi32, op.va, op.vb));
const auto result = m_ir->CreateAdd(ab[0], ab[1]);
const auto saturated = Saturate(result, ICmpInst::ICMP_UGT, m_ir->getInt64(0xffffffff));
SetVr(op.vd, saturated.first);
SetSat(IsNotZero(saturated.second));
const auto a = get_vr<s32[4]>(op.va);
const auto b = get_vr<s32[4]>(op.vb);
const auto s = eval(a + b);
const auto x = eval(ucarry(a, b, s) >> 31);
set_vr(op.vd, eval(s | x));
SetSat(IsNotZero(x.value));
}
void PPUTranslator::VAND(ppu_opcode_t op)
{
const auto ab = GetVrs(VrType::vi32, op.va, op.vb);
SetVr(op.vd, m_ir->CreateAnd(ab[0], ab[1]));
const auto a = get_vr<u32[4]>(op.va);
const auto b = get_vr<u32[4]>(op.vb);
set_vr(op.vd, eval(a & b));
}
void PPUTranslator::VANDC(ppu_opcode_t op)
{
const auto ab = GetVrs(VrType::vi32, op.va, op.vb);
SetVr(op.vd, m_ir->CreateAnd(ab[0], m_ir->CreateNot(ab[1])));
const auto a = get_vr<u32[4]>(op.va);
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)
{
const auto ab = SExt(GetVrs(VrType::vi8, op.va, op.vb));
SetVr(op.vd, AVG_OP(ab[0], ab[1]));
const auto a = get_vr<s8[16]>(op.va);
const auto b = get_vr<s8[16]>(op.vb);
set_vr(op.vd, eval(avg(a, b)));
}
void PPUTranslator::VAVGSH(ppu_opcode_t op)
{
const auto ab = SExt(GetVrs(VrType::vi16, op.va, op.vb));
SetVr(op.vd, AVG_OP(ab[0], ab[1]));
const auto a = get_vr<s16[8]>(op.va);
const auto b = get_vr<s16[8]>(op.vb);
set_vr(op.vd, eval(avg(a, b)));
}
void PPUTranslator::VAVGSW(ppu_opcode_t op)
{
const auto ab = SExt(GetVrs(VrType::vi32, op.va, op.vb));
SetVr(op.vd, AVG_OP(ab[0], ab[1]));
const auto a = get_vr<s32[4]>(op.va);
const auto b = get_vr<s32[4]>(op.vb);
set_vr(op.vd, eval(avg(a, b)));
}
void PPUTranslator::VAVGUB(ppu_opcode_t op)
{
const auto ab = ZExt(GetVrs(VrType::vi8, op.va, op.vb));
SetVr(op.vd, AVG_OP(ab[0], ab[1]));
const auto a = get_vr<u8[16]>(op.va);
const auto b = get_vr<u8[16]>(op.vb);
set_vr(op.vd, eval(avg(a, b)));
}
void PPUTranslator::VAVGUH(ppu_opcode_t op)
{
const auto ab = ZExt(GetVrs(VrType::vi16, op.va, op.vb));
SetVr(op.vd, AVG_OP(ab[0], ab[1]));
const auto a = get_vr<u16[8]>(op.va);
const auto b = get_vr<u16[8]>(op.vb);
set_vr(op.vd, eval(avg(a, b)));
}
void PPUTranslator::VAVGUW(ppu_opcode_t op)
{
const auto ab = ZExt(GetVrs(VrType::vi32, op.va, op.vb));
SetVr(op.vd, AVG_OP(ab[0], ab[1]));
const auto a = get_vr<u32[4]>(op.va);
const auto b = get_vr<u32[4]>(op.vb);
set_vr(op.vd, eval(avg(a, b)));
}
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)
{
const auto ab = GetVrs(VrType::vi32, op.va, op.vb);
SetVr(op.vd, m_ir->CreateNot(m_ir->CreateOr(ab[0], ab[1])));
const auto a = get_vr<u32[4]>(op.va);
const auto b = get_vr<u32[4]>(op.vb);
set_vr(op.vd, eval(~(a | b)));
}
void PPUTranslator::VOR(ppu_opcode_t op)
{
const auto ab = GetVrs(VrType::vi32, op.va, op.vb);
SetVr(op.vd, m_ir->CreateOr(ab[0], ab[1]));
const auto a = get_vr<u32[4]>(op.va);
const auto b = get_vr<u32[4]>(op.vb);
set_vr(op.vd, eval(a | b));
}
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)
{
const auto ab = GetVrs(VrType::vi32, op.va, op.vb);
SetVr(op.vd, ZExt(m_ir->CreateICmpUGE(ab[0], ab[1]), GetType<u32[4]>()));
const auto a = get_vr<u32[4]>(op.va);
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)
{
const auto ab = GetVrs(VrType::vf, op.va, op.vb);
SetVr(op.vd, m_ir->CreateFSub(ab[0], ab[1]));
const auto a = get_vr<f32[4]>(op.va);
const auto b = get_vr<f32[4]>(op.vb);
set_vr(op.vd, eval(a - b));
}
void PPUTranslator::VSUBSBS(ppu_opcode_t op)
{
const auto ab = SExt(GetVrs(VrType::vi8, op.va, op.vb));
const auto result = m_ir->CreateSub(ab[0], ab[1]);
const auto saturated = SaturateSigned(result, -0x80, 0x7f);
SetVr(op.vd, saturated.first);
SetSat(IsNotZero(saturated.second));
const auto a = get_vr<s8[16]>(op.va);
const auto b = get_vr<s8[16]>(op.vb);
const auto d = eval(a - b);
const auto z = eval((a >> 7) ^ 0x7f);
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)
{
const auto ab = SExt(GetVrs(VrType::vi16, op.va, op.vb));
const auto result = m_ir->CreateSub(ab[0], ab[1]);
const auto saturated = SaturateSigned(result, -0x8000, 0x7fff);
SetVr(op.vd, saturated.first);
SetSat(IsNotZero(saturated.second));
const auto a = get_vr<s16[8]>(op.va);
const auto b = get_vr<s16[8]>(op.vb);
const auto d = eval(a - b);
const auto z = eval((a >> 15) ^ 0x7fff);
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)
{
const auto ab = SExt(GetVrs(VrType::vi32, op.va, op.vb));
const auto result = m_ir->CreateSub(ab[0], ab[1]);
const auto saturated = SaturateSigned(result, -0x80000000ll, 0x7fffffff);
SetVr(op.vd, saturated.first);
SetSat(IsNotZero(saturated.second));
const auto a = get_vr<s32[4]>(op.va);
const auto b = get_vr<s32[4]>(op.vb);
const auto d = eval(a - b);
const auto z = eval((a >> 31) ^ 0x7fffffff);
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)
{
const auto ab = GetVrs(VrType::vi8, op.va, op.vb);
SetVr(op.vd, m_ir->CreateSub(ab[0], ab[1]));
const auto a = get_vr<u8[16]>(op.va);
const auto b = get_vr<u8[16]>(op.vb);
set_vr(op.vd, eval(a - b));
}
void PPUTranslator::VSUBUBS(ppu_opcode_t op)
{
const auto ab = ZExt(GetVrs(VrType::vi8, op.va, op.vb));
const auto result = m_ir->CreateSub(ab[0], ab[1]);
const auto saturated = Saturate(result, ICmpInst::ICMP_SLT, m_ir->getInt16(0));
SetVr(op.vd, saturated.first);
SetSat(IsNotZero(saturated.second));
const auto a = get_vr<s8[16]>(op.va);
const auto b = get_vr<s8[16]>(op.vb);
const auto d = eval(a - b);
const auto x = eval(ucarry(b, d, a) >> 7);
set_vr(op.vd, eval(d & ~x));
SetSat(IsNotZero(x.value));
}
void PPUTranslator::VSUBUHM(ppu_opcode_t op)
{
const auto ab = GetVrs(VrType::vi16, op.va, op.vb);
SetVr(op.vd, m_ir->CreateSub(ab[0], ab[1]));
const auto a = get_vr<u16[8]>(op.va);
const auto b = get_vr<u16[8]>(op.vb);
set_vr(op.vd, eval(a - b));
}
void PPUTranslator::VSUBUHS(ppu_opcode_t op)
{
const auto ab = ZExt(GetVrs(VrType::vi16, op.va, op.vb));
const auto result = m_ir->CreateSub(ab[0], ab[1]);
const auto saturated = Saturate(result, ICmpInst::ICMP_SLT, m_ir->getInt32(0));
SetVr(op.vd, saturated.first);
SetSat(IsNotZero(saturated.second));
const auto a = get_vr<s16[8]>(op.va);
const auto b = get_vr<s16[8]>(op.vb);
const auto d = eval(a - b);
const auto x = eval(ucarry(b, d, a) >> 15);
set_vr(op.vd, eval(d & ~x));
SetSat(IsNotZero(x.value));
}
void PPUTranslator::VSUBUWM(ppu_opcode_t op)
{
const auto ab = GetVrs(VrType::vi32, op.va, op.vb);
SetVr(op.vd, m_ir->CreateSub(ab[0], ab[1]));
const auto a = get_vr<u32[4]>(op.va);
const auto b = get_vr<u32[4]>(op.vb);
set_vr(op.vd, eval(a - b));
}
void PPUTranslator::VSUBUWS(ppu_opcode_t op)
{
const auto ab = ZExt(GetVrs(VrType::vi32, op.va, op.vb));
const auto result = m_ir->CreateSub(ab[0], ab[1]);
const auto saturated = Saturate(result, ICmpInst::ICMP_SLT, m_ir->getInt64(0));
SetVr(op.vd, saturated.first);
SetSat(IsNotZero(saturated.second));
const auto a = get_vr<s32[4]>(op.va);
const auto b = get_vr<s32[4]>(op.vb);
const auto d = eval(a - b);
const auto x = eval(ucarry(b, d, a) >> 31);
set_vr(op.vd, eval(d & ~x));
SetSat(IsNotZero(x.value));
}
void PPUTranslator::VSUMSWS(ppu_opcode_t op)

View File

@ -2,117 +2,12 @@
#ifdef LLVM_AVAILABLE
#include <unordered_map>
#include <map>
#include <unordered_set>
#include <set>
#include <array>
#include <vector>
#include "../rpcs3/Emu/CPU/CPUTranslator.h"
#include "../rpcs3/Emu/Cell/PPUOpcodes.h"
#include "../rpcs3/Emu/Cell/PPUAnalyser.h"
#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"
template<typename T, typename = void>
struct TypeGen
class PPUTranslator final : public cpu_translator
{
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
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
const llvm::AttributeSet m_pure_attr;
// IR builder
llvm::IRBuilder<>* m_ir;
// LLVM function
llvm::Function* m_function;
@ -191,6 +83,20 @@ class PPUTranslator final //: public CPUTranslator
#undef DEF_VALUE
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
llvm::Value* GetAddr(u64 _add = 0);
@ -382,19 +288,6 @@ public:
// Write to memory
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
template<typename T>
llvm::Value* GetUndef()

View File

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

View File

@ -1767,6 +1767,17 @@ bool SPUThread::stop_and_signal(u32 code)
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:
{
/* ===== 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);
if (!thread)
if (UNLIKELY(!thread))
{
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_OK;
return CELL_ESTAT;
}
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
{
bool m_key_repeat; // for future use
KbData m_data;
KbConfig m_config;
std::vector<KbButton> m_buttons;
@ -255,6 +256,7 @@ struct Keyboard
Keyboard()
: m_data()
, m_config()
, m_key_repeat(false)
{
}
};
@ -274,19 +276,20 @@ public:
{
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)
{
if(button.m_keyCode != code)
continue;
KbData& data = keyboard.m_data;
KbConfig& config = keyboard.m_config;
if (pressed)
{
// Meta Keys
if (code == 308 || code == 307 || code == 306 ||
code == 393 || code == 396 || code == 394)
if (code == 308 || code == 307 || code == 306 || code == 393 || code == 396 || code == 394)
{
data.mkey |= button.m_outKeyCode;
}
@ -310,17 +313,17 @@ public:
data.len++;
}
}
if (!pressed)
else
{
// Meta Keys
if (code == 308 || code == 307 || code == 306 ||
code == 393 || code == 396 || code == 394)
if (code == 308 || code == 307 || code == 306 || code == 393 || code == 396 || code == 394)
{
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 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");
code = "((" + code + "- 0.5) * 2.)";
}
if (dst.saturate)
{
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" : "");
@ -195,12 +228,12 @@ std::string FragmentProgramDecompiler::AddX2d()
//Failure to catch causes infinite values since theres alot of rcp(0)
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)
{
return "max(abs(" + code + "), 0.000001)";
return "max(abs(" + code + "), 0.0000000001)";
}
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];
if (reg.requires_gather(xy_read, zw_read))
{
properties.has_gather_op = true;
AddCode(reg.gather_r());
}
}
}
@ -407,7 +443,10 @@ template<typename T> std::string FragmentProgramDecompiler::GetSRC(T src)
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:
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
insertGlobalFunctions(OS);
std::string float2 = getFloatTypeName(2);
std::string float4 = getFloatTypeName(4);
//Declare register gather/merge if needed
if (properties.has_gather_op)
{
std::string float2 = getFloatTypeName(2);
std::string float4 = getFloatTypeName(4);
OS << float4 << " gather(" << float4 << " _h0, " << float4 << " _h1)\n";
OS << "{\n";
OS << " float x = uintBitsToFloat(packHalf2x16(_h0.xy));\n";
OS << " float y = uintBitsToFloat(packHalf2x16(_h0.zw));\n";
OS << " float z = uintBitsToFloat(packHalf2x16(_h1.xy));\n";
OS << " float w = uintBitsToFloat(packHalf2x16(_h1.zw));\n";
OS << " return " << float4 << "(x, y, z, w);\n";
OS << "}\n\n";
OS << float4 << " gather(" << float4 << " _h0, " << float4 << " _h1)\n";
OS << "{\n";
OS << " float x = uintBitsToFloat(packHalf2x16(_h0.xy));\n";
OS << " float y = uintBitsToFloat(packHalf2x16(_h0.zw));\n";
OS << " float z = uintBitsToFloat(packHalf2x16(_h1.xy));\n";
OS << " float w = uintBitsToFloat(packHalf2x16(_h1.zw));\n";
OS << " return " << float4 << "(x, y, z, w);\n";
OS << "}\n\n";
OS << float2 << " gather(" << float4 << " _h)\n";
OS << "{\n";
OS << " float x = uintBitsToFloat(packHalf2x16(_h.xy));\n";
OS << " float y = uintBitsToFloat(packHalf2x16(_h.zw));\n";
OS << " return " << float2 << "(x, y);\n";
OS << "}\n\n";
OS << float2 << " gather(" << float4 << " _h)\n";
OS << "{\n";
OS << " float x = uintBitsToFloat(packHalf2x16(_h.xy));\n";
OS << " float y = uintBitsToFloat(packHalf2x16(_h.zw));\n";
OS << " return " << float2 << "(x, y);\n";
OS << "}\n\n";
}
insertMainStart(OS);
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_FLR: SetDst("floor($0)"); 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_LRP: SetDst(getFloatTypeName(4) + "($2 * (1 - $0) + $1 * $0)"); 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...)
*/
virtual void insertMainEnd(std::stringstream &OS) = 0;
public:
struct
{
bool has_lit_op = false;
bool has_gather_op = false;
bool has_wpos_input = false;
}
properties;
ParamArray m_parr;
FragmentProgramDecompiler(const RSXFragmentProgram &prog, u32& size);
FragmentProgramDecompiler(const FragmentProgramDecompiler&) = delete;

View File

@ -281,31 +281,18 @@ namespace glsl
OS << " if (desc.attribute_size == 0)\n";
OS << " {\n";
OS << " //default values\n";
OS << " switch (location)\n";
OS << " {\n";
OS << " case 0:\n";
OS << " //position\n";
OS << " return vec4(0., 0., 0., 1.);\n";
OS << " case 1:\n";
OS << " case 2:\n";
OS << " //weight, normals\n";
OS << " return vec4(0.);\n";
OS << " case 3:\n";
OS << " //diffuse\n";
OS << " return vec4(1.);\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 << " const vec4 defaults[] = \n";
OS << " { vec4(0., 0., 0., 1.), //position\n";
OS << " vec4(0.), vec4(0.), //weight, normals\n";
OS << " vec4(1.), //diffuse\n";
OS << " vec4(0.), vec4(0.), //specular, fog\n";
OS << " vec4(1.), //point size\n";
OS << " vec4(0.), //in_7\n";
OS << " //in_tc registers\n";
OS << " vec4(0.), vec4(0.), vec4(0.), vec4(0.),\n";
OS << " vec4(0.), vec4(0.), vec4(0.), vec4(0.)\n";
OS << " };\n";
OS << " return defaults[location];\n";
OS << " }\n\n";
OS << " int vertex_id = " << vertex_id_name << " - int(vertex_base_index);\n";
OS << " if (desc.frequency == 0)\n";
@ -326,84 +313,95 @@ namespace glsl
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)";
OS << "{\n";
OS << " vec4 clamped_val = val;\n";
OS << " clamped_val.x = max(val.x, 0.);\n";
OS << " clamped_val.y = max(val.y, 0.);\n";
OS << " vec4 result;\n";
OS << " result.x = 1.;\n";
OS << " result.w = 1.;\n";
OS << " result.y = clamped_val.x;\n";
OS << " result.z = clamped_val.x > 0. ? exp(clamped_val.w * log(max(clamped_val.y, 0.000001))) : 0.;\n";
OS << " return result;\n";
OS << "}\n\n";
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";
if (require_lit_emulation)
{
OS << "vec4 lit_legacy(vec4 val)";
OS << "{\n";
OS << " vec4 clamped_val = val;\n";
OS << " clamped_val.x = max(val.x, 0.);\n";
OS << " clamped_val.y = max(val.y, 0.);\n";
OS << " vec4 result;\n";
OS << " result.x = 1.;\n";
OS << " result.w = 1.;\n";
OS << " result.y = clamped_val.x;\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 << "}\n\n";
}
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;
}
program_common::insert_compare_op(OS);
//NOTE: Memory layout is fetched as byteswapped BGRA [GBAR] (GOW collection, DS2, DeS)
//The A component (Z) is useless (should contain stencil8 or just 1)
OS << "vec4 decodeLinearDepth(float depth_value)\n";
OS << "{\n";
OS << " uint value = uint(depth_value * 16777215);\n";
OS << " uint b = (value & 0xff);\n";
OS << " uint g = (value >> 8) & 0xff;\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";
if (require_depth_conversion)
{
//NOTE: Memory layout is fetched as byteswapped BGRA [GBAR] (GOW collection, DS2, DeS)
//The A component (Z) is useless (should contain stencil8 or just 1)
OS << "vec4 decodeLinearDepth(float depth_value)\n";
OS << "{\n";
OS << " uint value = uint(depth_value * 16777215);\n";
OS << " uint b = (value & 0xff);\n";
OS << " uint g = (value >> 8) & 0xff;\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 << "{\n";
OS << " switch (remap_index)\n";
OS << " {\n";
OS << " case 0: return src.a;\n";
OS << " case 1: return src.r;\n";
OS << " case 2: return src.g;\n";
OS << " case 3: return src.b;\n";
OS << " }\n";
OS << "}\n\n";
OS << "float read_value(vec4 src, uint remap_index)\n";
OS << "{\n";
OS << " switch (remap_index)\n";
OS << " {\n";
OS << " case 0: return src.a;\n";
OS << " case 1: return src.r;\n";
OS << " case 2: return src.g;\n";
OS << " case 3: return src.b;\n";
OS << " }\n";
OS << "}\n\n";
OS << "vec4 texture2DReconstruct(sampler2D tex, vec2 coord, float remap)\n";
OS << "{\n";
OS << " vec4 result = decodeLinearDepth(texture(tex, coord.xy).r);\n";
OS << " uint remap_vector = floatBitsToUint(remap) & 0xFF;\n";
OS << " if (remap_vector == 0xE4) return result;\n\n";
OS << " vec4 tmp;\n";
OS << " uint remap_a = remap_vector & 0x3;\n";
OS << " uint remap_r = (remap_vector >> 2) & 0x3;\n";
OS << " uint remap_g = (remap_vector >> 4) & 0x3;\n";
OS << " uint remap_b = (remap_vector >> 6) & 0x3;\n";
OS << " tmp.a = read_value(result, remap_a);\n";
OS << " tmp.r = read_value(result, remap_r);\n";
OS << " tmp.g = read_value(result, remap_g);\n";
OS << " tmp.b = read_value(result, remap_b);\n";
OS << " return tmp;\n";
OS << "}\n\n";
OS << "vec4 texture2DReconstruct(sampler2D tex, vec2 coord, float remap)\n";
OS << "{\n";
OS << " vec4 result = decodeLinearDepth(texture(tex, coord.xy).r);\n";
OS << " uint remap_vector = floatBitsToUint(remap) & 0xFF;\n";
OS << " if (remap_vector == 0xE4) return result;\n\n";
OS << " vec4 tmp;\n";
OS << " uint remap_a = remap_vector & 0x3;\n";
OS << " uint remap_r = (remap_vector >> 2) & 0x3;\n";
OS << " uint remap_g = (remap_vector >> 4) & 0x3;\n";
OS << " uint remap_b = (remap_vector >> 6) & 0x3;\n";
OS << " tmp.a = read_value(result, remap_a);\n";
OS << " tmp.r = read_value(result, remap_r);\n";
OS << " tmp.g = read_value(result, remap_g);\n";
OS << " tmp.b = read_value(result, remap_b);\n";
OS << " return tmp;\n";
OS << "}\n\n";
}
OS << "vec4 get_wpos()\n";
OS << "{\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";
if (require_wpos)
{
OS << "vec4 get_wpos()\n";
OS << "{\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)

View File

@ -376,7 +376,7 @@ void VertexProgramDecompiler::SetDSTSca(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)
@ -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_EXP: SetDSTSca("exp($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:
{
AddCode("$if ($cond) //BRA");

View File

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

View File

@ -274,6 +274,9 @@ namespace rsx
//Set when a hw blit engine incompatibility is detected
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
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
@ -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;
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 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;
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
//Delete used resources before attaching it to framebuffer memory
read_only_tex_invalidate = true;
free_texture_section(region);
m_texture_memory_in_use -= region.get_section_size();
}
@ -1116,7 +1120,7 @@ namespace rsx
}
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)
{
const u32 format = gcm_format & ~(CELL_GCM_TEXTURE_UN | CELL_GCM_TEXTURE_LN);
@ -1240,7 +1244,7 @@ namespace rsx
else
{
//issue a texture barrier to ensure previous writes are visible
insert_texture_barrier();
insert_texture_barrier(cmd, texptr);
break;
}
}
@ -1258,7 +1262,7 @@ namespace rsx
else
{
//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))
{
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
{
@ -1333,7 +1337,7 @@ namespace rsx
{
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
{
@ -1391,7 +1395,7 @@ namespace rsx
if (rsc.is_bound)
{
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,
@ -1875,6 +1879,20 @@ namespace rsx
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)
{
if (!g_cfg.video.strict_rendering_mode)

View File

@ -194,7 +194,7 @@ namespace
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)
@ -248,8 +248,11 @@ void GLFragmentDecompilerThread::insertMainStart(std::stringstream & OS)
}
}
OS << " vec4 ssa = gl_FrontFacing ? vec4(1.) : vec4(-1.);\n";
OS << " vec4 wpos = get_wpos();\n";
if (m_parr.HasParam(PF_PARAM_IN, "vec4", "ssa"))
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])
{

View File

@ -176,21 +176,6 @@ void GLGSRender::begin()
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()
{
std::chrono::time_point<steady_clock> state_check_start = steady_clock::now();
@ -321,7 +306,7 @@ void GLGSRender::end()
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)
{
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 };
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:
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
//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_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 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)
{
@ -210,8 +215,21 @@ void GLGSRender::init_buffers(rsx::framebuffer_creation_context context, bool sk
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;
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] < 64 || clip_vertical != clip_horizontal)
if (lg2w < clipw_log2 || lg2h < cliph_log2)
{
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)
@ -364,6 +394,8 @@ void GLGSRender::init_buffers(rsx::framebuffer_creation_context context, bool sk
break;
}
m_gl_texture_cache.clear_ro_tex_invalidate_intr();
//Mark buffer regions as NO_ACCESS on Cell visible side
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);
}
}
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()

View File

@ -8,6 +8,18 @@
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)
{
switch (texture_format)

View File

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

View File

@ -765,8 +765,9 @@ namespace gl
break;
}
glBindTexture(GL_TEXTURE_2D, vram_texture);
apply_component_mapping_flags(GL_TEXTURE_2D, gcm_format, flags);
auto target = gl::get_target(type);
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);
cached.set_dirty(false);
@ -836,7 +837,7 @@ namespace gl
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();

View File

@ -149,7 +149,7 @@ void GLVertexDecompilerThread::insertOutputs(std::stringstream & OS, const std::
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);
std::string parameters = "";

View File

@ -34,6 +34,9 @@ void gl::init()
#ifdef __unix__
glewExperimental = true;
glewInit();
#ifndef __APPLE__
glxewInit();
#endif
#endif
}
@ -41,5 +44,19 @@ void gl::set_swapinterval(int interval)
{
#ifdef _WIN32
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
}
}

View File

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

View File

@ -144,6 +144,10 @@ namespace vk
glslang::TProgram program;
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;
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))
{
program.addShader(&shader_object);
success = program.link(EShMsgVulkanRules);
success = program.link(msg);
if (success)
{
glslang::TIntermediate* bytes = program.getIntermediate(lang);
glslang::GlslangToSpv(*bytes, spv);
glslang::SpvOptions options;
options.disableOptimizer = false;
options.optimizeSize = true;
glslang::GlslangToSpv(*program.getIntermediate(lang), spv, &options);
}
}
else

View File

@ -197,7 +197,7 @@ namespace vk
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)
@ -251,8 +251,11 @@ void VKFragmentDecompilerThread::insertMainStart(std::stringstream & OS)
}
}
OS << " vec4 ssa = gl_FrontFacing ? vec4(1.) : vec4(-1.);\n";
OS << " vec4 wpos = get_wpos();\n";
if (m_parr.HasParam(PF_PARAM_IN, "vec4", "ssa"))
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);

View File

@ -84,7 +84,10 @@ namespace vk
}
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:
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.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 = {};
rp_info.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO;
rp_info.attachmentCount = static_cast<uint32_t>(attachments.size());
rp_info.pAttachments = attachments.data();
rp_info.subpassCount = 1;
rp_info.pSubpasses = &subpass;
rp_info.pDependencies = &dependency;
rp_info.dependencyCount = 1;
rp_info.pDependencies = nullptr;
rp_info.dependencyCount = 0;
VkRenderPass result;
CHECK_RESULT(vkCreateRenderPass(dev, &rp_info, NULL, &result));
@ -1143,8 +1137,22 @@ void VKGSRender::end()
if (replace)
{
fs_sampler_handles[i] = std::make_unique<vk::sampler>(*m_device, wrap_s, wrap_t, wrap_r, false, lod_bias, af_level, min_lod, max_lod,
min_filter, mag_filter, mip_mode, border_color, compare_enabled, depth_compare_mode);
for (auto &sampler : m_current_frame->samplers_to_clean)
{
if (sampler->matches(wrap_s, wrap_t, wrap_r, false, lod_bias, af_level, min_lod, max_lod,
min_filter, mag_filter, mip_mode, border_color, compare_enabled, depth_compare_mode))
{
fs_sampler_handles[i] = std::move(sampler);
replace = false;
break;
}
}
if (replace)
{
fs_sampler_handles[i] = std::make_unique<vk::sampler>(*m_device, wrap_s, wrap_t, wrap_r, false, lod_bias, af_level, min_lod, max_lod,
min_filter, mag_filter, mip_mode, border_color, compare_enabled, depth_compare_mode);
}
}
}
else
@ -1188,6 +1196,7 @@ void VKGSRender::end()
if (replace)
{
//This is unlikely, there is no need to check the dirty pool
vs_sampler_handles[i] = std::make_unique<vk::sampler>(
*m_device,
VK_SAMPLER_ADDRESS_MODE_REPEAT, VK_SAMPLER_ADDRESS_MODE_REPEAT, VK_SAMPLER_ADDRESS_MODE_REPEAT,
@ -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
//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_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 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)
{
@ -2500,8 +2513,21 @@ void VKGSRender::prepare_rtts(rsx::framebuffer_creation_context context)
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;
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] < 64 || clip_width != clip_height)
if (lg2w < clipw_log2 || lg2h < cliph_log2)
{
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)
@ -2990,7 +3028,7 @@ void VKGSRender::flip(int buffer)
VkImageLayout target_layout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR;
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 {};
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
m_overlay_cleanup_requests.push_back(0);
}
}

View File

@ -388,6 +388,45 @@ namespace vk
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()
{
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);
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 leave_uninterruptible();
bool is_uninterruptible();

View File

@ -831,8 +831,10 @@ namespace vk
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:

View File

@ -185,7 +185,7 @@ void VKVertexDecompilerThread::insertOutputs(std::stringstream & OS, const std::
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);
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)
info = std::make_unique<image_info>(("Icons/ui/" + res).c_str());
#ifndef _WIN32
// Check for Icons in ../share/rpcs3 for AppImages and /usr/bin/
if (info->data == nullptr)
{
char result[ PATH_MAX ];
@ -483,6 +484,11 @@ namespace rsx
std::string executablePath = dirname(result);
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
if (info->data != nullptr)
@ -1331,6 +1337,8 @@ namespace rsx
s16 m_selected_entry = -1;
u16 m_elements_count = 0;
bool m_cancel_only = false;
public:
list_view(u16 width, u16 height)
{
@ -1461,6 +1469,17 @@ namespace rsx
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
{
layout_container::translate(_x, _y);
@ -1478,9 +1497,11 @@ namespace rsx
compiled.add(m_highlight_box->get_compiled());
compiled.add(m_scroll_indicator_top->get_compiled());
compiled.add(m_scroll_indicator_bottom->get_compiled());
compiled.add(m_accept_btn->get_compiled());
compiled.add(m_cancel_btn->get_compiled());
if (!m_cancel_only)
compiled.add(m_accept_btn->get_compiled());
compiled_resources = compiled;
}

View File

@ -254,6 +254,7 @@ namespace rsx
std::unique_ptr<list_view> m_list;
std::unique_ptr<label> m_description;
std::unique_ptr<label> m_time_thingy;
std::unique_ptr<label> m_no_saves_text;
std::string current_time()
{
@ -264,6 +265,8 @@ namespace rsx
return buf;
}
bool m_no_saves = false;
public:
save_dialog()
{
@ -297,6 +300,8 @@ namespace rsx
switch (button_press)
{
case pad_button::cross:
if (m_no_saves)
break;
return_code = m_list->get_selected_index();
//Fall through
case pad_button::circle:
@ -320,6 +325,10 @@ namespace rsx
result.add(m_list->get_compiled());
result.add(m_description->get_compiled());
result.add(m_time_thingy->get_compiled());
if (m_no_saves)
result.add(m_no_saves_text->get_compiled());
return result;
}
@ -349,6 +358,20 @@ namespace rsx
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();
if (auto err = run_input_loop())

View File

@ -282,6 +282,7 @@ namespace rsx
struct progress_dialog_helper
{
std::shared_ptr<MsgDialogBase> dlg;
atomic_t<bool> initialized{ false };
virtual void create()
{
@ -300,7 +301,13 @@ namespace rsx
Emu.CallAfter([&]()
{
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)

View File

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

View File

@ -250,6 +250,7 @@
<ClCompile Include="Emu\Cell\Modules\sceNp2.cpp" />
<ClCompile Include="Emu\Cell\Modules\sceNpClans.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\sceNpTrophy.cpp" />
<ClCompile Include="Emu\Cell\Modules\sceNpTus.cpp" />

View File

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

View File

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

View File

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

View File

@ -1,5 +1,7 @@
#include "rpcs3_app.h"
#include "rpcs3qt/qt_utils.h"
#include "rpcs3qt/welcome_dialog.h"
#include "Emu/System.h"
@ -167,37 +169,40 @@ void rpcs3_app::InitializeCallbacks()
}
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)
{
case video_renderer::null:
{
gs_frame* ret = new gs_frame("Null", w, h, RPCS3MainWin->GetAppIcon(), disableMouse);
gameWindow = ret;
return std::unique_ptr<gs_frame>(ret);
frame = new gs_frame("Null", frame_geometry, RPCS3MainWin->GetAppIcon(), disableMouse);
break;
}
case video_renderer::opengl:
{
gl_gs_frame* ret = new gl_gs_frame(w, h, RPCS3MainWin->GetAppIcon(), disableMouse);
gameWindow = ret;
return std::unique_ptr<gl_gs_frame>(ret);
frame = new gl_gs_frame(frame_geometry, RPCS3MainWin->GetAppIcon(), disableMouse);
break;
}
case video_renderer::vulkan:
{
gs_frame* ret = new gs_frame("Vulkan", w, h, RPCS3MainWin->GetAppIcon(), disableMouse);
gameWindow = ret;
return std::unique_ptr<gs_frame>(ret);
frame = new gs_frame("Vulkan", frame_geometry, RPCS3MainWin->GetAppIcon(), disableMouse);
break;
}
#ifdef _MSC_VER
case video_renderer::dx12:
{
gs_frame* ret = new gs_frame("DirectX 12", w, h, RPCS3MainWin->GetAppIcon(), disableMouse);
gameWindow = ret;
return std::unique_ptr<gs_frame>(ret);
frame = new gs_frame("DirectX 12", frame_geometry, RPCS3MainWin->GetAppIcon(), disableMouse);
break;
}
#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>

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()->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()->setMaximumSectionSize(m_Icon_Size.height());
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_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++)
{
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);
}
// std::set is used to remove duplicates from the list
for (const auto& dir : std::set<std::string>(std::make_move_iterator(path_list.begin()), std::make_move_iterator(path_list.end())))
// Used to remove duplications from the list (serial -> set of cats)
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 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;
}
const auto& psf = psf::load_object(sfo_file);
const auto psf = psf::load_object(sfo_file);
GameInfo game;
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.sound_format = psf::get_integer(psf, "SOUND_FORMAT");
// Detect duplication
if (!serial_cat[game.serial].emplace(game.category).second)
{
continue;
}
bool bootable = false;
auto cat = category::cat_boot.find(game.category);
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 });
}
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)
{
@ -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();
}
if (1)
{
if (Boot(m_game_data[i].info))

View File

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

View File

@ -9,7 +9,7 @@ private:
QSurfaceFormat m_format;
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;
void set_current(draw_context_t context) override;

View File

@ -23,7 +23,7 @@
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)
{
//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);
resize(w, h);
setGeometry(geometry);
setTitle(m_windowTitle);
setVisibility(Hidden);
create();
@ -70,6 +69,18 @@ void gs_frame::paintEvent(QPaintEvent *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)
{
auto l_handleKeyEvent = [this ,keyEvent]()

View File

@ -9,6 +9,7 @@
class gs_frame : public QWindow, public GSFrameBase
{
Q_OBJECT
u64 m_frames = 0;
QString m_windowTitle;
bool m_show_fps;
@ -20,7 +21,7 @@ class gs_frame : public QWindow, public GSFrameBase
bool m_minimized = false;
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;
void set_current(draw_context_t context) override;
@ -29,6 +30,7 @@ public:
wm_event get_default_wm_event() const override;
protected:
virtual void paintEvent(QPaintEvent *event);
virtual void showEvent(QShowEvent *event);
void keyPressEvent(QKeyEvent *keyEvent) override;
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 <functional>
#include <unordered_map>
#include <algorithm>
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;
}
}