Compare commits
15 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| a3f28c170c | |||
| 7f509298a9 | |||
| e2f3a1952f | |||
| c5828faf0f | |||
| cfb573694c | |||
| 8e7301b446 | |||
| f2ae336474 | |||
| 3e2549e873 | |||
| 3dd03e1066 | |||
| 637547718f | |||
| ccc09353ea | |||
| 9dfd00d5b0 | |||
| cb0673e58d | |||
| ecf9a037cc | |||
| c97b06ecf0 |
@@ -8,7 +8,6 @@
|
||||
[submodule "llvm"]
|
||||
path = llvm
|
||||
url = https://github.com/llvm-mirror/llvm
|
||||
branch = release_50
|
||||
[submodule "rsx_program_decompiler"]
|
||||
path = rsx_program_decompiler
|
||||
url = https://github.com/RPCS3/rsx_program_decompiler
|
||||
|
||||
+25
-24
@@ -29,6 +29,10 @@ matrix:
|
||||
exclude:
|
||||
- os: osx
|
||||
compiler: gcc
|
||||
include:
|
||||
- os: linux
|
||||
compiler: clang
|
||||
env: WITHOUT_LLVM="yes"
|
||||
|
||||
|
||||
git:
|
||||
@@ -43,21 +47,19 @@ before_install:
|
||||
export GCC_COLORS='error=01;31:warning=01;35:note=01;36:caret=01;32:locus=01:quote=01';
|
||||
fi;
|
||||
- if [ "$TRAVIS_OS_NAME" = "linux" ]; then
|
||||
wget http://download.qt.io/official_releases/online_installers/qt-unified-linux-x64-online.run ;
|
||||
chmod a+x ./qt-unified-linux-x64-online.run ;
|
||||
export QT_QPA_PLATFORM=minimal ;
|
||||
./qt-unified-linux-x64-online.run --script qt-installer-noninteractive.qs --no-force-installations ;
|
||||
sudo add-apt-repository ppa:beineri/opt-qt59-trusty -y;
|
||||
sudo apt-get update;
|
||||
sudo apt-get install qt59base -y --allow-unauthenticated;
|
||||
fi;
|
||||
|
||||
# Add coverall for C++ so coverall.io could be triggered. Even it should be --coverage and gcov.
|
||||
# Install updated libglew-dev since the version provided by trusty is outdated
|
||||
- if [ "$TRAVIS_OS_NAME" = "linux" ]; then
|
||||
pip install --user cpp-coveralls requests[security];
|
||||
wget http://mirrors.kernel.org/ubuntu/pool/main/g/glew/libglew-dev_1.13.0-2_amd64.deb;
|
||||
wget http://mirrors.kernel.org/ubuntu/pool/main/g/glew/libglew1.13_1.13.0-2_amd64.deb;
|
||||
wget http://mirrors.kernel.org/ubuntu/pool/universe/v/vulkan/libvulkan1_1.0.42.0+dfsg1-1ubuntu1~16.04.1_amd64.deb;
|
||||
wget http://mirrors.kernel.org/ubuntu/pool/universe/v/vulkan/libvulkan-dev_1.0.42.0+dfsg1-1ubuntu1~16.04.1_amd64.deb;
|
||||
sudo dpkg -i libglew1.13_1.13.0-2_amd64.deb libglew-dev_1.13.0-2_amd64.deb libvulkan1_1.0.42.0+dfsg1-1ubuntu1~16.04.1_amd64.deb libvulkan-dev_1.0.42.0+dfsg1-1ubuntu1~16.04.1_amd64.deb;
|
||||
wget http://mirrors.kernel.org/ubuntu/pool/universe/v/vulkan/libvulkan-dev_1.0.21.0+dfsg1-1~16.04.1_amd64.deb;
|
||||
wget http://mirrors.kernel.org/ubuntu/pool/universe/v/vulkan/libvulkan1_1.0.21.0+dfsg1-1~16.04.1_amd64.deb;
|
||||
sudo dpkg -i libglew1.13_1.13.0-2_amd64.deb libglew-dev_1.13.0-2_amd64.deb libvulkan1_1.0.21.0+dfsg1-1~16.04.1_amd64.deb libvulkan-dev_1.0.21.0+dfsg1-1~16.04.1_amd64.deb;
|
||||
else
|
||||
brew update; brew update;
|
||||
brew install ccache glew llvm40;
|
||||
@@ -65,31 +67,31 @@ before_install:
|
||||
|
||||
before_script:
|
||||
- git submodule update --init asmjit 3rdparty/ffmpeg 3rdparty/pugixml 3rdparty/GSL 3rdparty/libpng Utilities/yaml-cpp 3rdparty/cereal 3rdparty/hidapi Vulkan/glslang Vulkan/Vulkan-LoaderAndValidationLayers
|
||||
- source /opt/qt59/bin/qt59-env.sh
|
||||
- mkdir build
|
||||
- cd build
|
||||
- export CMAKE_PREFIX_PATH=~/Qt/5.9.1/gcc_64/lib/cmake
|
||||
- cmake .. -DCMAKE_INSTALL_PREFIX=/usr;
|
||||
- if [ -z "$WITHOUT_LLVM" ]; then
|
||||
cmake .. -DCMAKE_INSTALL_PREFIX=/usr;
|
||||
else
|
||||
cmake .. -DCMAKE_INSTALL_PREFIX=/usr -DWITHOUT_LLVM=ON;
|
||||
fi;
|
||||
- make -j 3
|
||||
- # AppImage generation
|
||||
- if [ "$TRAVIS_BRANCH" = "master" ] && [ "$CC" = "clang-4.0" ] && [ "$TRAVIS_PULL_REQUEST" = false ]; then
|
||||
export LD_LIBRARY_PATH=~/Qt/5.9.1/gcc_64/lib;
|
||||
export LD_LIBRARY_PATH=${PWD}/3rdparty/libpng:/opt/qt59/lib/:$LD_LIBRARY_PATH ;
|
||||
make DESTDIR=appdir install ; find appdir/ ;
|
||||
find ../bin ;
|
||||
wget -c "https://github.com/probonopd/linuxdeployqt/releases/download/continuous/linuxdeployqt-continuous-x86_64.AppImage" ;
|
||||
chmod a+x linuxdeployqt*.AppImage ;
|
||||
export PATH=~/Qt/5.9.1/gcc_64/bin/:${PATH} ;
|
||||
./linuxdeployqt*.AppImage --appimage-extract ;
|
||||
unset QTDIR; unset QT_PLUGIN_PATH ;
|
||||
./linuxdeployqt*.AppImage ./appdir/usr/share/applications/*.desktop -bundle-non-qt-libs ;
|
||||
mkdir ./appdir/usr/plugins/xcbglintegrations/ ;
|
||||
mkdir ./appdir/usr/plugins/imageformats/ ;
|
||||
cp ~/Qt/5.9.1/gcc_64/lib/libQt5Svg.so.5 ./appdir/usr/lib/ ;
|
||||
cp ~/Qt/5.9.1/gcc_64/plugins/xcbglintegrations/* ./appdir/usr/plugins/xcbglintegrations/ ;
|
||||
cp ~/Qt/5.9.1/gcc_64/plugins/imageformats/* ./appdir/usr/plugins/imageformats/ ;
|
||||
cp ~/Qt/5.9.1/gcc_64/plugins/platforms/* ./appdir/usr/plugins/platforms/ ;
|
||||
export PATH=${TRAVIS_BUILD_DIR}/build/squashfs-root/usr/bin/:${PATH} ;
|
||||
./squashfs-root/usr/bin/appimagetool ${TRAVIS_BUILD_DIR}/build/appdir ;
|
||||
./linuxdeployqt*.AppImage ./appdir/usr/share/applications/*.desktop -appimage ;
|
||||
find ./appdir -executable -type f -exec ldd {} \; | grep " => /usr" | cut -d " " -f 2-3 | sort | uniq ;
|
||||
curl ${UPLOAD_URL}${TRAVIS_COMMIT:0:7}-${TRAVIS_BUILD_NUMBER}_linux64 --upload-file ./RPCS3*.AppImage;
|
||||
zip -r9 rpcs3.zip ./RPCS3*.AppImage;
|
||||
if [ -z "$WITHOUT_LLVM" ]; then
|
||||
export LLVM="-LLVM";
|
||||
fi;
|
||||
curl ${UPLOAD_URL}${TRAVIS_COMMIT:0:7}-${TRAVIS_BUILD_NUMBER}${LLVM}_linux64 --upload-file rpcs3.zip;
|
||||
fi;
|
||||
|
||||
script:
|
||||
@@ -122,10 +124,9 @@ addons:
|
||||
- libstdc++-5-dev
|
||||
- lib32stdc++6
|
||||
- zlib1g-dev
|
||||
# We need to install qt 5.9.1 manually because the version trusty provides is too old.
|
||||
# We need to install qt 5.8 manually because the version trusty provides is too old.
|
||||
#- qtbase5-dev
|
||||
- libudev-dev
|
||||
- libevdev-dev
|
||||
coverity_scan:
|
||||
project:
|
||||
name: $TRAVIS_REPO_SLUG
|
||||
|
||||
+9
-37
@@ -12,7 +12,6 @@
|
||||
#include "File.h"
|
||||
#include "Log.h"
|
||||
#include "mutex.h"
|
||||
#include "sysinfo.h"
|
||||
#include "VirtualMemory.h"
|
||||
|
||||
#ifdef _MSC_VER
|
||||
@@ -344,30 +343,22 @@ public:
|
||||
LOG_SUCCESS(GENERAL, "LLVM: Created module: %s", module->getName().data());
|
||||
}
|
||||
|
||||
static std::unique_ptr<llvm::MemoryBuffer> load(const std::string& path)
|
||||
std::unique_ptr<llvm::MemoryBuffer> getObject(const llvm::Module* module) override
|
||||
{
|
||||
if (fs::file cached{path, fs::read})
|
||||
std::string name = m_path;
|
||||
name.append(module->getName());
|
||||
|
||||
if (fs::file cached{name, fs::read})
|
||||
{
|
||||
auto buf = llvm::MemoryBuffer::getNewUninitMemBuffer(cached.size());
|
||||
cached.read(const_cast<char*>(buf->getBufferStart()), buf->getBufferSize());
|
||||
return buf;
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
std::unique_ptr<llvm::MemoryBuffer> getObject(const llvm::Module* module) override
|
||||
{
|
||||
std::string path = m_path;
|
||||
path.append(module->getName());
|
||||
|
||||
if (auto buf = load(path))
|
||||
{
|
||||
LOG_SUCCESS(GENERAL, "LLVM: Loaded module: %s", module->getName().data());
|
||||
return buf;
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
else
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@@ -378,20 +369,6 @@ jit_compiler::jit_compiler(const std::unordered_map<std::string, std::uintptr_t>
|
||||
if (m_cpu.empty())
|
||||
{
|
||||
m_cpu = llvm::sys::getHostCPUName();
|
||||
|
||||
if (m_cpu == "sandybridge" ||
|
||||
m_cpu == "ivybridge" ||
|
||||
m_cpu == "haswell" ||
|
||||
m_cpu == "broadwell" ||
|
||||
m_cpu == "skylake" ||
|
||||
m_cpu == "skylake-avx512" ||
|
||||
m_cpu == "cannonlake")
|
||||
{
|
||||
if (!utils::has_avx())
|
||||
{
|
||||
m_cpu = "nehalem";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::string result;
|
||||
@@ -453,11 +430,6 @@ void jit_compiler::add(std::unique_ptr<llvm::Module> module, const std::string&
|
||||
}
|
||||
}
|
||||
|
||||
void jit_compiler::add(const std::string& path)
|
||||
{
|
||||
m_engine->addObjectFile(std::move(llvm::object::ObjectFile::createObjectFile(*ObjectCache::load(path)).get()));
|
||||
}
|
||||
|
||||
void jit_compiler::fin()
|
||||
{
|
||||
m_engine->finalizeObject();
|
||||
|
||||
+1
-4
@@ -49,12 +49,9 @@ public:
|
||||
return m_context;
|
||||
}
|
||||
|
||||
// Add module (path to obj cache dir)
|
||||
// Add module
|
||||
void add(std::unique_ptr<llvm::Module> module, const std::string& path);
|
||||
|
||||
// Add object (path to obj file)
|
||||
void add(const std::string& path);
|
||||
|
||||
// Finalize
|
||||
void fin();
|
||||
|
||||
|
||||
@@ -1413,6 +1413,13 @@ static LONG exception_filter(PEXCEPTION_POINTERS pExp)
|
||||
|
||||
msg += fmt::format("RPCS3 image base: %p.\n", GetModuleHandle(NULL));
|
||||
|
||||
if (pExp->ExceptionRecord->ExceptionCode == EXCEPTION_ILLEGAL_INSTRUCTION)
|
||||
{
|
||||
msg += "\n"
|
||||
"Illegal instruction exception occured.\n"
|
||||
"Note that your CPU must support SSSE3 extension.\n";
|
||||
}
|
||||
|
||||
// TODO: print registers and the callstack
|
||||
|
||||
// Report fatal error
|
||||
|
||||
+4
-35
@@ -14,13 +14,9 @@ void fmt_class_string<patch_type>::format(std::string& out, u64 arg)
|
||||
case patch_type::le16: return "le16";
|
||||
case patch_type::le32: return "le32";
|
||||
case patch_type::le64: return "le64";
|
||||
case patch_type::bef32: return "bef32";
|
||||
case patch_type::bef64: return "bef64";
|
||||
case patch_type::be16: return "be16";
|
||||
case patch_type::be32: return "be32";
|
||||
case patch_type::be64: return "be64";
|
||||
case patch_type::lef32: return "lef32";
|
||||
case patch_type::lef64: return "lef64";
|
||||
}
|
||||
|
||||
return unknown;
|
||||
@@ -43,44 +39,23 @@ void patch_engine::append(const std::string& patch)
|
||||
u64 type64 = 0;
|
||||
cfg::try_to_enum_value(&type64, &fmt_class_string<patch_type>::format, patch[0].Scalar());
|
||||
|
||||
struct patch info{};
|
||||
struct patch info;
|
||||
info.type = static_cast<patch_type>(type64);
|
||||
info.offset = patch[1].as<u32>();
|
||||
|
||||
switch (info.type)
|
||||
{
|
||||
case patch_type::bef32:
|
||||
case patch_type::lef32:
|
||||
{
|
||||
info.value_as<f32>() = patch[2].as<f32>();
|
||||
break;
|
||||
}
|
||||
case patch_type::bef64:
|
||||
case patch_type::lef64:
|
||||
{
|
||||
info.value_as<f64>() = patch[2].as<f64>();
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
info.value = patch[2].as<u64>();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
info.value = patch[2].as<u64>();
|
||||
data.emplace_back(info);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::size_t patch_engine::apply(const std::string& name, u8* dst) const
|
||||
void patch_engine::apply(const std::string& name, u8* dst) const
|
||||
{
|
||||
const auto found = m_map.find(name);
|
||||
|
||||
if (found == m_map.cend())
|
||||
{
|
||||
return 0;
|
||||
return;
|
||||
}
|
||||
|
||||
// Apply modifications sequentially
|
||||
@@ -101,13 +76,11 @@ std::size_t patch_engine::apply(const std::string& name, u8* dst) const
|
||||
break;
|
||||
}
|
||||
case patch_type::le32:
|
||||
case patch_type::lef32:
|
||||
{
|
||||
*reinterpret_cast<le_t<u32, 1>*>(ptr) = static_cast<u32>(p.value);
|
||||
break;
|
||||
}
|
||||
case patch_type::le64:
|
||||
case patch_type::lef64:
|
||||
{
|
||||
*reinterpret_cast<le_t<u64, 1>*>(ptr) = static_cast<u64>(p.value);
|
||||
break;
|
||||
@@ -118,19 +91,15 @@ std::size_t patch_engine::apply(const std::string& name, u8* dst) const
|
||||
break;
|
||||
}
|
||||
case patch_type::be32:
|
||||
case patch_type::bef32:
|
||||
{
|
||||
*reinterpret_cast<be_t<u32, 1>*>(ptr) = static_cast<u32>(p.value);
|
||||
break;
|
||||
}
|
||||
case patch_type::be64:
|
||||
case patch_type::bef64:
|
||||
{
|
||||
*reinterpret_cast<be_t<u64, 1>*>(ptr) = static_cast<u64>(p.value);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return found->second.size();
|
||||
}
|
||||
|
||||
+2
-12
@@ -11,13 +11,9 @@ enum class patch_type
|
||||
le16,
|
||||
le32,
|
||||
le64,
|
||||
lef32,
|
||||
lef64,
|
||||
be16,
|
||||
be32,
|
||||
be64,
|
||||
bef32,
|
||||
bef64,
|
||||
};
|
||||
|
||||
class patch_engine
|
||||
@@ -27,12 +23,6 @@ class patch_engine
|
||||
patch_type type;
|
||||
u32 offset;
|
||||
u64 value;
|
||||
|
||||
template <typename T>
|
||||
T& value_as()
|
||||
{
|
||||
return *reinterpret_cast<T*>(reinterpret_cast<char*>(&value));
|
||||
}
|
||||
};
|
||||
|
||||
// Database
|
||||
@@ -42,6 +32,6 @@ public:
|
||||
// Load from file
|
||||
void append(const std::string& path);
|
||||
|
||||
// Apply patch (returns the number of entries applied)
|
||||
std::size_t apply(const std::string& name, u8* dst) const;
|
||||
// Apply patch
|
||||
void apply(const std::string& name, u8* dst) const;
|
||||
};
|
||||
|
||||
@@ -1,61 +0,0 @@
|
||||
#include "sysinfo.h"
|
||||
#include "StrFmt.h"
|
||||
|
||||
#ifdef _WIN32
|
||||
#include "windows.h"
|
||||
#else
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
std::string utils::get_system_info()
|
||||
{
|
||||
std::string result;
|
||||
std::string brand;
|
||||
|
||||
if (get_cpuid(0x80000000, 0)[0] >= 0x80000004)
|
||||
{
|
||||
for (u32 i = 0; i < 3; i++)
|
||||
{
|
||||
brand.append(reinterpret_cast<const char*>(get_cpuid(0x80000002 + i, 0).data()), 16);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
brand = "Unknown CPU";
|
||||
}
|
||||
|
||||
brand.erase(0, brand.find_first_not_of(' '));
|
||||
brand.erase(brand.find_last_not_of(' ') + 1);
|
||||
|
||||
while (auto found = brand.find(" ") + 1)
|
||||
{
|
||||
brand.erase(brand.begin() + found);
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
::SYSTEM_INFO sysInfo;
|
||||
::GetNativeSystemInfo(&sysInfo);
|
||||
::MEMORYSTATUSEX memInfo;
|
||||
memInfo.dwLength = sizeof(memInfo);
|
||||
::GlobalMemoryStatusEx(&memInfo);
|
||||
const u32 num_proc = sysInfo.dwNumberOfProcessors;
|
||||
const u64 mem_total = memInfo.ullTotalPhys;
|
||||
#else
|
||||
const u32 num_proc = ::sysconf(_SC_NPROCESSORS_ONLN);
|
||||
const u64 mem_total = ::sysconf(_SC_PHYS_PAGES) * ::sysconf(_SC_PAGE_SIZE);
|
||||
#endif
|
||||
|
||||
fmt::append(result, "%s | %d Threads | %.2f GiB RAM", brand, num_proc, mem_total / (1024.0f * 1024 * 1024));
|
||||
|
||||
if (has_avx())
|
||||
{
|
||||
result += " | AVX";
|
||||
}
|
||||
|
||||
if (has_rtm())
|
||||
{
|
||||
result += " | TSX";
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
@@ -1,54 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include "types.h"
|
||||
#include <string>
|
||||
|
||||
namespace utils
|
||||
{
|
||||
inline std::array<u32, 4> get_cpuid(u32 func, u32 subfunc)
|
||||
{
|
||||
int regs[4];
|
||||
#ifdef _MSC_VER
|
||||
__cpuidex(regs, func, subfunc);
|
||||
#else
|
||||
__asm__ volatile("cpuid" : "=a" (regs[0]), "=b" (regs[1]), "=c" (regs[2]), "=d" (regs[3]) : "a" (func), "c" (subfunc));
|
||||
#endif
|
||||
return {0u+regs[0], 0u+regs[1], 0u+regs[2], 0u+regs[3]};
|
||||
}
|
||||
|
||||
inline bool has_ssse3()
|
||||
{
|
||||
return get_cpuid(0, 0)[0] >= 0x1 && get_cpuid(1, 0)[2] & 0x200;
|
||||
}
|
||||
|
||||
inline bool has_avx()
|
||||
{
|
||||
return get_cpuid(0, 0)[0] >= 0x1 && get_cpuid(1, 0)[2] & 0x10000000;
|
||||
}
|
||||
|
||||
inline bool has_rtm()
|
||||
{
|
||||
// Check RTM and MPX extensions in order to filter out TSX on Haswell CPUs
|
||||
return get_cpuid(0, 0)[0] >= 0x7 && (get_cpuid(7, 0)[1] & 0x4800) == 0x4800;
|
||||
}
|
||||
|
||||
inline bool transaction_enter()
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
const auto status = _xbegin();
|
||||
|
||||
if (status == _XBEGIN_STARTED)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!(status & _XABORT_RETRY))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::string get_system_info();
|
||||
}
|
||||
+2
-2
@@ -1,4 +1,4 @@
|
||||
version: '0.0.3-{build}'
|
||||
version: '0.0.2-{build}'
|
||||
|
||||
os: Visual Studio 2017
|
||||
platform: x64
|
||||
@@ -32,7 +32,7 @@ install:
|
||||
|
||||
artifacts:
|
||||
- path: bin
|
||||
name: 'rpcs3-v0.0.3-$(Date)-$(COMMIT_SHA)_win64'
|
||||
name: 'rpcs3-v0.0.2-$(Date)-$(COMMIT_SHA)_win64'
|
||||
type: zip
|
||||
|
||||
cache:
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
make_fself compiled.elf EBOOT.BIN
|
||||
+1
-1
Submodule llvm updated: 079c1f30fc...9a59c1b6f3
@@ -1,60 +0,0 @@
|
||||
// http://stackoverflow.com/a/34032216/78204
|
||||
|
||||
function Controller() {
|
||||
installer.autoRejectMessageBoxes();
|
||||
installer.setMessageBoxAutomaticAnswer("OverwriteTargetDirectory", QMessageBox.Yes);
|
||||
installer.installationFinished.connect(function() {
|
||||
gui.clickButton(buttons.NextButton);
|
||||
})
|
||||
}
|
||||
|
||||
Controller.prototype.WelcomePageCallback = function() {
|
||||
gui.clickButton(buttons.NextButton);
|
||||
}
|
||||
|
||||
Controller.prototype.CredentialsPageCallback = function() {
|
||||
gui.clickButton(buttons.NextButton);
|
||||
}
|
||||
|
||||
Controller.prototype.IntroductionPageCallback = function() {
|
||||
gui.clickButton(buttons.NextButton);
|
||||
}
|
||||
|
||||
Controller.prototype.TargetDirectoryPageCallback = function()
|
||||
{
|
||||
gui.currentPageWidget().TargetDirectoryLineEdit.setText(installer.value("HomeDir") + "/Qt");
|
||||
//gui.currentPageWidget().TargetDirectoryLineEdit.setText(installer.value("InstallerDirPath") + "/Qt");
|
||||
//gui.currentPageWidget().TargetDirectoryLineEdit.setText("/scratch/Qt");
|
||||
gui.clickButton(buttons.NextButton);
|
||||
}
|
||||
|
||||
Controller.prototype.ComponentSelectionPageCallback = function() {
|
||||
var widget = gui.currentPageWidget();
|
||||
|
||||
widget.deselectAll();
|
||||
widget.selectComponent("qt.591.gcc_64");
|
||||
|
||||
gui.clickButton(buttons.NextButton);
|
||||
}
|
||||
|
||||
Controller.prototype.LicenseAgreementPageCallback = function() {
|
||||
gui.currentPageWidget().AcceptLicenseRadioButton.setChecked(true);
|
||||
gui.clickButton(buttons.NextButton);
|
||||
}
|
||||
|
||||
Controller.prototype.StartMenuDirectoryPageCallback = function() {
|
||||
gui.clickButton(buttons.NextButton);
|
||||
}
|
||||
|
||||
Controller.prototype.ReadyForInstallationPageCallback = function()
|
||||
{
|
||||
gui.clickButton(buttons.NextButton);
|
||||
}
|
||||
|
||||
Controller.prototype.FinishedPageCallback = function() {
|
||||
var checkBoxForm = gui.currentPageWidget().LaunchQtCreatorCheckBoxForm
|
||||
if (checkBoxForm && checkBoxForm.launchQtCreatorCheckBox) {
|
||||
checkBoxForm.launchQtCreatorCheckBox.checked = false;
|
||||
}
|
||||
gui.clickButton(buttons.FinishButton);
|
||||
}
|
||||
+17
-23
@@ -85,9 +85,10 @@ else()
|
||||
endif()
|
||||
|
||||
if(NOT MSVC)
|
||||
if($ENV{CI})
|
||||
set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -O1") # fix for travis gcc OoM crash. Might be fixed with the move to containers.
|
||||
endif()
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fexceptions")
|
||||
# This hides our LLVM from mesa's LLVM, otherwise we get some unresolvable conflicts.
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wl,--exclude-libs,ALL")
|
||||
if(WIN32)
|
||||
set(CMAKE_RC_COMPILER_INIT windres)
|
||||
enable_language(RC)
|
||||
@@ -97,7 +98,7 @@ if(NOT MSVC)
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wl,--allow-multiple-definition")
|
||||
endif()
|
||||
|
||||
add_compile_options(-msse -msse2 -mcx16 -mssse3 -mrtm)
|
||||
add_compile_options(-msse -msse2 -mcx16 -mssse3)
|
||||
|
||||
if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang")
|
||||
# This fixes 'some' of the st11range issues. See issue #2516
|
||||
@@ -108,10 +109,9 @@ if(NOT MSVC)
|
||||
CHECK_C_COMPILER_FLAG("-no-pie" HAS_NO_PIE)
|
||||
if(HAS_NO_PIE)
|
||||
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -no-pie")
|
||||
endif()
|
||||
CHECK_C_COMPILER_FLAG("-nopie" HAS_NOPIE)
|
||||
if(HAS_NOPIE)
|
||||
if (NOT HAS_NO_PIE)
|
||||
else()
|
||||
CHECK_C_COMPILER_FLAG("-nopie" HAS_NO_PIE)
|
||||
if(HAS_NO_PIE)
|
||||
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -nopie")
|
||||
endif()
|
||||
endif()
|
||||
@@ -158,17 +158,6 @@ elseif(WIN32)
|
||||
set(PLATFORM_ARCH "Windows/x86_64")
|
||||
else()
|
||||
set(PLATFORM_ARCH "linux/x86_64")
|
||||
option(USE_LIBEVDEV "libevdev-based joystick support" ON)
|
||||
endif()
|
||||
|
||||
if(USE_LIBEVDEV)
|
||||
find_package(PkgConfig)
|
||||
pkg_check_modules(LIBEVDEV libevdev)
|
||||
if(LIBEVDEV_FOUND)
|
||||
add_definitions(-DHAVE_LIBEVDEV)
|
||||
include_directories(SYSTEM ${LIBEVDEV_INCLUDE_DIRS})
|
||||
list(APPEND ADDITIONAL_LIBS ${LIBEVDEV_LDFLAGS})
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# Select the version of libpng to use, default is builtin
|
||||
@@ -225,10 +214,16 @@ if(NOT LLVM_FOUND)
|
||||
else()
|
||||
add_definitions(${LLVM_DEFINITIONS})
|
||||
add_definitions(-DLLVM_AVAILABLE)
|
||||
if (CMAKE_BUILD_TYPE STREQUAL "Release")
|
||||
llvm_map_components_to_libnames(LLVM_LIBS mcjit vectorize ipo x86codegen x86disassembler)
|
||||
|
||||
#Use static linking for windows binary but always dynamic on *nix
|
||||
if (WIN32)
|
||||
if (CMAKE_BUILD_TYPE STREQUAL "Release")
|
||||
llvm_map_components_to_libnames(LLVM_LIBS mcjit vectorize ipo x86codegen x86disassembler)
|
||||
else()
|
||||
llvm_map_components_to_libnames(LLVM_LIBS mcjit vectorize ipo x86codegen x86disassembler mcdisassembler)
|
||||
endif()
|
||||
else()
|
||||
llvm_map_components_to_libnames(LLVM_LIBS mcjit vectorize ipo x86codegen x86disassembler mcdisassembler)
|
||||
set(LLVM_LIBS LLVM)
|
||||
endif()
|
||||
|
||||
if (NOT MSVC)
|
||||
@@ -288,7 +283,6 @@ endif()
|
||||
# Ignore autogenerated moc_* files if present
|
||||
set (EXCLUDE_FILES ${EXCLUDE_FILES} "moc_")
|
||||
set (EXCLUDE_FILES ${EXCLUDE_FILES} "rpcs3_automoc")
|
||||
set (EXCLUDE_FILES ${EXCLUDE_FILES} "qrc_resources.cpp")
|
||||
|
||||
foreach (TMP_PATH ${RPCS3_SRC})
|
||||
foreach (EXCLUDE_PATH ${EXCLUDE_FILES})
|
||||
@@ -300,7 +294,7 @@ foreach (TMP_PATH ${RPCS3_SRC})
|
||||
endforeach(TMP_PATH)
|
||||
|
||||
# Remove the Qt moc files as part of clean, they are compiled when generating automoc
|
||||
file(GLOB_RECURSE TMP_MOC "${RPCS3_SRC_DIR}/moc_*.cpp" "${RPCS3_SRC_DIR}/rpcs3_automoc.cpp" "${RPCS3_SRC_DIR}/qrc_resources.cpp")
|
||||
file(GLOB_RECURSE TMP_MOC "${RPCS3_SRC_DIR}/moc_*.cpp" "${RPCS3_SRC_DIR}/rpcs3_automoc.cpp")
|
||||
set_directory_properties(PROPERTIES ADDITIONAL_MAKE_CLEAN_FILES "${TMP_MOC}")
|
||||
|
||||
if (WIN32)
|
||||
|
||||
+4
-22
@@ -1,12 +1,9 @@
|
||||
#include "stdafx.h"
|
||||
#include "Utilities/sysinfo.h"
|
||||
#include "Emu/Memory/vm.h"
|
||||
#include "Emu/Cell/SPUThread.h"
|
||||
#include "Emu/Cell/lv2/sys_sync.h"
|
||||
#include "MFC.h"
|
||||
|
||||
const bool s_use_rtm = utils::has_rtm();
|
||||
|
||||
template <>
|
||||
void fmt_class_string<MFC>::format(std::string& out, u64 arg)
|
||||
{
|
||||
@@ -148,25 +145,10 @@ void mfc_thread::cpu_task()
|
||||
vm::reservation_acquire(cmd.eal, 128);
|
||||
|
||||
// Store unconditionally
|
||||
if (s_use_rtm && utils::transaction_enter())
|
||||
{
|
||||
if (!vm::reader_lock{vm::try_to_lock})
|
||||
{
|
||||
_xabort(0);
|
||||
}
|
||||
|
||||
data = to_write;
|
||||
vm::reservation_update(cmd.eal, 128);
|
||||
vm::notify(cmd.eal, 128);
|
||||
_xend();
|
||||
}
|
||||
else
|
||||
{
|
||||
vm::writer_lock lock(0);
|
||||
data = to_write;
|
||||
vm::reservation_update(cmd.eal, 128);
|
||||
vm::notify(cmd.eal, 128);
|
||||
}
|
||||
vm::writer_lock lock(0);
|
||||
data = to_write;
|
||||
vm::reservation_update(cmd.eal, 128);
|
||||
vm::notify(cmd.eal, 128);
|
||||
}
|
||||
else if (cmd.cmd & MFC_LIST_MASK)
|
||||
{
|
||||
|
||||
@@ -2,35 +2,16 @@
|
||||
#include "Emu/System.h"
|
||||
#include "Emu/Cell/PPUModule.h"
|
||||
|
||||
namespace vm { using namespace ps3; }
|
||||
|
||||
logs::channel cellCrossController("cellCrossController");
|
||||
|
||||
struct CellCrossControllerParam
|
||||
s32 cellCrossController_37E1F502() // LittleBigPlanet 2 and 3
|
||||
{
|
||||
vm::bcptr<char> pPackageFileName;
|
||||
vm::bcptr<char> pSignatureFileName;
|
||||
vm::bcptr<char> pIconFileName;
|
||||
vm::bptr<void> option;
|
||||
};
|
||||
|
||||
struct CellCrossControllerPackageInfo
|
||||
{
|
||||
vm::bcptr<char> pTitle;
|
||||
vm::bcptr<char> pTitleId;
|
||||
vm::bcptr<char> pAppVer;
|
||||
};
|
||||
|
||||
using CellCrossControllerCallback = void(s32 status, s32 errorCode, vm::ptr<void> option, vm::ptr<void> userdata);
|
||||
|
||||
s32 cellCrossControllerInitialize(vm::cptr<CellCrossControllerParam> pParam, vm::cptr<CellCrossControllerPackageInfo> pPkgInfo, vm::ptr<CellCrossControllerCallback> cb, vm::ptr<void> userdata) // LittleBigPlanet 2 and 3
|
||||
{
|
||||
cellCrossController.todo("cellCrossControllerInitialize(pParam=*0x%x, pPkgInfo=*0x%x, cb=*0x%x, userdata=*0x%x)", pParam, pPkgInfo, cb, userdata);
|
||||
cellCrossController.todo("cellCrossController_37E1F502");
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
|
||||
DECLARE(ppu_module_manager::cellCrossController)("cellCrossController", []()
|
||||
{
|
||||
REG_FUNC(cellCrossController, cellCrossControllerInitialize);
|
||||
REG_FNID(cellCrossController, 0x37E1F502, cellCrossController_37E1F502);
|
||||
});
|
||||
|
||||
@@ -554,7 +554,7 @@ s32 cellFontExtend(u32 a1, u32 a2, u32 a3)
|
||||
//Something happens
|
||||
}
|
||||
//Something happens?
|
||||
return -1;
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
s32 cellFontRenderCharGlyphImageVertical()
|
||||
|
||||
@@ -80,13 +80,14 @@ struct content_permission final
|
||||
// SFO file
|
||||
psf::registry sfo;
|
||||
|
||||
// Temporary directory path
|
||||
std::string temp;
|
||||
// True if temporary directory is created and must be moved or deleted
|
||||
bool is_temporary = false;
|
||||
|
||||
template <typename Dir, typename Sfo>
|
||||
content_permission(Dir&& dir, Sfo&& sfo)
|
||||
content_permission(Dir&& dir, Sfo&& sfo, bool is_temp = false)
|
||||
: dir(std::forward<Dir>(dir))
|
||||
, sfo(std::forward<Sfo>(sfo))
|
||||
, is_temporary(is_temp)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -94,9 +95,9 @@ struct content_permission final
|
||||
{
|
||||
try
|
||||
{
|
||||
if (!temp.empty())
|
||||
if (is_temporary)
|
||||
{
|
||||
fs::remove_all(temp);
|
||||
fs::remove_all(vfs::get("/dev_hdd1/game/" + dir));
|
||||
}
|
||||
}
|
||||
catch (...)
|
||||
@@ -182,14 +183,13 @@ s32 cellHddGameGetSizeKB(vm::ptr<u32> size)
|
||||
{
|
||||
cellGame.warning("cellHddGameGetSizeKB(size=*0x%x)", size);
|
||||
|
||||
const std::string local_dir = vfs::get("/dev_hdd0/game/" + Emu.GetTitleID());
|
||||
|
||||
const std::string& local_dir = vfs::get("/dev_hdd0/game/" + Emu.GetTitleID());
|
||||
if (!fs::is_dir(local_dir))
|
||||
{
|
||||
return CELL_HDDGAME_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
*size = ::narrow<u32>(fs::get_dir_size(local_dir) / 1024);
|
||||
*size = (u32)(fs::get_dir_size(local_dir)/1024);
|
||||
|
||||
return CELL_OK;
|
||||
}
|
||||
@@ -209,16 +209,16 @@ s32 cellGameDataGetSizeKB(vm::ptr<u32> size)
|
||||
{
|
||||
cellGame.warning("cellGameDataGetSizeKB(size=*0x%x)", size);
|
||||
|
||||
const std::string local_dir = vfs::get("/dev_hdd0/game/" + Emu.GetTitleID());
|
||||
|
||||
const std::string& local_dir = vfs::get("/dev_hdd0/game/" + Emu.GetTitleID());
|
||||
if (!fs::is_dir(local_dir))
|
||||
{
|
||||
return CELL_GAMEDATA_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
*size = ::narrow<u32>(fs::get_dir_size(local_dir) / 1024);
|
||||
*size = (u32)(fs::get_dir_size(local_dir)/1024);
|
||||
|
||||
return CELL_OK;
|
||||
|
||||
}
|
||||
|
||||
s32 cellGameDataSetSystemVer()
|
||||
@@ -383,7 +383,7 @@ error_code cellGameContentPermit(vm::ptr<char[CELL_GAME_PATH_MAX]> contentInfoPa
|
||||
|
||||
const std::string dir = prm->dir.empty() ? "/dev_bdvd/PS3_GAME"s : "/dev_hdd0/game/" + prm->dir;
|
||||
|
||||
if (!prm->temp.empty())
|
||||
if (prm->is_temporary)
|
||||
{
|
||||
// Make temporary directory persistent
|
||||
const auto vdir = vfs::get(dir);
|
||||
@@ -393,7 +393,7 @@ error_code cellGameContentPermit(vm::ptr<char[CELL_GAME_PATH_MAX]> contentInfoPa
|
||||
fmt::throw_exception("cellGameContentPermit(): epic fail: directory '%s' already exists", dir);
|
||||
}
|
||||
|
||||
if (fs::rename(prm->temp, vdir))
|
||||
if (fs::rename(vfs::get("/dev_hdd1/game/" + prm->dir), vdir))
|
||||
{
|
||||
cellGame.success("cellGameContentPermit(): directory '%s' has been created", dir);
|
||||
}
|
||||
@@ -406,7 +406,7 @@ error_code cellGameContentPermit(vm::ptr<char[CELL_GAME_PATH_MAX]> contentInfoPa
|
||||
psf::save_object(fs::file(vdir + "/PARAM.SFO", fs::rewrite), prm->sfo);
|
||||
|
||||
// Disable deletion
|
||||
prm->temp.clear();
|
||||
prm->is_temporary = false;
|
||||
}
|
||||
|
||||
strcpy_trunc(*contentInfoPath, dir);
|
||||
@@ -570,8 +570,8 @@ error_code cellGameCreateGameData(vm::ptr<CellGameSetInitParams> init, vm::ptr<c
|
||||
strcpy_trunc(*tmp_contentInfoPath, tmp_contentInfo);
|
||||
strcpy_trunc(*tmp_usrdirPath, tmp_usrdir);
|
||||
|
||||
prm->temp = vfs::get(tmp_contentInfo);
|
||||
cellGame.success("cellGameCreateGameData(): temporary directory '%s' has been created", tmp_contentInfo);
|
||||
prm->is_temporary = true;
|
||||
|
||||
// Initial PARAM.SFO parameters (overwrite)
|
||||
prm->sfo =
|
||||
@@ -714,10 +714,9 @@ error_code cellGameSetParamString(s32 id, vm::cptr<char> buf)
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
error_code cellGameGetSizeKB(vm::ptr<s32> size)
|
||||
s32 cellGameGetSizeKB(vm::ptr<s32> size)
|
||||
{
|
||||
cellGame.warning("cellGameGetSizeKB(size=*0x%x)", size);
|
||||
|
||||
const auto prm = fxm::get<content_permission>();
|
||||
|
||||
if (!prm)
|
||||
@@ -725,14 +724,13 @@ error_code cellGameGetSizeKB(vm::ptr<s32> size)
|
||||
return CELL_GAME_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
const std::string local_dir = !prm->temp.empty() ? prm->temp : vfs::get("/dev_hdd0/game/" + prm->dir);
|
||||
|
||||
const std::string& local_dir = prm->is_temporary? vfs::get("/dev_hdd1/game/"s + prm->dir) : vfs::get("/dev_hdd0/game/"s + prm->dir); //should we check the temporary folder?
|
||||
if (!fs::is_dir(local_dir))
|
||||
{
|
||||
return CELL_GAME_ERROR_ACCESS_ERROR;
|
||||
return CELL_GAME_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
*size = ::narrow<u32>(fs::get_dir_size(local_dir) / 1024);
|
||||
*size = (u32)(fs::get_dir_size(local_dir)/1024);
|
||||
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
@@ -5,15 +5,14 @@
|
||||
|
||||
logs::channel cellGameExec("cellGameExec");
|
||||
|
||||
s32 cellGameSetExitParam(u32 execdata)
|
||||
s32 cellGameSetExitParam()
|
||||
{
|
||||
cellGameExec.todo("cellGameSetExitParam(execdata=0x%x)", execdata);
|
||||
return CELL_OK;
|
||||
fmt::throw_exception("Unimplemented" HERE);
|
||||
}
|
||||
|
||||
s32 cellGameGetHomeDataExportPath(vm::ptr<char> exportPath)
|
||||
{
|
||||
cellGameExec.warning("cellGameGetHomeDataExportPath(exportPath=*0x%x)", exportPath);
|
||||
cellGameExec.warning("cellGameGetHomeDataExportPath(exportPath=0x%x)", exportPath);
|
||||
|
||||
// TODO: PlayStation home is defunct.
|
||||
|
||||
@@ -22,17 +21,12 @@ s32 cellGameGetHomeDataExportPath(vm::ptr<char> exportPath)
|
||||
|
||||
s32 cellGameGetHomePath()
|
||||
{
|
||||
UNIMPLEMENTED_FUNC(cellGameExec);
|
||||
return CELL_OK;
|
||||
fmt::throw_exception("Unimplemented" HERE);
|
||||
}
|
||||
|
||||
s32 cellGameGetHomeDataImportPath(vm::ptr<char> importPath)
|
||||
s32 cellGameGetHomeDataImportPath()
|
||||
{
|
||||
cellGameExec.warning("cellGameGetHomeDataImportPath(importPath=*0x%x)", importPath);
|
||||
|
||||
// TODO: PlayStation home is defunct.
|
||||
|
||||
return CELL_GAME_ERROR_NOAPP;
|
||||
fmt::throw_exception("Unimplemented" HERE);
|
||||
}
|
||||
|
||||
s32 cellGameGetHomeLaunchOptionPath(vm::ptr<char> commonPath, vm::ptr<char> personalPath)
|
||||
@@ -43,9 +37,9 @@ s32 cellGameGetHomeLaunchOptionPath(vm::ptr<char> commonPath, vm::ptr<char> pers
|
||||
return CELL_GAME_ERROR_NOAPP;
|
||||
}
|
||||
|
||||
s32 cellGameGetBootGameInfo(vm::ptr<u32> type, vm::ptr<char> dirName, vm::ptr<u32> execdata)
|
||||
s32 cellGameGetBootGameInfo(vm::ptr<u32> type, vm::ptr<char> dirName, vm::ptr<u32> execData)
|
||||
{
|
||||
cellGameExec.todo("cellGameGetBootGameInfo(type=*0x%x, dirName=%s, execdata=*0x%x)", type, dirName, execdata);
|
||||
cellGameExec.todo("cellGameGetBootGameInfo(type=*0x%x, dirName=%s, execData=*0x%x)", type, dirName, execData);
|
||||
|
||||
// TODO: Support more boot types
|
||||
*type = CELL_GAME_GAMETYPE_SYS;
|
||||
|
||||
@@ -26,19 +26,16 @@ const u32 tiled_pitches[] = {
|
||||
0x00010000
|
||||
};
|
||||
|
||||
struct CellGcmSysConfig {
|
||||
u32 zculls_addr;
|
||||
vm::ptr<CellGcmDisplayInfo> gcm_buffers{ vm::null };
|
||||
u32 tiles_addr;
|
||||
u32 ctxt_addr;
|
||||
CellGcmConfig current_config;
|
||||
CellGcmContextData current_context;
|
||||
gcmInfo gcm_info;
|
||||
};
|
||||
|
||||
u64 system_mode = 0;
|
||||
u32 local_size = 0;
|
||||
u32 local_addr = 0;
|
||||
u64 system_mode = 0;
|
||||
|
||||
CellGcmConfig current_config;
|
||||
CellGcmContextData current_context;
|
||||
gcmInfo gcm_info;
|
||||
|
||||
u32 map_offset_addr = 0;
|
||||
u32 map_offset_pos = 0;
|
||||
|
||||
// Auxiliary functions
|
||||
|
||||
@@ -85,12 +82,7 @@ void InitOffsetTable()
|
||||
u32 cellGcmGetLabelAddress(u8 index)
|
||||
{
|
||||
cellGcmSys.trace("cellGcmGetLabelAddress(index=%d)", index);
|
||||
const auto m_config = fxm::get<CellGcmSysConfig>();
|
||||
|
||||
if (!m_config)
|
||||
return 0;
|
||||
|
||||
return m_config->gcm_info.label_addr + 0x10 * index;
|
||||
return gcm_info.label_addr + 0x10 * index;
|
||||
}
|
||||
|
||||
vm::ptr<CellGcmReportData> cellGcmGetReportDataAddressLocation(u32 index, u32 location)
|
||||
@@ -102,7 +94,7 @@ vm::ptr<CellGcmReportData> cellGcmGetReportDataAddressLocation(u32 index, u32 lo
|
||||
cellGcmSys.error("cellGcmGetReportDataAddressLocation: Wrong local index (%d)", index);
|
||||
return vm::null;
|
||||
}
|
||||
return vm::ptr<CellGcmReportData>::make(0x40301400 + index * 0x10);
|
||||
return vm::ptr<CellGcmReportData>::make(0xC0000000 + index * 0x10);
|
||||
}
|
||||
|
||||
if (location == CELL_GCM_LOCATION_MAIN) {
|
||||
@@ -125,7 +117,7 @@ u64 cellGcmGetTimeStamp(u32 index)
|
||||
cellGcmSys.error("cellGcmGetTimeStamp: Wrong local index (%d)", index);
|
||||
return 0;
|
||||
}
|
||||
return vm::read64(0x40301400 + index * 0x10);
|
||||
return vm::read64(0xC0000000 + index * 0x10);
|
||||
}
|
||||
|
||||
u32 cellGcmGetCurrentField()
|
||||
@@ -152,7 +144,7 @@ u32 cellGcmGetNotifyDataAddress(u32 index)
|
||||
*/
|
||||
vm::ptr<CellGcmReportData> _cellGcmFunc12()
|
||||
{
|
||||
return vm::ptr<CellGcmReportData>::make(0x40301400); // TODO
|
||||
return vm::ptr<CellGcmReportData>::make(0xC0000000); // TODO
|
||||
}
|
||||
|
||||
u32 cellGcmGetReport(u32 type, u32 index)
|
||||
@@ -180,7 +172,7 @@ u32 cellGcmGetReportDataAddress(u32 index)
|
||||
cellGcmSys.error("cellGcmGetReportDataAddress: Wrong local index (%d)", index);
|
||||
return 0;
|
||||
}
|
||||
return 0x40301400 + index * 0x10;
|
||||
return 0xC0000000 + index * 0x10;
|
||||
}
|
||||
|
||||
u32 cellGcmGetReportDataLocation(u32 index, u32 location)
|
||||
@@ -200,7 +192,7 @@ u64 cellGcmGetTimeStampLocation(u32 index, u32 location)
|
||||
cellGcmSys.error("cellGcmGetTimeStampLocation: Wrong local index (%d)", index);
|
||||
return 0;
|
||||
}
|
||||
return vm::read64(0x40301400 + index * 0x10);
|
||||
return vm::read64(0xC0000000 + index * 0x10);
|
||||
}
|
||||
|
||||
if (location == CELL_GCM_LOCATION_MAIN) {
|
||||
@@ -222,31 +214,20 @@ u64 cellGcmGetTimeStampLocation(u32 index, u32 location)
|
||||
u32 cellGcmGetControlRegister()
|
||||
{
|
||||
cellGcmSys.trace("cellGcmGetControlRegister()");
|
||||
const auto m_config = fxm::get<CellGcmSysConfig>();
|
||||
|
||||
if (!m_config)
|
||||
return 0;
|
||||
return m_config->gcm_info.control_addr;
|
||||
return gcm_info.control_addr;
|
||||
}
|
||||
|
||||
u32 cellGcmGetDefaultCommandWordSize()
|
||||
{
|
||||
cellGcmSys.trace("cellGcmGetDefaultCommandWordSize()");
|
||||
const auto m_config = fxm::get<CellGcmSysConfig>();
|
||||
|
||||
if (!m_config)
|
||||
return 0;
|
||||
return m_config->gcm_info.command_size;
|
||||
return gcm_info.command_size;
|
||||
}
|
||||
|
||||
u32 cellGcmGetDefaultSegmentWordSize()
|
||||
{
|
||||
cellGcmSys.trace("cellGcmGetDefaultSegmentWordSize()");
|
||||
const auto m_config = fxm::get<CellGcmSysConfig>();
|
||||
|
||||
if (!m_config)
|
||||
return 0;
|
||||
return m_config->gcm_info.segment_size;
|
||||
return gcm_info.segment_size;
|
||||
}
|
||||
|
||||
s32 cellGcmInitDefaultFifoMode(s32 mode)
|
||||
@@ -299,10 +280,8 @@ s32 cellGcmBindZcull(u8 index, u32 offset, u32 width, u32 height, u32 cullStart,
|
||||
void cellGcmGetConfiguration(vm::ptr<CellGcmConfig> config)
|
||||
{
|
||||
cellGcmSys.trace("cellGcmGetConfiguration(config=*0x%x)", config);
|
||||
const auto m_config = fxm::get<CellGcmSysConfig>();
|
||||
|
||||
if (m_config)
|
||||
*config = m_config->current_config;
|
||||
*config = current_config;
|
||||
}
|
||||
|
||||
u32 cellGcmGetFlipStatus()
|
||||
@@ -318,9 +297,9 @@ u32 cellGcmGetTiledPitchSize(u32 size)
|
||||
{
|
||||
cellGcmSys.trace("cellGcmGetTiledPitchSize(size=%d)", size);
|
||||
|
||||
for (size_t i = 0; i < sizeof(tiled_pitches) / sizeof(tiled_pitches[0]) - 1; i++) {
|
||||
if (tiled_pitches[i] < size && size <= tiled_pitches[i + 1]) {
|
||||
return tiled_pitches[i + 1];
|
||||
for (size_t i=0; i < sizeof(tiled_pitches) / sizeof(tiled_pitches[0]) - 1; i++) {
|
||||
if (tiled_pitches[i] < size && size <= tiled_pitches[i+1]) {
|
||||
return tiled_pitches[i+1];
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
@@ -345,12 +324,8 @@ s32 _cellGcmInitBody(vm::pptr<CellGcmContextData> context, u32 cmdSize, u32 ioSi
|
||||
{
|
||||
cellGcmSys.warning("_cellGcmInitBody(context=**0x%x, cmdSize=0x%x, ioSize=0x%x, ioAddress=0x%x)", context, cmdSize, ioSize, ioAddress);
|
||||
|
||||
auto m_config = fxm::make<CellGcmSysConfig>();
|
||||
if (!m_config)
|
||||
return CELL_GCM_ERROR_FAILURE;
|
||||
|
||||
m_config->current_config.ioAddress = 0;
|
||||
m_config->current_config.localAddress = 0;
|
||||
current_config.ioAddress = 0;
|
||||
current_config.localAddress = 0;
|
||||
local_size = 0;
|
||||
local_addr = 0;
|
||||
|
||||
@@ -381,42 +356,33 @@ s32 _cellGcmInitBody(vm::pptr<CellGcmContextData> context, u32 cmdSize, u32 ioSi
|
||||
return CELL_GCM_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
m_config->current_config.ioSize = ioSize;
|
||||
m_config->current_config.ioAddress = ioAddress;
|
||||
m_config->current_config.localSize = local_size;
|
||||
m_config->current_config.localAddress = local_addr;
|
||||
m_config->current_config.memoryFrequency = 650000000;
|
||||
m_config->current_config.coreFrequency = 500000000;
|
||||
map_offset_addr = 0;
|
||||
map_offset_pos = 0;
|
||||
current_config.ioSize = ioSize;
|
||||
current_config.ioAddress = ioAddress;
|
||||
current_config.localSize = local_size;
|
||||
current_config.localAddress = local_addr;
|
||||
current_config.memoryFrequency = 650000000;
|
||||
current_config.coreFrequency = 500000000;
|
||||
|
||||
// Create contexts
|
||||
|
||||
u32 addr = vm::falloc(0x40000000, 0x400000);
|
||||
if (addr == 0 || addr != 0x40000000)
|
||||
fmt::throw_exception("Failed to alloc 0x40000000.");
|
||||
|
||||
g_defaultCommandBufferBegin = ioAddress;
|
||||
g_defaultCommandBufferFragmentCount = cmdSize / (32 * 1024);
|
||||
|
||||
m_config->gcm_info.context_addr = 0x40000000;
|
||||
m_config->gcm_info.control_addr = 0x40100000;
|
||||
m_config->gcm_info.label_addr = 0x40300000;
|
||||
gcm_info.context_addr = vm::alloc(0x1000, vm::main);
|
||||
gcm_info.control_addr = vm::alloc(0x1000, vm::main);
|
||||
gcm_info.label_addr = vm::alloc(0x1000, vm::main); // ???
|
||||
|
||||
m_config->current_context.begin.set(g_defaultCommandBufferBegin + 4096); // 4 kb reserved at the beginning
|
||||
m_config->current_context.end.set(g_defaultCommandBufferBegin + 32 * 1024 - 4); // 4b at the end for jump
|
||||
m_config->current_context.current = m_config->current_context.begin;
|
||||
m_config->current_context.callback.set(ppu_function_manager::addr + 8 * FIND_FUNC(cellGcmCallback));
|
||||
current_context.begin.set(g_defaultCommandBufferBegin + 4096); // 4 kb reserved at the beginning
|
||||
current_context.end.set(g_defaultCommandBufferBegin + 32 * 1024 - 4); // 4b at the end for jump
|
||||
current_context.current = current_context.begin;
|
||||
current_context.callback.set(ppu_function_manager::addr + 8 * FIND_FUNC(cellGcmCallback));
|
||||
|
||||
m_config->ctxt_addr = context.addr();
|
||||
m_config->gcm_buffers.set(vm::alloc(sizeof(CellGcmDisplayInfo) * 8, vm::main));
|
||||
m_config->zculls_addr = vm::alloc(sizeof(CellGcmZcullInfo) * 8, vm::main);
|
||||
m_config->tiles_addr = vm::alloc(sizeof(CellGcmTileInfo) * 15, vm::main);
|
||||
vm::_ref<CellGcmContextData>(gcm_info.context_addr) = current_context;
|
||||
context->set(gcm_info.context_addr);
|
||||
|
||||
vm::_ref<CellGcmContextData>(m_config->gcm_info.context_addr) = m_config->current_context;
|
||||
context->set(m_config->gcm_info.context_addr);
|
||||
|
||||
// 0x40 is to offset CellGcmControl from RsxDmaControl
|
||||
m_config->gcm_info.control_addr += 0x40;
|
||||
auto& ctrl = vm::_ref<CellGcmControl>(m_config->gcm_info.control_addr);
|
||||
auto& ctrl = vm::_ref<CellGcmControl>(gcm_info.control_addr);
|
||||
ctrl.put = 0;
|
||||
ctrl.get = 0;
|
||||
ctrl.ref = -1;
|
||||
@@ -424,10 +390,15 @@ s32 _cellGcmInitBody(vm::pptr<CellGcmContextData> context, u32 cmdSize, u32 ioSi
|
||||
const auto render = fxm::get<GSRender>();
|
||||
render->intr_thread = idm::make_ptr<ppu_thread>("_gcm_intr_thread", 1, 0x4000);
|
||||
render->intr_thread->run();
|
||||
render->ctxt_addr = context.addr();
|
||||
render->gcm_buffers.set(vm::alloc(sizeof(CellGcmDisplayInfo) * 8, vm::main));
|
||||
render->zculls_addr = vm::alloc(sizeof(CellGcmZcullInfo) * 8, vm::main);
|
||||
render->tiles_addr = vm::alloc(sizeof(CellGcmTileInfo) * 15, vm::main);
|
||||
render->gcm_buffers_count = 0;
|
||||
render->gcm_current_buffer = 0;
|
||||
render->main_mem_addr = 0;
|
||||
render->isHLE = true;
|
||||
render->label_addr = m_config->gcm_info.label_addr;
|
||||
render->init(ioAddress, ioSize, m_config->gcm_info.control_addr - 0x40, local_addr);
|
||||
render->label_addr = gcm_info.label_addr;
|
||||
render->init(g_defaultCommandBufferBegin, cmdSize, gcm_info.control_addr, local_addr);
|
||||
|
||||
return CELL_OK;
|
||||
}
|
||||
@@ -460,10 +431,6 @@ s32 cellGcmSetDisplayBuffer(u8 id, u32 offset, u32 pitch, u32 width, u32 height)
|
||||
{
|
||||
cellGcmSys.trace("cellGcmSetDisplayBuffer(id=0x%x, offset=0x%x, pitch=%d, width=%d, height=%d)", id, offset, width ? pitch / width : pitch, width, height);
|
||||
|
||||
auto m_config = fxm::get<CellGcmSysConfig>();
|
||||
if (!m_config)
|
||||
return CELL_GCM_ERROR_FAILURE;
|
||||
|
||||
if (id > 7)
|
||||
{
|
||||
cellGcmSys.error("cellGcmSetDisplayBuffer: CELL_GCM_ERROR_FAILURE");
|
||||
@@ -472,21 +439,16 @@ s32 cellGcmSetDisplayBuffer(u8 id, u32 offset, u32 pitch, u32 width, u32 height)
|
||||
|
||||
const auto render = fxm::get<GSRender>();
|
||||
|
||||
auto buffers = render->display_buffers;
|
||||
auto buffers = render->gcm_buffers;
|
||||
|
||||
buffers[id].offset = offset;
|
||||
buffers[id].pitch = pitch;
|
||||
buffers[id].width = width;
|
||||
buffers[id].height = height;
|
||||
|
||||
m_config->gcm_buffers[id].offset = offset;
|
||||
m_config->gcm_buffers[id].pitch = pitch;
|
||||
m_config->gcm_buffers[id].width = width;
|
||||
m_config->gcm_buffers[id].height = height;
|
||||
|
||||
if (id + 1 > render->display_buffers_count)
|
||||
if (id + 1 > render->gcm_buffers_count)
|
||||
{
|
||||
render->display_buffers_count = id + 1;
|
||||
render->gcm_buffers_count = id + 1;
|
||||
}
|
||||
|
||||
return CELL_OK;
|
||||
@@ -503,7 +465,17 @@ void cellGcmSetFlipMode(u32 mode)
|
||||
{
|
||||
cellGcmSys.warning("cellGcmSetFlipMode(mode=%d)", mode);
|
||||
|
||||
fxm::get<GSRender>()->requested_vsync.store(mode == CELL_GCM_DISPLAY_VSYNC);
|
||||
switch (mode)
|
||||
{
|
||||
case CELL_GCM_DISPLAY_HSYNC:
|
||||
case CELL_GCM_DISPLAY_VSYNC:
|
||||
case CELL_GCM_DISPLAY_HSYNC_WITH_NOISE:
|
||||
fxm::get<GSRender>()->flip_mode = mode;
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void cellGcmSetFlipStatus()
|
||||
@@ -516,9 +488,6 @@ void cellGcmSetFlipStatus()
|
||||
s32 cellGcmSetPrepareFlip(ppu_thread& ppu, vm::ptr<CellGcmContextData> ctxt, u32 id)
|
||||
{
|
||||
cellGcmSys.trace("cellGcmSetPrepareFlip(ctxt=*0x%x, id=0x%x)", ctxt, id);
|
||||
auto m_config = fxm::get<CellGcmSysConfig>();
|
||||
if (!m_config)
|
||||
return CELL_GCM_ERROR_FAILURE;
|
||||
|
||||
if (id > 7)
|
||||
{
|
||||
@@ -537,9 +506,9 @@ s32 cellGcmSetPrepareFlip(ppu_thread& ppu, vm::ptr<CellGcmContextData> ctxt, u32
|
||||
|
||||
const u32 cmd_size = rsx::make_command(ctxt->current, GCM_FLIP_COMMAND, { id });
|
||||
|
||||
if (ctxt.addr() == m_config->gcm_info.context_addr)
|
||||
if (ctxt.addr() == gcm_info.context_addr)
|
||||
{
|
||||
vm::_ref<CellGcmControl>(m_config->gcm_info.control_addr).put += cmd_size;
|
||||
vm::_ref<CellGcmControl>(gcm_info.control_addr).put += cmd_size;
|
||||
}
|
||||
|
||||
return id;
|
||||
@@ -566,12 +535,15 @@ void cellGcmSetSecondVFrequency(u32 freq)
|
||||
switch (freq)
|
||||
{
|
||||
case CELL_GCM_DISPLAY_FREQUENCY_59_94HZ:
|
||||
render->frequency_mode = freq;
|
||||
render->fps_limit = 59.94;
|
||||
break;
|
||||
case CELL_GCM_DISPLAY_FREQUENCY_SCANOUT:
|
||||
render->frequency_mode = freq;
|
||||
cellGcmSys.todo("Unimplemented display frequency: Scanout");
|
||||
break;
|
||||
case CELL_GCM_DISPLAY_FREQUENCY_DISABLE:
|
||||
render->frequency_mode = freq;
|
||||
cellGcmSys.todo("Unimplemented display frequency: Disabled");
|
||||
break;
|
||||
default:
|
||||
@@ -585,10 +557,6 @@ s32 cellGcmSetTileInfo(u8 index, u8 location, u32 offset, u32 size, u32 pitch, u
|
||||
cellGcmSys.warning("cellGcmSetTileInfo(index=%d, location=%d, offset=%d, size=%d, pitch=%d, comp=%d, base=%d, bank=%d)",
|
||||
index, location, offset, size, pitch, comp, base, bank);
|
||||
|
||||
auto m_config = fxm::get<CellGcmSysConfig>();
|
||||
if (!m_config)
|
||||
return CELL_GCM_ERROR_FAILURE;
|
||||
|
||||
if (index >= rsx::limits::tiles_count || base >= 2048 || bank >= 4)
|
||||
{
|
||||
cellGcmSys.error("cellGcmSetTileInfo: CELL_GCM_ERROR_INVALID_VALUE");
|
||||
@@ -623,7 +591,7 @@ s32 cellGcmSetTileInfo(u8 index, u8 location, u32 offset, u32 size, u32 pitch, u
|
||||
tile.base = base;
|
||||
tile.bank = bank;
|
||||
|
||||
vm::_ptr<CellGcmTileInfo>(m_config->tiles_addr)[index] = tile.pack();
|
||||
vm::_ptr<CellGcmTileInfo>(render->tiles_addr)[index] = tile.pack();
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
@@ -656,7 +624,7 @@ void cellGcmSetWaitFlip(vm::ptr<CellGcmContextData> ctxt)
|
||||
s32 cellGcmSetWaitFlipUnsafe()
|
||||
{
|
||||
cellGcmSys.todo("cellGcmSetWaitFlipUnsafe()");
|
||||
|
||||
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
@@ -665,10 +633,6 @@ void cellGcmSetZcull(u8 index, u32 offset, u32 width, u32 height, u32 cullStart,
|
||||
cellGcmSys.todo("cellGcmSetZcull(index=%d, offset=0x%x, width=%d, height=%d, cullStart=0x%x, zFormat=0x%x, aaFormat=0x%x, zCullDir=0x%x, zCullFormat=0x%x, sFunc=0x%x, sRef=0x%x, sMask=0x%x)",
|
||||
index, offset, width, height, cullStart, zFormat, aaFormat, zCullDir, zCullFormat, sFunc, sRef, sMask);
|
||||
|
||||
auto m_config = fxm::get<CellGcmSysConfig>();
|
||||
if (!m_config)
|
||||
return;
|
||||
|
||||
if (index >= rsx::limits::zculls_count)
|
||||
{
|
||||
cellGcmSys.error("cellGcmSetZcull: CELL_GCM_ERROR_INVALID_VALUE");
|
||||
@@ -679,7 +643,7 @@ void cellGcmSetZcull(u8 index, u32 offset, u32 width, u32 height, u32 cullStart,
|
||||
|
||||
auto& zcull = render->zculls[index];
|
||||
zcull.offset = offset;
|
||||
zcull.width = width;
|
||||
zcull.width = width;
|
||||
zcull.height = height;
|
||||
zcull.cullStart = cullStart;
|
||||
zcull.zFormat = zFormat;
|
||||
@@ -690,7 +654,7 @@ void cellGcmSetZcull(u8 index, u32 offset, u32 width, u32 height, u32 cullStart,
|
||||
zcull.sRef = sRef;
|
||||
zcull.sMask = sMask;
|
||||
|
||||
vm::_ptr<CellGcmZcullInfo>(m_config->zculls_addr)[index] = zcull.pack();
|
||||
vm::_ptr<CellGcmZcullInfo>(render->zculls_addr)[index] = zcull.pack();
|
||||
}
|
||||
|
||||
s32 cellGcmUnbindTile(u8 index)
|
||||
@@ -726,35 +690,26 @@ s32 cellGcmUnbindZcull(u8 index)
|
||||
u32 cellGcmGetTileInfo()
|
||||
{
|
||||
cellGcmSys.warning("cellGcmGetTileInfo()");
|
||||
auto m_config = fxm::get<CellGcmSysConfig>();
|
||||
if (!m_config)
|
||||
return 0;
|
||||
return m_config->tiles_addr;
|
||||
return fxm::get<GSRender>()->tiles_addr;
|
||||
}
|
||||
|
||||
u32 cellGcmGetZcullInfo()
|
||||
{
|
||||
cellGcmSys.warning("cellGcmGetZcullInfo()");
|
||||
auto m_config = fxm::get<CellGcmSysConfig>();
|
||||
if (!m_config)
|
||||
return 0;
|
||||
return m_config->zculls_addr;
|
||||
return fxm::get<GSRender>()->zculls_addr;
|
||||
}
|
||||
|
||||
u32 cellGcmGetDisplayInfo()
|
||||
{
|
||||
cellGcmSys.warning("cellGcmGetDisplayInfo()");
|
||||
auto m_config = fxm::get<CellGcmSysConfig>();
|
||||
if (!m_config)
|
||||
return 0;
|
||||
return m_config->gcm_buffers.addr();
|
||||
return fxm::get<GSRender>()->gcm_buffers.addr();
|
||||
}
|
||||
|
||||
s32 cellGcmGetCurrentDisplayBufferId(vm::ptr<u8> id)
|
||||
{
|
||||
cellGcmSys.warning("cellGcmGetCurrentDisplayBufferId(id=*0x%x)", id);
|
||||
|
||||
if ((*id = fxm::get<GSRender>()->current_display_buffer) > UINT8_MAX)
|
||||
if ((*id = fxm::get<GSRender>()->gcm_current_buffer) > UINT8_MAX)
|
||||
{
|
||||
fmt::throw_exception("Unexpected" HERE);
|
||||
}
|
||||
@@ -921,7 +876,7 @@ s32 cellGcmIoOffsetToAddress(u32 ioOffset, vm::ptr<u32> address)
|
||||
|
||||
u32 realAddr;
|
||||
|
||||
if (!RSXIOMem.getRealAddr(ioOffset, realAddr))
|
||||
if (!RSXIOMem.getRealAddr(ioOffset, realAddr))
|
||||
return CELL_GCM_ERROR_FAILURE;
|
||||
|
||||
*address = realAddr;
|
||||
@@ -943,6 +898,7 @@ s32 gcmMapEaIoAddress(u32 ea, u32 io, u32 size, bool is_strict)
|
||||
{
|
||||
offsetTable.ioAddress[(ea >> 20) + i] = (io >> 20) + i;
|
||||
offsetTable.eaAddress[(io >> 20) + i] = (ea >> 20) + i;
|
||||
render->strict_ordering[(io >> 20) + i] = is_strict;
|
||||
}
|
||||
}
|
||||
else
|
||||
@@ -992,7 +948,6 @@ s32 cellGcmMapMainMemory(u32 ea, u32 size, vm::ptr<u32> offset)
|
||||
{
|
||||
cellGcmSys.warning("cellGcmMapMainMemory(ea=0x%x, size=0x%x, offset=*0x%x)", ea, size, offset);
|
||||
|
||||
if (size == 0) return CELL_OK;
|
||||
if ((ea & 0xFFFFF) || (size & 0xFFFFF)) return CELL_GCM_ERROR_FAILURE;
|
||||
|
||||
u32 io = RSXIOMem.Map(ea, size);
|
||||
@@ -1007,6 +962,7 @@ s32 cellGcmMapMainMemory(u32 ea, u32 size, vm::ptr<u32> offset)
|
||||
{
|
||||
offsetTable.ioAddress[(ea >> 20) + i] = (u16)((io >> 20) + i);
|
||||
offsetTable.eaAddress[(io >> 20) + i] = (u16)((ea >> 20) + i);
|
||||
render->strict_ordering[(io >> 20) + i] = false;
|
||||
}
|
||||
|
||||
*offset = io;
|
||||
@@ -1157,27 +1113,23 @@ s32 cellGcmSetCursorImageOffset(u32 offset)
|
||||
void cellGcmSetDefaultCommandBuffer()
|
||||
{
|
||||
cellGcmSys.warning("cellGcmSetDefaultCommandBuffer()");
|
||||
auto m_config = fxm::get<CellGcmSysConfig>();
|
||||
if (m_config)
|
||||
vm::write32(m_config->ctxt_addr, m_config->gcm_info.context_addr);
|
||||
vm::write32(fxm::get<GSRender>()->ctxt_addr, gcm_info.context_addr);
|
||||
}
|
||||
|
||||
s32 cellGcmSetDefaultCommandBufferAndSegmentWordSize(u32 bufferSize, u32 segmentSize)
|
||||
{
|
||||
cellGcmSys.warning("cellGcmSetDefaultCommandBufferAndSegmentWordSize(bufferSize=0x%x, segmentSize=0x%x)", bufferSize, segmentSize);
|
||||
auto m_config = fxm::get<CellGcmSysConfig>();
|
||||
if (!m_config)
|
||||
return CELL_GCM_ERROR_FAILURE;
|
||||
const auto& put = vm::_ref<CellGcmControl>(m_config->gcm_info.control_addr).put;
|
||||
const auto& get = vm::_ref<CellGcmControl>(m_config->gcm_info.control_addr).get;
|
||||
|
||||
const auto& put = vm::_ref<CellGcmControl>(gcm_info.control_addr).put;
|
||||
const auto& get = vm::_ref<CellGcmControl>(gcm_info.control_addr).get;
|
||||
|
||||
if (put != 0x1000 || get != 0x1000 || bufferSize < segmentSize * 2)
|
||||
{
|
||||
return CELL_GCM_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
m_config->gcm_info.command_size = bufferSize;
|
||||
m_config->gcm_info.segment_size = segmentSize;
|
||||
gcm_info.command_size = bufferSize;
|
||||
gcm_info.segment_size = segmentSize;
|
||||
|
||||
return CELL_OK;
|
||||
}
|
||||
@@ -1196,11 +1148,9 @@ s32 _cellGcmSetFlipCommand(ppu_thread& ppu, vm::ptr<CellGcmContextData> ctx, u32
|
||||
s32 _cellGcmSetFlipCommandWithWaitLabel(ppu_thread& ppu, vm::ptr<CellGcmContextData> ctx, u32 id, u32 label_index, u32 label_value)
|
||||
{
|
||||
cellGcmSys.trace("cellGcmSetFlipCommandWithWaitLabel(ctx=*0x%x, id=0x%x, label_index=0x%x, label_value=0x%x)", ctx, id, label_index, label_value);
|
||||
auto m_config = fxm::get<CellGcmSysConfig>();
|
||||
if (!m_config)
|
||||
return CELL_GCM_ERROR_FAILURE;
|
||||
|
||||
s32 res = cellGcmSetPrepareFlip(ppu, ctx, id);
|
||||
vm::write32(m_config->gcm_info.label_addr + 0x10 * label_index, label_value);
|
||||
vm::write32(gcm_info.label_addr + 0x10 * label_index, label_value);
|
||||
return res < 0 ? CELL_GCM_ERROR_FAILURE : CELL_OK;
|
||||
}
|
||||
|
||||
@@ -1209,10 +1159,6 @@ s32 cellGcmSetTile(u8 index, u8 location, u32 offset, u32 size, u32 pitch, u8 co
|
||||
cellGcmSys.warning("cellGcmSetTile(index=%d, location=%d, offset=%d, size=%d, pitch=%d, comp=%d, base=%d, bank=%d)",
|
||||
index, location, offset, size, pitch, comp, base, bank);
|
||||
|
||||
auto m_config = fxm::get<CellGcmSysConfig>();
|
||||
if (!m_config)
|
||||
return CELL_GCM_ERROR_FAILURE;
|
||||
|
||||
// Copied form cellGcmSetTileInfo
|
||||
if (index >= rsx::limits::tiles_count || base >= 2048 || bank >= 4)
|
||||
{
|
||||
@@ -1248,7 +1194,7 @@ s32 cellGcmSetTile(u8 index, u8 location, u32 offset, u32 size, u32 pitch, u8 co
|
||||
tile.base = base;
|
||||
tile.bank = bank;
|
||||
|
||||
vm::_ptr<CellGcmTileInfo>(m_config->tiles_addr)[index] = tile.pack();
|
||||
vm::_ptr<CellGcmTileInfo>(render->tiles_addr)[index] = tile.pack();
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
@@ -1340,11 +1286,8 @@ static bool isInCommandBufferExcept(u32 getPos, u32 bufferBegin, u32 bufferEnd)
|
||||
s32 cellGcmCallback(ppu_thread& ppu, vm::ptr<CellGcmContextData> context, u32 count)
|
||||
{
|
||||
cellGcmSys.trace("cellGcmCallback(context=*0x%x, count=0x%x)", context, count);
|
||||
auto m_config = fxm::get<CellGcmSysConfig>();
|
||||
if (!m_config)
|
||||
return CELL_GCM_ERROR_FAILURE;
|
||||
|
||||
auto& ctrl = vm::_ref<CellGcmControl>(m_config->gcm_info.control_addr);
|
||||
auto& ctrl = vm::_ref<CellGcmControl>(gcm_info.control_addr);
|
||||
|
||||
// Flush command buffer (ie allow RSX to read up to context->current)
|
||||
ctrl.put.exchange(getOffsetFromAddress(context->current.addr()));
|
||||
@@ -1485,4 +1428,4 @@ DECLARE(ppu_module_manager::cellGcmSys)("cellGcmSys", []()
|
||||
|
||||
// Special
|
||||
REG_FUNC(cellGcmSys, cellGcmCallback).flags = MFF_HIDDEN;
|
||||
});
|
||||
});
|
||||
|
||||
@@ -141,12 +141,6 @@ s32 cellOskDialogExtRegisterKeyboardEventHookCallback(u16 hookEventMode, vm::ptr
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
s32 cellOskDialogExtRegisterKeyboardEventHookCallbackEx(u16 hookEventMode, vm::ptr<cellOskDialogHardwareKeyboardEventHookCallback> pCallback)
|
||||
{
|
||||
cellOskDialog.todo("cellOskDialogExtRegisterKeyboardEventHookCallbackEx(hookEventMode=%u, pCallback=*0x%x)", hookEventMode, pCallback);
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
s32 cellOskDialogExtAddJapaneseOptionDictionary(vm::cpptr<char> filePath)
|
||||
{
|
||||
cellOskDialog.todo("cellOskDialogExtAddJapaneseOptionDictionary(filePath=**0x%0x)", filePath);
|
||||
@@ -253,7 +247,6 @@ DECLARE(ppu_module_manager::cellOskDialog)("cellOskExtUtility", []()
|
||||
{
|
||||
REG_FUNC(cellOskExtUtility, cellOskDialogExtInputDeviceUnlock);
|
||||
REG_FUNC(cellOskExtUtility, cellOskDialogExtRegisterKeyboardEventHookCallback);
|
||||
REG_FUNC(cellOskExtUtility, cellOskDialogExtRegisterKeyboardEventHookCallbackEx);
|
||||
REG_FUNC(cellOskExtUtility, cellOskDialogExtAddJapaneseOptionDictionary);
|
||||
REG_FUNC(cellOskExtUtility, cellOskDialogExtEnableClipboard);
|
||||
REG_FUNC(cellOskExtUtility, cellOskDialogExtSendFinishMessage);
|
||||
|
||||
@@ -1,90 +1,41 @@
|
||||
#include "stdafx.h"
|
||||
#include "Emu/Cell/PPUModule.h"
|
||||
|
||||
namespace vm { using namespace ps3; }
|
||||
|
||||
logs::channel cellRec("cellRec");
|
||||
|
||||
struct CellRecSpursParam
|
||||
s32 cellRecOpen()
|
||||
{
|
||||
vm::bptr<struct CellSpurs> pSpurs;
|
||||
be_t<s32> spu_usage_rate;
|
||||
u8 priority[8];
|
||||
};
|
||||
|
||||
struct CellRecOption
|
||||
{
|
||||
be_t<s32> option;
|
||||
union
|
||||
{
|
||||
be_t<s32> ppu_thread_priority;
|
||||
be_t<s32> spu_thread_priority;
|
||||
be_t<s32> capture_priority;
|
||||
be_t<s32> use_system_spu;
|
||||
be_t<s32> fit_to_youtube;
|
||||
be_t<s32> xmb_bgm;
|
||||
be_t<s32> mpeg4_fast_encode;
|
||||
be_t<u32> ring_sec;
|
||||
be_t<s32> video_input;
|
||||
be_t<s32> audio_input;
|
||||
be_t<s32> audio_input_mix_vol;
|
||||
be_t<s32> reduce_memsize;
|
||||
be_t<s32> show_xmb;
|
||||
vm::bptr<char> metadata_filename;
|
||||
vm::bptr<CellRecSpursParam> pSpursParam;
|
||||
be_t<u64> dummy;
|
||||
} value;
|
||||
};
|
||||
|
||||
struct CellRecParam
|
||||
{
|
||||
be_t<s32> videoFmt;
|
||||
be_t<s32> audioFmt;
|
||||
be_t<s32> numOfOpt;
|
||||
vm::bptr<CellRecOption> pOpt;
|
||||
};
|
||||
|
||||
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)
|
||||
{
|
||||
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);
|
||||
return CELL_OK;
|
||||
fmt::throw_exception("Unimplemented" HERE);
|
||||
}
|
||||
|
||||
s32 cellRecClose(s32 isDiscard)
|
||||
s32 cellRecClose()
|
||||
{
|
||||
cellRec.todo("cellRecClose(isDiscard=0x%x)", isDiscard);
|
||||
return CELL_OK;
|
||||
fmt::throw_exception("Unimplemented" HERE);
|
||||
}
|
||||
|
||||
void cellRecGetInfo(s32 info, vm::ptr<u64> pValue)
|
||||
s32 cellRecGetInfo()
|
||||
{
|
||||
cellRec.todo("cellRecGetInfo(info=0x%x, pValue=*0x%x)", info, pValue);
|
||||
fmt::throw_exception("Unimplemented" HERE);
|
||||
}
|
||||
|
||||
s32 cellRecStop()
|
||||
{
|
||||
cellRec.todo("cellRecStop()");
|
||||
return CELL_OK;
|
||||
fmt::throw_exception("Unimplemented" HERE);
|
||||
}
|
||||
|
||||
s32 cellRecStart()
|
||||
{
|
||||
cellRec.todo("cellRecStart()");
|
||||
return CELL_OK;
|
||||
fmt::throw_exception("Unimplemented" HERE);
|
||||
}
|
||||
|
||||
u32 cellRecQueryMemSize(vm::cptr<CellRecParam> pParam)
|
||||
s32 cellRecQueryMemSize()
|
||||
{
|
||||
cellRec.todo("cellRecQueryMemSize(pParam=*0x%x)", pParam);
|
||||
return 1 * 1024 * 1024; // dummy memory size
|
||||
fmt::throw_exception("Unimplemented" HERE);
|
||||
}
|
||||
|
||||
s32 cellRecSetInfo(s32 setInfo, u64 value)
|
||||
s32 cellRecSetInfo()
|
||||
{
|
||||
cellRec.todo("cellRecSetInfo(setInfo=0x%x, value=0x%x)", setInfo, value);
|
||||
return CELL_OK;
|
||||
fmt::throw_exception("Unimplemented" HERE);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -123,8 +123,8 @@ s32 cellRescGetFlipStatus()
|
||||
|
||||
s32 cellRescGetRegisterCount()
|
||||
{
|
||||
cellResc.todo("cellRescGetRegisterCount()");
|
||||
return 0;
|
||||
UNIMPLEMENTED_FUNC(cellResc);
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
u64 cellRescGetLastFlipTime()
|
||||
@@ -134,9 +134,10 @@ u64 cellRescGetLastFlipTime()
|
||||
return 0;
|
||||
}
|
||||
|
||||
void cellRescSetRegisterCount(s32 regCount)
|
||||
s32 cellRescSetRegisterCount()
|
||||
{
|
||||
cellResc.todo("cellRescSetRegisterCount(regCount=0x%x)", regCount);
|
||||
UNIMPLEMENTED_FUNC(cellResc);
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
void cellRescSetVBlankHandler(vm::ptr<void(u32)> handler)
|
||||
|
||||
@@ -248,126 +248,12 @@ s32 cellSailRecorderCancel()
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
s32 cellSailRecorderRegisterComposer()
|
||||
{
|
||||
UNIMPLEMENTED_FUNC(cellSailRec);
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
s32 cellSailRecorderUnregisterComposer()
|
||||
{
|
||||
UNIMPLEMENTED_FUNC(cellSailRec);
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
s32 cellSailRecorderDumpImage()
|
||||
{
|
||||
UNIMPLEMENTED_FUNC(cellSailRec);
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
s32 cellSailComposerInitialize()
|
||||
{
|
||||
UNIMPLEMENTED_FUNC(cellSailRec);
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
s32 cellSailComposerFinalize()
|
||||
{
|
||||
UNIMPLEMENTED_FUNC(cellSailRec);
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
s32 cellSailComposerGetStreamParameter()
|
||||
{
|
||||
UNIMPLEMENTED_FUNC(cellSailRec);
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
s32 cellSailComposerGetEsAudioParameter()
|
||||
{
|
||||
UNIMPLEMENTED_FUNC(cellSailRec);
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
s32 cellSailComposerGetEsUserParameter()
|
||||
{
|
||||
UNIMPLEMENTED_FUNC(cellSailRec);
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
s32 cellSailComposerGetEsVideoParameter()
|
||||
{
|
||||
UNIMPLEMENTED_FUNC(cellSailRec);
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
s32 cellSailComposerGetEsAudioAu()
|
||||
{
|
||||
UNIMPLEMENTED_FUNC(cellSailRec);
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
s32 cellSailComposerGetEsUserAu()
|
||||
{
|
||||
UNIMPLEMENTED_FUNC(cellSailRec);
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
s32 cellSailComposerGetEsVideoAu()
|
||||
{
|
||||
UNIMPLEMENTED_FUNC(cellSailRec);
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
s32 cellSailComposerTryGetEsAudioAu()
|
||||
{
|
||||
UNIMPLEMENTED_FUNC(cellSailRec);
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
s32 cellSailComposerTryGetEsUserAu()
|
||||
{
|
||||
UNIMPLEMENTED_FUNC(cellSailRec);
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
s32 cellSailComposerTryGetEsVideoAu()
|
||||
{
|
||||
UNIMPLEMENTED_FUNC(cellSailRec);
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
s32 cellSailComposerReleaseEsAudioAu()
|
||||
{
|
||||
UNIMPLEMENTED_FUNC(cellSailRec);
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
s32 cellSailComposerReleaseEsUserAu()
|
||||
{
|
||||
UNIMPLEMENTED_FUNC(cellSailRec);
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
s32 cellSailComposerReleaseEsVideoAu()
|
||||
{
|
||||
UNIMPLEMENTED_FUNC(cellSailRec);
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
s32 cellSailComposerNotifyCallCompleted()
|
||||
{
|
||||
UNIMPLEMENTED_FUNC(cellSailRec);
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
s32 cellSailComposerNotifySessionError()
|
||||
{
|
||||
UNIMPLEMENTED_FUNC(cellSailRec);
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
DECLARE(ppu_module_manager::cellSailRec)("cellSailRec", []()
|
||||
{
|
||||
static ppu_static_module cellMp4("cellMp4");
|
||||
@@ -415,26 +301,6 @@ DECLARE(ppu_module_manager::cellSailRec)("cellSailRec", []()
|
||||
REG_FUNC(cellSailRec, cellSailRecorderStart);
|
||||
REG_FUNC(cellSailRec, cellSailRecorderStop);
|
||||
REG_FUNC(cellSailRec, cellSailRecorderCancel);
|
||||
REG_FUNC(cellSailRec, cellSailRecorderRegisterComposer);
|
||||
REG_FUNC(cellSailRec, cellSailRecorderUnregisterComposer);
|
||||
|
||||
REG_FUNC(cellSailRec, cellSailRecorderDumpImage);
|
||||
|
||||
REG_FUNC(cellSailRec, cellSailComposerInitialize);
|
||||
REG_FUNC(cellSailRec, cellSailComposerFinalize);
|
||||
REG_FUNC(cellSailRec, cellSailComposerGetStreamParameter);
|
||||
REG_FUNC(cellSailRec, cellSailComposerGetEsAudioParameter);
|
||||
REG_FUNC(cellSailRec, cellSailComposerGetEsUserParameter);
|
||||
REG_FUNC(cellSailRec, cellSailComposerGetEsVideoParameter);
|
||||
REG_FUNC(cellSailRec, cellSailComposerGetEsAudioAu);
|
||||
REG_FUNC(cellSailRec, cellSailComposerGetEsUserAu);
|
||||
REG_FUNC(cellSailRec, cellSailComposerGetEsVideoAu);
|
||||
REG_FUNC(cellSailRec, cellSailComposerTryGetEsAudioAu);
|
||||
REG_FUNC(cellSailRec, cellSailComposerTryGetEsUserAu);
|
||||
REG_FUNC(cellSailRec, cellSailComposerTryGetEsVideoAu);
|
||||
REG_FUNC(cellSailRec, cellSailComposerReleaseEsAudioAu);
|
||||
REG_FUNC(cellSailRec, cellSailComposerReleaseEsUserAu);
|
||||
REG_FUNC(cellSailRec, cellSailComposerReleaseEsVideoAu);
|
||||
REG_FUNC(cellSailRec, cellSailComposerNotifyCallCompleted);
|
||||
REG_FUNC(cellSailRec, cellSailComposerNotifySessionError);
|
||||
});
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#include "stdafx.h"
|
||||
#include "stdafx.h"
|
||||
#include "Emu/System.h"
|
||||
#include "Emu/Cell/PPUModule.h"
|
||||
#include "Emu/Cell/Modules/cellSysutil.h"
|
||||
@@ -725,7 +725,7 @@ s32 static NEVER_INLINE save_op_get_list_item(vm::cptr<char> dirName, vm::ptr<Ce
|
||||
userId = 1u;
|
||||
}
|
||||
std::string save_path = vfs::get(fmt::format("/dev_hdd0/home/%08u/savedata/%s/", userId, dirName.get_ptr()));
|
||||
std::string sfo = save_path + "PARAM.SFO";
|
||||
std::string sfo = save_path + "param.sfo";
|
||||
|
||||
if (!fs::is_dir(save_path) && !fs::is_file(sfo))
|
||||
{
|
||||
@@ -743,26 +743,20 @@ s32 static NEVER_INLINE save_op_get_list_item(vm::cptr<char> dirName, vm::ptr<Ce
|
||||
strcpy_trunc(sysFileParam->detail, psf.at("DETAIL").as_string());
|
||||
}
|
||||
|
||||
if (dir)
|
||||
fs::stat_t dir_info{};
|
||||
if (!fs::stat(save_path, dir_info))
|
||||
{
|
||||
fs::stat_t dir_info{};
|
||||
if (!fs::stat(save_path, dir_info))
|
||||
{
|
||||
return CELL_SAVEDATA_ERROR_INTERNAL;
|
||||
}
|
||||
|
||||
// get file stats, namely directory
|
||||
strcpy_trunc(dir->dirName, dirName.get_ptr());
|
||||
dir->atime = dir_info.atime;
|
||||
dir->ctime = dir_info.ctime;
|
||||
dir->mtime = dir_info.mtime;
|
||||
return CELL_SAVEDATA_ERROR_INTERNAL;
|
||||
}
|
||||
|
||||
if (bind)
|
||||
{
|
||||
//TODO: Set bind in accordance to any problems
|
||||
*bind = 0;
|
||||
}
|
||||
// get file stats, namely directory
|
||||
strcpy_trunc(dir->dirName, dirName.get_ptr());
|
||||
dir->atime = dir_info.atime;
|
||||
dir->ctime = dir_info.ctime;
|
||||
dir->mtime = dir_info.mtime;
|
||||
|
||||
//TODO: Set bind in accordance to any problems
|
||||
*bind = 0;
|
||||
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
+29
-38
@@ -1,9 +1,9 @@
|
||||
#include "stdafx.h"
|
||||
#include "Emu/Cell/PPUModule.h"
|
||||
|
||||
#include "cellSubDisplay.h"
|
||||
#include "cellSubdisplay.h"
|
||||
|
||||
logs::channel cellSubDisplay("cellSubDisplay");
|
||||
logs::channel cellSubdisplay("cellSubdisplay");
|
||||
|
||||
template<>
|
||||
void fmt_class_string<CellSubDisplayError>::format(std::string& out, u64 arg)
|
||||
@@ -28,51 +28,51 @@ void fmt_class_string<CellSubDisplayError>::format(std::string& out, u64 arg)
|
||||
|
||||
error_code cellSubDisplayInit(vm::ptr<CellSubDisplayParam> pParam, vm::ptr<CellSubDisplayHandler> func, vm::ptr<void> userdata, u32 container)
|
||||
{
|
||||
cellSubDisplay.todo("cellSubDisplayInit(pParam=*0x%x, func=*0x%x, userdata=*0x%x, container=0x%x)", pParam, func, userdata, container);
|
||||
cellSubdisplay.todo("cellSubDisplayInit(pParam=*0x%x, func=*0x%x, userdata=*0x%x, container=0x%x)", pParam, func, userdata, container);
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
error_code cellSubDisplayEnd()
|
||||
{
|
||||
cellSubDisplay.todo("cellSubDisplayEnd()");
|
||||
cellSubdisplay.todo("cellSubDisplayEnd()");
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
error_code cellSubDisplayGetRequiredMemory(vm::ptr<CellSubDisplayParam> pParam)
|
||||
{
|
||||
cellSubDisplay.warning("cellSubDisplayGetRequiredMemory(pParam=*0x%x)", pParam);
|
||||
cellSubdisplay.warning("cellSubDisplayGetRequiredMemory(pParam=*0x%x)", pParam);
|
||||
|
||||
switch (pParam->version)
|
||||
if (pParam->version == CELL_SUBDISPLAY_VERSION_0002)
|
||||
{
|
||||
case CELL_SUBDISPLAY_VERSION_0001: return not_an_error(CELL_SUBDISPLAY_0001_MEMORY_CONTAINER_SIZE);
|
||||
case CELL_SUBDISPLAY_VERSION_0002: return not_an_error(CELL_SUBDISPLAY_0002_MEMORY_CONTAINER_SIZE);
|
||||
case CELL_SUBDISPLAY_VERSION_0003: return not_an_error(CELL_SUBDISPLAY_0003_MEMORY_CONTAINER_SIZE);
|
||||
return not_an_error(CELL_SUBDISPLAY_0002_MEMORY_CONTAINER_SIZE);
|
||||
}
|
||||
else
|
||||
{
|
||||
return not_an_error(CELL_SUBDISPLAY_0001_MEMORY_CONTAINER_SIZE);
|
||||
}
|
||||
|
||||
return CELL_SUBDISPLAY_ERROR_INVALID_VALUE;
|
||||
}
|
||||
|
||||
error_code cellSubDisplayStart()
|
||||
{
|
||||
cellSubDisplay.todo("cellSubDisplayStart()");
|
||||
cellSubdisplay.todo("cellSubDisplayStart()");
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
error_code cellSubDisplayStop()
|
||||
{
|
||||
cellSubDisplay.todo("cellSubDisplayStop()");
|
||||
cellSubdisplay.todo("cellSubDisplayStop()");
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
error_code cellSubDisplayGetVideoBuffer(s32 groupId, vm::pptr<void> ppVideoBuf, vm::ptr<u32> pSize)
|
||||
{
|
||||
cellSubDisplay.todo("cellSubDisplayGetVideoBuffer(groupId=%d, ppVideoBuf=**0x%x, pSize=*0x%x)", groupId, ppVideoBuf, pSize);
|
||||
cellSubdisplay.todo("cellSubDisplayGetVideoBuffer(groupId=%d, ppVideoBuf=**0x%x, pSize=*0x%x)", groupId, ppVideoBuf, pSize);
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
error_code cellSubDisplayAudioOutBlocking(s32 groupId, vm::ptr<void> pvData, s32 samples)
|
||||
{
|
||||
cellSubDisplay.todo("cellSubDisplayAudioOutBlocking(groupId=%d, pvData=*0x%x, samples=%d)", groupId, pvData, samples);
|
||||
cellSubdisplay.todo("cellSubDisplayAudioOutBlocking(groupId=%d, pvData=*0x%x, samples=%d)", groupId, pvData, samples);
|
||||
|
||||
if (samples % 1024)
|
||||
{
|
||||
@@ -84,7 +84,7 @@ error_code cellSubDisplayAudioOutBlocking(s32 groupId, vm::ptr<void> pvData, s32
|
||||
|
||||
error_code cellSubDisplayAudioOutNonBlocking(s32 groupId, vm::ptr<void> pvData, s32 samples)
|
||||
{
|
||||
cellSubDisplay.todo("cellSubDisplayAudioOutNonBlocking(groupId=%d, pvData=*0x%x, samples=%d)", groupId, pvData, samples);
|
||||
cellSubdisplay.todo("cellSubDisplayAudioOutNonBlocking(groupId=%d, pvData=*0x%x, samples=%d)", groupId, pvData, samples);
|
||||
|
||||
if (samples % 1024)
|
||||
{
|
||||
@@ -96,43 +96,34 @@ error_code cellSubDisplayAudioOutNonBlocking(s32 groupId, vm::ptr<void> pvData,
|
||||
|
||||
error_code cellSubDisplayGetPeerNum(s32 groupId)
|
||||
{
|
||||
cellSubDisplay.todo("cellSubDisplayGetPeerNum(groupId=%d)", groupId);
|
||||
cellSubdisplay.todo("cellSubDisplayGetPeerNum(groupId=%d)", groupId);
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
error_code cellSubDisplayGetPeerList(s32 groupId, vm::ptr<CellSubDisplayPeerInfo> pInfo, vm::ptr<s32> pNum)
|
||||
{
|
||||
cellSubDisplay.todo("cellSubDisplayGetPeerList(groupId=%d, pInfo=*0x%x, pNum=*0x%x)", groupId, pInfo, pNum);
|
||||
cellSubdisplay.todo("cellSubDisplayGetPeerList(groupId=%d, pInfo=*0x%x, pNum=*0x%x)", groupId, pInfo, pNum);
|
||||
|
||||
*pNum = 0;
|
||||
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
error_code cellSubDisplayGetTouchInfo(s32 groupId, vm::ptr<CellSubDisplayTouchInfo> pTouchInfo, vm::ptr<s32> pNumTouchInfo)
|
||||
{
|
||||
cellSubDisplay.todo("cellSubDisplayGetTouchInfo(groupId=%d, pTouchInfo=*0x%x, pNumTouchInfo=*0x%x)", groupId, pTouchInfo, pNumTouchInfo);
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
DECLARE(ppu_module_manager::cellSubDisplay)("cellSubDisplay", []()
|
||||
DECLARE(ppu_module_manager::cellSubdisplay)("cellSubdisplay", []()
|
||||
{
|
||||
// Initialization / Termination Functions
|
||||
REG_FUNC(cellSubDisplay, cellSubDisplayInit);
|
||||
REG_FUNC(cellSubDisplay, cellSubDisplayEnd);
|
||||
REG_FUNC(cellSubDisplay, cellSubDisplayGetRequiredMemory);
|
||||
REG_FUNC(cellSubDisplay, cellSubDisplayStart);
|
||||
REG_FUNC(cellSubDisplay, cellSubDisplayStop);
|
||||
REG_FUNC(cellSubdisplay, cellSubDisplayInit);
|
||||
REG_FUNC(cellSubdisplay, cellSubDisplayEnd);
|
||||
REG_FUNC(cellSubdisplay, cellSubDisplayGetRequiredMemory);
|
||||
REG_FUNC(cellSubdisplay, cellSubDisplayStart);
|
||||
REG_FUNC(cellSubdisplay, cellSubDisplayStop);
|
||||
|
||||
// Data Setting Functions
|
||||
REG_FUNC(cellSubDisplay, cellSubDisplayGetVideoBuffer);
|
||||
REG_FUNC(cellSubDisplay, cellSubDisplayAudioOutBlocking);
|
||||
REG_FUNC(cellSubDisplay, cellSubDisplayAudioOutNonBlocking);
|
||||
REG_FUNC(cellSubdisplay, cellSubDisplayGetVideoBuffer);
|
||||
REG_FUNC(cellSubdisplay, cellSubDisplayAudioOutBlocking);
|
||||
REG_FUNC(cellSubdisplay, cellSubDisplayAudioOutNonBlocking);
|
||||
|
||||
// Peer Status Acquisition Functions
|
||||
REG_FUNC(cellSubDisplay, cellSubDisplayGetPeerNum);
|
||||
REG_FUNC(cellSubDisplay, cellSubDisplayGetPeerList);
|
||||
|
||||
//
|
||||
REG_FUNC(cellSubDisplay, cellSubDisplayGetTouchInfo);
|
||||
REG_FUNC(cellSubdisplay, cellSubDisplayGetPeerNum);
|
||||
REG_FUNC(cellSubdisplay, cellSubDisplayGetPeerList);
|
||||
});
|
||||
@@ -23,11 +23,9 @@ enum
|
||||
CELL_SUBDISPLAY_STATUS_FATALERROR = 3,
|
||||
CELL_SUBDISPLAY_VERSION_0001 = 1,
|
||||
CELL_SUBDISPLAY_VERSION_0002 = 2,
|
||||
CELL_SUBDISPLAY_VERSION_0003 = 3,
|
||||
CELL_SUBDISPLAY_MODE_REMOTEPLAY = 1,
|
||||
CELL_SUBDISPLAY_VIDEO_FORMAT_A8R8G8B8 = 1,
|
||||
CELL_SUBDISPLAY_VIDEO_FORMAT_R8G8B8A8 = 2,
|
||||
CELL_SUBDISPLAY_VIDEO_FORMAT_YUV420 = 3,
|
||||
CELL_SUBDISPLAY_VIDEO_ASPECT_RATIO_16_9 = 0,
|
||||
CELL_SUBDISPLAY_VIDEO_ASPECT_RATIO_4_3 = 1,
|
||||
CELL_SUBDISPLAY_VIDEO_MODE_SETDATA = 0,
|
||||
@@ -36,7 +34,6 @@ enum
|
||||
CELL_SUBDISPLAY_AUDIO_MODE_CAPTURE = 1,
|
||||
CELL_SUBDISPLAY_0001_MEMORY_CONTAINER_SIZE = 8 * 1024 * 1024,
|
||||
CELL_SUBDISPLAY_0002_MEMORY_CONTAINER_SIZE = 10 * 1024 * 1024,
|
||||
CELL_SUBDISPLAY_0003_MEMORY_CONTAINER_SIZE = 10 * 1024 * 1024,
|
||||
CELL_SUBDISPLAY_NICKNAME_LEN = 256,
|
||||
CELL_SUBDISPLAY_PSPID_LEN = 16,
|
||||
};
|
||||
@@ -85,12 +82,4 @@ struct CellSubDisplayPeerInfo
|
||||
CellSubDisplayNickname pspNickname;
|
||||
};
|
||||
|
||||
struct CellSubDisplayTouchInfo
|
||||
{
|
||||
u8 status;
|
||||
u8 force;
|
||||
be_t<u16> x;
|
||||
be_t<u16> y;
|
||||
};
|
||||
|
||||
using CellSubDisplayHandler = void(s32 cbMsg, u64 cbParam, vm::ptr<void> userdata);
|
||||
@@ -251,7 +251,6 @@ static const char* get_module_id(u16 id)
|
||||
case 0xf034: return "CELL_SYSMODULE_SAIL_REC";
|
||||
case 0xf035: return "CELL_SYSMODULE_SYSUTIL_NP_TROPHY";
|
||||
case 0xf044: return "CELL_SYSMODULE_SYSUTIL_NP_EULA";
|
||||
case 0xf053: return "CELL_SYSMODULE_ADEC_AT3MULTI";
|
||||
case 0xf054: return "CELL_SYSMODULE_LIBATRAC3MULTI";
|
||||
case 0xffff: return "CELL_SYSMODULE_INVALID";
|
||||
}
|
||||
|
||||
@@ -471,12 +471,6 @@ s32 _ZN4cxml8DocumentD1Ev()
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
s32 _ZN4cxml8Document5ClearEv()
|
||||
{
|
||||
UNIMPLEMENTED_FUNC(cellSysutil);
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
s32 _ZN4cxml8Document13CreateElementEPKciPNS_7ElementE()
|
||||
{
|
||||
UNIMPLEMENTED_FUNC(cellSysutil);
|
||||
@@ -513,12 +507,6 @@ s32 _ZNK4cxml7Element12GetAttributeEPKcPNS_9AttributeE()
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
s32 _ZNK4cxml7Element13GetFirstChildEv()
|
||||
{
|
||||
UNIMPLEMENTED_FUNC(cellSysutil);
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
s32 _ZNK4cxml7Element14GetNextSiblingEv()
|
||||
{
|
||||
UNIMPLEMENTED_FUNC(cellSysutil);
|
||||
@@ -549,12 +537,6 @@ s32 _ZN8cxmlutil6GetIntERKN4cxml7ElementEPKcPi()
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
s32 _ZN8cxmlutil8GetFloatERKN4cxml7ElementEPKcPf()
|
||||
{
|
||||
UNIMPLEMENTED_FUNC(cellSysutil);
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
s32 _ZN8cxmlutil9GetStringERKN4cxml7ElementEPKcPS5_Pj()
|
||||
{
|
||||
UNIMPLEMENTED_FUNC(cellSysutil);
|
||||
@@ -654,7 +636,6 @@ DECLARE(ppu_module_manager::cellSysutil)("cellSysutil", []()
|
||||
|
||||
REG_FUNC(cellSysutil, _ZN4cxml8DocumentC1Ev);
|
||||
REG_FUNC(cellSysutil, _ZN4cxml8DocumentD1Ev);
|
||||
REG_FUNC(cellSysutil, _ZN4cxml8Document5ClearEv);
|
||||
REG_FUNC(cellSysutil, _ZN4cxml8Document13CreateElementEPKciPNS_7ElementE);
|
||||
REG_FUNC(cellSysutil, _ZN4cxml8Document14SetHeaderMagicEPKc);
|
||||
REG_FUNC(cellSysutil, _ZN4cxml8Document16CreateFromBufferEPKvjb);
|
||||
@@ -662,14 +643,12 @@ DECLARE(ppu_module_manager::cellSysutil)("cellSysutil", []()
|
||||
|
||||
REG_FUNC(cellSysutil, _ZNK4cxml4File7GetAddrEv);
|
||||
REG_FUNC(cellSysutil, _ZNK4cxml7Element12GetAttributeEPKcPNS_9AttributeE);
|
||||
REG_FUNC(cellSysutil, _ZNK4cxml7Element13GetFirstChildEv);
|
||||
REG_FUNC(cellSysutil, _ZNK4cxml7Element14GetNextSiblingEv);
|
||||
REG_FUNC(cellSysutil, _ZNK4cxml9Attribute6GetIntEPi);
|
||||
REG_FUNC(cellSysutil, _ZNK4cxml9Attribute7GetFileEPNS_4FileE);
|
||||
|
||||
REG_FUNC(cellSysutil, _ZN8cxmlutil6SetIntERKN4cxml7ElementEPKci);
|
||||
REG_FUNC(cellSysutil, _ZN8cxmlutil6GetIntERKN4cxml7ElementEPKcPi);
|
||||
REG_FUNC(cellSysutil, _ZN8cxmlutil8GetFloatERKN4cxml7ElementEPKcPf);
|
||||
REG_FUNC(cellSysutil, _ZN8cxmlutil9GetStringERKN4cxml7ElementEPKcPS5_Pj);
|
||||
REG_FUNC(cellSysutil, _ZN8cxmlutil9SetStringERKN4cxml7ElementEPKcS5_);
|
||||
REG_FUNC(cellSysutil, _ZN8cxmlutil16CheckElementNameERKN4cxml7ElementEPKc);
|
||||
|
||||
@@ -54,8 +54,7 @@ s32 cellSysutilAvc2SetVoiceMuting()
|
||||
|
||||
s32 cellSysutilAvc2StartVoiceDetection()
|
||||
{
|
||||
cellSysutilAvc2.todo("cellSysutilAvc2StartVoiceDetection()");
|
||||
return CELL_OK;
|
||||
fmt::throw_exception("Unimplemented" HERE);
|
||||
}
|
||||
|
||||
s32 cellSysutilAvc2UnloadAsync()
|
||||
@@ -88,10 +87,10 @@ s32 cellSysutilAvc2SetWindowString()
|
||||
fmt::throw_exception("Unimplemented" HERE);
|
||||
}
|
||||
|
||||
s32 cellSysutilAvc2EstimateMemoryContainerSize(vm::cptr<CellSysutilAvc2InitParam> initparam, vm::ptr<u32> size)
|
||||
s32 cellSysutilAvc2EstimateMemoryContainerSize()
|
||||
{
|
||||
cellSysutilAvc2.todo("cellSysutilAvc2EstimateMemoryContainerSize(initparam=*0x%x, size=*0x%x)", initparam, size);
|
||||
return CELL_OK;
|
||||
UNIMPLEMENTED_FUNC(cellSysutilAvc2);
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
s32 cellSysutilAvc2SetVideoMuting()
|
||||
@@ -131,10 +130,9 @@ s32 cellSysutilAvc2GetSpeakerVolumeLevel()
|
||||
|
||||
s32 cellSysutilAvc2IsCameraAttached(vm::ptr<u8> status)
|
||||
{
|
||||
cellSysutilAvc2.todo("cellSysutilAvc2IsCameraAttached(status=*0x%x)", status);
|
||||
cellSysutilAvc2.todo("cellSysutilAvc2IsCameraAttached()");
|
||||
|
||||
*status = CELL_AVC2_CAMERA_STATUS_DETACHED;
|
||||
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
@@ -275,16 +273,14 @@ s32 cellSysutilAvc2SetSpeakerMuting()
|
||||
fmt::throw_exception("Unimplemented" HERE);
|
||||
}
|
||||
|
||||
s32 cellSysutilAvc2Load(SceNpMatching2ContextId ctx_id, u32 container, vm::ptr<CellSysutilAvc2Callback> callback_func, vm::ptr<void> user_data, vm::cptr<CellSysutilAvc2InitParam> init_param)
|
||||
s32 cellSysutilAvc2Load()
|
||||
{
|
||||
cellSysutilAvc2.todo("cellSysutilAvc2Load(ctx_id=0x%x, container=0x%x, callback_func=*0x%x, user_data=*0x%x, init_param=*0x%x)", ctx_id, container, callback_func, user_data, init_param);
|
||||
return CELL_OK;
|
||||
fmt::throw_exception("Unimplemented" HERE);
|
||||
}
|
||||
|
||||
s32 cellSysutilAvc2SetAttribute(vm::cptr<CellSysutilAvc2Attribute> attr)
|
||||
s32 cellSysutilAvc2SetAttribute()
|
||||
{
|
||||
cellSysutilAvc2.todo("cellSysutilAvc2SetAttribute(attr=*0x%x)", attr);
|
||||
return CELL_OK;
|
||||
fmt::throw_exception("Unimplemented" HERE);
|
||||
}
|
||||
|
||||
s32 cellSysutilAvc2UnloadAsync2()
|
||||
@@ -307,13 +303,10 @@ s32 cellSysutilAvc2HideWindow()
|
||||
fmt::throw_exception("Unimplemented" HERE);
|
||||
}
|
||||
|
||||
s32 cellSysutilAvc2GetVoiceMuting(vm::ptr<u8> muting)
|
||||
s32 cellSysutilAvc2GetVoiceMuting()
|
||||
{
|
||||
cellSysutilAvc2.todo("cellSysutilAvc2GetVoiceMuting(muting=*0x%x)", muting);
|
||||
|
||||
*muting = 1;
|
||||
|
||||
return CELL_OK;
|
||||
UNIMPLEMENTED_FUNC(cellSysutilAvc2);
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
s32 cellSysutilAvc2GetScreenShowStatus()
|
||||
|
||||
@@ -511,9 +511,9 @@ s32 sceNpBasicGetEvent(vm::ptr<s32> event, vm::ptr<SceNpUserInfo> from, vm::ptr<
|
||||
sceNp.warning("sceNpBasicGetEvent(event=*0x%x, from=*0x%x, data=*0x%x, size=*0x%x)", event, from, data, size);
|
||||
|
||||
// TODO: Check for other error and pass other events
|
||||
//*event = SCE_NP_BASIC_EVENT_OFFLINE; // This event only indicates a contact is offline, not the current status of the connection
|
||||
*event = SCE_NP_BASIC_EVENT_OFFLINE;
|
||||
|
||||
return SCE_NP_BASIC_ERROR_NO_EVENT;
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
s32 sceNpCommerceCreateCtx()
|
||||
@@ -1511,18 +1511,6 @@ s32 sceNpScoreGetRankingByRangeAsync()
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
s32 sceNpScoreGetFriendsRanking()
|
||||
{
|
||||
UNIMPLEMENTED_FUNC(sceNp);
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
s32 sceNpScoreGetFriendsRankingAsync()
|
||||
{
|
||||
UNIMPLEMENTED_FUNC(sceNp);
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
s32 sceNpScoreCensorComment()
|
||||
{
|
||||
UNIMPLEMENTED_FUNC(sceNp);
|
||||
@@ -2025,8 +2013,6 @@ DECLARE(ppu_module_manager::sceNp)("sceNp", []()
|
||||
REG_FUNC(sceNp, sceNpScoreGetRankingByNpIdAsync);
|
||||
REG_FUNC(sceNp, sceNpScoreGetRankingByRange);
|
||||
REG_FUNC(sceNp, sceNpScoreGetRankingByRangeAsync);
|
||||
REG_FUNC(sceNp, sceNpScoreGetFriendsRanking);
|
||||
REG_FUNC(sceNp, sceNpScoreGetFriendsRankingAsync);
|
||||
REG_FUNC(sceNp, sceNpScoreCensorComment);
|
||||
REG_FUNC(sceNp, sceNpScoreCensorCommentAsync);
|
||||
REG_FUNC(sceNp, sceNpScoreSanitizeComment);
|
||||
|
||||
@@ -678,7 +678,7 @@ union SceNpSignalingConnectionInfo
|
||||
SceNpId npId;
|
||||
struct address {
|
||||
be_t<u32> addr; // in_addr
|
||||
be_t<u16> port; // in_port_t
|
||||
//in_port_t port; // TODO: Implement this?
|
||||
};
|
||||
be_t<u32> packet_loss;
|
||||
};
|
||||
|
||||
@@ -469,42 +469,6 @@ s32 sceNpMatching2SignalingGetPeerNetInfoResult()
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
s32 sceNpAuthOAuthInit()
|
||||
{
|
||||
UNIMPLEMENTED_FUNC(sceNp2);
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
s32 sceNpAuthOAuthTerm()
|
||||
{
|
||||
UNIMPLEMENTED_FUNC(sceNp2);
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
s32 sceNpAuthCreateOAuthRequest()
|
||||
{
|
||||
UNIMPLEMENTED_FUNC(sceNp2);
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
s32 sceNpAuthDeleteOAuthRequest()
|
||||
{
|
||||
UNIMPLEMENTED_FUNC(sceNp2);
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
s32 sceNpAuthAbortOAuthRequest()
|
||||
{
|
||||
UNIMPLEMENTED_FUNC(sceNp2);
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
s32 sceNpAuthGetAuthorizationCode()
|
||||
{
|
||||
UNIMPLEMENTED_FUNC(sceNp2);
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
DECLARE(ppu_module_manager::sceNp2)("sceNp2", []()
|
||||
{
|
||||
REG_FUNC(sceNp2, sceNpMatching2DestroyContext);
|
||||
@@ -580,11 +544,4 @@ DECLARE(ppu_module_manager::sceNp2)("sceNp2", []()
|
||||
REG_FUNC(sceNp2, sceNpMatching2SignalingGetLocalNetInfo);
|
||||
REG_FUNC(sceNp2, sceNpMatching2SignalingGetPeerNetInfo);
|
||||
REG_FUNC(sceNp2, sceNpMatching2SignalingGetPeerNetInfoResult);
|
||||
|
||||
REG_FUNC(sceNp2, sceNpAuthOAuthInit);
|
||||
REG_FUNC(sceNp2, sceNpAuthOAuthTerm);
|
||||
REG_FUNC(sceNp2, sceNpAuthCreateOAuthRequest);
|
||||
REG_FUNC(sceNp2, sceNpAuthDeleteOAuthRequest);
|
||||
REG_FUNC(sceNp2, sceNpAuthAbortOAuthRequest);
|
||||
REG_FUNC(sceNp2, sceNpAuthGetAuthorizationCode);
|
||||
});
|
||||
|
||||
@@ -155,11 +155,6 @@ s32 sceNpSnsFbLoadThrottle()
|
||||
fmt::throw_exception("Unimplemented" HERE);
|
||||
}
|
||||
|
||||
s32 sceNpSnsFbGetLongAccessToken()
|
||||
{
|
||||
fmt::throw_exception("Unimplemented" HERE);
|
||||
}
|
||||
|
||||
|
||||
DECLARE(ppu_module_manager::sceNpSns)("sceNpSns", []()
|
||||
{
|
||||
@@ -169,7 +164,7 @@ DECLARE(ppu_module_manager::sceNpSns)("sceNpSns", []()
|
||||
REG_FUNC(sceNpSns, sceNpSnsFbDestroyHandle);
|
||||
REG_FUNC(sceNpSns, sceNpSnsFbAbortHandle);
|
||||
REG_FUNC(sceNpSns, sceNpSnsFbGetAccessToken);
|
||||
REG_FUNC(sceNpSns, sceNpSnsFbGetLongAccessToken);
|
||||
|
||||
REG_FUNC(sceNpSns, sceNpSnsFbStreamPublish);
|
||||
REG_FUNC(sceNpSns, sceNpSnsFbCheckThrottle);
|
||||
REG_FUNC(sceNpSns, sceNpSnsFbCheckConfig);
|
||||
|
||||
@@ -140,18 +140,6 @@ s32 sceNpTusGetMultiUserVariableVUserAsync()
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
s32 sceNpTusGetFriendsVariable()
|
||||
{
|
||||
UNIMPLEMENTED_FUNC(sceNpTus);
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
s32 sceNpTusGetFriendsVariableAsync()
|
||||
{
|
||||
UNIMPLEMENTED_FUNC(sceNpTus);
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
s32 sceNpTusAddAndGetVariable()
|
||||
{
|
||||
UNIMPLEMENTED_FUNC(sceNpTus);
|
||||
@@ -320,18 +308,6 @@ s32 sceNpTusGetMultiUserDataStatusVUserAsync()
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
s32 sceNpTusGetFriendsDataStatus()
|
||||
{
|
||||
UNIMPLEMENTED_FUNC(sceNpTus);
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
s32 sceNpTusGetFriendsDataStatusAsync()
|
||||
{
|
||||
UNIMPLEMENTED_FUNC(sceNpTus);
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
s32 sceNpTusDeleteMultiSlotData()
|
||||
{
|
||||
UNIMPLEMENTED_FUNC(sceNpTus);
|
||||
@@ -356,18 +332,6 @@ s32 sceNpTusDeleteMultiSlotDataVUserAsync()
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
s32 sceNpTssGetData()
|
||||
{
|
||||
UNIMPLEMENTED_FUNC(sceNpTus);
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
s32 sceNpTssGetDataAsync()
|
||||
{
|
||||
UNIMPLEMENTED_FUNC(sceNpTus);
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
DECLARE(ppu_module_manager::sceNpTus)("sceNpTus", []()
|
||||
{
|
||||
REG_FUNC(sceNpTus, sceNpTusInit);
|
||||
@@ -392,8 +356,6 @@ DECLARE(ppu_module_manager::sceNpTus)("sceNpTus", []()
|
||||
REG_FUNC(sceNpTus, sceNpTusGetMultiUserVariableVUser);
|
||||
REG_FUNC(sceNpTus, sceNpTusGetMultiUserVariableAsync);
|
||||
REG_FUNC(sceNpTus, sceNpTusGetMultiUserVariableVUserAsync);
|
||||
REG_FUNC(sceNpTus, sceNpTusGetFriendsVariable);
|
||||
REG_FUNC(sceNpTus, sceNpTusGetFriendsVariableAsync);
|
||||
REG_FUNC(sceNpTus, sceNpTusAddAndGetVariable);
|
||||
REG_FUNC(sceNpTus, sceNpTusAddAndGetVariableVUser);
|
||||
REG_FUNC(sceNpTus, sceNpTusAddAndGetVariableAsync);
|
||||
@@ -422,12 +384,8 @@ DECLARE(ppu_module_manager::sceNpTus)("sceNpTus", []()
|
||||
REG_FUNC(sceNpTus, sceNpTusGetMultiUserDataStatusVUser);
|
||||
REG_FUNC(sceNpTus, sceNpTusGetMultiUserDataStatusAsync);
|
||||
REG_FUNC(sceNpTus, sceNpTusGetMultiUserDataStatusVUserAsync);
|
||||
REG_FUNC(sceNpTus, sceNpTusGetFriendsDataStatus);
|
||||
REG_FUNC(sceNpTus, sceNpTusGetFriendsDataStatusAsync);
|
||||
REG_FUNC(sceNpTus, sceNpTusDeleteMultiSlotData);
|
||||
REG_FUNC(sceNpTus, sceNpTusDeleteMultiSlotDataVUser);
|
||||
REG_FUNC(sceNpTus, sceNpTusDeleteMultiSlotDataAsync);
|
||||
REG_FUNC(sceNpTus, sceNpTusDeleteMultiSlotDataVUserAsync);
|
||||
REG_FUNC(sceNpTus, sceNpTssGetData);
|
||||
REG_FUNC(sceNpTus, sceNpTssGetDataAsync);
|
||||
});
|
||||
|
||||
@@ -18,11 +18,11 @@ vm::ptr<void> _sys_memset(vm::ptr<void> dst, s32 value, u32 size);
|
||||
struct sys_lwmutex_t;
|
||||
struct sys_lwmutex_attribute_t;
|
||||
|
||||
error_code sys_lwmutex_create(vm::ptr<sys_lwmutex_t> lwmutex, vm::ptr<sys_lwmutex_attribute_t> attr);
|
||||
error_code sys_lwmutex_lock(ppu_thread& CPU, vm::ptr<sys_lwmutex_t> lwmutex, u64 timeout);
|
||||
error_code sys_lwmutex_trylock(ppu_thread& CPU, vm::ptr<sys_lwmutex_t> lwmutex);
|
||||
error_code sys_lwmutex_unlock(ppu_thread& CPU, vm::ptr<sys_lwmutex_t> lwmutex);
|
||||
error_code sys_lwmutex_destroy(ppu_thread& CPU, vm::ptr<sys_lwmutex_t> lwmutex);
|
||||
s32 sys_lwmutex_create(vm::ptr<sys_lwmutex_t> lwmutex, vm::ptr<sys_lwmutex_attribute_t> attr);
|
||||
s32 sys_lwmutex_lock(ppu_thread& CPU, vm::ptr<sys_lwmutex_t> lwmutex, u64 timeout);
|
||||
s32 sys_lwmutex_trylock(ppu_thread& CPU, vm::ptr<sys_lwmutex_t> lwmutex);
|
||||
s32 sys_lwmutex_unlock(ppu_thread& CPU, vm::ptr<sys_lwmutex_t> lwmutex);
|
||||
s32 sys_lwmutex_destroy(ppu_thread& CPU, vm::ptr<sys_lwmutex_t> lwmutex);
|
||||
|
||||
struct sys_lwmutex_locker
|
||||
{
|
||||
@@ -45,11 +45,11 @@ struct sys_lwmutex_locker
|
||||
struct sys_lwcond_t;
|
||||
struct sys_lwcond_attribute_t;
|
||||
|
||||
error_code sys_lwcond_create(vm::ptr<sys_lwcond_t> lwcond, vm::ptr<sys_lwmutex_t> lwmutex, vm::ptr<sys_lwcond_attribute_t> attr);
|
||||
error_code sys_lwcond_destroy(vm::ptr<sys_lwcond_t> lwcond);
|
||||
error_code sys_lwcond_signal(ppu_thread& CPU, vm::ptr<sys_lwcond_t> lwcond);
|
||||
error_code sys_lwcond_signal_all(ppu_thread& CPU, vm::ptr<sys_lwcond_t> lwcond);
|
||||
error_code sys_lwcond_signal_to(ppu_thread& CPU, vm::ptr<sys_lwcond_t> lwcond, u32 ppu_thread_id);
|
||||
error_code sys_lwcond_wait(ppu_thread& CPU, vm::ptr<sys_lwcond_t> lwcond, u64 timeout);
|
||||
s32 sys_lwcond_create(vm::ptr<sys_lwcond_t> lwcond, vm::ptr<sys_lwmutex_t> lwmutex, vm::ptr<sys_lwcond_attribute_t> attr);
|
||||
s32 sys_lwcond_destroy(vm::ptr<sys_lwcond_t> lwcond);
|
||||
s32 sys_lwcond_signal(ppu_thread& CPU, vm::ptr<sys_lwcond_t> lwcond);
|
||||
s32 sys_lwcond_signal_all(ppu_thread& CPU, vm::ptr<sys_lwcond_t> lwcond);
|
||||
s32 sys_lwcond_signal_to(ppu_thread& CPU, vm::ptr<sys_lwcond_t> lwcond, u32 ppu_thread_id);
|
||||
s32 sys_lwcond_wait(ppu_thread& CPU, vm::ptr<sys_lwcond_t> lwcond, u64 timeout);
|
||||
|
||||
void sys_ppu_thread_exit(ppu_thread& CPU, u64 val);
|
||||
|
||||
@@ -16,5 +16,5 @@ void sys_libc_memcpy(vm::ptr<void> dst, vm::cptr<void> src, u32 size)
|
||||
|
||||
DECLARE(ppu_module_manager::sys_libc)("sys_libc", []()
|
||||
{
|
||||
REG_FNID(sys_libc, "memcpy", sys_libc_memcpy).flags = MFF_FORCED_HLE;
|
||||
REG_FNID(sys_libc, "memcpy", sys_libc_memcpy);
|
||||
});
|
||||
|
||||
@@ -5,24 +5,17 @@
|
||||
|
||||
#include "Emu/Cell/lv2/sys_lwmutex.h"
|
||||
#include "Emu/Cell/lv2/sys_lwcond.h"
|
||||
#include "Emu/Cell/lv2/sys_mutex.h"
|
||||
#include "Emu/Cell/lv2/sys_cond.h"
|
||||
#include "sysPrxForUser.h"
|
||||
|
||||
extern logs::channel sysPrxForUser;
|
||||
|
||||
extern bool g_avoid_lwm = false;
|
||||
|
||||
error_code sys_lwcond_create(vm::ptr<sys_lwcond_t> lwcond, vm::ptr<sys_lwmutex_t> lwmutex, vm::ptr<sys_lwcond_attribute_t> attr)
|
||||
s32 sys_lwcond_create(vm::ptr<sys_lwcond_t> lwcond, vm::ptr<sys_lwmutex_t> lwmutex, vm::ptr<sys_lwcond_attribute_t> attr)
|
||||
{
|
||||
sysPrxForUser.trace("sys_lwcond_create(lwcond=*0x%x, lwmutex=*0x%x, attr=*0x%x)", lwcond, lwmutex, attr);
|
||||
|
||||
vm::var<u32> out_id;
|
||||
vm::var<sys_cond_attribute_t> attrs;
|
||||
attrs->pshared = SYS_SYNC_NOT_PROCESS_SHARED;
|
||||
attrs->name_u64 = attr->name_u64;
|
||||
|
||||
if (auto res = g_avoid_lwm ? sys_cond_create(out_id, lwmutex->sleep_queue, attrs) : _sys_lwcond_create(out_id, lwmutex->sleep_queue, lwcond, attr->name_u64, 0))
|
||||
if (s32 res = _sys_lwcond_create(out_id, lwmutex->sleep_queue, lwcond, attr->name_u64, 0))
|
||||
{
|
||||
return res;
|
||||
}
|
||||
@@ -32,16 +25,11 @@ error_code sys_lwcond_create(vm::ptr<sys_lwcond_t> lwcond, vm::ptr<sys_lwmutex_t
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
error_code sys_lwcond_destroy(vm::ptr<sys_lwcond_t> lwcond)
|
||||
s32 sys_lwcond_destroy(vm::ptr<sys_lwcond_t> lwcond)
|
||||
{
|
||||
sysPrxForUser.trace("sys_lwcond_destroy(lwcond=*0x%x)", lwcond);
|
||||
|
||||
if (g_avoid_lwm)
|
||||
{
|
||||
return sys_cond_destroy(lwcond->lwcond_queue);
|
||||
}
|
||||
|
||||
if (error_code res = _sys_lwcond_destroy(lwcond->lwcond_queue))
|
||||
if (s32 res = _sys_lwcond_destroy(lwcond->lwcond_queue))
|
||||
{
|
||||
return res;
|
||||
}
|
||||
@@ -50,20 +38,16 @@ error_code sys_lwcond_destroy(vm::ptr<sys_lwcond_t> lwcond)
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
error_code sys_lwcond_signal(ppu_thread& ppu, vm::ptr<sys_lwcond_t> lwcond)
|
||||
s32 sys_lwcond_signal(ppu_thread& ppu, vm::ptr<sys_lwcond_t> lwcond)
|
||||
{
|
||||
sysPrxForUser.trace("sys_lwcond_signal(lwcond=*0x%x)", lwcond);
|
||||
|
||||
if (g_avoid_lwm)
|
||||
{
|
||||
return sys_cond_signal(ppu, lwcond->lwcond_queue);
|
||||
}
|
||||
|
||||
const vm::ptr<sys_lwmutex_t> lwmutex = lwcond->lwmutex;
|
||||
|
||||
if ((lwmutex->attribute & SYS_SYNC_ATTR_PROTOCOL_MASK) == SYS_SYNC_RETRY)
|
||||
{
|
||||
return _sys_lwcond_signal(ppu, lwcond->lwcond_queue, 0, -1, 2);
|
||||
// TODO (protocol ignored)
|
||||
//return _sys_lwcond_signal(lwcond->lwcond_queue, 0, -1, 2);
|
||||
}
|
||||
|
||||
if (lwmutex->vars.owner.load() == ppu.id)
|
||||
@@ -72,21 +56,18 @@ error_code sys_lwcond_signal(ppu_thread& ppu, vm::ptr<sys_lwcond_t> lwcond)
|
||||
lwmutex->all_info++;
|
||||
|
||||
// call the syscall
|
||||
if (error_code res = _sys_lwcond_signal(ppu, lwcond->lwcond_queue, lwmutex->sleep_queue, -1, 1))
|
||||
if (s32 res = _sys_lwcond_signal(ppu, lwcond->lwcond_queue, lwmutex->sleep_queue, -1, 1))
|
||||
{
|
||||
ppu.test_state();
|
||||
lwmutex->all_info--;
|
||||
|
||||
if (res != CELL_EPERM)
|
||||
{
|
||||
return res;
|
||||
}
|
||||
return res == CELL_EPERM ? CELL_OK : res;
|
||||
}
|
||||
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
if (error_code res = sys_lwmutex_trylock(ppu, lwmutex))
|
||||
if (s32 res = sys_lwmutex_trylock(ppu, lwmutex))
|
||||
{
|
||||
// if locking failed
|
||||
|
||||
@@ -103,7 +84,7 @@ error_code sys_lwcond_signal(ppu_thread& ppu, vm::ptr<sys_lwcond_t> lwcond)
|
||||
lwmutex->all_info++;
|
||||
|
||||
// call the syscall
|
||||
if (error_code res = _sys_lwcond_signal(ppu, lwcond->lwcond_queue, lwmutex->sleep_queue, -1, 3))
|
||||
if (s32 res = _sys_lwcond_signal(ppu, lwcond->lwcond_queue, lwmutex->sleep_queue, -1, 3))
|
||||
{
|
||||
ppu.test_state();
|
||||
lwmutex->all_info--;
|
||||
@@ -111,35 +92,28 @@ error_code sys_lwcond_signal(ppu_thread& ppu, vm::ptr<sys_lwcond_t> lwcond)
|
||||
// unlock the lightweight mutex
|
||||
sys_lwmutex_unlock(ppu, lwmutex);
|
||||
|
||||
if (res != CELL_ENOENT)
|
||||
{
|
||||
return res;
|
||||
}
|
||||
return res == CELL_ENOENT ? CELL_OK : res;
|
||||
}
|
||||
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
error_code sys_lwcond_signal_all(ppu_thread& ppu, vm::ptr<sys_lwcond_t> lwcond)
|
||||
s32 sys_lwcond_signal_all(ppu_thread& ppu, vm::ptr<sys_lwcond_t> lwcond)
|
||||
{
|
||||
sysPrxForUser.trace("sys_lwcond_signal_all(lwcond=*0x%x)", lwcond);
|
||||
|
||||
if (g_avoid_lwm)
|
||||
{
|
||||
return sys_cond_signal_all(ppu, lwcond->lwcond_queue);
|
||||
}
|
||||
|
||||
const vm::ptr<sys_lwmutex_t> lwmutex = lwcond->lwmutex;
|
||||
|
||||
if ((lwmutex->attribute & SYS_SYNC_ATTR_PROTOCOL_MASK) == SYS_SYNC_RETRY)
|
||||
{
|
||||
return _sys_lwcond_signal_all(ppu, lwcond->lwcond_queue, lwmutex->sleep_queue, 2);
|
||||
// TODO (protocol ignored)
|
||||
//return _sys_lwcond_signal_all(lwcond->lwcond_queue, lwmutex->sleep_queue, 2);
|
||||
}
|
||||
|
||||
if (lwmutex->vars.owner.load() == ppu.id)
|
||||
{
|
||||
// if owns the mutex, call the syscall
|
||||
const error_code res = _sys_lwcond_signal_all(ppu, lwcond->lwcond_queue, lwmutex->sleep_queue, 1);
|
||||
const s32 res = _sys_lwcond_signal_all(ppu, lwcond->lwcond_queue, lwmutex->sleep_queue, 1);
|
||||
|
||||
if (res <= 0)
|
||||
{
|
||||
@@ -153,7 +127,7 @@ error_code sys_lwcond_signal_all(ppu_thread& ppu, vm::ptr<sys_lwcond_t> lwcond)
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
if (error_code res = sys_lwmutex_trylock(ppu, lwmutex))
|
||||
if (s32 res = sys_lwmutex_trylock(ppu, lwmutex))
|
||||
{
|
||||
// if locking failed
|
||||
|
||||
@@ -167,7 +141,7 @@ error_code sys_lwcond_signal_all(ppu_thread& ppu, vm::ptr<sys_lwcond_t> lwcond)
|
||||
}
|
||||
|
||||
// if locking succeeded, call the syscall
|
||||
error_code res = _sys_lwcond_signal_all(ppu, lwcond->lwcond_queue, lwmutex->sleep_queue, 1);
|
||||
s32 res = _sys_lwcond_signal_all(ppu, lwcond->lwcond_queue, lwmutex->sleep_queue, 1);
|
||||
|
||||
ppu.test_state();
|
||||
|
||||
@@ -184,20 +158,16 @@ error_code sys_lwcond_signal_all(ppu_thread& ppu, vm::ptr<sys_lwcond_t> lwcond)
|
||||
return res;
|
||||
}
|
||||
|
||||
error_code sys_lwcond_signal_to(ppu_thread& ppu, vm::ptr<sys_lwcond_t> lwcond, u32 ppu_thread_id)
|
||||
s32 sys_lwcond_signal_to(ppu_thread& ppu, vm::ptr<sys_lwcond_t> lwcond, u32 ppu_thread_id)
|
||||
{
|
||||
sysPrxForUser.trace("sys_lwcond_signal_to(lwcond=*0x%x, ppu_thread_id=0x%x)", lwcond, ppu_thread_id);
|
||||
|
||||
if (g_avoid_lwm)
|
||||
{
|
||||
return sys_cond_signal_to(ppu, lwcond->lwcond_queue, ppu_thread_id);
|
||||
}
|
||||
|
||||
const vm::ptr<sys_lwmutex_t> lwmutex = lwcond->lwmutex;
|
||||
|
||||
if ((lwmutex->attribute & SYS_SYNC_ATTR_PROTOCOL_MASK) == SYS_SYNC_RETRY)
|
||||
{
|
||||
return _sys_lwcond_signal(ppu, lwcond->lwcond_queue, 0, ppu_thread_id, 2);
|
||||
// TODO (protocol ignored)
|
||||
//return _sys_lwcond_signal(lwcond->lwcond_queue, 0, ppu_thread_id, 2);
|
||||
}
|
||||
|
||||
if (lwmutex->vars.owner.load() == ppu.id)
|
||||
@@ -206,7 +176,7 @@ error_code sys_lwcond_signal_to(ppu_thread& ppu, vm::ptr<sys_lwcond_t> lwcond, u
|
||||
lwmutex->all_info++;
|
||||
|
||||
// call the syscall
|
||||
if (error_code res = _sys_lwcond_signal(ppu, lwcond->lwcond_queue, lwmutex->sleep_queue, ppu_thread_id, 1))
|
||||
if (s32 res = _sys_lwcond_signal(ppu, lwcond->lwcond_queue, lwmutex->sleep_queue, ppu_thread_id, 1))
|
||||
{
|
||||
ppu.test_state();
|
||||
lwmutex->all_info--;
|
||||
@@ -217,7 +187,7 @@ error_code sys_lwcond_signal_to(ppu_thread& ppu, vm::ptr<sys_lwcond_t> lwcond, u
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
if (error_code res = sys_lwmutex_trylock(ppu, lwmutex))
|
||||
if (s32 res = sys_lwmutex_trylock(ppu, lwmutex))
|
||||
{
|
||||
// if locking failed
|
||||
|
||||
@@ -234,7 +204,7 @@ error_code sys_lwcond_signal_to(ppu_thread& ppu, vm::ptr<sys_lwcond_t> lwcond, u
|
||||
lwmutex->all_info++;
|
||||
|
||||
// call the syscall
|
||||
if (error_code res = _sys_lwcond_signal(ppu, lwcond->lwcond_queue, lwmutex->sleep_queue, ppu_thread_id, 3))
|
||||
if (s32 res = _sys_lwcond_signal(ppu, lwcond->lwcond_queue, lwmutex->sleep_queue, ppu_thread_id, 3))
|
||||
{
|
||||
ppu.test_state();
|
||||
lwmutex->all_info--;
|
||||
@@ -248,15 +218,10 @@ error_code sys_lwcond_signal_to(ppu_thread& ppu, vm::ptr<sys_lwcond_t> lwcond, u
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
error_code sys_lwcond_wait(ppu_thread& ppu, vm::ptr<sys_lwcond_t> lwcond, u64 timeout)
|
||||
s32 sys_lwcond_wait(ppu_thread& ppu, vm::ptr<sys_lwcond_t> lwcond, u64 timeout)
|
||||
{
|
||||
sysPrxForUser.trace("sys_lwcond_wait(lwcond=*0x%x, timeout=0x%llx)", lwcond, timeout);
|
||||
|
||||
if (g_avoid_lwm)
|
||||
{
|
||||
return sys_cond_wait(ppu, lwcond->lwcond_queue, timeout);
|
||||
}
|
||||
|
||||
const be_t<u32> tid(ppu.id);
|
||||
|
||||
const vm::ptr<sys_lwmutex_t> lwmutex = lwcond->lwmutex;
|
||||
@@ -275,7 +240,7 @@ error_code sys_lwcond_wait(ppu_thread& ppu, vm::ptr<sys_lwcond_t> lwcond, u64 ti
|
||||
lwmutex->recursive_count = 0;
|
||||
|
||||
// call the syscall
|
||||
const error_code res = _sys_lwcond_queue_wait(ppu, lwcond->lwcond_queue, lwmutex->sleep_queue, timeout);
|
||||
s32 res = _sys_lwcond_queue_wait(ppu, lwcond->lwcond_queue, lwmutex->sleep_queue, timeout);
|
||||
|
||||
if (res == CELL_OK || res == CELL_ESRCH)
|
||||
{
|
||||
@@ -288,7 +253,7 @@ error_code sys_lwcond_wait(ppu_thread& ppu, vm::ptr<sys_lwcond_t> lwcond, u64 ti
|
||||
const auto old = lwmutex->vars.owner.exchange(tid);
|
||||
lwmutex->recursive_count = recursive_value;
|
||||
|
||||
if (old == lwmutex_free || old == lwmutex_dead)
|
||||
if (old != lwmutex_reserved)
|
||||
{
|
||||
fmt::throw_exception("Locking failed (lwmutex=*0x%x, owner=0x%x)" HERE, lwmutex, old);
|
||||
}
|
||||
@@ -298,20 +263,17 @@ error_code sys_lwcond_wait(ppu_thread& ppu, vm::ptr<sys_lwcond_t> lwcond, u64 ti
|
||||
|
||||
if (res == CELL_EBUSY || res == CELL_ETIMEDOUT)
|
||||
{
|
||||
if (error_code res2 = sys_lwmutex_lock(ppu, lwmutex, 0))
|
||||
const s32 res2 = sys_lwmutex_lock(ppu, lwmutex, 0);
|
||||
|
||||
if (res2 == CELL_OK)
|
||||
{
|
||||
return res2;
|
||||
// if successfully locked, restore recursive value
|
||||
lwmutex->recursive_count = recursive_value;
|
||||
|
||||
return res == CELL_EBUSY ? CELL_OK : res;
|
||||
}
|
||||
|
||||
// if successfully locked, restore recursive value
|
||||
lwmutex->recursive_count = recursive_value;
|
||||
|
||||
if (res == CELL_EBUSY)
|
||||
{
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
return res;
|
||||
return res2;
|
||||
}
|
||||
|
||||
if (res == CELL_EDEADLK)
|
||||
@@ -320,15 +282,15 @@ error_code sys_lwcond_wait(ppu_thread& ppu, vm::ptr<sys_lwcond_t> lwcond, u64 ti
|
||||
const auto old = lwmutex->vars.owner.exchange(tid);
|
||||
lwmutex->recursive_count = recursive_value;
|
||||
|
||||
if (old == lwmutex_free || old == lwmutex_dead)
|
||||
if (old != lwmutex_reserved)
|
||||
{
|
||||
fmt::throw_exception("Locking failed (lwmutex=*0x%x, owner=0x%x)" HERE, lwmutex, old);
|
||||
}
|
||||
|
||||
return not_an_error(CELL_ETIMEDOUT);
|
||||
return CELL_ETIMEDOUT;
|
||||
}
|
||||
|
||||
fmt::throw_exception("Unexpected syscall result (lwcond=*0x%x, result=0x%x)" HERE, lwcond, +res);
|
||||
fmt::throw_exception("Unexpected syscall result (lwcond=*0x%x, result=0x%x)" HERE, lwcond, res);
|
||||
}
|
||||
|
||||
void sysPrxForUser_sys_lwcond_init()
|
||||
|
||||
@@ -5,14 +5,11 @@
|
||||
#include "Emu/Cell/PPUModule.h"
|
||||
|
||||
#include "Emu/Cell/lv2/sys_lwmutex.h"
|
||||
#include "Emu/Cell/lv2/sys_mutex.h"
|
||||
#include "sysPrxForUser.h"
|
||||
|
||||
extern logs::channel sysPrxForUser;
|
||||
|
||||
extern bool g_avoid_lwm;
|
||||
|
||||
error_code sys_lwmutex_create(vm::ptr<sys_lwmutex_t> lwmutex, vm::ptr<sys_lwmutex_attribute_t> attr)
|
||||
s32 sys_lwmutex_create(vm::ptr<sys_lwmutex_t> lwmutex, vm::ptr<sys_lwmutex_attribute_t> attr)
|
||||
{
|
||||
sysPrxForUser.trace("sys_lwmutex_create(lwmutex=*0x%x, attr=*0x%x)", lwmutex, attr);
|
||||
|
||||
@@ -35,16 +32,8 @@ error_code sys_lwmutex_create(vm::ptr<sys_lwmutex_t> lwmutex, vm::ptr<sys_lwmute
|
||||
}
|
||||
|
||||
vm::var<u32> out_id;
|
||||
vm::var<sys_mutex_attribute_t> attrs;
|
||||
attrs->protocol = attr->protocol;
|
||||
attrs->recursive = attr->recursive;
|
||||
attrs->pshared = SYS_SYNC_NOT_PROCESS_SHARED;
|
||||
attrs->adaptive = SYS_SYNC_NOT_ADAPTIVE;
|
||||
attrs->ipc_key = 0;
|
||||
attrs->flags = 0;
|
||||
attrs->name_u64 = attr->name_u64;
|
||||
|
||||
if (error_code res = g_avoid_lwm ? sys_mutex_create(out_id, attrs) : _sys_lwmutex_create(out_id, protocol, lwmutex, 0x80000001, attr->name_u64, 0))
|
||||
if (s32 res = _sys_lwmutex_create(out_id, protocol, lwmutex, 0x80000001, attr->name_u64, 0))
|
||||
{
|
||||
return res;
|
||||
}
|
||||
@@ -56,15 +45,10 @@ error_code sys_lwmutex_create(vm::ptr<sys_lwmutex_t> lwmutex, vm::ptr<sys_lwmute
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
error_code sys_lwmutex_destroy(ppu_thread& ppu, vm::ptr<sys_lwmutex_t> lwmutex)
|
||||
s32 sys_lwmutex_destroy(ppu_thread& ppu, vm::ptr<sys_lwmutex_t> lwmutex)
|
||||
{
|
||||
sysPrxForUser.trace("sys_lwmutex_destroy(lwmutex=*0x%x)", lwmutex);
|
||||
|
||||
if (g_avoid_lwm)
|
||||
{
|
||||
return sys_mutex_destroy(lwmutex->sleep_queue);
|
||||
}
|
||||
|
||||
// check to prevent recursive locking in the next call
|
||||
if (lwmutex->vars.owner.load() == ppu.id)
|
||||
{
|
||||
@@ -72,13 +56,13 @@ error_code sys_lwmutex_destroy(ppu_thread& ppu, vm::ptr<sys_lwmutex_t> lwmutex)
|
||||
}
|
||||
|
||||
// attempt to lock the mutex
|
||||
if (error_code res = sys_lwmutex_trylock(ppu, lwmutex))
|
||||
if (s32 res = sys_lwmutex_trylock(ppu, lwmutex))
|
||||
{
|
||||
return res;
|
||||
}
|
||||
|
||||
// call the syscall
|
||||
if (error_code res = _sys_lwmutex_destroy(lwmutex->sleep_queue))
|
||||
if (s32 res = _sys_lwmutex_destroy(lwmutex->sleep_queue))
|
||||
{
|
||||
// unlock the mutex if failed
|
||||
sys_lwmutex_unlock(ppu, lwmutex);
|
||||
@@ -92,15 +76,10 @@ error_code sys_lwmutex_destroy(ppu_thread& ppu, vm::ptr<sys_lwmutex_t> lwmutex)
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
error_code sys_lwmutex_lock(ppu_thread& ppu, vm::ptr<sys_lwmutex_t> lwmutex, u64 timeout)
|
||||
s32 sys_lwmutex_lock(ppu_thread& ppu, vm::ptr<sys_lwmutex_t> lwmutex, u64 timeout)
|
||||
{
|
||||
sysPrxForUser.trace("sys_lwmutex_lock(lwmutex=*0x%x, timeout=0x%llx)", lwmutex, timeout);
|
||||
|
||||
if (g_avoid_lwm)
|
||||
{
|
||||
return sys_mutex_lock(ppu, lwmutex->sleep_queue, timeout);
|
||||
}
|
||||
|
||||
const be_t<u32> tid(ppu.id);
|
||||
|
||||
// try to lock lightweight mutex
|
||||
@@ -167,7 +146,7 @@ error_code sys_lwmutex_lock(ppu_thread& ppu, vm::ptr<sys_lwmutex_t> lwmutex, u64
|
||||
}
|
||||
|
||||
// lock using the syscall
|
||||
const error_code res = _sys_lwmutex_lock(ppu, lwmutex->sleep_queue, timeout);
|
||||
const s32 res = _sys_lwmutex_lock(ppu, lwmutex->sleep_queue, timeout);
|
||||
|
||||
lwmutex->all_info--;
|
||||
|
||||
@@ -193,15 +172,10 @@ error_code sys_lwmutex_lock(ppu_thread& ppu, vm::ptr<sys_lwmutex_t> lwmutex, u64
|
||||
return res;
|
||||
}
|
||||
|
||||
error_code sys_lwmutex_trylock(ppu_thread& ppu, vm::ptr<sys_lwmutex_t> lwmutex)
|
||||
s32 sys_lwmutex_trylock(ppu_thread& ppu, vm::ptr<sys_lwmutex_t> lwmutex)
|
||||
{
|
||||
sysPrxForUser.trace("sys_lwmutex_trylock(lwmutex=*0x%x)", lwmutex);
|
||||
|
||||
if (g_avoid_lwm)
|
||||
{
|
||||
return sys_mutex_trylock(ppu, lwmutex->sleep_queue);
|
||||
}
|
||||
|
||||
const be_t<u32> tid(ppu.id);
|
||||
|
||||
// try to lock lightweight mutex
|
||||
@@ -245,7 +219,7 @@ error_code sys_lwmutex_trylock(ppu_thread& ppu, vm::ptr<sys_lwmutex_t> lwmutex)
|
||||
if (old_owner == lwmutex_reserved)
|
||||
{
|
||||
// should be locked by the syscall
|
||||
const error_code res = _sys_lwmutex_trylock(lwmutex->sleep_queue);
|
||||
const s32 res = _sys_lwmutex_trylock(lwmutex->sleep_queue);
|
||||
|
||||
if (res == CELL_OK)
|
||||
{
|
||||
@@ -262,18 +236,13 @@ error_code sys_lwmutex_trylock(ppu_thread& ppu, vm::ptr<sys_lwmutex_t> lwmutex)
|
||||
}
|
||||
|
||||
// locked by another thread
|
||||
return not_an_error(CELL_EBUSY);
|
||||
return CELL_EBUSY;
|
||||
}
|
||||
|
||||
error_code sys_lwmutex_unlock(ppu_thread& ppu, vm::ptr<sys_lwmutex_t> lwmutex)
|
||||
s32 sys_lwmutex_unlock(ppu_thread& ppu, vm::ptr<sys_lwmutex_t> lwmutex)
|
||||
{
|
||||
sysPrxForUser.trace("sys_lwmutex_unlock(lwmutex=*0x%x)", lwmutex);
|
||||
|
||||
if (g_avoid_lwm)
|
||||
{
|
||||
return sys_mutex_unlock(ppu, lwmutex->sleep_queue);
|
||||
}
|
||||
|
||||
const be_t<u32> tid(ppu.id);
|
||||
|
||||
// check owner
|
||||
|
||||
@@ -1,17 +1,10 @@
|
||||
#include "stdafx.h"
|
||||
|
||||
#include "Utilities/StrUtil.h"
|
||||
|
||||
#include "Emu/System.h"
|
||||
#include "Emu/IdManager.h"
|
||||
#include "Emu/Cell/PPUModule.h"
|
||||
|
||||
#include "Emu/Cell/lv2/sys_mutex.h"
|
||||
#include "Emu/Cell/lv2/sys_cond.h"
|
||||
|
||||
#include "sysPrxForUser.h"
|
||||
|
||||
|
||||
extern logs::channel sysPrxForUser;
|
||||
|
||||
using sys_mempool_t = u32;
|
||||
@@ -22,9 +15,6 @@ struct memory_pool_t
|
||||
static const u32 id_step = 1;
|
||||
static const u32 id_count = 1023;
|
||||
|
||||
u32 mutexid;
|
||||
u32 condid;
|
||||
|
||||
vm::ptr<void> chunk;
|
||||
u64 chunk_size;
|
||||
u64 block_size;
|
||||
@@ -32,7 +22,13 @@ struct memory_pool_t
|
||||
std::vector<vm::ptr<void>> free_blocks;
|
||||
};
|
||||
|
||||
s32 sys_mempool_create(ppu_thread& ppu, vm::ptr<sys_mempool_t> mempool, vm::ptr<void> chunk, const u64 chunk_size, const u64 block_size, const u64 ralignment)
|
||||
vm::ptr<void> sys_mempool_allocate_block(sys_mempool_t mempool)
|
||||
{
|
||||
sysPrxForUser.todo("sys_mempool_allocate_block(mempool=%d)", mempool);
|
||||
return vm::null;
|
||||
}
|
||||
|
||||
s32 sys_mempool_create(vm::ptr<sys_mempool_t> mempool, vm::ptr<void> chunk, const u64 chunk_size, const u64 block_size, const u64 ralignment)
|
||||
{
|
||||
sysPrxForUser.warning("sys_mempool_create(mempool=*0x%x, chunk=*0x%x, chunk_size=%d, block_size=%d, ralignment=%d)", mempool, chunk, chunk_size, block_size, ralignment);
|
||||
|
||||
@@ -76,65 +72,18 @@ s32 sys_mempool_create(ppu_thread& ppu, vm::ptr<sys_mempool_t> mempool, vm::ptr<
|
||||
{
|
||||
memory_pool->free_blocks[i] = vm::ptr<void>::make(chunk.addr() + i * block_size);
|
||||
}
|
||||
|
||||
// Create synchronization variables
|
||||
vm::var<u32> mutexid;
|
||||
vm::var<sys_mutex_attribute_t> attr;
|
||||
attr->protocol = SYS_SYNC_PRIORITY;
|
||||
attr->recursive = SYS_SYNC_NOT_RECURSIVE;
|
||||
attr->pshared = SYS_SYNC_NOT_PROCESS_SHARED;
|
||||
attr->adaptive = SYS_SYNC_NOT_ADAPTIVE;
|
||||
attr->ipc_key = 0; // No idea what this is
|
||||
attr->flags = 0; // Also no idea what this is.
|
||||
strcpy_trunc(attr->name, "mp_m" + std::to_string(*mempool));
|
||||
|
||||
error_code ret = sys_mutex_create(mutexid, attr);
|
||||
if (ret != 0)
|
||||
{ // TODO: Better exception handling.
|
||||
fmt::throw_exception("mempool %x failed to create mutex", mempool);
|
||||
}
|
||||
memory_pool->mutexid = *mutexid;
|
||||
|
||||
vm::var<u32> condid;
|
||||
vm::var<sys_cond_attribute_t> condAttr;
|
||||
condAttr->pshared = SYS_SYNC_NOT_PROCESS_SHARED;
|
||||
condAttr->flags = 0; // No idea what this is
|
||||
condAttr->ipc_key = 0; // Also no idea what this is
|
||||
strcpy_trunc(condAttr->name, "mp_c" + std::to_string(*mempool));
|
||||
|
||||
ret = sys_cond_create(condid, *mutexid, condAttr);
|
||||
if (ret != CELL_OK)
|
||||
{ // TODO: Better exception handling.
|
||||
fmt::throw_exception("mempool %x failed to create condition variable", mempool);
|
||||
}
|
||||
memory_pool->condid = *condid;
|
||||
|
||||
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
void sys_mempool_destroy(ppu_thread& ppu, sys_mempool_t mempool)
|
||||
void sys_mempool_destroy(sys_mempool_t mempool)
|
||||
{
|
||||
sysPrxForUser.warning("sys_mempool_destroy(mempool=%d)", mempool);
|
||||
|
||||
auto memory_pool = idm::get<memory_pool_t>(mempool);
|
||||
if (memory_pool)
|
||||
{
|
||||
u32 condid = memory_pool->condid;
|
||||
u32 mutexid = memory_pool->mutexid;
|
||||
|
||||
sys_mutex_lock(ppu, memory_pool->mutexid, 0);
|
||||
idm::remove<memory_pool_t>(mempool);
|
||||
sys_mutex_unlock(ppu, mutexid);
|
||||
sys_mutex_destroy(mutexid);
|
||||
sys_cond_destroy(condid);
|
||||
}
|
||||
else
|
||||
{
|
||||
sysPrxForUser.error("Trying to destroy an already destroyed mempool=%d", mempool);
|
||||
}
|
||||
idm::remove<memory_pool_t>(mempool);
|
||||
}
|
||||
|
||||
s32 sys_mempool_free_block(ppu_thread& ppu, sys_mempool_t mempool, vm::ptr<void> block)
|
||||
s32 sys_mempool_free_block(sys_mempool_t mempool, vm::ptr<void> block)
|
||||
{
|
||||
sysPrxForUser.warning("sys_mempool_free_block(mempool=%d, block=*0x%x)", mempool, block);
|
||||
|
||||
@@ -144,21 +93,16 @@ s32 sys_mempool_free_block(ppu_thread& ppu, sys_mempool_t mempool, vm::ptr<void>
|
||||
return CELL_EINVAL;
|
||||
}
|
||||
|
||||
sys_mutex_lock(ppu, memory_pool->mutexid, 0);
|
||||
|
||||
// Cannot free a block not belonging to this memory pool
|
||||
if (block.addr() > memory_pool->chunk.addr() + memory_pool->chunk_size)
|
||||
{
|
||||
sys_mutex_unlock(ppu, memory_pool->mutexid);
|
||||
return CELL_EINVAL;
|
||||
}
|
||||
memory_pool->free_blocks.push_back(block);
|
||||
sys_cond_signal(ppu, memory_pool->condid);
|
||||
sys_mutex_unlock(ppu, memory_pool->mutexid);
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
u64 sys_mempool_get_count(ppu_thread& ppu, sys_mempool_t mempool)
|
||||
u64 sys_mempool_get_count(sys_mempool_t mempool)
|
||||
{
|
||||
sysPrxForUser.warning("sys_mempool_get_count(mempool=%d)", mempool);
|
||||
|
||||
@@ -167,40 +111,11 @@ u64 sys_mempool_get_count(ppu_thread& ppu, sys_mempool_t mempool)
|
||||
{
|
||||
return CELL_EINVAL;
|
||||
}
|
||||
sys_mutex_lock(ppu, memory_pool->mutexid, 0);
|
||||
u64 ret = memory_pool->free_blocks.size();
|
||||
sys_mutex_unlock(ppu, memory_pool->mutexid);
|
||||
return ret;
|
||||
|
||||
return memory_pool->free_blocks.size();
|
||||
}
|
||||
|
||||
vm::ptr<void> sys_mempool_allocate_block(ppu_thread& ppu, sys_mempool_t mempool)
|
||||
{
|
||||
sysPrxForUser.warning("sys_mempool_allocate_block(mempool=%d)", mempool);
|
||||
|
||||
auto memory_pool = idm::get<memory_pool_t>(mempool);
|
||||
if (!memory_pool)
|
||||
{ // if the memory pool gets deleted-- is null, clearly it's impossible to allocate memory.
|
||||
return vm::null;
|
||||
}
|
||||
sys_mutex_lock(ppu, memory_pool->mutexid, 0);
|
||||
|
||||
while (memory_pool->free_blocks.size() == 0) // while is to guard against spurious wakeups
|
||||
{
|
||||
sys_cond_wait(ppu, memory_pool->condid, 0);
|
||||
memory_pool = idm::get<memory_pool_t>(mempool);
|
||||
if (!memory_pool) // in case spurious wake up was from delete, don't die by accessing a freed pool.
|
||||
{ // No need to unlock as if the pool is freed, the lock was freed as well.
|
||||
return vm::null;
|
||||
}
|
||||
}
|
||||
|
||||
auto block_ptr = memory_pool->free_blocks.back();
|
||||
memory_pool->free_blocks.pop_back();
|
||||
sys_mutex_unlock(ppu, memory_pool->mutexid);
|
||||
return block_ptr;
|
||||
}
|
||||
|
||||
vm::ptr<void> sys_mempool_try_allocate_block(ppu_thread& ppu, sys_mempool_t mempool)
|
||||
vm::ptr<void> sys_mempool_try_allocate_block(sys_mempool_t mempool)
|
||||
{
|
||||
sysPrxForUser.warning("sys_mempool_try_allocate_block(mempool=%d)", mempool);
|
||||
|
||||
@@ -211,14 +126,12 @@ vm::ptr<void> sys_mempool_try_allocate_block(ppu_thread& ppu, sys_mempool_t memp
|
||||
return vm::null;
|
||||
}
|
||||
|
||||
sys_mutex_lock(ppu, memory_pool->mutexid, 0);
|
||||
|
||||
auto block_ptr = memory_pool->free_blocks.back();
|
||||
memory_pool->free_blocks.pop_back();
|
||||
sys_mutex_unlock(ppu, memory_pool->mutexid);
|
||||
return block_ptr;
|
||||
}
|
||||
|
||||
|
||||
void sysPrxForUser_sys_mempool_init()
|
||||
{
|
||||
REG_FUNC(sysPrxForUser, sys_mempool_allocate_block);
|
||||
|
||||
@@ -567,43 +567,24 @@ namespace sys_net
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (level != PS3_SOL_SOCKET && level != IPPROTO_TCP)
|
||||
if (level != SOL_SOCKET && level != IPPROTO_TCP)
|
||||
{
|
||||
fmt::throw_exception("Invalid socket option level!" HERE);
|
||||
}
|
||||
|
||||
s32 ret;
|
||||
|
||||
if (level == PS3_SOL_SOCKET)
|
||||
#ifdef _WIN32
|
||||
if (level == SOL_SOCKET)
|
||||
{
|
||||
switch (optname)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
case OP_SO_NBIO:
|
||||
{
|
||||
unsigned long mode = *(unsigned long*)optval.get_ptr();
|
||||
ret = ioctlsocket(sock->s, FIONBIO, &mode);
|
||||
break;
|
||||
}
|
||||
#else
|
||||
case OP_SO_NBIO:
|
||||
{
|
||||
// Obtain the flags
|
||||
s32 flags = fcntl(s, F_GETFL, 0);
|
||||
|
||||
if (flags < 0)
|
||||
{
|
||||
fmt::throw_exception("Failed to obtain socket flags." HERE);
|
||||
}
|
||||
|
||||
u32 mode = *(u32*)optval.get_ptr();
|
||||
flags = mode ? (flags &~O_NONBLOCK) : (flags | O_NONBLOCK);
|
||||
|
||||
// Re-set the flags
|
||||
ret = fcntl(sock->s, F_SETFL, flags);
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
case OP_SO_SNDBUF:
|
||||
{
|
||||
u32 sendbuff = *(u32*)optval.get_ptr();
|
||||
@@ -642,14 +623,12 @@ namespace sys_net
|
||||
}
|
||||
case OP_SO_USECRYPTO:
|
||||
{
|
||||
libnet.todo("Socket option OP_SO_USECRYPTO is unimplemented");
|
||||
ret = CELL_OK;
|
||||
libnet.warning("Socket option OP_SO_USECRYPTO is unimplemented");
|
||||
break;
|
||||
}
|
||||
case OP_SO_USESIGNATURE:
|
||||
{
|
||||
libnet.todo("Socket option OP_SO_USESIGNATURE is unimplemented");
|
||||
ret = CELL_OK;
|
||||
libnet.warning("Socket option OP_SO_USESIGNATURE is unimplemented");
|
||||
break;
|
||||
}
|
||||
case OP_SO_BROADCAST:
|
||||
@@ -665,7 +644,7 @@ namespace sys_net
|
||||
break;
|
||||
}
|
||||
default:
|
||||
libnet.error("Unknown socket option: 0x%x", optname);
|
||||
libnet.error("Unknown socket option for Win32: 0x%x", optname);
|
||||
}
|
||||
}
|
||||
else if (level == PROTO_IPPROTO_TCP)
|
||||
@@ -674,31 +653,71 @@ namespace sys_net
|
||||
{
|
||||
case OP_TCP_NODELAY:
|
||||
{
|
||||
#ifdef _WIN32
|
||||
const char delay = *(char*)optval.get_ptr();
|
||||
ret = ::setsockopt(sock->s, IPPROTO_TCP, TCP_NODELAY, &delay, sizeof(delay));
|
||||
#else
|
||||
u32 delay = *(u32*)optval.get_ptr();
|
||||
ret = ::setsockopt(sock->s, IPPROTO_TCP, TCP_NODELAY, &delay, optlen);
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
|
||||
case OP_TCP_MAXSEG:
|
||||
{
|
||||
#ifdef _WIN32
|
||||
libnet.warning("TCP_MAXSEG can't be set on Windows.");
|
||||
#else
|
||||
u32 maxseg = *(u32*)optval.get_ptr();
|
||||
ret = ::setsockopt(sock->s, IPPROTO_TCP, TCP_MAXSEG, &maxseg, optlen);
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
libnet.error("Unknown TCP option: 0x%x", optname);
|
||||
libnet.error("Unknown TCP option for Win32: 0x%x", optname);
|
||||
}
|
||||
}
|
||||
#else
|
||||
if (level == SOL_SOCKET)
|
||||
{
|
||||
switch (optname)
|
||||
{
|
||||
case OP_SO_NBIO:
|
||||
{
|
||||
// Obtain the flags
|
||||
s32 flags = fcntl(s, F_GETFL, 0);
|
||||
|
||||
if (flags < 0)
|
||||
{
|
||||
fmt::throw_exception("Failed to obtain socket flags." HERE);
|
||||
}
|
||||
|
||||
u32 mode = *(u32*)optval.get_ptr();
|
||||
flags = mode ? (flags &~O_NONBLOCK) : (flags | O_NONBLOCK);
|
||||
|
||||
// Re-set the flags
|
||||
ret = fcntl(sock->s, F_SETFL, flags);
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
libnet.error("Unknown socket option for Unix: 0x%x", optname);
|
||||
}
|
||||
}
|
||||
else if (level == PROTO_IPPROTO_TCP)
|
||||
{
|
||||
switch (optname)
|
||||
{
|
||||
case OP_TCP_NODELAY:
|
||||
{
|
||||
u32 delay = *(u32*)optval.get_ptr();
|
||||
ret = ::setsockopt(sock->s, IPPROTO_TCP, TCP_NODELAY, &delay, optlen);
|
||||
break;
|
||||
}
|
||||
|
||||
case OP_TCP_MAXSEG:
|
||||
{
|
||||
u32 maxseg = *(u32*)optval.get_ptr();
|
||||
ret = ::setsockopt(sock->s, IPPROTO_TCP, TCP_MAXSEG, &maxseg, optlen);
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
libnet.error("Unknown TCP option for Unix: 0x%x", optname);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
if (ret != 0)
|
||||
{
|
||||
@@ -802,8 +821,8 @@ namespace sys_net
|
||||
|
||||
s32 socketselect(s32 nfds, vm::ptr<fd_set> readfds, vm::ptr<fd_set> writefds, vm::ptr<fd_set> exceptfds, vm::ptr<timeval> timeout)
|
||||
{
|
||||
libnet.warning("socketselect(nfds=%d, readfds=*0x%x, writefds=*0x%x, exceptfds=*0x%x, timeout.tv_sec=%d, timeout.tv_usec=%d)",
|
||||
nfds, readfds, writefds, exceptfds, timeout->tv_sec, timeout->tv_usec);
|
||||
libnet.warning("socketselect(nfds=%d, readfds=*0x%x, writefds=*0x%x, exceptfds=*0x%x, timeout=*0x%x)", nfds, readfds, writefds, exceptfds, timeout);
|
||||
|
||||
::timeval _timeout;
|
||||
|
||||
if (timeout)
|
||||
@@ -811,12 +830,8 @@ namespace sys_net
|
||||
_timeout.tv_sec = timeout->tv_sec;
|
||||
_timeout.tv_usec = timeout->tv_usec;
|
||||
}
|
||||
|
||||
if (_timeout.tv_usec >= 1000000)
|
||||
{
|
||||
_timeout.tv_sec = _timeout.tv_sec ? _timeout.tv_sec - 1 : _timeout.tv_sec + 1;
|
||||
_timeout.tv_usec = 0;
|
||||
}
|
||||
|
||||
//libnet.error("timeval: %d . %d", _timeout.tv_sec, _timeout.tv_usec);
|
||||
|
||||
::fd_set _readfds;
|
||||
::fd_set _writefds;
|
||||
|
||||
@@ -9,9 +9,6 @@ namespace vm { using namespace ps3; }
|
||||
|
||||
namespace sys_net
|
||||
{
|
||||
|
||||
// It turns out SOL_SOCKET is equal to 1 on Linux, but 0xffff on Windows, and it appears the PS3 uses 0xffff, like Windows
|
||||
#define PS3_SOL_SOCKET 0xffff
|
||||
// Error codes
|
||||
enum
|
||||
{
|
||||
|
||||
@@ -229,7 +229,7 @@ error_code sys_prx_get_module_info(ppu_thread& ppu, u32 id, u64 flags, vm::ptr<s
|
||||
return _sys_prx_get_module_info(id, 0, opt);
|
||||
}
|
||||
|
||||
error_code sys_prx_get_module_id_by_name(vm::cptr<char> name, u64 flags, vm::ptr<sys_prx_get_module_id_by_name_option_t> pOpt)
|
||||
error_code sys_prx_get_module_id_by_name(vm::cptr<char> name, u64 flags, vm::ps3::ptr<sys_prx_get_module_id_by_name_option_t> pOpt)
|
||||
{
|
||||
sysPrxForUser.trace("sys_prx_get_module_id_by_name(name=%s, flags=0x%x, pOpt=*0x%x)", name, flags, pOpt);
|
||||
|
||||
|
||||
@@ -129,11 +129,11 @@ extern std::string ppu_get_syscall_name(u64 code)
|
||||
case 152: return "sys_raw_spu_get_int_mask";
|
||||
case 153: return "sys_raw_spu_set_int_stat";
|
||||
case 154: return "sys_raw_spu_get_int_stat";
|
||||
case 155: return "_sys_spu_image_get_information";
|
||||
case 155: return "sys_spu_image_get_information?";
|
||||
case 156: return "sys_spu_image_open";
|
||||
case 157: return "_sys_spu_image_import";
|
||||
case 158: return "_sys_spu_image_close";
|
||||
case 159: return "_sys_raw_spu_image_load";
|
||||
case 157: return "sys_spu_image_import";
|
||||
case 158: return "sys_spu_image_close";
|
||||
case 159: return "sys_raw_spu_load";
|
||||
case 160: return "sys_raw_spu_create";
|
||||
case 161: return "sys_raw_spu_destroy";
|
||||
case 163: return "sys_raw_spu_read_puint_mb";
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
#include "stdafx.h"
|
||||
#include "Utilities/VirtualMemory.h"
|
||||
#include "Utilities/bin_patch.h"
|
||||
#include "Crypto/sha1.h"
|
||||
#include "Crypto/unself.h"
|
||||
#include "Loader/ELF.h"
|
||||
@@ -202,7 +201,7 @@ static void ppu_initialize_modules(const std::shared_ptr<ppu_linkage_info>& link
|
||||
&ppu_module_manager::cellSpurs,
|
||||
&ppu_module_manager::cellSpursJq,
|
||||
&ppu_module_manager::cellSsl,
|
||||
&ppu_module_manager::cellSubDisplay,
|
||||
&ppu_module_manager::cellSubdisplay,
|
||||
&ppu_module_manager::cellSync,
|
||||
&ppu_module_manager::cellSync2,
|
||||
&ppu_module_manager::cellSysconf,
|
||||
@@ -505,7 +504,7 @@ static auto ppu_load_exports(const std::shared_ptr<ppu_linkage_info>& link, u32
|
||||
// Static function
|
||||
const auto _sf = _sm && _sm->functions.count(fnid) ? &_sm->functions.at(fnid) : nullptr;
|
||||
|
||||
if (_sf && (_sf->flags & MFF_FORCED_HLE) && g_cfg.core.hook_functions)
|
||||
if (_sf && (_sf->flags & MFF_FORCED_HLE))
|
||||
{
|
||||
// Inject a branch to the HLE implementation
|
||||
const u32 _entry = vm::read32(faddr);
|
||||
@@ -933,6 +932,11 @@ void ppu_unload_prx(const lv2_prx& prx)
|
||||
|
||||
void ppu_load_exec(const ppu_exec_object& elf)
|
||||
{
|
||||
if (g_cfg.core.hook_functions)
|
||||
{
|
||||
LOG_TODO(LOADER, "'Hook static functions' option deactivated");
|
||||
}
|
||||
|
||||
// Set for delayed initialization in ppu_initialize()
|
||||
const auto _main = fxm::make<ppu_module>();
|
||||
|
||||
@@ -950,11 +954,6 @@ void ppu_load_exec(const ppu_exec_object& elf)
|
||||
u32 primary_stacksize = 0x100000;
|
||||
u32 malloc_pagesize = 0x100000;
|
||||
|
||||
// Executable hash
|
||||
sha1_context sha;
|
||||
sha1_starts(&sha);
|
||||
u8 sha1_hash[20];
|
||||
|
||||
// Allocate memory at fixed positions
|
||||
for (const auto& prog : elf.progs)
|
||||
{
|
||||
@@ -965,11 +964,7 @@ void ppu_load_exec(const ppu_exec_object& elf)
|
||||
const u32 size = _seg.size = ::narrow<u32>(prog.p_memsz, "p_memsz" HERE);
|
||||
const u32 type = _seg.type = prog.p_type;
|
||||
const u32 flag = _seg.flags = prog.p_flags;
|
||||
|
||||
// Hash big-endian values
|
||||
sha1_update(&sha, (uchar*)&prog.p_type, sizeof(prog.p_type));
|
||||
sha1_update(&sha, (uchar*)&prog.p_flags, sizeof(prog.p_flags));
|
||||
|
||||
|
||||
if (type == 0x1 /* LOAD */ && prog.p_memsz)
|
||||
{
|
||||
if (prog.bin.size() > size || prog.bin.size() != prog.p_filesz)
|
||||
@@ -978,11 +973,8 @@ void ppu_load_exec(const ppu_exec_object& elf)
|
||||
if (!vm::falloc(addr, size, vm::main))
|
||||
fmt::throw_exception("vm::falloc() failed (addr=0x%x, memsz=0x%x)", addr, size);
|
||||
|
||||
// Copy segment data, hash it
|
||||
// Copy segment data
|
||||
std::memcpy(vm::base(addr), prog.bin.data(), prog.bin.size());
|
||||
sha1_update(&sha, (uchar*)&prog.p_vaddr, sizeof(prog.p_vaddr));
|
||||
sha1_update(&sha, (uchar*)&prog.p_memsz, sizeof(prog.p_memsz));
|
||||
sha1_update(&sha, prog.bin.data(), prog.bin.size());
|
||||
|
||||
// Initialize executable code if necessary
|
||||
if (prog.p_flags & 0x1)
|
||||
@@ -1012,28 +1004,6 @@ void ppu_load_exec(const ppu_exec_object& elf)
|
||||
}
|
||||
}
|
||||
|
||||
sha1_finish(&sha, sha1_hash);
|
||||
|
||||
// Format patch name
|
||||
std::string hash("PPU-0000000000000000000000000000000000000000");
|
||||
for (u32 i = 0; i < sizeof(sha1_hash); i++)
|
||||
{
|
||||
constexpr auto pal = "0123456789abcdef";
|
||||
hash[4 + i * 2] = pal[sha1_hash[i] >> 4];
|
||||
hash[5 + i * 2] = pal[sha1_hash[i] & 15];
|
||||
}
|
||||
|
||||
// Apply the patch
|
||||
auto applied = fxm::check_unlocked<patch_engine>()->apply(hash, vm::g_base_addr);
|
||||
|
||||
if (!Emu.GetTitleID().empty())
|
||||
{
|
||||
// Alternative patch
|
||||
applied += fxm::check_unlocked<patch_engine>()->apply(Emu.GetTitleID() + '-' + hash, vm::g_base_addr);
|
||||
}
|
||||
|
||||
LOG_NOTICE(LOADER, "PPU executable hash: %s (<- %u)", hash, applied);
|
||||
|
||||
// Initialize HLE modules
|
||||
ppu_initialize_modules(link);
|
||||
|
||||
@@ -1198,7 +1168,7 @@ void ppu_load_exec(const ppu_exec_object& elf)
|
||||
{ "cellFont", "libfont.sprx" },
|
||||
{ "cellFontFT", "libfontFT.sprx" },
|
||||
{ "cellFontFT", "libfreetype.sprx" },
|
||||
{ "cellGcmSys", "libgcm_sys.sprx" },
|
||||
{ "cellGcmSys", "libgcm_sys.sprx"},
|
||||
{ "cellGifDec", "libgifdec.sprx" },
|
||||
{ "cellGifDec", "libsre.sprx" },
|
||||
{ "cellJpgDec", "libjpgdec.sprx" },
|
||||
@@ -1294,7 +1264,7 @@ void ppu_load_exec(const ppu_exec_object& elf)
|
||||
if (!fs::is_dir(lle_dir))
|
||||
{
|
||||
LOG_ERROR(GENERAL, "/dev_flash/sys/external/ directory does not exist!"
|
||||
"\nYou should install the PS3 Firmware (Menu: File -> Install Firmware)."
|
||||
"\nYou should install the PS3 Firmware (Menu: Tools -> Install Firmware)."
|
||||
"\nVisit https://rpcs3.net/ for Quickstart Guide and more information.");
|
||||
}
|
||||
|
||||
|
||||
@@ -189,7 +189,7 @@ public:
|
||||
static const ppu_static_module cellSpurs;
|
||||
static const ppu_static_module cellSpursJq;
|
||||
static const ppu_static_module cellSsl;
|
||||
static const ppu_static_module cellSubDisplay;
|
||||
static const ppu_static_module cellSubdisplay;
|
||||
static const ppu_static_module cellSync;
|
||||
static const ppu_static_module cellSync2;
|
||||
static const ppu_static_module cellSysconf;
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
#include "stdafx.h"
|
||||
#include "Utilities/VirtualMemory.h"
|
||||
#include "Utilities/sysinfo.h"
|
||||
#include "Crypto/sha1.h"
|
||||
#include "Emu/Memory/Memory.h"
|
||||
#include "Emu/System.h"
|
||||
@@ -54,8 +53,6 @@
|
||||
#include <cfenv>
|
||||
#include "Utilities/GSL.h"
|
||||
|
||||
const bool s_use_rtm = utils::has_rtm();
|
||||
|
||||
extern u64 get_system_time();
|
||||
|
||||
namespace vm { using namespace ps3; }
|
||||
@@ -828,26 +825,6 @@ extern bool ppu_stwcx(ppu_thread& ppu, u32 addr, u32 reg_value)
|
||||
return false;
|
||||
}
|
||||
|
||||
if (s_use_rtm && utils::transaction_enter())
|
||||
{
|
||||
if (!vm::reader_lock{vm::try_to_lock})
|
||||
{
|
||||
_xabort(0);
|
||||
}
|
||||
|
||||
const bool result = ppu.rtime == vm::reservation_acquire(addr, sizeof(u32)) && data.compare_and_swap_test(static_cast<u32>(ppu.rdata), reg_value);
|
||||
|
||||
if (result)
|
||||
{
|
||||
vm::reservation_update(addr, sizeof(u32));
|
||||
vm::notify(addr, sizeof(u32));
|
||||
}
|
||||
|
||||
_xend();
|
||||
ppu.raddr = 0;
|
||||
return result;
|
||||
}
|
||||
|
||||
vm::writer_lock lock(0);
|
||||
|
||||
const bool result = ppu.rtime == vm::reservation_acquire(addr, sizeof(u32)) && data.compare_and_swap_test(static_cast<u32>(ppu.rdata), reg_value);
|
||||
@@ -872,26 +849,6 @@ extern bool ppu_stdcx(ppu_thread& ppu, u32 addr, u64 reg_value)
|
||||
return false;
|
||||
}
|
||||
|
||||
if (s_use_rtm && utils::transaction_enter())
|
||||
{
|
||||
if (!vm::reader_lock{vm::try_to_lock})
|
||||
{
|
||||
_xabort(0);
|
||||
}
|
||||
|
||||
const bool result = ppu.rtime == vm::reservation_acquire(addr, sizeof(u64)) && data.compare_and_swap_test(ppu.rdata, reg_value);
|
||||
|
||||
if (result)
|
||||
{
|
||||
vm::reservation_update(addr, sizeof(u64));
|
||||
vm::notify(addr, sizeof(u64));
|
||||
}
|
||||
|
||||
_xend();
|
||||
ppu.raddr = 0;
|
||||
return result;
|
||||
}
|
||||
|
||||
vm::writer_lock lock(0);
|
||||
|
||||
const bool result = ppu.rtime == vm::reservation_acquire(addr, sizeof(u64)) && data.compare_and_swap_test(ppu.rdata, reg_value);
|
||||
@@ -1163,12 +1120,6 @@ extern void ppu_initialize(const ppu_module& info)
|
||||
sha1_update(&ctx, vm::ps3::_ptr<const u8>(func.addr), func.size);
|
||||
}
|
||||
|
||||
if (info.name == "liblv2.sprx")
|
||||
{
|
||||
const be_t<u64> forced_upd = 1;
|
||||
sha1_update(&ctx, reinterpret_cast<const u8*>(&forced_upd), sizeof(forced_upd));
|
||||
}
|
||||
|
||||
sha1_finish(&ctx, output);
|
||||
fmt::append(obj_name, "-%016X-%s.obj", reinterpret_cast<be_t<u64>&>(output), jit->cpu());
|
||||
}
|
||||
@@ -1191,8 +1142,7 @@ extern void ppu_initialize(const ppu_module& info)
|
||||
if (fs::is_file(cache_path + obj_name))
|
||||
{
|
||||
semaphore_lock lock(jmutex);
|
||||
jit->add(cache_path + obj_name);
|
||||
LOG_SUCCESS(PPU, "LLVM: Loaded module %s", obj_name);
|
||||
ppu_initialize2(*jit, part, cache_path, obj_name);
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -1223,7 +1173,7 @@ extern void ppu_initialize(const ppu_module& info)
|
||||
|
||||
// Proceed with original JIT instance
|
||||
semaphore_lock lock(jmutex);
|
||||
jit->add(cache_path + obj_name);
|
||||
ppu_initialize2(*jit, part, cache_path, obj_name);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1303,8 +1253,6 @@ extern void ppu_initialize(const ppu_module& info)
|
||||
}
|
||||
}
|
||||
}
|
||||
#else
|
||||
fmt::throw_exception("LLVM is not available in this build.");
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -1338,6 +1286,8 @@ static void ppu_initialize2(jit_compiler& jit, const ppu_module& module_part, co
|
||||
|
||||
std::shared_ptr<MsgDialogBase> dlg;
|
||||
|
||||
// Check cached file
|
||||
if (!fs::is_file(cache_path + obj_name))
|
||||
{
|
||||
legacy::FunctionPassManager pm(module.get());
|
||||
|
||||
|
||||
@@ -295,6 +295,7 @@ Value* PPUTranslator::RegLoad(Value*& local)
|
||||
if (local)
|
||||
{
|
||||
// Simple load
|
||||
assert(!m_globals[index] || m_globals[index]->getType() == local->getType()->getPointerTo());
|
||||
return local;
|
||||
}
|
||||
|
||||
@@ -306,6 +307,7 @@ Value* PPUTranslator::RegLoad(Value*& local)
|
||||
void PPUTranslator::RegStore(llvm::Value* value, llvm::Value*& local)
|
||||
{
|
||||
const auto glb = RegInit(local);
|
||||
assert(glb->getType() == value->getType()->getPointerTo());
|
||||
local = value;
|
||||
}
|
||||
|
||||
@@ -329,7 +331,7 @@ void PPUTranslator::FlushRegisters()
|
||||
m_ir->SetInsertPoint(block);
|
||||
}
|
||||
|
||||
m_ir->CreateStore(local, m_ir->CreateBitCast(m_globals[index], local->getType()->getPointerTo()));
|
||||
m_ir->CreateStore(local, m_globals[index]);
|
||||
m_globals[index] = nullptr;
|
||||
}
|
||||
}
|
||||
@@ -4267,7 +4269,7 @@ Value* PPUTranslator::GetVr(u32 vr, VrType type)
|
||||
|
||||
switch (type)
|
||||
{
|
||||
case VrType::vi32: return m_ir->CreateBitCast(value, GetType<u32[4]>());
|
||||
case VrType::vi32: return value;
|
||||
case VrType::vi8: return m_ir->CreateBitCast(value, GetType<u8[16]>());
|
||||
case VrType::vi16: return m_ir->CreateBitCast(value, GetType<u16[8]>());
|
||||
case VrType::vf: return m_ir->CreateBitCast(value, GetType<f32[4]>());
|
||||
@@ -4296,7 +4298,7 @@ void PPUTranslator::SetVr(u32 vr, Value* value)
|
||||
}
|
||||
}
|
||||
|
||||
RegStore(value, m_vr[vr]);
|
||||
RegStore(m_ir->CreateBitCast(value, GetType<u32[4]>()), m_vr[vr]);
|
||||
}
|
||||
|
||||
Value* PPUTranslator::GetCrb(u32 crb)
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
|
||||
const spu_decoder<spu_itype> s_spu_itype;
|
||||
|
||||
spu_function_t* SPUDatabase::find(const be_t<u32>* data, u64 key, u32 max_size)
|
||||
std::shared_ptr<spu_function_t> SPUDatabase::find(const be_t<u32>* data, u64 key, u32 max_size)
|
||||
{
|
||||
for (auto found = m_db.equal_range(key); found.first != found.second; found.first++)
|
||||
{
|
||||
@@ -14,7 +14,7 @@ spu_function_t* SPUDatabase::find(const be_t<u32>* data, u64 key, u32 max_size)
|
||||
// Compare binary data explicitly (TODO: optimize)
|
||||
if (LIKELY(func->size <= max_size) && std::memcmp(func->data.data(), data, func->size) == 0)
|
||||
{
|
||||
return func.get();
|
||||
return func;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -33,7 +33,7 @@ SPUDatabase::~SPUDatabase()
|
||||
// TODO: serialize database
|
||||
}
|
||||
|
||||
spu_function_t* SPUDatabase::analyse(const be_t<u32>* ls, u32 entry, u32 max_limit)
|
||||
std::shared_ptr<spu_function_t> SPUDatabase::analyse(const be_t<u32>* ls, u32 entry, u32 max_limit)
|
||||
{
|
||||
// Check arguments (bounds and alignment)
|
||||
if (max_limit > 0x40000 || entry >= max_limit || entry % 4 || max_limit % 4)
|
||||
@@ -43,27 +43,23 @@ spu_function_t* SPUDatabase::analyse(const be_t<u32>* ls, u32 entry, u32 max_lim
|
||||
|
||||
// Key for multimap
|
||||
const u64 key = entry | u64{ ls[entry / 4] } << 32;
|
||||
const be_t<u32>* base = ls + entry / 4;
|
||||
const u32 block_sz = max_limit - entry;
|
||||
|
||||
{
|
||||
reader_lock lock(m_mutex);
|
||||
|
||||
// Try to find existing function in the database
|
||||
if (auto func = find(base, key, block_sz))
|
||||
if (auto func = find(ls + entry / 4, key, max_limit - entry))
|
||||
{
|
||||
return func;
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
writer_lock lock(m_mutex);
|
||||
writer_lock lock(m_mutex);
|
||||
|
||||
// Double-check
|
||||
if (auto func = find(base, key, block_sz))
|
||||
{
|
||||
return func;
|
||||
}
|
||||
// Double-check
|
||||
if (auto func = find(ls + entry / 4, key, max_limit - entry))
|
||||
{
|
||||
return func;
|
||||
}
|
||||
|
||||
// Initialize block entries with the function entry point
|
||||
@@ -85,15 +81,11 @@ spu_function_t* SPUDatabase::analyse(const be_t<u32>* ls, u32 entry, u32 max_lim
|
||||
|
||||
const auto type = s_spu_itype.decode(op.opcode);
|
||||
|
||||
// Find existing function
|
||||
if (pos != entry && find(ls + pos / 4, pos | u64{ op.opcode } << 32, limit - pos))
|
||||
{
|
||||
reader_lock lock(m_mutex);
|
||||
|
||||
// Find existing function
|
||||
if (pos != entry && find(ls + pos / 4, pos | u64{ op.opcode } << 32, limit - pos))
|
||||
{
|
||||
limit = pos;
|
||||
break;
|
||||
}
|
||||
limit = pos;
|
||||
break;
|
||||
}
|
||||
|
||||
// Additional analysis at the beginning of the block
|
||||
@@ -319,16 +311,10 @@ spu_function_t* SPUDatabase::analyse(const be_t<u32>* ls, u32 entry, u32 max_lim
|
||||
// Set whether the function can reset stack
|
||||
func->does_reset_stack = ila_sp_pos < limit;
|
||||
|
||||
// Lock here just before we write to the db
|
||||
// Its is unlikely that the second check will pass anyway so we delay this step since compiling functions is very fast
|
||||
{
|
||||
writer_lock lock(m_mutex);
|
||||
// Add function to the database
|
||||
m_db.emplace(key, func);
|
||||
|
||||
// Add function to the database
|
||||
m_db.emplace(key, func);
|
||||
}
|
||||
LOG_SUCCESS(SPU, "Function detected [0x%05x-0x%05x] (size=0x%x)", func->addr, func->addr + func->size, func->size);
|
||||
|
||||
LOG_NOTICE(SPU, "Function detected [0x%05x-0x%05x] (size=0x%x)", func->addr, func->addr + func->size, func->size);
|
||||
|
||||
return func.get();
|
||||
return func;
|
||||
}
|
||||
|
||||
@@ -289,12 +289,12 @@ class SPUDatabase final : spu_itype
|
||||
std::unordered_multimap<u64, std::shared_ptr<spu_function_t>> m_db;
|
||||
|
||||
// For internal use
|
||||
spu_function_t* find(const be_t<u32>* data, u64 key, u32 max_size);
|
||||
std::shared_ptr<spu_function_t> find(const be_t<u32>* data, u64 key, u32 max_size);
|
||||
|
||||
public:
|
||||
SPUDatabase();
|
||||
~SPUDatabase();
|
||||
|
||||
// Try to retrieve SPU function information
|
||||
spu_function_t* analyse(const be_t<u32>* ls, u32 entry, u32 limit = 0x40000);
|
||||
std::shared_ptr<spu_function_t> analyse(const be_t<u32>* ls, u32 entry, u32 limit = 0x40000);
|
||||
};
|
||||
|
||||
@@ -5,7 +5,6 @@
|
||||
#include "SPUThread.h"
|
||||
#include "SPURecompiler.h"
|
||||
#include "SPUASMJITRecompiler.h"
|
||||
#include <algorithm>
|
||||
|
||||
extern u64 get_system_time();
|
||||
|
||||
@@ -23,15 +22,8 @@ void spu_recompiler_base::enter(SPUThread& spu)
|
||||
// Get SPU LS pointer
|
||||
const auto _ls = vm::ps3::_ptr<u32>(spu.offset);
|
||||
|
||||
// Search if cached data matches
|
||||
auto func = spu.compiled_cache[spu.pc / 4];
|
||||
|
||||
// Check shared db if we dont have a match
|
||||
if (!func || !std::equal(func->data.begin(), func->data.end(), _ls + spu.pc / 4, [](const be_t<u32>& l, const be_t<u32>& r) { return *(u32*)(u8*)&l == *(u32*)(u8*)&r; }))
|
||||
{
|
||||
func = spu.spu_db->analyse(_ls, spu.pc);
|
||||
spu.compiled_cache[spu.pc / 4] = func;
|
||||
}
|
||||
// Always validate (TODO)
|
||||
const auto func = spu.spu_db->analyse(_ls, spu.pc);
|
||||
|
||||
// Reset callstack if necessary
|
||||
if ((func->does_reset_stack && spu.recursion_level) || spu.recursion_level >= 128)
|
||||
@@ -40,7 +32,6 @@ void spu_recompiler_base::enter(SPUThread& spu)
|
||||
return;
|
||||
}
|
||||
|
||||
// Compile if needed
|
||||
if (!func->compiled)
|
||||
{
|
||||
if (!spu.spu_rec)
|
||||
|
||||
+10
-146
@@ -1,6 +1,5 @@
|
||||
#include "stdafx.h"
|
||||
#include "Utilities/lockless.h"
|
||||
#include "Utilities/sysinfo.h"
|
||||
#include "Emu/Memory/Memory.h"
|
||||
#include "Emu/System.h"
|
||||
|
||||
@@ -23,8 +22,6 @@
|
||||
#include <atomic>
|
||||
#include <thread>
|
||||
|
||||
const bool s_use_rtm = utils::has_rtm();
|
||||
|
||||
#ifdef _MSC_VER
|
||||
bool operator ==(const u128& lhs, const u128& rhs)
|
||||
{
|
||||
@@ -33,7 +30,6 @@ bool operator ==(const u128& lhs, const u128& rhs)
|
||||
#endif
|
||||
|
||||
extern u64 get_timebased_time();
|
||||
extern u64 get_system_time();
|
||||
|
||||
extern thread_local u64 g_tls_fault_spu;
|
||||
|
||||
@@ -59,81 +55,6 @@ void fmt_class_string<spu_decoder_type>::format(std::string& out, u64 arg)
|
||||
});
|
||||
}
|
||||
|
||||
namespace spu
|
||||
{
|
||||
namespace scheduler
|
||||
{
|
||||
std::array<std::atomic<u8>, 65536> atomic_instruction_table = {};
|
||||
constexpr u32 native_jiffy_duration_us = 1500; //About 1ms resolution with a half offset
|
||||
|
||||
void acquire_pc_address(u32 pc, u32 timeout_ms = 3)
|
||||
{
|
||||
const u8 max_concurrent_instructions = (u8)g_cfg.core.preferred_spu_threads;
|
||||
const u32 pc_offset = pc >> 2;
|
||||
|
||||
if (atomic_instruction_table[pc_offset].load(std::memory_order_consume) >= max_concurrent_instructions)
|
||||
{
|
||||
if (timeout_ms > 0)
|
||||
{
|
||||
const auto timeout = timeout_ms * 1000u; //convert to microseconds
|
||||
const auto start = get_system_time();
|
||||
auto remaining = timeout;
|
||||
|
||||
while (atomic_instruction_table[pc_offset].load(std::memory_order_consume) >= max_concurrent_instructions)
|
||||
{
|
||||
if (remaining >= native_jiffy_duration_us)
|
||||
std::this_thread::sleep_for(1ms);
|
||||
else
|
||||
std::this_thread::yield();
|
||||
|
||||
const auto now = get_system_time();
|
||||
const auto elapsed = now - start;
|
||||
|
||||
if (elapsed > timeout) break;
|
||||
remaining = timeout - elapsed;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
//Slight pause if function is overburdened
|
||||
thread_ctrl::wait_for(100);
|
||||
}
|
||||
}
|
||||
|
||||
atomic_instruction_table[pc_offset]++;
|
||||
}
|
||||
|
||||
void release_pc_address(u32 pc)
|
||||
{
|
||||
const u32 pc_offset = pc >> 2;
|
||||
|
||||
atomic_instruction_table[pc_offset]--;
|
||||
}
|
||||
|
||||
struct concurrent_execution_watchdog
|
||||
{
|
||||
u32 pc = 0;
|
||||
bool active = false;
|
||||
|
||||
concurrent_execution_watchdog(SPUThread& spu)
|
||||
:pc(spu.pc)
|
||||
{
|
||||
if (g_cfg.core.preferred_spu_threads > 0)
|
||||
{
|
||||
acquire_pc_address(pc, (u32)g_cfg.core.spu_delay_penalty);
|
||||
active = true;
|
||||
}
|
||||
}
|
||||
|
||||
~concurrent_execution_watchdog()
|
||||
{
|
||||
if (active)
|
||||
release_pc_address(pc);
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
void spu_int_ctrl_t::set(u64 ints)
|
||||
{
|
||||
// leave only enabled interrupts
|
||||
@@ -562,7 +483,6 @@ void SPUThread::do_dma_transfer(const spu_mfc_cmd& args, bool from_mfc)
|
||||
|
||||
void SPUThread::process_mfc_cmd()
|
||||
{
|
||||
spu::scheduler::concurrent_execution_watchdog watchdog(*this);
|
||||
LOG_TRACE(SPU, "DMAC: cmd=%s, lsa=0x%x, ea=0x%llx, tag=0x%x, size=0x%x", ch_mfc_cmd.cmd, ch_mfc_cmd.lsa, ch_mfc_cmd.eal, ch_mfc_cmd.tag, ch_mfc_cmd.size);
|
||||
|
||||
const auto mfc = fxm::check_unlocked<mfc_thread>();
|
||||
@@ -579,7 +499,7 @@ void SPUThread::process_mfc_cmd()
|
||||
}
|
||||
|
||||
// TODO: investigate lost notifications
|
||||
std::this_thread::yield();
|
||||
std::this_thread::sleep_for(0us);
|
||||
_mm_lfence();
|
||||
}
|
||||
};
|
||||
@@ -624,22 +544,9 @@ void SPUThread::process_mfc_cmd()
|
||||
thread_ctrl::wait_for(100);
|
||||
}
|
||||
}
|
||||
else if (s_use_rtm && utils::transaction_enter())
|
||||
{
|
||||
if (!vm::reader_lock{vm::try_to_lock})
|
||||
{
|
||||
_xabort(0);
|
||||
}
|
||||
|
||||
rtime = vm::reservation_acquire(raddr, 128);
|
||||
rdata = data;
|
||||
_xend();
|
||||
|
||||
_ref<decltype(rdata)>(ch_mfc_cmd.lsa & 0x3ffff) = rdata;
|
||||
return ch_atomic_stat.set_value(MFC_GETLLAR_SUCCESS);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Fast path
|
||||
rdata = data;
|
||||
_mm_lfence();
|
||||
}
|
||||
@@ -670,36 +577,15 @@ void SPUThread::process_mfc_cmd()
|
||||
if (raddr == ch_mfc_cmd.eal && rtime == vm::reservation_acquire(raddr, 128) && rdata == data)
|
||||
{
|
||||
// TODO: vm::check_addr
|
||||
if (s_use_rtm && utils::transaction_enter())
|
||||
vm::writer_lock lock;
|
||||
|
||||
if (rtime == vm::reservation_acquire(raddr, 128) && rdata == data)
|
||||
{
|
||||
if (!vm::reader_lock{vm::try_to_lock})
|
||||
{
|
||||
_xabort(0);
|
||||
}
|
||||
data = to_write;
|
||||
result = true;
|
||||
|
||||
if (rtime == vm::reservation_acquire(raddr, 128) && rdata == data)
|
||||
{
|
||||
data = to_write;
|
||||
result = true;
|
||||
|
||||
vm::reservation_update(raddr, 128);
|
||||
vm::notify(raddr, 128);
|
||||
}
|
||||
|
||||
_xend();
|
||||
}
|
||||
else
|
||||
{
|
||||
vm::writer_lock lock;
|
||||
|
||||
if (rtime == vm::reservation_acquire(raddr, 128) && rdata == data)
|
||||
{
|
||||
data = to_write;
|
||||
result = true;
|
||||
|
||||
vm::reservation_update(raddr, 128);
|
||||
vm::notify(raddr, 128);
|
||||
}
|
||||
vm::reservation_update(raddr, 128);
|
||||
vm::notify(raddr, 128);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -735,23 +621,6 @@ void SPUThread::process_mfc_cmd()
|
||||
|
||||
// Store unconditionally
|
||||
// TODO: vm::check_addr
|
||||
|
||||
if (s_use_rtm && utils::transaction_enter())
|
||||
{
|
||||
if (!vm::reader_lock{vm::try_to_lock})
|
||||
{
|
||||
_xabort(0);
|
||||
}
|
||||
|
||||
data = to_write;
|
||||
vm::reservation_update(ch_mfc_cmd.eal, 128);
|
||||
vm::notify(ch_mfc_cmd.eal, 128);
|
||||
_xend();
|
||||
|
||||
ch_atomic_stat.set_value(MFC_PUTLLUC_SUCCESS);
|
||||
return;
|
||||
}
|
||||
|
||||
vm::writer_lock lock(0);
|
||||
data = to_write;
|
||||
vm::reservation_update(ch_mfc_cmd.eal, 128);
|
||||
@@ -1028,7 +897,7 @@ bool SPUThread::get_ch_value(u32 ch, u32& out)
|
||||
if (ctr > 10000)
|
||||
{
|
||||
ctr = 0;
|
||||
std::this_thread::yield();
|
||||
std::this_thread::sleep_for(0us);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -1109,11 +978,6 @@ bool SPUThread::get_ch_value(u32 ch, u32& out)
|
||||
case SPU_RdDec:
|
||||
{
|
||||
out = ch_dec_value - (u32)(get_timebased_time() - ch_dec_start_timestamp);
|
||||
|
||||
//Polling: We might as well hint to the scheduler to slot in another thread since this one is counting down
|
||||
if (g_cfg.core.spu_loop_detection && out > spu::scheduler::native_jiffy_duration_us)
|
||||
std::this_thread::yield();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -582,7 +582,6 @@ public:
|
||||
|
||||
std::exception_ptr pending_exception;
|
||||
|
||||
std::array<struct spu_function_t*, 65536> compiled_cache{};
|
||||
std::shared_ptr<class SPUDatabase> spu_db;
|
||||
std::shared_ptr<class spu_recompiler_base> spu_rec;
|
||||
u32 recursion_level = 0;
|
||||
|
||||
@@ -195,18 +195,18 @@ const std::array<ppu_function_t, 1024> s_ppu_syscall_table
|
||||
BIND_FUNC(sys_time_get_current_time), //145 (0x091)
|
||||
null_func,//BIND_FUNC(sys_time_get_system_time), //146 (0x092) ROOT
|
||||
BIND_FUNC(sys_time_get_timebase_frequency), //147 (0x093)
|
||||
BIND_FUNC(_sys_rwlock_trywlock), //148 (0x094)
|
||||
null_func,//BIND_FUNC(_sys_rwlock_trywlock) //148 (0x094)
|
||||
null_func, //149 (0x095) UNS
|
||||
BIND_FUNC(sys_raw_spu_create_interrupt_tag), //150 (0x096)
|
||||
BIND_FUNC(sys_raw_spu_set_int_mask), //151 (0x097)
|
||||
BIND_FUNC(sys_raw_spu_get_int_mask), //152 (0x098)
|
||||
BIND_FUNC(sys_raw_spu_set_int_stat), //153 (0x099)
|
||||
BIND_FUNC(sys_raw_spu_get_int_stat), //154 (0x09A)
|
||||
BIND_FUNC(_sys_spu_image_get_information), //155 (0x09B)
|
||||
null_func,//BIND_FUNC(sys_spu_image_get_information?) //155 (0x09B)
|
||||
BIND_FUNC(sys_spu_image_open), //156 (0x09C)
|
||||
BIND_FUNC(_sys_spu_image_import), //157 (0x09D)
|
||||
BIND_FUNC(_sys_spu_image_close), //158 (0x09E)
|
||||
BIND_FUNC(_sys_raw_spu_image_load), //159 (0x09F)
|
||||
null_func,//BIND_FUNC(sys_spu_image_import) //157 (0x09D)
|
||||
null_func,//BIND_FUNC(sys_spu_image_close) //158 (0x09E)
|
||||
null_func,//BIND_FUNC(sys_raw_spu_load) //159 (0x09F)
|
||||
BIND_FUNC(sys_raw_spu_create), //160 (0x0A0)
|
||||
BIND_FUNC(sys_raw_spu_destroy), //161 (0x0A1)
|
||||
null_func, //162 (0x0A2) UNS
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
#include "Emu/Memory/Memory.h"
|
||||
#include "Emu/System.h"
|
||||
#include "Emu/IdManager.h"
|
||||
#include "Emu/IPC.h"
|
||||
|
||||
#include "Emu/Cell/ErrorCodes.h"
|
||||
#include "Emu/Cell/PPUThread.h"
|
||||
@@ -13,14 +12,18 @@ namespace vm { using namespace ps3; }
|
||||
|
||||
logs::channel sys_cond("sys_cond");
|
||||
|
||||
template<> DECLARE(ipc_manager<lv2_cond, u64>::g_ipc) {};
|
||||
|
||||
extern u64 get_system_time();
|
||||
|
||||
error_code sys_cond_create(vm::ptr<u32> cond_id, u32 mutex_id, vm::ptr<sys_cond_attribute_t> attr)
|
||||
{
|
||||
sys_cond.warning("sys_cond_create(cond_id=*0x%x, mutex_id=0x%x, attr=*0x%x)", cond_id, mutex_id, attr);
|
||||
|
||||
if (attr->pshared != SYS_SYNC_NOT_PROCESS_SHARED || attr->ipc_key || attr->flags)
|
||||
{
|
||||
sys_cond.error("sys_cond_create(): unknown attributes (pshared=0x%x, ipc_key=0x%llx, flags=0x%x)", attr->pshared, attr->ipc_key, attr->flags);
|
||||
return CELL_EINVAL;
|
||||
}
|
||||
|
||||
auto mutex = idm::get<lv2_obj, lv2_mutex>(mutex_id);
|
||||
|
||||
if (!mutex)
|
||||
@@ -28,21 +31,13 @@ error_code sys_cond_create(vm::ptr<u32> cond_id, u32 mutex_id, vm::ptr<sys_cond_
|
||||
return CELL_ESRCH;
|
||||
}
|
||||
|
||||
if (auto error = lv2_obj::create<lv2_cond>(attr->pshared, attr->ipc_key, attr->flags, [&]
|
||||
if (const u32 id = idm::make<lv2_obj, lv2_cond>(attr->name_u64, std::move(mutex)))
|
||||
{
|
||||
return std::make_shared<lv2_cond>(
|
||||
attr->pshared,
|
||||
attr->flags,
|
||||
attr->ipc_key,
|
||||
attr->name_u64,
|
||||
std::move(mutex));
|
||||
}))
|
||||
{
|
||||
return error;
|
||||
*cond_id = id;
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
*cond_id = idm::last_id();
|
||||
return CELL_OK;
|
||||
return CELL_EAGAIN;
|
||||
}
|
||||
|
||||
error_code sys_cond_destroy(u32 cond_id)
|
||||
@@ -56,6 +51,7 @@ error_code sys_cond_destroy(u32 cond_id)
|
||||
return CELL_EBUSY;
|
||||
}
|
||||
|
||||
cond.mutex->cond_count--;
|
||||
return {};
|
||||
});
|
||||
|
||||
|
||||
@@ -30,20 +30,15 @@ struct lv2_cond final : lv2_obj
|
||||
atomic_t<u32> waiters{0};
|
||||
std::deque<cpu_thread*> sq;
|
||||
|
||||
lv2_cond(u32 shared, s32 flags, u64 key, u64 name, std::shared_ptr<lv2_mutex> mutex)
|
||||
: shared(shared)
|
||||
, key(key)
|
||||
, flags(flags)
|
||||
lv2_cond(u64 name, std::shared_ptr<lv2_mutex> mutex)
|
||||
: shared(0)
|
||||
, key(0)
|
||||
, flags(0)
|
||||
, name(name)
|
||||
, mutex(std::move(mutex))
|
||||
{
|
||||
this->mutex->cond_count++;
|
||||
}
|
||||
|
||||
~lv2_cond()
|
||||
{
|
||||
this->mutex->cond_count--;
|
||||
}
|
||||
};
|
||||
|
||||
class ppu_thread;
|
||||
|
||||
@@ -99,12 +99,10 @@ error_code sys_event_queue_create(vm::ptr<u32> equeue_id, vm::ptr<sys_event_queu
|
||||
return CELL_EINVAL;
|
||||
}
|
||||
|
||||
auto queue = std::make_shared<lv2_event_queue>(protocol, type, attr->name_u64, event_queue_key, size);
|
||||
|
||||
if (event_queue_key == SYS_EVENT_QUEUE_LOCAL)
|
||||
{
|
||||
// Not an IPC queue
|
||||
if (const u32 _id = idm::import_existing<lv2_obj, lv2_event_queue>(std::move(queue)))
|
||||
if (const u32 _id = idm::make<lv2_obj, lv2_event_queue>(protocol, type, attr->name_u64, event_queue_key, size))
|
||||
{
|
||||
*equeue_id = _id;
|
||||
return CELL_OK;
|
||||
@@ -113,27 +111,25 @@ error_code sys_event_queue_create(vm::ptr<u32> equeue_id, vm::ptr<sys_event_queu
|
||||
return CELL_EAGAIN;
|
||||
}
|
||||
|
||||
// Create IPC queue
|
||||
if (!ipc_manager<lv2_event_queue, u64>::add(event_queue_key, [&]() -> std::shared_ptr<lv2_event_queue>
|
||||
{
|
||||
if (const u32 _id = idm::import_existing<lv2_obj, lv2_event_queue>(queue))
|
||||
{
|
||||
*equeue_id = _id;
|
||||
return std::move(queue);
|
||||
}
|
||||
std::shared_ptr<lv2_event_queue> result;
|
||||
|
||||
return nullptr;
|
||||
// Create IPC queue
|
||||
if (!ipc_manager<lv2_event_queue, u64>::add(event_queue_key, [&]() -> const std::shared_ptr<lv2_event_queue>&
|
||||
{
|
||||
result = idm::make_ptr<lv2_obj, lv2_event_queue>(protocol, type, attr->name_u64, event_queue_key, size);
|
||||
return result;
|
||||
}))
|
||||
{
|
||||
return CELL_EEXIST;
|
||||
}
|
||||
|
||||
if (queue)
|
||||
if (result)
|
||||
{
|
||||
return CELL_EAGAIN;
|
||||
*equeue_id = idm::last_id();
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
return CELL_OK;
|
||||
return CELL_EAGAIN;
|
||||
}
|
||||
|
||||
error_code sys_event_queue_destroy(ppu_thread& ppu, u32 equeue_id, s32 mode)
|
||||
@@ -228,8 +224,6 @@ error_code sys_event_queue_receive(ppu_thread& ppu, u32 equeue_id, vm::ptr<sys_e
|
||||
{
|
||||
sys_event.trace("sys_event_queue_receive(equeue_id=0x%x, *0x%x, timeout=0x%llx)", equeue_id, dummy_event, timeout);
|
||||
|
||||
ppu.gpr[3] = CELL_OK;
|
||||
|
||||
const auto queue = idm::get<lv2_obj, lv2_event_queue>(equeue_id, [&](lv2_event_queue& queue) -> CellError
|
||||
{
|
||||
if (queue.type != SYS_PPU_QUEUE)
|
||||
@@ -269,6 +263,8 @@ error_code sys_event_queue_receive(ppu_thread& ppu, u32 equeue_id, vm::ptr<sys_e
|
||||
}
|
||||
|
||||
// If cancelled, gpr[3] will be non-zero. Other registers must contain event data.
|
||||
ppu.gpr[3] = 0;
|
||||
|
||||
while (!ppu.state.test_and_reset(cpu_flag::signal))
|
||||
{
|
||||
if (timeout)
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
#include "Emu/Memory/Memory.h"
|
||||
#include "Emu/System.h"
|
||||
#include "Emu/IdManager.h"
|
||||
#include "Emu/IPC.h"
|
||||
|
||||
#include "Emu/Cell/ErrorCodes.h"
|
||||
#include "Emu/Cell/PPUThread.h"
|
||||
@@ -14,8 +13,6 @@ namespace vm { using namespace ps3; }
|
||||
|
||||
logs::channel sys_event_flag("sys_event_flag");
|
||||
|
||||
template<> DECLARE(ipc_manager<lv2_event_flag, u64>::g_ipc) {};
|
||||
|
||||
extern u64 get_system_time();
|
||||
|
||||
error_code sys_event_flag_create(vm::ptr<u32> id, vm::ptr<sys_event_flag_attribute_t> attr, u64 init)
|
||||
@@ -40,6 +37,12 @@ error_code sys_event_flag_create(vm::ptr<u32> id, vm::ptr<sys_event_flag_attribu
|
||||
return CELL_EINVAL;
|
||||
}
|
||||
|
||||
if (attr->pshared != SYS_SYNC_NOT_PROCESS_SHARED || attr->ipc_key || attr->flags)
|
||||
{
|
||||
sys_event_flag.error("sys_event_flag_create(): unknown attributes (pshared=0x%x, ipc_key=0x%llx, flags=0x%x)", attr->pshared, attr->ipc_key, attr->flags);
|
||||
return CELL_EINVAL;
|
||||
}
|
||||
|
||||
const u32 type = attr->type;
|
||||
|
||||
if (type != SYS_SYNC_WAITER_SINGLE && type != SYS_SYNC_WAITER_MULTIPLE)
|
||||
@@ -48,23 +51,13 @@ error_code sys_event_flag_create(vm::ptr<u32> id, vm::ptr<sys_event_flag_attribu
|
||||
return CELL_EINVAL;
|
||||
}
|
||||
|
||||
if (auto error = lv2_obj::create<lv2_event_flag>(attr->pshared, attr->ipc_key, attr->flags, [&]
|
||||
if (const u32 _id = idm::make<lv2_obj, lv2_event_flag>(protocol, type, attr->name_u64, init))
|
||||
{
|
||||
return std::make_shared<lv2_event_flag>(
|
||||
attr->protocol,
|
||||
attr->pshared,
|
||||
attr->ipc_key,
|
||||
attr->flags,
|
||||
attr->type,
|
||||
attr->name_u64,
|
||||
init);
|
||||
}))
|
||||
{
|
||||
return error;
|
||||
*id = _id;
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
*id = idm::last_id();
|
||||
return CELL_OK;
|
||||
return CELL_EAGAIN;
|
||||
}
|
||||
|
||||
error_code sys_event_flag_destroy(u32 id)
|
||||
|
||||
@@ -45,11 +45,11 @@ struct lv2_event_flag final : lv2_obj
|
||||
atomic_t<u64> pattern;
|
||||
std::deque<cpu_thread*> sq;
|
||||
|
||||
lv2_event_flag(u32 protocol, u32 shared, u64 key, s32 flags, s32 type, u64 name, u64 pattern)
|
||||
lv2_event_flag(u32 protocol, s32 type, u64 name, u64 pattern)
|
||||
: protocol(protocol)
|
||||
, shared(shared)
|
||||
, key(key)
|
||||
, flags(flags)
|
||||
, shared(0)
|
||||
, key(0)
|
||||
, flags(0)
|
||||
, type(type)
|
||||
, name(name)
|
||||
, pattern(pattern)
|
||||
|
||||
@@ -24,7 +24,7 @@ error_code _sys_lwcond_create(vm::ptr<u32> lwcond_id, u32 lwmutex_id, vm::ptr<sy
|
||||
return CELL_ESRCH;
|
||||
}
|
||||
|
||||
if (const u32 id = idm::make<lv2_obj, lv2_lwcond>(name, lwmutex_id, control))
|
||||
if (const u32 id = idm::make<lv2_obj, lv2_lwcond>(name, lwmutex_id))
|
||||
{
|
||||
*lwcond_id = id;
|
||||
return CELL_OK;
|
||||
@@ -79,9 +79,9 @@ error_code _sys_lwcond_signal(ppu_thread& ppu, u32 lwcond_id, u32 lwmutex_id, u3
|
||||
{
|
||||
mutex = idm::check_unlocked<lv2_obj, lv2_lwmutex>(lwmutex_id);
|
||||
|
||||
if (cond.waiters)
|
||||
if (mutex && cond.waiters)
|
||||
{
|
||||
semaphore_lock lock(cond.mutex);
|
||||
semaphore_lock lock(mutex->mutex);
|
||||
|
||||
cpu_thread* result = nullptr;
|
||||
|
||||
@@ -99,7 +99,7 @@ error_code _sys_lwcond_signal(ppu_thread& ppu, u32 lwcond_id, u32 lwmutex_id, u3
|
||||
}
|
||||
else
|
||||
{
|
||||
result = cond.schedule<ppu_thread>(cond.sq, cond.control->lwmutex->attribute & SYS_SYNC_ATTR_PROTOCOL_MASK);
|
||||
result = cond.schedule<ppu_thread>(cond.sq, mutex->protocol);
|
||||
}
|
||||
|
||||
if (result)
|
||||
@@ -111,10 +111,8 @@ error_code _sys_lwcond_signal(ppu_thread& ppu, u32 lwcond_id, u32 lwmutex_id, u3
|
||||
static_cast<ppu_thread*>(result)->gpr[3] = CELL_EBUSY;
|
||||
}
|
||||
|
||||
if (mode == 1)
|
||||
if (mode != 2 && !mutex->signaled.fetch_op([](u32& v) { if (v) v--; }))
|
||||
{
|
||||
verify(HERE), !mutex->signaled;
|
||||
semaphore_lock lock(mutex->mutex);
|
||||
mutex->sq.emplace_back(result);
|
||||
result = nullptr;
|
||||
mode = 2; // Enforce CELL_OK
|
||||
@@ -172,13 +170,13 @@ error_code _sys_lwcond_signal_all(ppu_thread& ppu, u32 lwcond_id, u32 lwmutex_id
|
||||
{
|
||||
mutex = idm::check_unlocked<lv2_obj, lv2_lwmutex>(lwmutex_id);
|
||||
|
||||
if (cond.waiters)
|
||||
if (mutex && cond.waiters)
|
||||
{
|
||||
semaphore_lock lock(cond.mutex);
|
||||
semaphore_lock lock(mutex->mutex);
|
||||
|
||||
u32 result = 0;
|
||||
|
||||
while (const auto cpu = cond.schedule<ppu_thread>(cond.sq, cond.control->lwmutex->attribute & SYS_SYNC_ATTR_PROTOCOL_MASK))
|
||||
while (const auto cpu = cond.schedule<ppu_thread>(cond.sq, mutex->protocol))
|
||||
{
|
||||
cond.waiters--;
|
||||
|
||||
@@ -187,10 +185,8 @@ error_code _sys_lwcond_signal_all(ppu_thread& ppu, u32 lwcond_id, u32 lwmutex_id
|
||||
static_cast<ppu_thread*>(cpu)->gpr[3] = CELL_EBUSY;
|
||||
}
|
||||
|
||||
if (mode == 1)
|
||||
if (mode != 2 && !mutex->signaled.fetch_op([](u32& v) { if (v) v--; }))
|
||||
{
|
||||
verify(HERE), !mutex->signaled;
|
||||
semaphore_lock lock(mutex->mutex);
|
||||
mutex->sq.emplace_back(cpu);
|
||||
}
|
||||
else
|
||||
@@ -241,15 +237,13 @@ error_code _sys_lwcond_queue_wait(ppu_thread& ppu, u32 lwcond_id, u32 lwmutex_id
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
semaphore_lock lock(cond.mutex);
|
||||
semaphore_lock lock(mutex->mutex);
|
||||
|
||||
// Add a waiter
|
||||
cond.waiters++;
|
||||
cond.sq.emplace_back(&ppu);
|
||||
cond.sleep(ppu, timeout);
|
||||
|
||||
semaphore_lock lock2(mutex->mutex);
|
||||
|
||||
// Process lwmutex sleep queue
|
||||
if (const auto cpu = mutex->schedule<ppu_thread>(mutex->sq, mutex->protocol))
|
||||
{
|
||||
@@ -280,7 +274,7 @@ error_code _sys_lwcond_queue_wait(ppu_thread& ppu, u32 lwcond_id, u32 lwmutex_id
|
||||
|
||||
if (passed >= timeout)
|
||||
{
|
||||
semaphore_lock lock(cond->mutex);
|
||||
semaphore_lock lock(mutex->mutex);
|
||||
|
||||
if (!cond->unqueue(cond->sq, &ppu))
|
||||
{
|
||||
|
||||
@@ -25,16 +25,13 @@ struct lv2_lwcond final : lv2_obj
|
||||
|
||||
const u64 name;
|
||||
const u32 lwid;
|
||||
vm::ps3::ptr<sys_lwcond_t> control;
|
||||
|
||||
semaphore<> mutex;
|
||||
atomic_t<u32> waiters{0};
|
||||
std::deque<cpu_thread*> sq;
|
||||
|
||||
lv2_lwcond(u64 name, u32 lwid, vm::ps3::ptr<sys_lwcond_t> control)
|
||||
lv2_lwcond(u64 name, u32 lwid)
|
||||
: name(name)
|
||||
, lwid(lwid)
|
||||
, control(control)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
#include "Emu/Memory/Memory.h"
|
||||
#include "Emu/System.h"
|
||||
#include "Emu/IdManager.h"
|
||||
#include "Emu/IPC.h"
|
||||
|
||||
#include "Emu/Cell/ErrorCodes.h"
|
||||
#include "Emu/Cell/PPUThread.h"
|
||||
@@ -12,8 +11,6 @@ namespace vm { using namespace ps3; }
|
||||
|
||||
logs::channel sys_mutex("sys_mutex");
|
||||
|
||||
template<> DECLARE(ipc_manager<lv2_mutex, u64>::g_ipc) {};
|
||||
|
||||
extern u64 get_system_time();
|
||||
|
||||
error_code sys_mutex_create(vm::ptr<u32> mutex_id, vm::ptr<sys_mutex_attribute_t> attr)
|
||||
@@ -25,53 +22,48 @@ error_code sys_mutex_create(vm::ptr<u32> mutex_id, vm::ptr<sys_mutex_attribute_t
|
||||
return CELL_EFAULT;
|
||||
}
|
||||
|
||||
switch (attr->protocol)
|
||||
const u32 protocol = attr->protocol;
|
||||
|
||||
switch (protocol)
|
||||
{
|
||||
case SYS_SYNC_FIFO: break;
|
||||
case SYS_SYNC_PRIORITY: break;
|
||||
case SYS_SYNC_PRIORITY_INHERIT:
|
||||
sys_mutex.fatal("sys_mutex_create(): SYS_SYNC_PRIORITY_INHERIT");
|
||||
sys_mutex.todo("sys_mutex_create(): SYS_SYNC_PRIORITY_INHERIT");
|
||||
break;
|
||||
default:
|
||||
{
|
||||
sys_mutex.error("sys_mutex_create(): unknown protocol (0x%x)", attr->protocol);
|
||||
sys_mutex.error("sys_mutex_create(): unknown protocol (0x%x)", protocol);
|
||||
return CELL_EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
switch (attr->recursive)
|
||||
const u32 recursive = attr->recursive;
|
||||
|
||||
switch (recursive)
|
||||
{
|
||||
case SYS_SYNC_RECURSIVE: break;
|
||||
case SYS_SYNC_NOT_RECURSIVE: break;
|
||||
default:
|
||||
{
|
||||
sys_mutex.error("sys_mutex_create(): unknown recursive (0x%x)", attr->recursive);
|
||||
sys_mutex.error("sys_mutex_create(): unknown recursive (0x%x)", recursive);
|
||||
return CELL_EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
if (attr->adaptive != SYS_SYNC_NOT_ADAPTIVE)
|
||||
if (attr->pshared != SYS_SYNC_NOT_PROCESS_SHARED || attr->adaptive != SYS_SYNC_NOT_ADAPTIVE || attr->ipc_key || attr->flags)
|
||||
{
|
||||
sys_mutex.todo("sys_mutex_create(): unexpected adaptive (0x%x)", attr->adaptive);
|
||||
sys_mutex.error("sys_mutex_create(): unknown attributes (pshared=0x%x, adaptive=0x%x, ipc_key=0x%llx, flags=0x%x)", attr->pshared, attr->adaptive, attr->ipc_key, attr->flags);
|
||||
return CELL_EINVAL;
|
||||
}
|
||||
|
||||
if (auto error = lv2_obj::create<lv2_mutex>(attr->pshared, attr->ipc_key, attr->flags, [&]()
|
||||
if (const u32 id = idm::make<lv2_obj, lv2_mutex>(protocol, recursive, attr->name_u64))
|
||||
{
|
||||
return std::make_shared<lv2_mutex>(
|
||||
attr->protocol,
|
||||
attr->recursive,
|
||||
attr->pshared,
|
||||
attr->adaptive,
|
||||
attr->ipc_key,
|
||||
attr->flags,
|
||||
attr->name_u64);
|
||||
}))
|
||||
{
|
||||
return error;
|
||||
*mutex_id = id;
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
*mutex_id = idm::last_id();
|
||||
return CELL_OK;
|
||||
return CELL_EAGAIN;
|
||||
}
|
||||
|
||||
error_code sys_mutex_destroy(u32 mutex_id)
|
||||
|
||||
@@ -37,13 +37,13 @@ struct lv2_mutex final : lv2_obj
|
||||
atomic_t<u32> cond_count{0}; // Condition Variables
|
||||
std::deque<cpu_thread*> sq;
|
||||
|
||||
lv2_mutex(u32 protocol, u32 recursive, u32 shared, u32 adaptive, u64 key, s32 flags, u64 name)
|
||||
lv2_mutex(u32 protocol, u32 recursive, u64 name)
|
||||
: protocol(protocol)
|
||||
, recursive(recursive)
|
||||
, shared(shared)
|
||||
, adaptive(adaptive)
|
||||
, key(key)
|
||||
, flags(flags)
|
||||
, shared(0)
|
||||
, adaptive(0)
|
||||
, key(0)
|
||||
, flags(0)
|
||||
, name(name)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -306,7 +306,7 @@ error_code _sys_prx_get_module_list(u64 flags, vm::ptr<sys_prx_get_module_list_o
|
||||
|
||||
error_code _sys_prx_get_module_info(u32 id, u64 flags, vm::ptr<sys_prx_module_info_option_t> pOpt)
|
||||
{
|
||||
sys_prx.todo("_sys_prx_get_module_info(id=0x%x, flags=%d, pOpt=*0x%x)", id, flags, pOpt);
|
||||
sys_prx.todo("_sys_prx_get_module_info(id=%d, flags=%d, pOpt=*0x%x)", id, flags, pOpt);
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
|
||||
@@ -43,14 +43,7 @@ struct sys_prx_load_module_option_t
|
||||
vm::ps3::bptr<void> base_addr;
|
||||
};
|
||||
|
||||
struct sys_prx_segment_info_t
|
||||
{
|
||||
be_t<u64> base;
|
||||
be_t<u64> filesz;
|
||||
be_t<u64> memsz;
|
||||
be_t<u64> index;
|
||||
be_t<u64> type;
|
||||
};
|
||||
struct sys_prx_segment_info_t;// TODO
|
||||
|
||||
struct sys_prx_module_info_t
|
||||
{
|
||||
|
||||
+269
-196
@@ -14,13 +14,94 @@ logs::channel sys_rsx("sys_rsx");
|
||||
|
||||
extern u64 get_timebased_time();
|
||||
|
||||
struct SysRsxConfig {
|
||||
be_t<u32> rsx_event_port{ 0 };
|
||||
u32 driverInfo{ 0 };
|
||||
struct RsxDriverInfo {
|
||||
be_t<u32> version_driver; // 0x0
|
||||
be_t<u32> version_gpu; // 0x4
|
||||
be_t<u32> memory_size; // 0x8
|
||||
be_t<u32> hardware_channel; // 0xC
|
||||
be_t<u32> nvcore_frequency; // 0x10
|
||||
be_t<u32> memory_frequency; // 0x14
|
||||
be_t<u32> unk1[4]; // 0x18 - 0x24
|
||||
be_t<u32> unk2; // 0x28 -- pgraph stuff
|
||||
be_t<u32> reportsNotifyOffset;// 0x2C offset to notify memory
|
||||
be_t<u32> reportsOffset; // 0x30 offset to reports memory
|
||||
be_t<u32> reportsReportOffset;// 0x34 offset to reports in reports memory
|
||||
be_t<u32> unk3[6]; // 0x38-0x54
|
||||
be_t<u32> systemModeFlags; // 0x54
|
||||
u8 unk4[0x1064]; // 0x10B8
|
||||
struct Head {
|
||||
be_t<u64> lastFlipTime; // 0x0 last flip time
|
||||
be_t<u32> flipFlags; // 0x8 flags to handle flip/queue
|
||||
be_t<u32> unk1; // 0xC
|
||||
be_t<u32> flipBufferId; // 0x10
|
||||
be_t<u32> queuedBufferId; // 0x14 todo: this is definately not this variable but its 'unused' so im using it for queueId to pass to flip handler
|
||||
be_t<u32> unk3; // 0x18
|
||||
be_t<u32> unk6; // 0x18 possible low bits of time stamp? used in getlastVBlankTime
|
||||
be_t<u64> lastSecondVTime; // 0x20 last time for second vhandler freq
|
||||
be_t<u64> unk4; // 0x28
|
||||
be_t<u64> vBlankCount; // 0x30
|
||||
be_t<u32> unk; // 0x38 possible u32, 'flip field', top/bottom for interlaced
|
||||
be_t<u32> unk5; // 0x3C possible high bits of time stamp? used in getlastVBlankTime
|
||||
} head[8]; // size = 0x40, 0x200
|
||||
be_t<u32> unk7; // 0x12B8
|
||||
be_t<u32> unk8; // 0x12BC
|
||||
be_t<u32> handlers; // 0x12C0 -- flags showing which handlers are set
|
||||
be_t<u32> unk9; // 0x12C4
|
||||
be_t<u32> unk10; // 0x12C8
|
||||
be_t<u32> userCmdParam; // 0x12CC
|
||||
be_t<u32> handler_queue; // 0x12D0
|
||||
be_t<u32> unk11; // 0x12D4
|
||||
be_t<u32> unk12; // 0x12D8
|
||||
be_t<u32> unk13; // 0x12DC
|
||||
be_t<u32> unk14; // 0x12E0
|
||||
be_t<u32> unk15; // 0x12E4
|
||||
be_t<u32> unk16; // 0x12E8
|
||||
be_t<u32> unk17; // 0x12F0
|
||||
be_t<u32> lastError; // 0x12F4 error param for cellGcmSetGraphicsHandler
|
||||
// todo: theres more to this
|
||||
};
|
||||
template <size_t S> class Sizer { };
|
||||
Sizer<sizeof(RsxDriverInfo)> foo;
|
||||
static_assert(sizeof(RsxDriverInfo) == 0x12F8, "rsxSizeTest");
|
||||
static_assert(sizeof(RsxDriverInfo::Head) == 0x40, "rsxHeadSizeTest");
|
||||
|
||||
struct RsxDmaControl {
|
||||
u8 resv[0x40];
|
||||
be_t<u32> put;
|
||||
be_t<u32> get;
|
||||
be_t<u32> ref;
|
||||
be_t<u32> unk[2];
|
||||
be_t<u32> unk1;
|
||||
};
|
||||
|
||||
struct RsxSemaphore {
|
||||
be_t<u32> val;
|
||||
be_t<u32> pad;
|
||||
be_t<u64> timestamp;
|
||||
};
|
||||
|
||||
struct RsxNotify {
|
||||
be_t<u64> timestamp;
|
||||
be_t<u64> zero;
|
||||
};
|
||||
|
||||
struct RsxReport {
|
||||
be_t<u64> timestamp;
|
||||
be_t<u32> val;
|
||||
be_t<u32> pad;
|
||||
};
|
||||
|
||||
struct RsxReports {
|
||||
RsxSemaphore semaphore[0x100];
|
||||
RsxNotify notify[64];
|
||||
RsxReport report[2048];
|
||||
};
|
||||
|
||||
be_t<u32> g_rsx_event_port{ 0 };
|
||||
u32 g_driverInfo{ 0 };
|
||||
|
||||
u64 rsxTimeStamp() {
|
||||
return get_timebased_time();
|
||||
return get_timebased_time();
|
||||
}
|
||||
|
||||
s32 sys_rsx_device_open()
|
||||
@@ -49,10 +130,10 @@ s32 sys_rsx_device_close()
|
||||
*/
|
||||
s32 sys_rsx_memory_allocate(vm::ptr<u32> mem_handle, vm::ptr<u64> mem_addr, u32 size, u64 flags, u64 a5, u64 a6, u64 a7)
|
||||
{
|
||||
sys_rsx.warning("sys_rsx_memory_allocate(mem_handle=*0x%x, mem_addr=*0x%x, size=0x%x, flags=0x%llx, a5=0x%llx, a6=0x%llx, a7=0x%llx)", mem_handle, mem_addr, size, flags, a5, a6, a7);
|
||||
sys_rsx.todo("sys_rsx_memory_allocate(mem_handle=*0x%x, mem_addr=*0x%x, size=0x%x, flags=0x%llx, a5=0x%llx, a6=0x%llx, a7=0x%llx)", mem_handle, mem_addr, size, flags, a5, a6, a7);
|
||||
|
||||
*mem_handle = 1;
|
||||
*mem_addr = vm::falloc(0xC0000000, size, vm::video);
|
||||
*mem_handle = 1;
|
||||
*mem_addr = vm::falloc(0xC0000000, size, vm::video);
|
||||
|
||||
return CELL_OK;
|
||||
}
|
||||
@@ -79,83 +160,87 @@ s32 sys_rsx_memory_free(u32 mem_handle)
|
||||
*/
|
||||
s32 sys_rsx_context_allocate(vm::ptr<u32> context_id, vm::ptr<u64> lpar_dma_control, vm::ptr<u64> lpar_driver_info, vm::ptr<u64> lpar_reports, u64 mem_ctx, u64 system_mode)
|
||||
{
|
||||
sys_rsx.warning("sys_rsx_context_allocate(context_id=*0x%x, lpar_dma_control=*0x%x, lpar_driver_info=*0x%x, lpar_reports=*0x%x, mem_ctx=0x%llx, system_mode=0x%llx)",
|
||||
context_id, lpar_dma_control, lpar_driver_info, lpar_reports, mem_ctx, system_mode);
|
||||
sys_rsx.todo("sys_rsx_context_allocate(context_id=*0x%x, lpar_dma_control=*0x%x, lpar_driver_info=*0x%x, lpar_reports=*0x%x, mem_ctx=0x%llx, system_mode=0x%llx)",
|
||||
context_id, lpar_dma_control, lpar_driver_info, lpar_reports, mem_ctx, system_mode);
|
||||
|
||||
auto m_sysrsx = fxm::make<SysRsxConfig>();
|
||||
if (!m_sysrsx)
|
||||
fmt::throw_exception("sys_rsx_context_allocate called twice.");
|
||||
vm::falloc(0x40000000, 0x10000000, vm::rsx_context);
|
||||
|
||||
u32 addr = vm::falloc(0x40000000, 0x400000);
|
||||
if (addr == 0 || addr != 0x40000000)
|
||||
fmt::throw_exception("Failed to alloc 0x40000000.");
|
||||
*context_id = 0x55555555;
|
||||
|
||||
*context_id = 0x55555555;
|
||||
*lpar_dma_control = 0x40100000;
|
||||
*lpar_driver_info = 0x40200000;
|
||||
*lpar_reports = 0x40300000;
|
||||
|
||||
*lpar_dma_control = 0x40100000;
|
||||
*lpar_driver_info = 0x40200000;
|
||||
*lpar_reports = 0x40300000;
|
||||
auto &reports = vm::_ref<RsxReports>(*lpar_reports);
|
||||
std::memset(&reports, 0, sizeof(RsxReports));
|
||||
|
||||
auto &reports = vm::_ref<RsxReports>(*lpar_reports);
|
||||
std::memset(&reports, 0, sizeof(RsxReports));
|
||||
for (int i = 0; i < 64; ++i)
|
||||
reports.notify[i].timestamp = (u64)-1;
|
||||
|
||||
for (int i = 0; i < 64; ++i)
|
||||
reports.notify[i].timestamp = (u64)-1;
|
||||
for (int i = 0; i < 256; ++i) {
|
||||
reports.semaphore[i].val = 0x1337C0D3;
|
||||
reports.semaphore[i].pad = 0x1337BABE;
|
||||
reports.semaphore[i].timestamp = (u64)-1; // technically different but should be fine
|
||||
}
|
||||
|
||||
for (int i = 0; i < 256; ++i) {
|
||||
reports.semaphore[i].val = 0x1337C0D3;
|
||||
reports.semaphore[i].pad = 0x1337BABE;
|
||||
reports.semaphore[i].timestamp = (u64)-1; // technically different but should be fine
|
||||
}
|
||||
for (int i = 0; i < 2048; ++i)
|
||||
reports.report[i].timestamp = (u64)-1;
|
||||
|
||||
for (int i = 0; i < 2048; ++i)
|
||||
reports.report[i].timestamp = (u64)-1;
|
||||
auto &sysReports = vm::_ref<RsxSemaphore>(0x40000030);
|
||||
// slight hack for testing....
|
||||
sysReports.val = 1;
|
||||
|
||||
auto &driverInfo = vm::_ref<RsxDriverInfo>(*lpar_driver_info);
|
||||
auto &driverInfo = vm::_ref<RsxDriverInfo>(*lpar_driver_info);
|
||||
|
||||
std::memset(&driverInfo, 0, sizeof(RsxDriverInfo));
|
||||
std::memset(&driverInfo, 0, sizeof(RsxDriverInfo));
|
||||
|
||||
driverInfo.version_driver = 0x211;
|
||||
driverInfo.version_gpu = 0x5c;
|
||||
driverInfo.memory_size = 0xFE00000;
|
||||
driverInfo.nvcore_frequency = 500000000; // 0x1DCD6500
|
||||
driverInfo.memory_frequency = 650000000; // 0x26BE3680
|
||||
driverInfo.reportsNotifyOffset = 0x1000;
|
||||
driverInfo.reportsOffset = 0;
|
||||
driverInfo.reportsReportOffset = 0x1400;
|
||||
driverInfo.systemModeFlags = system_mode;
|
||||
driverInfo.hardware_channel = 1; // * i think* this 1 for games, 0 for vsh
|
||||
driverInfo.version_driver = 0x211;
|
||||
driverInfo.version_gpu = 0x5c;
|
||||
driverInfo.memory_size = 0xFE00000;
|
||||
driverInfo.nvcore_frequency = 500000000; // 0x1DCD6500
|
||||
driverInfo.memory_frequency = 650000000; // 0x26BE3680
|
||||
driverInfo.reportsNotifyOffset = 0x1000;
|
||||
driverInfo.reportsOffset = 0;
|
||||
driverInfo.reportsReportOffset = 0x1400;
|
||||
driverInfo.systemModeFlags = system_mode;
|
||||
driverInfo.hardware_channel = 1; // * i think* this 1 for games, 0 for vsh
|
||||
|
||||
m_sysrsx->driverInfo = *lpar_driver_info;
|
||||
g_driverInfo = *lpar_driver_info;
|
||||
|
||||
auto &dmaControl = vm::_ref<RsxDmaControl>(*lpar_dma_control);
|
||||
dmaControl.get = 0;
|
||||
dmaControl.put = 0;
|
||||
dmaControl.ref = 0xFFFFFFFF;
|
||||
auto &dmaControl = vm::_ref<RsxDmaControl>(*lpar_dma_control);
|
||||
dmaControl.get = 0;
|
||||
dmaControl.put = 0;
|
||||
dmaControl.ref = 0xFFFFFFFF;
|
||||
|
||||
if (false/*system_mode == CELL_GCM_SYSTEM_MODE_IOMAP_512MB*/)
|
||||
RSXIOMem.SetRange(0, 0x20000000 /*512MB*/);
|
||||
else
|
||||
RSXIOMem.SetRange(0, 0x10000000 /*256MB*/);
|
||||
if (false/*system_mode == CELL_GCM_SYSTEM_MODE_IOMAP_512MB*/)
|
||||
RSXIOMem.SetRange(0, 0x20000000 /*512MB*/);
|
||||
else
|
||||
RSXIOMem.SetRange(0, 0x10000000 /*256MB*/);
|
||||
|
||||
sys_event_queue_attribute_t attr;
|
||||
attr.protocol = SYS_SYNC_PRIORITY;
|
||||
attr.type = SYS_PPU_QUEUE;
|
||||
auto queueId = vm::make_var<u32>(0);
|
||||
sys_event_queue_create(queueId, vm::make_var(attr), 0, 0x20);
|
||||
driverInfo.handler_queue = queueId->value();
|
||||
sys_event_queue_attribute_t attr;
|
||||
attr.protocol = SYS_SYNC_PRIORITY;
|
||||
attr.type = SYS_PPU_QUEUE;
|
||||
auto queueId = vm::make_var<u32>(0);
|
||||
sys_event_queue_create(queueId, vm::make_var(attr), 0, 0x20);
|
||||
driverInfo.handler_queue = queueId->value();
|
||||
|
||||
sys_event_port_create(queueId, SYS_EVENT_PORT_LOCAL, 0);
|
||||
sys_event_port_connect_local(queueId->value(), driverInfo.handler_queue);
|
||||
sys_event_port_create(queueId, SYS_EVENT_PORT_LOCAL, 0);
|
||||
sys_event_port_connect_local(queueId->value(), driverInfo.handler_queue);
|
||||
|
||||
m_sysrsx->rsx_event_port = queueId->value();
|
||||
g_rsx_event_port = queueId->value();
|
||||
|
||||
const auto render = fxm::get<GSRender>();
|
||||
render->display_buffers_count = 0;
|
||||
render->current_display_buffer = 0;
|
||||
render->main_mem_addr = 0;
|
||||
render->label_addr = *lpar_reports;
|
||||
render->init(0, 0, *lpar_dma_control, 0xC0000000);
|
||||
const auto render = fxm::get<GSRender>();
|
||||
render->ctrl = vm::_ptr<CellGcmControl>(*lpar_dma_control);
|
||||
//render->intr_thread = idm::make_ptr<ppu_thread>("_gcm_intr_thread", 1, 0x4000);
|
||||
//render->intr_thread->run();
|
||||
//render->ctxt_addr = 0;
|
||||
render->gcm_buffers.set((vm::alloc(sizeof(CellGcmDisplayInfo) * 8, vm::main)));
|
||||
render->zculls_addr = vm::alloc(sizeof(CellGcmZcullInfo) * 8, vm::main);
|
||||
render->gcm_buffers_count = 0;
|
||||
render->gcm_current_buffer = 0;
|
||||
render->main_mem_addr = 0;
|
||||
render->label_addr = *lpar_reports;
|
||||
render->init(0x30100000, 0x200000, *lpar_dma_control, 0xC0000000);
|
||||
|
||||
return CELL_OK;
|
||||
}
|
||||
@@ -181,11 +266,11 @@ s32 sys_rsx_context_free(u32 context_id)
|
||||
*/
|
||||
s32 sys_rsx_context_iomap(u32 context_id, u32 io, u32 ea, u32 size, u64 flags)
|
||||
{
|
||||
sys_rsx.warning("sys_rsx_context_iomap(context_id=0x%x, io=0x%x, ea=0x%x, size=0x%x, flags=0x%llx)", context_id, io, ea, size, flags);
|
||||
if (size == 0) return CELL_OK;
|
||||
if (RSXIOMem.Map(ea, size, io))
|
||||
return CELL_OK;
|
||||
return CELL_EINVAL;
|
||||
sys_rsx.todo("sys_rsx_context_iomap(context_id=0x%x, io=0x%x, ea=0x%x, size=0x%x, flags=0x%llx)", context_id, io, ea, size, flags);
|
||||
if (RSXIOMem.Map(ea, size, io))
|
||||
return CELL_OK;
|
||||
LOG_ERROR(RSX, "rsx_iomap failed");
|
||||
return CELL_EINVAL;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -197,140 +282,128 @@ s32 sys_rsx_context_iomap(u32 context_id, u32 io, u32 ea, u32 size, u64 flags)
|
||||
*/
|
||||
s32 sys_rsx_context_iounmap(u32 context_id, u32 io_addr, u32 a3, u32 size)
|
||||
{
|
||||
sys_rsx.warning("sys_rsx_context_iounmap(context_id=0x%x, io_addr=0x%x, a3=0x%x, size=0x%x)", context_id, io_addr, a3, size);
|
||||
if (RSXIOMem.UnmapAddress(io_addr, size))
|
||||
return CELL_OK;
|
||||
return CELL_EINVAL;
|
||||
sys_rsx.todo("sys_rsx_context_iounmap(context_id=0x%x, io_addr=0x%x, a3=0x%x, size=0x%x)", context_id, io_addr, a3, size);
|
||||
if (RSXIOMem.UnmapAddress(io_addr, size))
|
||||
return CELL_OK;
|
||||
LOG_ERROR(RSX, "rsx_iounmap failed");
|
||||
return CELL_EINVAL;
|
||||
}
|
||||
|
||||
/*
|
||||
* lv2 SysCall 674 (0x2A2): sys_rsx_context_attribute
|
||||
* @param context_id (IN): RSX context, e.g. 0x55555555
|
||||
* @param package_id (IN):
|
||||
* @param a3 (IN):
|
||||
* @param a4 (IN):
|
||||
* @param a5 (IN):
|
||||
* @param a6 (IN):
|
||||
* @param package_id (IN):
|
||||
* @param a3 (IN):
|
||||
* @param a4 (IN):
|
||||
* @param a5 (IN):
|
||||
* @param a6 (IN):
|
||||
*/
|
||||
s32 sys_rsx_context_attribute(s32 context_id, u32 package_id, u64 a3, u64 a4, u64 a5, u64 a6)
|
||||
{
|
||||
// Flip/queue/user command/vblank as trace to help with log spam
|
||||
if (package_id == 0x102 || package_id == 0x103 || package_id == 0xFED || package_id == 0xFEF)
|
||||
sys_rsx.trace("sys_rsx_context_attribute(context_id=0x%x, package_id=0x%x, a3=0x%llx, a4=0x%llx, a5=0x%llx, a6=0x%llx)", context_id, package_id, a3, a4, a5, a6);
|
||||
else
|
||||
sys_rsx.warning("sys_rsx_context_attribute(context_id=0x%x, package_id=0x%x, a3=0x%llx, a4=0x%llx, a5=0x%llx, a6=0x%llx)", context_id, package_id, a3, a4, a5, a6);
|
||||
if (package_id != 0xFED)
|
||||
sys_rsx.todo("sys_rsx_context_attribute(context_id=0x%x, package_id=0x%x, a3=0x%llx, a4=0x%llx, a5=0x%llx, a6=0x%llx)", context_id, package_id, a3, a4, a5, a6);
|
||||
|
||||
// todo: these event ports probly 'shouldnt' be here as i think its supposed to be interrupts that are sent from rsx somewhere in lv1
|
||||
// hle/lle protection
|
||||
if (g_driverInfo == 0)
|
||||
return CELL_OK;
|
||||
// todo: these event ports probly 'shouldnt' be here as i think its supposed to be interrupts that are sent from rsx somewhere in lv1
|
||||
|
||||
const auto render = fxm::get<GSRender>();
|
||||
|
||||
//hle protection
|
||||
if (render->isHLE)
|
||||
return 0;
|
||||
|
||||
auto m_sysrsx = fxm::get<SysRsxConfig>();
|
||||
|
||||
auto &driverInfo = vm::_ref<RsxDriverInfo>(m_sysrsx->driverInfo);
|
||||
switch (package_id)
|
||||
const auto render = fxm::get<GSRender>();
|
||||
auto &driverInfo = vm::_ref<RsxDriverInfo>(g_driverInfo);
|
||||
switch(package_id)
|
||||
{
|
||||
case 0x001: // FIFO
|
||||
render->ctrl->get = a3;
|
||||
render->ctrl->put = a4;
|
||||
render->ctrl->get = a3;
|
||||
render->ctrl->put = a4;
|
||||
break;
|
||||
|
||||
|
||||
case 0x100: // Display mode set
|
||||
break;
|
||||
case 0x101: // Display sync set, cellGcmSetFlipMode
|
||||
// a4 == 2 is vsync, a4 == 1 is hsync
|
||||
render->requested_vsync.store(a4 == 2);
|
||||
break;
|
||||
break;
|
||||
case 0x101: // Display sync set, cellGcmSetFlipMode
|
||||
break;
|
||||
|
||||
case 0x102: // Display flip
|
||||
driverInfo.head[a3].flipFlags |= 0x80000000;
|
||||
driverInfo.head[a3].lastFlipTime = rsxTimeStamp(); // should rsxthread set this?
|
||||
// lets give this a shot for giving bufferid back to gcm
|
||||
driverInfo.head[a3].flipBufferId = driverInfo.head[a3].queuedBufferId;
|
||||
// seems gcmSysWaitLabel uses this offset, so lets set it to 0 every flip
|
||||
vm::_ref<u32>(0x40300010) = 0;
|
||||
if (a3 == 0)
|
||||
sys_event_port_send(m_sysrsx->rsx_event_port, 0, (1 << 3), 0);
|
||||
if (a3 == 1)
|
||||
sys_event_port_send(m_sysrsx->rsx_event_port, 0, (1 << 4), 0);
|
||||
driverInfo.head[a3].flipFlags |= 0x80000000;
|
||||
driverInfo.head[a3].lastFlipTime = rsxTimeStamp(); // should rsxthread set this?
|
||||
// lets give this a shot for giving bufferid back to gcm
|
||||
driverInfo.head[a3].flipBufferId = driverInfo.head[a3].queuedBufferId;
|
||||
// seems gcmSysWaitLabel uses this offset, so lets set it to 0 every flip
|
||||
vm::_ref<u32>(0x40300010) = 0;
|
||||
if (a3 == 0)
|
||||
sys_event_port_send(g_rsx_event_port, 0, (1 << 3), 0);
|
||||
if (a3 == 1)
|
||||
sys_event_port_send(g_rsx_event_port, 0, (1 << 4), 0);
|
||||
break;
|
||||
|
||||
case 0x103: // Display Queue
|
||||
driverInfo.head[a3].queuedBufferId = a4;
|
||||
driverInfo.head[a3].flipFlags |= 0x40000000 | (1 << a4);
|
||||
if (a3 == 0)
|
||||
sys_event_port_send(m_sysrsx->rsx_event_port, 0, (1 << 5), 0);
|
||||
if (a3 == 1)
|
||||
sys_event_port_send(m_sysrsx->rsx_event_port, 0, (1 << 6), 0);
|
||||
driverInfo.head[a3].queuedBufferId = a4;
|
||||
driverInfo.head[a3].flipFlags |= 0x40000000 | (1 << a4);
|
||||
if (a3 == 0)
|
||||
sys_event_port_send(g_rsx_event_port, 0, (1 << 5), 0);
|
||||
if (a3 == 1)
|
||||
sys_event_port_send(g_rsx_event_port, 0, (1 << 6), 0);
|
||||
break;
|
||||
case 0x104: // Display buffer
|
||||
{
|
||||
u8 id = a3 & 0xFF;
|
||||
u32 width = (a4 >> 32) & 0xFFFFFFFF;
|
||||
u32 height = a4 & 0xFFFFFFFF;
|
||||
u32 pitch = (a5 >> 32) & 0xFFFFFFFF;
|
||||
u32 offset = a5 & 0xFFFFFFFF;
|
||||
if (id > 7)
|
||||
return -17;
|
||||
render->display_buffers[id].width = width;
|
||||
render->display_buffers[id].height = height;
|
||||
render->display_buffers[id].pitch = pitch;
|
||||
render->display_buffers[id].offset = offset;
|
||||
{
|
||||
u8 id = a3 & 0xFF;
|
||||
u32 width = (a4 >> 32) & 0xFFFFFFFF;
|
||||
u32 height = a4 & 0xFFFFFFFF;
|
||||
u32 pitch = (a5 >> 32) & 0xFFFFFFFF;
|
||||
u32 offset = a5 & 0xFFFFFFFF;
|
||||
if (id > 7)
|
||||
return -17;
|
||||
render->gcm_buffers[id].width = width;
|
||||
render->gcm_buffers[id].height = height;
|
||||
render->gcm_buffers[id].pitch = pitch;
|
||||
render->gcm_buffers[id].offset = offset;
|
||||
|
||||
render->display_buffers_count = std::max((u32)id + 1, render->display_buffers_count);
|
||||
}
|
||||
if (id + 1 > render->gcm_buffers_count)
|
||||
render->gcm_buffers_count = id + 1;
|
||||
}
|
||||
break;
|
||||
case 0x105: // destroy buffer?
|
||||
break;
|
||||
case 0x105: // destroy buffer?
|
||||
break;
|
||||
|
||||
case 0x106: // ? (Used by cellGcmInitPerfMon)
|
||||
break;
|
||||
case 0x108: // cellGcmSetSecondVFrequency
|
||||
// a4 == 3, CELL_GCM_DISPLAY_FREQUENCY_59_94HZ
|
||||
// a4 == 2, CELL_GCM_DISPLAY_FREQUENCY_SCANOUT
|
||||
// a4 == 4, CELL_GCM_DISPLAY_FREQUENCY_DISABLE
|
||||
// Note: Scanout/59_94 is ignored currently as we report refresh rate of 59_94hz as it is, so the difference doesnt matter
|
||||
render->enable_second_vhandler.store(a4 != 4);
|
||||
break;
|
||||
case 0x108: // ? set interrupt freq?
|
||||
break;
|
||||
case 0x10a: // ? Involved in managing flip status through cellGcmResetFlipStatus
|
||||
{
|
||||
if (a3 > 7)
|
||||
return -17;
|
||||
u32 flipStatus = driverInfo.head[a3].flipFlags;
|
||||
flipStatus = (flipStatus & a4) | a5;
|
||||
driverInfo.head[a3].flipFlags = flipStatus;
|
||||
}
|
||||
{
|
||||
if (a3 > 7)
|
||||
return -17;
|
||||
u32 flipStatus = driverInfo.head[a3].flipFlags;
|
||||
flipStatus = (flipStatus & a4) | a5;
|
||||
driverInfo.head[a3].flipFlags = flipStatus;
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x10D: // Called by cellGcmInitCursor
|
||||
break;
|
||||
case 0x10D: // Called by cellGcmInitCursor
|
||||
break;
|
||||
|
||||
case 0x300: // Tiles
|
||||
{
|
||||
//a4 high bits = ret.tile = (location + 1) | (bank << 4) | ((offset / 0x10000) << 16) | (location << 31);
|
||||
//a4 low bits = ret.limit = ((offset + size - 1) / 0x10000) << 16 | (location << 31);
|
||||
//a5 high bits = ret.pitch = (pitch / 0x100) << 8;
|
||||
//a5 low bits = ret.format = base | ((base + ((size - 1) / 0x10000)) << 13) | (comp << 26) | (1 << 30);
|
||||
{
|
||||
//a4 high bits = ret.tile = (location + 1) | (bank << 4) | ((offset / 0x10000) << 16) | (location << 31);
|
||||
//a4 low bits = ret.limit = ((offset + size - 1) / 0x10000) << 16 | (location << 31);
|
||||
//a5 high bits = ret.pitch = (pitch / 0x100) << 8;
|
||||
//a5 low bits = ret.format = base | ((base + ((size - 1) / 0x10000)) << 13) | (comp << 26) | (1 << 30);
|
||||
|
||||
auto& tile = render->tiles[a3];
|
||||
tile.location = ((a4 >> 32) & 0xF) - 1;
|
||||
tile.offset = ((((a4 >> 32) & 0xFFFFFFFF) >> 16) * 0x10000);
|
||||
tile.size = ((((a4 & 0x7FFFFFFF) >> 16) + 1) * 0x10000) - tile.offset;
|
||||
tile.pitch = (((a5 >> 32) & 0xFFFFFFFF) >> 8) * 0x100;
|
||||
tile.comp = ((a5 & 0xFFFFFFFF) >> 26) & 0xF;
|
||||
tile.base = (a5 & 0xFFFFFFFF) & 0x7FF;
|
||||
tile.bank = (((a4 >> 32) & 0xFFFFFFFF) >> 4) & 0xF;
|
||||
tile.binded = a5 != 0;
|
||||
}
|
||||
auto& tile = render->tiles[a3];
|
||||
tile.location = ((a4 >> 32) & 0xF) - 1;
|
||||
tile.offset = ((((a4 >> 32) & 0xFFFFFFFF) >> 16) * 0x10000);
|
||||
tile.size = ((((a4 & 0x7FFFFFFF) >> 16) + 1) * 0x10000) - tile.offset;
|
||||
tile.pitch = (((a5 >> 32) & 0xFFFFFFFF) >> 8) * 0x100;
|
||||
tile.comp = ((a5 & 0xFFFFFFFF) >> 26) & 0xF;
|
||||
tile.base = (a5 & 0xFFFFFFFF) & 0x7FF;
|
||||
tile.bank = (((a4 >> 32) & 0xFFFFFFFF) >> 4) & 0xF;
|
||||
tile.binded = a5 != 0;
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x301: // Depth-buffer (Z-cull)
|
||||
break;
|
||||
case 0x302: // something with zcull
|
||||
break;
|
||||
case 0x302: // something with zcull
|
||||
break;
|
||||
case 0x600: // Framebuffer setup
|
||||
break;
|
||||
|
||||
@@ -340,24 +413,24 @@ s32 sys_rsx_context_attribute(s32 context_id, u32 package_id, u64 a3, u64 a4, u6
|
||||
case 0x602: // Framebuffer blit sync
|
||||
break;
|
||||
|
||||
case 0x603: // Framebuffer close
|
||||
break;
|
||||
case 0x603: // Framebuffer close
|
||||
break;
|
||||
|
||||
case 0xFED: // hack: vblank command
|
||||
// todo: this is wrong and should be 'second' vblank handler and freq, but since currently everything is reported as being 59.94, this should be fine
|
||||
driverInfo.head[a3].vBlankCount++;
|
||||
driverInfo.head[a3].lastSecondVTime = rsxTimeStamp();
|
||||
sys_event_port_send(m_sysrsx->rsx_event_port, 0, (1 << 1), 0);
|
||||
if (render->enable_second_vhandler)
|
||||
sys_event_port_send(m_sysrsx->rsx_event_port, 0, (1 << 11), 0); // second vhandler
|
||||
break;
|
||||
case 0xFEF: // hack: user command
|
||||
// 'custom' invalid package id for now
|
||||
// as i think we need custom lv1 interrupts to handle this accurately
|
||||
// this also should probly be set by rsxthread
|
||||
driverInfo.userCmdParam = a4;
|
||||
sys_event_port_send(m_sysrsx->rsx_event_port, 0, (1 << 7), 0);
|
||||
break;
|
||||
case 0xFED: // hack: vblank command
|
||||
// todo: this is wrong and should be 'second' vblank handler and freq
|
||||
// although gcmSys seems just hardcoded at 1, so w/e
|
||||
driverInfo.head[a3].vBlankCount++;
|
||||
driverInfo.head[a3].lastSecondVTime = rsxTimeStamp();
|
||||
sys_event_port_send(g_rsx_event_port, 0, (1 << 1), 0);
|
||||
sys_event_port_send(g_rsx_event_port, 0, (1 << 11), 0); // second vhandler
|
||||
break;
|
||||
case 0xFEF: // hack: user command
|
||||
// 'custom' invalid package id for now
|
||||
// as i think we need custom lv1 interrupts to handle this accurately
|
||||
// this also should probly be set by rsxthread
|
||||
driverInfo.userCmdParam = a4;
|
||||
sys_event_port_send(g_rsx_event_port, 0, (1 << 7), 0);
|
||||
break;
|
||||
default:
|
||||
return CELL_EINVAL;
|
||||
}
|
||||
@@ -373,17 +446,17 @@ s32 sys_rsx_context_attribute(s32 context_id, u32 package_id, u64 a3, u64 a4, u6
|
||||
*/
|
||||
s32 sys_rsx_device_map(vm::ptr<u64> addr, vm::ptr<u64> a2, u32 dev_id)
|
||||
{
|
||||
sys_rsx.warning("sys_rsx_device_map(addr=*0x%x, a2=*0x%x, dev_id=0x%x)", addr, a2, dev_id);
|
||||
sys_rsx.todo("sys_rsx_device_map(addr=*0x%x, a2=*0x%x, dev_id=0x%x)", addr, a2, dev_id);
|
||||
|
||||
if (dev_id != 8) {
|
||||
if (dev_id != 8) {
|
||||
// TODO: lv1 related
|
||||
fmt::throw_exception("sys_rsx_device_map: Invalid dev_id %d", dev_id);
|
||||
fmt::throw_exception("sys_rsx_device_map: Invalid dev_id %d", dev_id);
|
||||
}
|
||||
|
||||
// a2 seems to not be referenced in cellGcmSys
|
||||
*a2 = 0;
|
||||
// a2 seems to not be referenced in cellGcmSys
|
||||
*a2 = 0;
|
||||
|
||||
*addr = 0x40000000;
|
||||
*addr = 0x40000000;
|
||||
|
||||
return CELL_OK;
|
||||
}
|
||||
@@ -400,11 +473,11 @@ s32 sys_rsx_device_unmap(u32 dev_id)
|
||||
}
|
||||
|
||||
/*
|
||||
* lv2 SysCall 677 (0x2A5): sys_rsx_attribute
|
||||
*/
|
||||
* lv2 SysCall 677 (0x2A5): sys_rsx_attribute
|
||||
*/
|
||||
s32 sys_rsx_attribute(u32 packageId, u32 a2, u32 a3, u32 a4, u32 a5)
|
||||
{
|
||||
sys_rsx.warning("sys_rsx_attribute(packageId=0x%x, a2=0x%x, a3=0x%x, a4=0x%x, a5=0x%x)", packageId, a2, a3, a4, a5);
|
||||
sys_rsx.todo("sys_rsx_attribute(packageId=0x%x, a2=0x%x, a3=0x%x, a4=0x%x, a5=0x%x)", packageId, a2, a3, a4, a5);
|
||||
|
||||
return CELL_OK;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,93 +1,5 @@
|
||||
#pragma once
|
||||
|
||||
struct RsxDriverInfo {
|
||||
be_t<u32> version_driver; // 0x0
|
||||
be_t<u32> version_gpu; // 0x4
|
||||
be_t<u32> memory_size; // 0x8
|
||||
be_t<u32> hardware_channel; // 0xC
|
||||
be_t<u32> nvcore_frequency; // 0x10
|
||||
be_t<u32> memory_frequency; // 0x14
|
||||
be_t<u32> unk1[4]; // 0x18 - 0x24
|
||||
be_t<u32> unk2; // 0x28 -- pgraph stuff
|
||||
be_t<u32> reportsNotifyOffset;// 0x2C offset to notify memory
|
||||
be_t<u32> reportsOffset; // 0x30 offset to reports memory
|
||||
be_t<u32> reportsReportOffset;// 0x34 offset to reports in reports memory
|
||||
be_t<u32> unk3[6]; // 0x38-0x54
|
||||
be_t<u32> systemModeFlags; // 0x54
|
||||
u8 unk4[0x1064]; // 0x10B8
|
||||
struct Head {
|
||||
be_t<u64> lastFlipTime; // 0x0 last flip time
|
||||
be_t<u32> flipFlags; // 0x8 flags to handle flip/queue
|
||||
be_t<u32> unk1; // 0xC
|
||||
be_t<u32> flipBufferId; // 0x10
|
||||
be_t<u32> queuedBufferId; // 0x14 todo: this is definately not this variable but its 'unused' so im using it for queueId to pass to flip handler
|
||||
be_t<u32> unk3; // 0x18
|
||||
be_t<u32> unk6; // 0x18 possible low bits of time stamp? used in getlastVBlankTime
|
||||
be_t<u64> lastSecondVTime; // 0x20 last time for second vhandler freq
|
||||
be_t<u64> unk4; // 0x28
|
||||
be_t<u64> vBlankCount; // 0x30
|
||||
be_t<u32> unk; // 0x38 possible u32, 'flip field', top/bottom for interlaced
|
||||
be_t<u32> unk5; // 0x3C possible high bits of time stamp? used in getlastVBlankTime
|
||||
} head[8]; // size = 0x40, 0x200
|
||||
be_t<u32> unk7; // 0x12B8
|
||||
be_t<u32> unk8; // 0x12BC
|
||||
be_t<u32> handlers; // 0x12C0 -- flags showing which handlers are set
|
||||
be_t<u32> unk9; // 0x12C4
|
||||
be_t<u32> unk10; // 0x12C8
|
||||
be_t<u32> userCmdParam; // 0x12CC
|
||||
be_t<u32> handler_queue; // 0x12D0
|
||||
be_t<u32> unk11; // 0x12D4
|
||||
be_t<u32> unk12; // 0x12D8
|
||||
be_t<u32> unk13; // 0x12DC
|
||||
be_t<u32> unk14; // 0x12E0
|
||||
be_t<u32> unk15; // 0x12E4
|
||||
be_t<u32> unk16; // 0x12E8
|
||||
be_t<u32> unk17; // 0x12F0
|
||||
be_t<u32> lastError; // 0x12F4 error param for cellGcmSetGraphicsHandler
|
||||
// todo: theres more to this
|
||||
};
|
||||
static_assert(sizeof(RsxDriverInfo) == 0x12F8, "rsxSizeTest");
|
||||
static_assert(sizeof(RsxDriverInfo::Head) == 0x40, "rsxHeadSizeTest");
|
||||
|
||||
struct RsxDmaControl {
|
||||
u8 resv[0x40];
|
||||
atomic_be_t<u32> put;
|
||||
atomic_be_t<u32> get;
|
||||
atomic_be_t<u32> ref;
|
||||
be_t<u32> unk[2];
|
||||
be_t<u32> unk1;
|
||||
};
|
||||
|
||||
struct RsxSemaphore {
|
||||
be_t<u32> val;
|
||||
be_t<u32> pad;
|
||||
be_t<u64> timestamp;
|
||||
};
|
||||
|
||||
struct RsxNotify {
|
||||
be_t<u64> timestamp;
|
||||
be_t<u64> zero;
|
||||
};
|
||||
|
||||
struct RsxReport {
|
||||
be_t<u64> timestamp;
|
||||
be_t<u32> val;
|
||||
be_t<u32> pad;
|
||||
};
|
||||
|
||||
struct RsxReports {
|
||||
RsxSemaphore semaphore[0x100];
|
||||
RsxNotify notify[64];
|
||||
RsxReport report[2048];
|
||||
};
|
||||
|
||||
struct RsxDisplayInfo {
|
||||
be_t<u32> offset;
|
||||
be_t<u32> pitch;
|
||||
be_t<u32> width;
|
||||
be_t<u32> height;
|
||||
};
|
||||
|
||||
// SysCalls
|
||||
s32 sys_rsx_device_open();
|
||||
s32 sys_rsx_device_close();
|
||||
@@ -100,4 +12,4 @@ s32 sys_rsx_context_iounmap(u32 context_id, u32 a2, u32 io_addr, u32 size);
|
||||
s32 sys_rsx_context_attribute(s32 context_id, u32 package_id, u64 a3, u64 a4, u64 a5, u64 a6);
|
||||
s32 sys_rsx_device_map(vm::ps3::ptr<u64> addr, vm::ps3::ptr<u64> a2, u32 dev_id);
|
||||
s32 sys_rsx_device_unmap(u32 dev_id);
|
||||
s32 sys_rsx_attribute(u32 a1, u32 a2, u32 a3, u32 a4, u32 a5);
|
||||
s32 sys_rsx_attribute(u32 a1, u32 a2, u32 a3, u32 a4, u32 a5);
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
#include "Emu/Memory/Memory.h"
|
||||
#include "Emu/System.h"
|
||||
#include "Emu/IdManager.h"
|
||||
#include "Emu/IPC.h"
|
||||
|
||||
#include "Emu/Cell/ErrorCodes.h"
|
||||
#include "Emu/Cell/PPUThread.h"
|
||||
@@ -12,8 +11,6 @@ namespace vm { using namespace ps3; }
|
||||
|
||||
logs::channel sys_rwlock("sys_rwlock");
|
||||
|
||||
template<> DECLARE(ipc_manager<lv2_rwlock, u64>::g_ipc) {};
|
||||
|
||||
extern u64 get_system_time();
|
||||
|
||||
error_code sys_rwlock_create(vm::ptr<u32> rw_lock_id, vm::ptr<sys_rwlock_attribute_t> attr)
|
||||
@@ -36,16 +33,19 @@ error_code sys_rwlock_create(vm::ptr<u32> rw_lock_id, vm::ptr<sys_rwlock_attribu
|
||||
return CELL_EINVAL;
|
||||
}
|
||||
|
||||
if (auto error = lv2_obj::create<lv2_rwlock>(attr->pshared, attr->ipc_key, attr->flags, [&]
|
||||
if (attr->pshared != SYS_SYNC_NOT_PROCESS_SHARED || attr->ipc_key || attr->flags)
|
||||
{
|
||||
return std::make_shared<lv2_rwlock>(protocol, attr->pshared, attr->ipc_key, attr->flags, attr->name_u64);
|
||||
}))
|
||||
{
|
||||
return error;
|
||||
sys_rwlock.error("sys_rwlock_create(): unknown attributes (pshared=0x%x, ipc_key=0x%llx, flags=0x%x)", attr->pshared, attr->ipc_key, attr->flags);
|
||||
return CELL_EINVAL;
|
||||
}
|
||||
|
||||
*rw_lock_id = idm::last_id();
|
||||
return CELL_OK;
|
||||
if (const u32 id = idm::make<lv2_obj, lv2_rwlock>(protocol, attr->name_u64))
|
||||
{
|
||||
*rw_lock_id = id;
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
return CELL_EAGAIN;
|
||||
}
|
||||
|
||||
error_code sys_rwlock_destroy(u32 rw_lock_id)
|
||||
@@ -225,9 +225,9 @@ error_code sys_rwlock_runlock(ppu_thread& ppu, u32 rw_lock_id)
|
||||
// Remove one reader
|
||||
const s64 _old = rwlock->owner.fetch_op([](s64& val)
|
||||
{
|
||||
if (val < -1)
|
||||
if (val < 0)
|
||||
{
|
||||
val += 2;
|
||||
val++;
|
||||
}
|
||||
});
|
||||
|
||||
@@ -260,7 +260,7 @@ error_code sys_rwlock_wlock(ppu_thread& ppu, u32 rw_lock_id, u64 timeout)
|
||||
{
|
||||
sys_rwlock.trace("sys_rwlock_wlock(rw_lock_id=0x%x, timeout=0x%llx)", rw_lock_id, timeout);
|
||||
|
||||
const auto rwlock = idm::get<lv2_obj, lv2_rwlock>(rw_lock_id, [&](lv2_rwlock& rwlock) -> s64
|
||||
const auto rwlock = idm::get<lv2_obj, lv2_rwlock>(rw_lock_id, [&](lv2_rwlock& rwlock)
|
||||
{
|
||||
const s64 val = rwlock.owner;
|
||||
|
||||
@@ -268,12 +268,12 @@ error_code sys_rwlock_wlock(ppu_thread& ppu, u32 rw_lock_id, u64 timeout)
|
||||
{
|
||||
if (rwlock.owner.compare_and_swap_test(0, ppu.id << 1))
|
||||
{
|
||||
return 0;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else if (val >> 1 == ppu.id)
|
||||
{
|
||||
return val;
|
||||
return false;
|
||||
}
|
||||
|
||||
semaphore_lock lock(rwlock.mutex);
|
||||
@@ -294,9 +294,10 @@ error_code sys_rwlock_wlock(ppu_thread& ppu, u32 rw_lock_id, u64 timeout)
|
||||
{
|
||||
rwlock.wq.emplace_back(&ppu);
|
||||
rwlock.sleep(ppu, timeout);
|
||||
return false;
|
||||
}
|
||||
|
||||
return _old;
|
||||
return true;
|
||||
});
|
||||
|
||||
if (!rwlock)
|
||||
@@ -304,12 +305,12 @@ error_code sys_rwlock_wlock(ppu_thread& ppu, u32 rw_lock_id, u64 timeout)
|
||||
return CELL_ESRCH;
|
||||
}
|
||||
|
||||
if (rwlock.ret == 0)
|
||||
if (rwlock.ret)
|
||||
{
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
if (rwlock.ret >> 1 == ppu.id)
|
||||
if (rwlock->owner >> 1 == ppu.id)
|
||||
{
|
||||
return CELL_EDEADLK;
|
||||
}
|
||||
@@ -418,7 +419,7 @@ error_code sys_rwlock_wunlock(ppu_thread& ppu, u32 rw_lock_id)
|
||||
|
||||
if (auto cpu = rwlock->schedule<ppu_thread>(rwlock->wq, rwlock->protocol))
|
||||
{
|
||||
rwlock->owner = cpu->id << 1 | !rwlock->wq.empty() | !rwlock->rq.empty();
|
||||
rwlock->owner = cpu->id << 1 | !rwlock->wq.empty();
|
||||
|
||||
rwlock->awake(*cpu);
|
||||
}
|
||||
|
||||
@@ -32,11 +32,11 @@ struct lv2_rwlock final : lv2_obj
|
||||
std::deque<cpu_thread*> rq;
|
||||
std::deque<cpu_thread*> wq;
|
||||
|
||||
lv2_rwlock(u32 protocol, u32 shared, u64 key, s32 flags, u64 name)
|
||||
lv2_rwlock(u32 protocol, u64 name)
|
||||
: protocol(protocol)
|
||||
, shared(shared)
|
||||
, key(key)
|
||||
, flags(flags)
|
||||
, shared(0)
|
||||
, key(0)
|
||||
, flags(0)
|
||||
, name(name)
|
||||
{
|
||||
}
|
||||
@@ -55,5 +55,3 @@ error_code sys_rwlock_runlock(ppu_thread& ppu, u32 rw_lock_id);
|
||||
error_code sys_rwlock_wlock(ppu_thread& ppu, u32 rw_lock_id, u64 timeout);
|
||||
error_code sys_rwlock_trywlock(ppu_thread& ppu, u32 rw_lock_id);
|
||||
error_code sys_rwlock_wunlock(ppu_thread& ppu, u32 rw_lock_id);
|
||||
|
||||
constexpr auto _sys_rwlock_trywlock = sys_rwlock_trywlock;
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
#include "Emu/Memory/Memory.h"
|
||||
#include "Emu/System.h"
|
||||
#include "Emu/IdManager.h"
|
||||
#include "Emu/IPC.h"
|
||||
|
||||
#include "Emu/Cell/ErrorCodes.h"
|
||||
#include "Emu/Cell/PPUThread.h"
|
||||
@@ -12,8 +11,6 @@ namespace vm { using namespace ps3; }
|
||||
|
||||
logs::channel sys_semaphore("sys_semaphore");
|
||||
|
||||
template<> DECLARE(ipc_manager<lv2_sema, u64>::g_ipc) {};
|
||||
|
||||
extern u64 get_system_time();
|
||||
|
||||
error_code sys_semaphore_create(vm::ptr<u32> sem_id, vm::ptr<sys_semaphore_attribute_t> attr, s32 initial_val, s32 max_val)
|
||||
@@ -42,16 +39,19 @@ error_code sys_semaphore_create(vm::ptr<u32> sem_id, vm::ptr<sys_semaphore_attri
|
||||
return CELL_EINVAL;
|
||||
}
|
||||
|
||||
if (auto error = lv2_obj::create<lv2_sema>(attr->pshared, attr->ipc_key, attr->flags, [&]
|
||||
if (attr->pshared != SYS_SYNC_NOT_PROCESS_SHARED || attr->ipc_key || attr->flags)
|
||||
{
|
||||
return std::make_shared<lv2_sema>(protocol, attr->pshared, attr->ipc_key, attr->flags, attr->name_u64, max_val, initial_val);
|
||||
}))
|
||||
{
|
||||
return error;
|
||||
sys_semaphore.error("sys_semaphore_create(): unknown attributes (pshared=0x%x, ipc_key=0x%x, flags=0x%x)", attr->pshared, attr->ipc_key, attr->flags);
|
||||
return CELL_EINVAL;
|
||||
}
|
||||
|
||||
*sem_id = idm::last_id();
|
||||
return CELL_OK;
|
||||
if (const u32 id = idm::make<lv2_obj, lv2_sema>(protocol, attr->name_u64, max_val, initial_val))
|
||||
{
|
||||
*sem_id = id;
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
return CELL_EAGAIN;
|
||||
}
|
||||
|
||||
error_code sys_semaphore_destroy(u32 sem_id)
|
||||
@@ -131,13 +131,7 @@ error_code sys_semaphore_wait(ppu_thread& ppu, u32 sem_id, u64 timeout)
|
||||
{
|
||||
semaphore_lock lock(sem->mutex);
|
||||
|
||||
if (!sem->unqueue(sem->sq, &ppu))
|
||||
{
|
||||
timeout = 0;
|
||||
continue;
|
||||
}
|
||||
|
||||
verify(HERE), 0 > sem->val.fetch_op([](s32& val)
|
||||
const s32 val = sem->val.fetch_op([](s32& val)
|
||||
{
|
||||
if (val < 0)
|
||||
{
|
||||
@@ -145,6 +139,13 @@ error_code sys_semaphore_wait(ppu_thread& ppu, u32 sem_id, u64 timeout)
|
||||
}
|
||||
});
|
||||
|
||||
if (val >= 0)
|
||||
{
|
||||
timeout = 0;
|
||||
continue;
|
||||
}
|
||||
|
||||
verify(HERE), sem->unqueue(sem->sq, &ppu);
|
||||
ppu.gpr[3] = CELL_ETIMEDOUT;
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -32,11 +32,11 @@ struct lv2_sema final : lv2_obj
|
||||
atomic_t<s32> val;
|
||||
std::deque<cpu_thread*> sq;
|
||||
|
||||
lv2_sema(u32 protocol, u32 shared, u64 key, s32 flags, u64 name, s32 max, s32 value)
|
||||
lv2_sema(u32 protocol, u64 name, s32 max, s32 value)
|
||||
: protocol(protocol)
|
||||
, shared(shared)
|
||||
, key(key)
|
||||
, flags(flags)
|
||||
, shared(0)
|
||||
, key(0)
|
||||
, flags(0)
|
||||
, name(name)
|
||||
, max(max)
|
||||
, val(value)
|
||||
|
||||
@@ -34,13 +34,24 @@ void sys_spu_image::load(const fs::file& stream)
|
||||
|
||||
const u32 addr = this->segs.addr() + 4096;
|
||||
|
||||
sha1_context ctx;
|
||||
u8 output[20];
|
||||
|
||||
sha1_starts(&ctx);
|
||||
sha1_update(&ctx, reinterpret_cast<const u8*>(&obj.header), sizeof(obj.header));
|
||||
|
||||
for (const auto& shdr : obj.shdrs)
|
||||
{
|
||||
sha1_update(&ctx, reinterpret_cast<const u8*>(&shdr), sizeof(spu_exec_object::shdr_t));
|
||||
|
||||
LOG_NOTICE(SPU, "** Section: sh_type=0x%x, addr=0x%llx, size=0x%llx, flags=0x%x", shdr.sh_type, shdr.sh_addr, shdr.sh_size, shdr.sh_flags);
|
||||
}
|
||||
|
||||
for (const auto& prog : obj.progs)
|
||||
{
|
||||
sha1_update(&ctx, reinterpret_cast<const u8*>(&prog), sizeof(spu_exec_object::phdr_t));
|
||||
sha1_update(&ctx, reinterpret_cast<const u8*>(prog.bin.data()), prog.bin.size());
|
||||
|
||||
LOG_NOTICE(SPU, "** Segment: p_type=0x%x, p_vaddr=0x%llx, p_filesz=0x%llx, p_memsz=0x%llx, flags=0x%x", prog.p_type, prog.p_vaddr, prog.p_filesz, prog.p_memsz, prog.p_flags);
|
||||
|
||||
if (prog.p_type == SYS_SPU_SEGMENT_TYPE_COPY)
|
||||
@@ -74,6 +85,22 @@ void sys_spu_image::load(const fs::file& stream)
|
||||
LOG_ERROR(SPU, "Unknown program type (0x%x)", prog.p_type);
|
||||
}
|
||||
}
|
||||
|
||||
sha1_finish(&ctx, output);
|
||||
|
||||
// Format patch name
|
||||
std::string hash("spu-");
|
||||
for (u8 x : output) fmt::append(hash, "%02x", x);
|
||||
LOG_NOTICE(LOADER, "Loaded SPU image: %s", hash);
|
||||
|
||||
// Apply the patch
|
||||
fxm::check_unlocked<patch_engine>()->apply(hash, vm::g_base_addr + addr);
|
||||
|
||||
if (!Emu.GetTitleID().empty())
|
||||
{
|
||||
// Alternative patch
|
||||
fxm::check_unlocked<patch_engine>()->apply(Emu.GetTitleID() + '-' + hash, vm::g_base_addr + addr);
|
||||
}
|
||||
}
|
||||
|
||||
void sys_spu_image::free()
|
||||
@@ -86,29 +113,15 @@ void sys_spu_image::free()
|
||||
|
||||
void sys_spu_image::deploy(u32 loc)
|
||||
{
|
||||
// Segment info dump
|
||||
std::string dump;
|
||||
|
||||
// Executable hash
|
||||
sha1_context sha;
|
||||
sha1_starts(&sha);
|
||||
u8 sha1_hash[20];
|
||||
|
||||
for (int i = 0; i < nsegs; i++)
|
||||
{
|
||||
auto& seg = segs[i];
|
||||
|
||||
fmt::append(dump, "\n\t[%d] t=0x%x, ls=0x%x, size=0x%x, addr=0x%x", i, seg.type, seg.ls, seg.size, seg.addr);
|
||||
|
||||
// Hash big-endian values
|
||||
sha1_update(&sha, (uchar*)&seg.type, sizeof(seg.type));
|
||||
sha1_update(&sha, (uchar*)&seg.size, sizeof(seg.size));
|
||||
LOG_NOTICE(SPU, "*** Deploy: t=0x%x, ls=0x%x, size=0x%x, addr=0x%x", seg.type, seg.ls, seg.size, seg.addr);
|
||||
|
||||
if (seg.type == SYS_SPU_SEGMENT_TYPE_COPY)
|
||||
{
|
||||
std::memcpy(vm::base(loc + seg.ls), vm::base(seg.addr), seg.size);
|
||||
sha1_update(&sha, (uchar*)&seg.ls, sizeof(seg.ls));
|
||||
sha1_update(&sha, vm::g_base_addr + seg.addr, seg.size);
|
||||
}
|
||||
else if (seg.type == SYS_SPU_SEGMENT_TYPE_FILL)
|
||||
{
|
||||
@@ -118,32 +131,8 @@ void sys_spu_image::deploy(u32 loc)
|
||||
}
|
||||
|
||||
std::fill_n(vm::_ptr<u32>(loc + seg.ls), seg.size / 4, seg.addr);
|
||||
sha1_update(&sha, (uchar*)&seg.ls, sizeof(seg.ls));
|
||||
sha1_update(&sha, (uchar*)&seg.addr, sizeof(seg.addr));
|
||||
}
|
||||
}
|
||||
|
||||
sha1_finish(&sha, sha1_hash);
|
||||
|
||||
// Format patch name
|
||||
std::string hash("SPU-0000000000000000000000000000000000000000");
|
||||
for (u32 i = 0; i < sizeof(sha1_hash); i++)
|
||||
{
|
||||
constexpr auto pal = "0123456789abcdef";
|
||||
hash[4 + i * 2] = pal[sha1_hash[i] >> 4];
|
||||
hash[5 + i * 2] = pal[sha1_hash[i] & 15];
|
||||
}
|
||||
|
||||
// Apply the patch
|
||||
auto applied = fxm::check_unlocked<patch_engine>()->apply(hash, vm::g_base_addr + loc);
|
||||
|
||||
if (!Emu.GetTitleID().empty())
|
||||
{
|
||||
// Alternative patch
|
||||
applied += fxm::check_unlocked<patch_engine>()->apply(Emu.GetTitleID() + '-' + hash, vm::g_base_addr + loc);
|
||||
}
|
||||
|
||||
LOG_NOTICE(LOADER, "Loaded SPU image: %s (<- %u)%s", hash, applied, dump);
|
||||
}
|
||||
|
||||
error_code sys_spu_initialize(u32 max_usable_spu, u32 max_raw_spu)
|
||||
@@ -158,13 +147,6 @@ error_code sys_spu_initialize(u32 max_usable_spu, u32 max_raw_spu)
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
error_code _sys_spu_image_get_information(vm::ptr<sys_spu_image> img, u32 ptr1, u32 ptr2)
|
||||
{
|
||||
sys_spu.todo("_sys_spu_image_get_information(img=*0x%x, 1=*0x%x, 2=*0x%x)", img, ptr1, ptr2);
|
||||
|
||||
fmt::throw_exception("Unimplemented syscall: _sys_spu_image_get_information");
|
||||
}
|
||||
|
||||
error_code sys_spu_image_open(vm::ptr<sys_spu_image> img, vm::cptr<char> path)
|
||||
{
|
||||
sys_spu.warning("sys_spu_image_open(img=*0x%x, path=%s)", img, path);
|
||||
@@ -182,27 +164,6 @@ error_code sys_spu_image_open(vm::ptr<sys_spu_image> img, vm::cptr<char> path)
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
error_code _sys_spu_image_import(vm::ptr<sys_spu_image> img, u32 src, u32 arg3, u32 arg4)
|
||||
{
|
||||
sys_spu.todo("_sys_spu_image_import(img=*0x%x, src=*0x%x, arg3=0x%x, arg4=0x%x)", img, src, arg3, arg4);
|
||||
|
||||
fmt::throw_exception("Unimplemented syscall: _sys_spu_image_import");
|
||||
}
|
||||
|
||||
error_code _sys_spu_image_close(vm::ptr<sys_spu_image> img)
|
||||
{
|
||||
sys_spu.todo("_sys_spu_image_close(img=*0x%x)", img);
|
||||
|
||||
fmt::throw_exception("Unimplemented syscall: _sys_spu_image_close");
|
||||
}
|
||||
|
||||
error_code _sys_raw_spu_image_load(vm::ptr<sys_spu_image> img, u32 ptr, u32 arg3)
|
||||
{
|
||||
sys_spu.todo("_sys_raw_spu_image_load(img=*0x%x, ptr=*0x%x, arg3=0x%x)", img, ptr, arg3);
|
||||
|
||||
fmt::throw_exception("Unimlemented syscall: _sys_raw_spu_image_load");
|
||||
}
|
||||
|
||||
error_code sys_spu_thread_initialize(vm::ptr<u32> thread, u32 group_id, u32 spu_num, vm::ptr<sys_spu_image> img, vm::ptr<sys_spu_thread_attribute> attr, vm::ptr<sys_spu_thread_argument> arg)
|
||||
{
|
||||
sys_spu.warning("sys_spu_thread_initialize(thread=*0x%x, group=0x%x, spu_num=%d, img=*0x%x, attr=*0x%x, arg=*0x%x)", thread, group_id, spu_num, img, attr, arg);
|
||||
|
||||
@@ -203,11 +203,7 @@ class ppu_thread;
|
||||
// Syscalls
|
||||
|
||||
error_code sys_spu_initialize(u32 max_usable_spu, u32 max_raw_spu);
|
||||
error_code _sys_spu_image_get_information(vm::ps3::ptr<sys_spu_image> img, u32 ptr1, u32 ptr2);
|
||||
error_code sys_spu_image_open(vm::ps3::ptr<sys_spu_image> img, vm::ps3::cptr<char> path);
|
||||
error_code _sys_spu_image_import(vm::ps3::ptr<sys_spu_image> img, u32 src, u32 arg3, u32 arg4);
|
||||
error_code _sys_spu_image_close(vm::ps3::ptr<sys_spu_image> img);
|
||||
error_code _sys_raw_spu_image_load(vm::ps3::ptr<sys_spu_image> img, u32 ptr, u32 arg3);
|
||||
error_code sys_spu_thread_initialize(vm::ps3::ptr<u32> thread, u32 group, u32 spu_num, vm::ps3::ptr<sys_spu_image>, vm::ps3::ptr<sys_spu_thread_attribute>, vm::ps3::ptr<sys_spu_thread_argument>);
|
||||
error_code sys_spu_thread_set_argument(u32 id, vm::ps3::ptr<sys_spu_thread_argument> arg);
|
||||
error_code sys_spu_thread_group_create(vm::ps3::ptr<u32> id, u32 num, s32 prio, vm::ps3::ptr<sys_spu_thread_group_attribute> attr);
|
||||
|
||||
+20
-101
@@ -7,52 +7,46 @@
|
||||
#include "Emu/Memory/vm.h"
|
||||
#include "Emu/CPU/CPUThread.h"
|
||||
#include "Emu/Cell/ErrorCodes.h"
|
||||
#include "Emu/IdManager.h"
|
||||
#include "Emu/IPC.h"
|
||||
|
||||
#include <deque>
|
||||
|
||||
// attr_protocol (waiting scheduling policy)
|
||||
enum
|
||||
{
|
||||
SYS_SYNC_FIFO = 0x1, // First In, First Out Order
|
||||
SYS_SYNC_PRIORITY = 0x2, // Priority Order
|
||||
SYS_SYNC_PRIORITY_INHERIT = 0x3, // Basic Priority Inheritance Protocol
|
||||
SYS_SYNC_RETRY = 0x4, // Not selected while unlocking
|
||||
SYS_SYNC_ATTR_PROTOCOL_MASK = 0xf,
|
||||
// First In, First Out
|
||||
SYS_SYNC_FIFO = 1,
|
||||
// Priority Order
|
||||
SYS_SYNC_PRIORITY = 2,
|
||||
// Basic Priority Inheritance Protocol (probably not implemented)
|
||||
SYS_SYNC_PRIORITY_INHERIT = 3,
|
||||
// Not selected while unlocking
|
||||
SYS_SYNC_RETRY = 4,
|
||||
//
|
||||
SYS_SYNC_ATTR_PROTOCOL_MASK = 0xF,
|
||||
};
|
||||
|
||||
// attr_recursive (recursive locks policy)
|
||||
enum
|
||||
{
|
||||
SYS_SYNC_RECURSIVE = 0x10,
|
||||
SYS_SYNC_NOT_RECURSIVE = 0x20,
|
||||
SYS_SYNC_ATTR_RECURSIVE_MASK = 0xf0,
|
||||
// Recursive locks are allowed
|
||||
SYS_SYNC_RECURSIVE = 0x10,
|
||||
// Recursive locks are NOT allowed
|
||||
SYS_SYNC_NOT_RECURSIVE = 0x20,
|
||||
//
|
||||
SYS_SYNC_ATTR_RECURSIVE_MASK = 0xF0, //???
|
||||
};
|
||||
|
||||
// attr_pshared (sharing among processes policy)
|
||||
// attr_pshared
|
||||
enum
|
||||
{
|
||||
SYS_SYNC_PROCESS_SHARED = 0x100,
|
||||
SYS_SYNC_NOT_PROCESS_SHARED = 0x200,
|
||||
SYS_SYNC_ATTR_PSHARED_MASK = 0xf00,
|
||||
};
|
||||
|
||||
// attr_flags (creation policy)
|
||||
enum
|
||||
{
|
||||
SYS_SYNC_NEWLY_CREATED = 0x1, // Create new object, fails if specified IPC key exists
|
||||
SYS_SYNC_NOT_CREATE = 0x2, // Reference existing object, fails if IPC key not found
|
||||
SYS_SYNC_NOT_CARE = 0x3, // Reference existing object, create new one if IPC key not found
|
||||
SYS_SYNC_ATTR_FLAGS_MASK = 0xf,
|
||||
SYS_SYNC_NOT_PROCESS_SHARED = 0x200,
|
||||
};
|
||||
|
||||
// attr_adaptive
|
||||
enum
|
||||
{
|
||||
SYS_SYNC_ADAPTIVE = 0x1000,
|
||||
SYS_SYNC_NOT_ADAPTIVE = 0x2000,
|
||||
SYS_SYNC_ATTR_ADAPTIVE_MASK = 0xf000,
|
||||
SYS_SYNC_ADAPTIVE = 0x1000,
|
||||
SYS_SYNC_NOT_ADAPTIVE = 0x2000,
|
||||
};
|
||||
|
||||
// Base class for some kernel objects (shared set of 8192 objects).
|
||||
@@ -132,81 +126,6 @@ struct lv2_obj
|
||||
|
||||
static void cleanup();
|
||||
|
||||
template <typename T, typename F>
|
||||
static error_code create(u32 pshared, u64 ipc_key, s32 flags, F&& make)
|
||||
{
|
||||
switch (pshared)
|
||||
{
|
||||
case SYS_SYNC_PROCESS_SHARED:
|
||||
{
|
||||
switch (flags)
|
||||
{
|
||||
case SYS_SYNC_NEWLY_CREATED:
|
||||
case SYS_SYNC_NOT_CARE:
|
||||
{
|
||||
std::shared_ptr<T> result = make();
|
||||
|
||||
if (!ipc_manager<T, u64>::add(ipc_key, [&] { if (!idm::import_existing<lv2_obj, T>(result)) result.reset(); return result; }, &result))
|
||||
{
|
||||
if (flags == SYS_SYNC_NEWLY_CREATED)
|
||||
{
|
||||
return CELL_EEXIST;
|
||||
}
|
||||
|
||||
if (!idm::import_existing<lv2_obj, T>(result))
|
||||
{
|
||||
return CELL_EAGAIN;
|
||||
}
|
||||
|
||||
return CELL_OK;
|
||||
}
|
||||
else if (!result)
|
||||
{
|
||||
return CELL_EAGAIN;
|
||||
}
|
||||
else
|
||||
{
|
||||
return CELL_OK;
|
||||
}
|
||||
}
|
||||
case SYS_SYNC_NOT_CREATE:
|
||||
{
|
||||
auto result = ipc_manager<T, u64>::get(ipc_key);
|
||||
|
||||
if (!result)
|
||||
{
|
||||
return CELL_ESRCH;
|
||||
}
|
||||
|
||||
if (!idm::import_existing<lv2_obj, T>(result))
|
||||
{
|
||||
return CELL_EAGAIN;
|
||||
}
|
||||
|
||||
return CELL_OK;
|
||||
}
|
||||
default:
|
||||
{
|
||||
return CELL_EINVAL;
|
||||
}
|
||||
}
|
||||
}
|
||||
case SYS_SYNC_NOT_PROCESS_SHARED:
|
||||
{
|
||||
if (!idm::import<lv2_obj, T>(std::forward<F>(make)))
|
||||
{
|
||||
return CELL_EAGAIN;
|
||||
}
|
||||
|
||||
return CELL_OK;
|
||||
}
|
||||
default:
|
||||
{
|
||||
return CELL_EINVAL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
// Scheduler mutex
|
||||
static semaphore<> g_mutex;
|
||||
|
||||
@@ -25,7 +25,7 @@ struct lv2_timer final : public lv2_obj, public named_thread
|
||||
void on_stop() override;
|
||||
|
||||
semaphore<> mutex;
|
||||
atomic_t<u32> state{SYS_TIMER_STATE_STOP};
|
||||
atomic_t<u32> state{SYS_TIMER_STATE_RUN};
|
||||
|
||||
std::weak_ptr<lv2_event_queue> port;
|
||||
u64 source;
|
||||
|
||||
+5
-14
@@ -7,7 +7,7 @@
|
||||
|
||||
// IPC manager for objects of type T and IPC keys of type K.
|
||||
// External declaration of g_ipc is required.
|
||||
template <typename T, typename K>
|
||||
template<typename T, typename K>
|
||||
class ipc_manager final
|
||||
{
|
||||
std::unordered_map<K, std::weak_ptr<T>> m_map;
|
||||
@@ -18,27 +18,18 @@ class ipc_manager final
|
||||
|
||||
public:
|
||||
// Add new object if specified ipc_key is not used
|
||||
template <typename F>
|
||||
static bool add(const K& ipc_key, F&& provider, std::shared_ptr<T>* out = nullptr)
|
||||
template<typename F>
|
||||
static bool add(const K& ipc_key, F&& provider)
|
||||
{
|
||||
writer_lock lock(g_ipc.m_mutex);
|
||||
|
||||
// Get object location
|
||||
std::weak_ptr<T>& wptr = g_ipc.m_map[ipc_key];
|
||||
|
||||
if ((out && !(*out = wptr.lock())) || wptr.expired())
|
||||
if (wptr.expired())
|
||||
{
|
||||
// Call a function which must return the object
|
||||
if (out)
|
||||
{
|
||||
*out = provider();
|
||||
wptr = *out;
|
||||
}
|
||||
else
|
||||
{
|
||||
wptr = provider();
|
||||
}
|
||||
|
||||
wptr = provider();
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -189,7 +189,6 @@ enum CellKbMappingType
|
||||
CELL_KB_MAPPING_BELGIAN_BELGIUM,
|
||||
CELL_KB_MAPPING_POLISH_POLAND,
|
||||
CELL_KB_MAPPING_PORTUGUESE_BRAZIL,
|
||||
CELL_KB_MAPPING_TURKISH_TURKEY
|
||||
};
|
||||
|
||||
static const u32 KB_MAX_KEYBOARDS = 127;
|
||||
|
||||
@@ -55,16 +55,13 @@ bool VirtualMemoryBlock::Map(u32 realaddr, u32 size, u32 addr)
|
||||
return false;
|
||||
}
|
||||
|
||||
for (u32 i = 0; i<m_mapped_memory.size(); ++i)
|
||||
/*for (u32 i = 0; i<m_mapped_memory.size(); ++i)
|
||||
{
|
||||
if (addr >= m_mapped_memory[i].addr && addr + size - 1 <= m_mapped_memory[i].addr + m_mapped_memory[i].size - 1)
|
||||
{
|
||||
// it seems mapping another range inside a previous one is legit on ps3
|
||||
// as long as it's coherent aliasing : offset from EA must match IO offset
|
||||
// example game using this pattern : BCES01584 - the last of us
|
||||
return (addr - m_mapped_memory[i].addr) == (realaddr - m_mapped_memory[i].realAddress);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}*/
|
||||
|
||||
m_mapped_memory.emplace_back(addr, realaddr, size);
|
||||
return true;
|
||||
|
||||
@@ -27,9 +27,9 @@
|
||||
|
||||
namespace vm
|
||||
{
|
||||
static u8* memory_reserve_4GiB(std::uintptr_t _addr = 0)
|
||||
static u8* memory_reserve_4GiB(std::uintptr_t addr = 0)
|
||||
{
|
||||
for (u64 addr = _addr + 0x100000000;; addr += 0x100000000)
|
||||
for (u64 addr = 0x100000000;; addr += 0x100000000)
|
||||
{
|
||||
if (auto ptr = utils::memory_reserve(0x100000000, (void*)addr))
|
||||
{
|
||||
@@ -783,10 +783,10 @@ namespace vm
|
||||
{
|
||||
std::make_shared<block_t>(0x00010000, 0x1FFF0000), // main
|
||||
std::make_shared<block_t>(0x20000000, 0x10000000), // user
|
||||
std::make_shared<block_t>(0x40000000, 0x30000000), // rsx contexts
|
||||
std::make_shared<block_t>(0xC0000000, 0x10000000), // video
|
||||
std::make_shared<block_t>(0xD0000000, 0x10000000), // stack
|
||||
std::make_shared<block_t>(0xE0000000, 0x20000000), // SPU reserved
|
||||
std::make_shared<block_t>(0x40000000, 0x10000000), // rsx contexts
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,6 +16,7 @@ namespace vm
|
||||
{
|
||||
main,
|
||||
user_space,
|
||||
rsx_context,
|
||||
video,
|
||||
stack,
|
||||
|
||||
|
||||
@@ -1,13 +1,10 @@
|
||||
#include "stdafx.h"
|
||||
#include "Utilities/sysinfo.h"
|
||||
#include "Emu/Memory/Memory.h"
|
||||
#include "Emu/System.h"
|
||||
|
||||
#include "ARMv7Thread.h"
|
||||
#include "ARMv7Interpreter.h"
|
||||
|
||||
const bool s_use_rtm = utils::has_rtm();
|
||||
|
||||
using namespace arm_code::arm_encoding_alias;
|
||||
|
||||
#define ARG(arg, ...) const u32 arg = args::arg::extract(__VA_ARGS__);
|
||||
@@ -2094,34 +2091,13 @@ void arm_interpreter::STREX(ARMv7Thread& cpu, const u32 op, const u32 cond)
|
||||
return;
|
||||
}
|
||||
|
||||
bool result;
|
||||
vm::writer_lock lock(0);
|
||||
|
||||
if (s_use_rtm && utils::transaction_enter())
|
||||
const bool result = cpu.rtime == vm::reservation_acquire(addr, cpu.rtime) && data.compare_and_swap_test(cpu.rdata, value);
|
||||
|
||||
if (result)
|
||||
{
|
||||
if (!vm::reader_lock{vm::try_to_lock})
|
||||
{
|
||||
_xabort(0);
|
||||
}
|
||||
|
||||
result = cpu.rtime == vm::reservation_acquire(addr, sizeof(u32)) && data.compare_and_swap_test(cpu.rdata, value);
|
||||
|
||||
if (result)
|
||||
{
|
||||
vm::reservation_update(addr, sizeof(u32));
|
||||
}
|
||||
|
||||
_xend();
|
||||
}
|
||||
else
|
||||
{
|
||||
vm::writer_lock lock(0);
|
||||
|
||||
result = cpu.rtime == vm::reservation_acquire(addr, sizeof(u32)) && data.compare_and_swap_test(cpu.rdata, value);
|
||||
|
||||
if (result)
|
||||
{
|
||||
vm::reservation_update(addr, sizeof(u32));
|
||||
}
|
||||
vm::reservation_update(addr, sizeof(u32));
|
||||
}
|
||||
|
||||
cpu.raddr = 0;
|
||||
|
||||
@@ -63,9 +63,6 @@ std::string CgBinaryDisasm::GetDSTDisasm(bool isSca)
|
||||
LOG_ERROR(RSX, "dst index out of range: %u", d3.dst);
|
||||
|
||||
ret += fmt::format("o[%d]", d3.dst) + GetVecMaskDisasm();
|
||||
// Vertex Program supports double destinations, notably in MOV
|
||||
if (d0.dst_tmp != 0x3f)
|
||||
ret += fmt::format(" R%d", d0.dst_tmp) + GetVecMaskDisasm();
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
@@ -125,13 +125,8 @@ namespace
|
||||
u32 min_block_size = std::min(src_stride, dst_stride);
|
||||
if (min_block_size == 0) min_block_size = dst_stride;
|
||||
|
||||
u32 iterations = 0;
|
||||
u32 remainder = is_128_aligned ? 0 : 1 + ((16 - min_block_size) / min_block_size);
|
||||
|
||||
if (vertex_count > remainder)
|
||||
iterations = vertex_count - remainder;
|
||||
else
|
||||
remainder = vertex_count;
|
||||
const u32 remainder = is_128_aligned? 0: (16 - min_block_size) / min_block_size;
|
||||
const u32 iterations = is_128_aligned? vertex_count: vertex_count - remainder;
|
||||
|
||||
for (u32 i = 0; i < iterations; ++i)
|
||||
{
|
||||
@@ -173,13 +168,8 @@ namespace
|
||||
u32 min_block_size = std::min(src_stride, dst_stride);
|
||||
if (min_block_size == 0) min_block_size = dst_stride;
|
||||
|
||||
u32 iterations = 0;
|
||||
u32 remainder = is_128_aligned ? 0 : 1 + ((16 - min_block_size) / min_block_size);
|
||||
|
||||
if (vertex_count > remainder)
|
||||
iterations = vertex_count - remainder;
|
||||
else
|
||||
remainder = vertex_count;
|
||||
const u32 remainder = is_128_aligned ? 0 : (16 - min_block_size) / min_block_size;
|
||||
const u32 iterations = is_128_aligned ? vertex_count : vertex_count - remainder;
|
||||
|
||||
for (u32 i = 0; i < iterations; ++i)
|
||||
{
|
||||
|
||||
@@ -41,21 +41,16 @@ std::string VertexProgramDecompiler::GetDST(bool isSca)
|
||||
{
|
||||
std::string ret;
|
||||
|
||||
std::string mask = GetMask(isSca);
|
||||
|
||||
switch (isSca ? 0x1f : d3.dst)
|
||||
{
|
||||
case 0x1f:
|
||||
ret += m_parr.AddParam(PF_PARAM_NONE, getFloatTypeName(4), std::string("tmp") + std::to_string(isSca ? d3.sca_dst_tmp : d0.dst_tmp)) + mask;
|
||||
ret += m_parr.AddParam(PF_PARAM_NONE, getFloatTypeName(4), std::string("tmp") + std::to_string(isSca ? d3.sca_dst_tmp : d0.dst_tmp));
|
||||
break;
|
||||
|
||||
default:
|
||||
if (d3.dst > 15)
|
||||
LOG_ERROR(RSX, "dst index out of range: %u", d3.dst);
|
||||
ret += m_parr.AddParam(PF_PARAM_NONE, getFloatTypeName(4), std::string("dst_reg") + std::to_string(d3.dst), d3.dst == 0 ? getFloatTypeName(4) + "(0.0f, 0.0f, 0.0f, 1.0f)" : getFloatTypeName(4) + "(0.0, 0.0, 0.0, 0.0)") + mask;
|
||||
// Handle double destination register as 'dst_reg = tmp'
|
||||
if (d0.dst_tmp != 0x3f)
|
||||
ret += " = " + m_parr.AddParam(PF_PARAM_NONE, getFloatTypeName(4), std::string("tmp") + std::to_string(d0.dst_tmp)) + mask;
|
||||
ret += m_parr.AddParam(PF_PARAM_NONE, getFloatTypeName(4), std::string("dst_reg") + std::to_string(d3.dst), d3.dst == 0 ? getFloatTypeName(4) + "(0.0f, 0.0f, 0.0f, 1.0f)" : getFloatTypeName(4) + "(0.0, 0.0, 0.0, 0.0)");
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -162,7 +157,7 @@ void VertexProgramDecompiler::SetDST(bool is_sca, std::string value)
|
||||
}
|
||||
else if (d3.dst != 0x1f || (is_sca ? d3.sca_dst_tmp != 0x3f : d0.dst_tmp != 0x3f))
|
||||
{
|
||||
dest = GetDST(is_sca);
|
||||
dest = GetDST(is_sca) + mask;
|
||||
}
|
||||
|
||||
//std::string code;
|
||||
@@ -314,7 +309,7 @@ void VertexProgramDecompiler::AddCodeCond(const std::string& dst, const std::str
|
||||
|
||||
swizzle = swizzle == "xyzw" ? "" : "." + swizzle;
|
||||
|
||||
std::string cond = compareFunction(cond_string_table[d0.cond], "cc" + std::to_string(d0.cond_reg_sel_1) + swizzle, getFloatTypeName(4) + "(0., 0., 0., 0.)");
|
||||
std::string cond = compareFunction(cond_string_table[d0.cond], "cc" + std::to_string(d0.cond_reg_sel_1) + swizzle.c_str(), getFloatTypeName(4) + "(0., 0., 0., 0.)");
|
||||
|
||||
ShaderVariable dst_var(dst);
|
||||
dst_var.symplify();
|
||||
|
||||
@@ -93,12 +93,7 @@ namespace rsx
|
||||
auto It = m_render_targets_storage.find(address);
|
||||
// TODO: Fix corner cases
|
||||
// This doesn't take overlapping surface(s) into account.
|
||||
|
||||
surface_storage_type old_surface_storage;
|
||||
surface_storage_type new_surface_storage;
|
||||
surface_type old_surface = nullptr;
|
||||
surface_type new_surface = nullptr;
|
||||
|
||||
if (It != m_render_targets_storage.end())
|
||||
{
|
||||
surface_storage_type &rtt = It->second;
|
||||
@@ -109,43 +104,10 @@ namespace rsx
|
||||
}
|
||||
|
||||
old_surface = Traits::get(rtt);
|
||||
old_surface_storage = std::move(rtt);
|
||||
invalidated_resources.push_back(std::move(rtt));
|
||||
m_render_targets_storage.erase(address);
|
||||
}
|
||||
|
||||
//Search invalidated resources for a suitable surface
|
||||
for (auto It = invalidated_resources.begin(); It != invalidated_resources.end(); It++)
|
||||
{
|
||||
auto &rtt = *It;
|
||||
if (Traits::rtt_has_format_width_height(rtt, color_format, width, height, true))
|
||||
{
|
||||
new_surface_storage = std::move(rtt);
|
||||
|
||||
if (old_surface)
|
||||
//Exchange this surface with the invalidated one
|
||||
rtt = std::move(old_surface_storage);
|
||||
else
|
||||
//rtt is now empty - erase it
|
||||
invalidated_resources.erase(It);
|
||||
|
||||
new_surface = Traits::get(new_surface_storage);
|
||||
Traits::invalidate_rtt_surface_contents(command_list, new_surface, old_surface, true);
|
||||
Traits::prepare_rtt_for_drawing(command_list, new_surface);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (old_surface != nullptr && new_surface == nullptr)
|
||||
//This was already determined to be invalid and is excluded from testing above
|
||||
invalidated_resources.push_back(std::move(old_surface_storage));
|
||||
|
||||
if (new_surface != nullptr)
|
||||
{
|
||||
//New surface was found among existing surfaces
|
||||
m_render_targets_storage[address] = std::move(new_surface_storage);
|
||||
return new_surface;
|
||||
}
|
||||
|
||||
m_render_targets_storage[address] = Traits::create_new_surface(address, color_format, width, height, old_surface, std::forward<Args>(extra_params)...);
|
||||
return Traits::get(m_render_targets_storage[address]);
|
||||
}
|
||||
@@ -157,11 +119,7 @@ namespace rsx
|
||||
surface_depth_format depth_format, size_t width, size_t height,
|
||||
Args&&... extra_params)
|
||||
{
|
||||
surface_storage_type old_surface_storage;
|
||||
surface_storage_type new_surface_storage;
|
||||
surface_type old_surface = nullptr;
|
||||
surface_type new_surface = nullptr;
|
||||
|
||||
auto It = m_depth_stencil_storage.find(address);
|
||||
if (It != m_depth_stencil_storage.end())
|
||||
{
|
||||
@@ -173,42 +131,10 @@ namespace rsx
|
||||
}
|
||||
|
||||
old_surface = Traits::get(ds);
|
||||
old_surface_storage = std::move(ds);
|
||||
invalidated_resources.push_back(std::move(ds));
|
||||
m_depth_stencil_storage.erase(address);
|
||||
}
|
||||
|
||||
//Search invalidated resources for a suitable surface
|
||||
for (auto It = invalidated_resources.begin(); It != invalidated_resources.end(); It++)
|
||||
{
|
||||
auto &ds = *It;
|
||||
if (Traits::ds_has_format_width_height(ds, depth_format, width, height, true))
|
||||
{
|
||||
new_surface_storage = std::move(ds);
|
||||
|
||||
if (old_surface)
|
||||
//Exchange this surface with the invalidated one
|
||||
ds = std::move(old_surface_storage);
|
||||
else
|
||||
invalidated_resources.erase(It);
|
||||
|
||||
new_surface = Traits::get(new_surface_storage);
|
||||
Traits::prepare_ds_for_drawing(command_list, new_surface);
|
||||
Traits::invalidate_depth_surface_contents(command_list, new_surface, old_surface, true);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (old_surface != nullptr && new_surface == nullptr)
|
||||
//This was already determined to be invalid and is excluded from testing above
|
||||
invalidated_resources.push_back(std::move(old_surface_storage));
|
||||
|
||||
if (new_surface != nullptr)
|
||||
{
|
||||
//New surface was found among existing surfaces
|
||||
m_depth_stencil_storage[address] = std::move(new_surface_storage);
|
||||
return new_surface;
|
||||
}
|
||||
|
||||
m_depth_stencil_storage[address] = Traits::create_new_surface(address, depth_format, width, height, old_surface, std::forward<Args>(extra_params)...);
|
||||
return Traits::get(m_depth_stencil_storage[address]);
|
||||
}
|
||||
@@ -432,10 +358,10 @@ namespace rsx
|
||||
void invalidate_surface_cache_data(command_list_type command_list)
|
||||
{
|
||||
for (auto &rtt : m_render_targets_storage)
|
||||
Traits::invalidate_rtt_surface_contents(command_list, Traits::get(std::get<1>(rtt)), nullptr, false);
|
||||
Traits::invalidate_rtt_surface_contents(command_list, Traits::get(std::get<1>(rtt)));
|
||||
|
||||
for (auto &ds : m_depth_stencil_storage)
|
||||
Traits::invalidate_depth_surface_contents(command_list, Traits::get(std::get<1>(ds)), nullptr, true);
|
||||
Traits::invalidate_depth_surface_contents(command_list, Traits::get(std::get<1>(ds)));
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -223,8 +223,9 @@ namespace
|
||||
const std::vector<std::pair<u32, u32>>& vertex_ranges, d3d12_data_heap& m_buffer_data)
|
||||
{
|
||||
size_t index_count = std::accumulate(
|
||||
vertex_ranges.begin(), vertex_ranges.end(), 0ll, [](size_t acc, const auto& pair) {
|
||||
return acc + get_index_count(rsx::method_registers.current_draw_clause.primitive, pair.second);
|
||||
vertex_ranges.begin(), vertex_ranges.end(), 0, [](size_t acc, const auto& pair) {
|
||||
return acc + get_index_count(
|
||||
rsx::method_registers.current_draw_clause.primitive, pair.second);
|
||||
});
|
||||
|
||||
// Alloc
|
||||
@@ -235,7 +236,7 @@ namespace
|
||||
void* mapped_buffer =
|
||||
m_buffer_data.map<void>(CD3DX12_RANGE(heap_offset, heap_offset + buffer_size));
|
||||
|
||||
u32 vertex_count = 0;
|
||||
size_t vertex_count = 0;
|
||||
for (const auto& pair : vertex_ranges)
|
||||
vertex_count += pair.second;
|
||||
|
||||
@@ -468,7 +469,7 @@ D3D12GSRender::upload_and_set_vertex_index_data(ID3D12GraphicsCommandList* comma
|
||||
return std::apply_visitor(
|
||||
draw_command_visitor(command_list, m_buffer_data, m_vertex_buffer_data.Get(),
|
||||
[this](
|
||||
const auto& state, const auto& list) { return get_vertex_buffers(state, list, 0); }),
|
||||
const auto& state, const auto& list) { return get_vertex_buffers(state, list); }),
|
||||
get_draw_command(rsx::method_registers));
|
||||
}
|
||||
|
||||
|
||||
@@ -324,17 +324,6 @@ void D3D12GSRender::end()
|
||||
{
|
||||
std::chrono::time_point<steady_clock> start_duration = steady_clock::now();
|
||||
|
||||
std::chrono::time_point<steady_clock> program_load_start = steady_clock::now();
|
||||
load_program();
|
||||
std::chrono::time_point<steady_clock> program_load_end = steady_clock::now();
|
||||
m_timers.program_load_duration += std::chrono::duration_cast<std::chrono::microseconds>(program_load_end - program_load_start).count();
|
||||
|
||||
if (!m_fragment_program.valid)
|
||||
{
|
||||
rsx::thread::end();
|
||||
return;
|
||||
}
|
||||
|
||||
std::chrono::time_point<steady_clock> rtt_duration_start = steady_clock::now();
|
||||
prepare_render_targets(get_current_resource_storage().command_list.Get());
|
||||
|
||||
@@ -355,6 +344,11 @@ void D3D12GSRender::end()
|
||||
std::chrono::time_point<steady_clock> vertex_index_duration_end = steady_clock::now();
|
||||
m_timers.vertex_index_duration += std::chrono::duration_cast<std::chrono::microseconds>(vertex_index_duration_end - vertex_index_duration_start).count();
|
||||
|
||||
std::chrono::time_point<steady_clock> program_load_start = steady_clock::now();
|
||||
load_program();
|
||||
std::chrono::time_point<steady_clock> program_load_end = steady_clock::now();
|
||||
m_timers.program_load_duration += std::chrono::duration_cast<std::chrono::microseconds>(program_load_end - program_load_start).count();
|
||||
|
||||
get_current_resource_storage().command_list->SetGraphicsRootSignature(m_shared_root_signature.Get());
|
||||
get_current_resource_storage().command_list->OMSetStencilRef(rsx::method_registers.stencil_func_ref());
|
||||
|
||||
@@ -523,9 +517,10 @@ void D3D12GSRender::flip(int buffer)
|
||||
size_t offset = 0;
|
||||
if (false)
|
||||
{
|
||||
u32 addr = rsx::get_address(display_buffers[current_display_buffer].offset, CELL_GCM_LOCATION_LOCAL);
|
||||
w = display_buffers[current_display_buffer].width;
|
||||
h = display_buffers[current_display_buffer].height;
|
||||
CellGcmDisplayInfo* buffers = nullptr;// = vm::ps3::_ptr<CellGcmDisplayInfo>(m_gcm_buffers_addr);
|
||||
u32 addr = rsx::get_address(gcm_buffers[gcm_current_buffer].offset, CELL_GCM_LOCATION_LOCAL);
|
||||
w = gcm_buffers[gcm_current_buffer].width;
|
||||
h = gcm_buffers[gcm_current_buffer].height;
|
||||
u8 *src_buffer = vm::ps3::_ptr<u8>(addr);
|
||||
|
||||
row_pitch = align(w * 4, 256);
|
||||
|
||||
@@ -56,9 +56,6 @@ void D3D12GSRender::load_program()
|
||||
m_vertex_program = get_current_vertex_program();
|
||||
m_fragment_program = get_current_fragment_program(rtt_lookup_func);
|
||||
|
||||
if (!m_fragment_program.valid)
|
||||
return;
|
||||
|
||||
D3D12PipelineProperties prop = {};
|
||||
prop.Topology = get_primitive_topology_type(rsx::method_registers.current_draw_clause.primitive);
|
||||
|
||||
|
||||
@@ -176,15 +176,15 @@ void D3D12GSRender::prepare_render_targets(ID3D12GraphicsCommandList *copycmdlis
|
||||
rsx::method_registers.clear_color_a() / 255.f,
|
||||
};
|
||||
|
||||
u32 clip_width = rsx::method_registers.surface_clip_width();
|
||||
u32 clip_height = rsx::method_registers.surface_clip_height();
|
||||
u32 clip_width = rsx::method_registers.surface_clip_width();
|
||||
u32 clip_height = rsx::method_registers.surface_clip_height();
|
||||
|
||||
if (clip_height == 0 || clip_width == 0)
|
||||
return;
|
||||
if (clip_height == 0 || clip_width == 0)
|
||||
return;
|
||||
|
||||
m_rtts.prepare_render_target(copycmdlist,
|
||||
rsx::method_registers.surface_color(), rsx::method_registers.surface_depth_fmt(),
|
||||
clip_width, clip_height,
|
||||
clip_width, clip_height,
|
||||
rsx::method_registers.surface_color_target(),
|
||||
get_color_surface_addresses(), get_zeta_surface_address(),
|
||||
m_device.Get(), clear_color, 1.f, 0);
|
||||
@@ -329,7 +329,7 @@ void D3D12GSRender::copy_render_target_to_dma_location()
|
||||
{
|
||||
for (u8 i : get_rtt_indexes(rsx::method_registers.surface_color_target()))
|
||||
{
|
||||
if (!address_color[i] || std::get<1>(m_rtts.m_bound_render_targets[i]) == nullptr)
|
||||
if (!address_color[i])
|
||||
continue;
|
||||
color_buffer_offset_in_heap[i] = download_to_readback_buffer(m_device.Get(), get_current_resource_storage().command_list.Get(), m_readback_resources, std::get<1>(m_rtts.m_bound_render_targets[i]), rsx::method_registers.surface_color());
|
||||
invalidate_address(address_color[i]);
|
||||
@@ -381,7 +381,7 @@ void D3D12GSRender::copy_render_target_to_dma_location()
|
||||
|
||||
for (u8 i : get_rtt_indexes(rsx::method_registers.surface_color_target()))
|
||||
{
|
||||
if (!address_color[i] || std::get<1>(m_rtts.m_bound_render_targets[i]) == nullptr)
|
||||
if (!address_color[i])
|
||||
continue;
|
||||
copy_readback_buffer_to_dest(dest_buffer[i], m_readback_resources, color_buffer_offset_in_heap[i], srcPitch, dstPitch, clip_h);
|
||||
}
|
||||
|
||||
@@ -116,30 +116,28 @@ struct render_target_traits
|
||||
command_list->ResourceBarrier(1, &CD3DX12_RESOURCE_BARRIER::Transition(ds, D3D12_RESOURCE_STATE_DEPTH_WRITE, D3D12_RESOURCE_STATE_GENERIC_READ));
|
||||
}
|
||||
|
||||
static
|
||||
void invalidate_rtt_surface_contents(
|
||||
gsl::not_null<ID3D12GraphicsCommandList*>,
|
||||
ID3D12Resource*, ID3D12Resource*, bool)
|
||||
ID3D12Resource*)
|
||||
{}
|
||||
|
||||
static
|
||||
void invalidate_depth_surface_contents(
|
||||
gsl::not_null<ID3D12GraphicsCommandList*>,
|
||||
ID3D12Resource*, ID3D12Resource*, bool)
|
||||
ID3D12Resource*)
|
||||
{
|
||||
//TODO
|
||||
}
|
||||
|
||||
|
||||
static
|
||||
bool rtt_has_format_width_height(const ComPtr<ID3D12Resource> &rtt, surface_color_format surface_color_format, size_t width, size_t height, bool=false)
|
||||
bool rtt_has_format_width_height(const ComPtr<ID3D12Resource> &rtt, surface_color_format surface_color_format, size_t width, size_t height)
|
||||
{
|
||||
DXGI_FORMAT dxgi_format = get_color_surface_format(surface_color_format);
|
||||
return rtt->GetDesc().Format == dxgi_format && rtt->GetDesc().Width == width && rtt->GetDesc().Height == height;
|
||||
}
|
||||
|
||||
static
|
||||
bool ds_has_format_width_height(const ComPtr<ID3D12Resource> &rtt, surface_depth_format, size_t width, size_t height, bool=false)
|
||||
bool ds_has_format_width_height(const ComPtr<ID3D12Resource> &rtt, surface_depth_format, size_t width, size_t height)
|
||||
{
|
||||
//TODO: Check format
|
||||
return rtt->GetDesc().Width == width && rtt->GetDesc().Height == height;
|
||||
|
||||
+13
-3
@@ -7,11 +7,21 @@
|
||||
|
||||
struct CellGcmControl
|
||||
{
|
||||
atomic_be_t<u32> put;
|
||||
atomic_be_t<u32> get;
|
||||
atomic_be_t<u32> ref;
|
||||
u8 resv[0x40];
|
||||
atomic_be_t<u32> put;
|
||||
atomic_be_t<u32> get;
|
||||
atomic_be_t<u32> ref;
|
||||
be_t<u32> unk[2];
|
||||
be_t<u32> unk1;
|
||||
};
|
||||
|
||||
/*struct CellGcmControl
|
||||
{
|
||||
atomic_be_t<u32> put;
|
||||
atomic_be_t<u32> get;
|
||||
atomic_be_t<u32> ref;
|
||||
};*/
|
||||
|
||||
struct CellGcmConfig
|
||||
{
|
||||
be_t<u32> localAddress;
|
||||
|
||||
+66
-115
@@ -26,11 +26,6 @@ GLGSRender::GLGSRender() : GSRender()
|
||||
{
|
||||
//TODO
|
||||
//shaders_cache.load(rsx::old_shaders_cache::shader_language::glsl);
|
||||
|
||||
if (g_cfg.video.disable_vertex_cache)
|
||||
m_vertex_cache.reset(new gl::null_vertex_cache());
|
||||
else
|
||||
m_vertex_cache.reset(new gl::weak_vertex_cache());
|
||||
}
|
||||
|
||||
u32 GLGSRender::enable(u32 condition, u32 cap)
|
||||
@@ -327,15 +322,17 @@ namespace
|
||||
|
||||
void GLGSRender::end()
|
||||
{
|
||||
std::chrono::time_point<steady_clock> program_start = steady_clock::now();
|
||||
//Load program here since it is dependent on vertex state
|
||||
|
||||
if (skip_frame || !framebuffer_status_valid || !load_program())
|
||||
if (skip_frame || !framebuffer_status_valid)
|
||||
{
|
||||
rsx::thread::end();
|
||||
return;
|
||||
}
|
||||
|
||||
std::chrono::time_point<steady_clock> program_start = steady_clock::now();
|
||||
|
||||
//Load program here since it is dependent on vertex state
|
||||
load_program();
|
||||
|
||||
std::chrono::time_point<steady_clock> program_stop = steady_clock::now();
|
||||
m_begin_time += (u32)std::chrono::duration_cast<std::chrono::microseconds>(program_stop - program_start).count();
|
||||
|
||||
@@ -367,80 +364,44 @@ void GLGSRender::end()
|
||||
surface->old_contents = nullptr;
|
||||
};
|
||||
|
||||
//Check if we have any 'recycled' surfaces in memory and if so, clear them
|
||||
std::vector<int> buffers_to_clear;
|
||||
bool clear_all_color = true;
|
||||
bool clear_depth = false;
|
||||
|
||||
for (int index = 0; index < 4; index++)
|
||||
{
|
||||
if (std::get<0>(m_rtts.m_bound_render_targets[index]) != 0)
|
||||
{
|
||||
if (std::get<1>(m_rtts.m_bound_render_targets[index])->cleared())
|
||||
clear_all_color = false;
|
||||
else
|
||||
buffers_to_clear.push_back(index);
|
||||
}
|
||||
}
|
||||
|
||||
gl::render_target *ds = std::get<1>(m_rtts.m_bound_depth_stencil);
|
||||
if (ds && !ds->cleared())
|
||||
{
|
||||
clear_depth = true;
|
||||
}
|
||||
//Temporarily disable pixel tests
|
||||
glDisable(GL_SCISSOR_TEST);
|
||||
glDepthMask(GL_TRUE);
|
||||
|
||||
glClearDepth(1.0);
|
||||
glClearStencil(255);
|
||||
|
||||
//Temporarily disable pixel tests
|
||||
glDisable(GL_SCISSOR_TEST);
|
||||
glClear(GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
|
||||
|
||||
if (clear_depth || buffers_to_clear.size() > 0)
|
||||
{
|
||||
GLenum mask = 0;
|
||||
|
||||
if (clear_depth)
|
||||
if (g_cfg.video.strict_rendering_mode)
|
||||
{
|
||||
glDepthMask(GL_TRUE);
|
||||
glClearDepth(1.0);
|
||||
glClearStencil(255);
|
||||
mask |= GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT;
|
||||
//Copy previous data if any
|
||||
if (ds->old_contents != nullptr)
|
||||
copy_rtt_contents(ds);
|
||||
}
|
||||
|
||||
if (clear_all_color)
|
||||
mask |= GL_COLOR_BUFFER_BIT;
|
||||
|
||||
glClear(mask);
|
||||
|
||||
if (buffers_to_clear.size() > 0 && !clear_all_color)
|
||||
{
|
||||
GLfloat colors[] = { 0.f, 0.f, 0.f, 0.f };
|
||||
//It is impossible for the render target to be typa A or B here (clear all would have been flagged)
|
||||
for (auto &i: buffers_to_clear)
|
||||
glClearBufferfv(draw_fbo.id(), i, colors);
|
||||
}
|
||||
|
||||
if (clear_depth)
|
||||
glDepthMask(rsx::method_registers.depth_write_enabled());
|
||||
glDepthMask(rsx::method_registers.depth_write_enabled());
|
||||
glEnable(GL_SCISSOR_TEST);
|
||||
|
||||
ds->set_cleared();
|
||||
}
|
||||
|
||||
if (g_cfg.video.strict_rendering_mode)
|
||||
{
|
||||
if (ds->old_contents != nullptr)
|
||||
copy_rtt_contents(ds);
|
||||
|
||||
for (auto &rtt : m_rtts.m_bound_render_targets)
|
||||
{
|
||||
if (std::get<0>(rtt) != 0)
|
||||
{
|
||||
auto surface = std::get<1>(rtt);
|
||||
if (surface->old_contents != nullptr)
|
||||
if (!surface->cleared() && surface->old_contents != nullptr)
|
||||
copy_rtt_contents(surface);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
glEnable(GL_SCISSOR_TEST);
|
||||
|
||||
std::chrono::time_point<steady_clock> textures_start = steady_clock::now();
|
||||
|
||||
//Setup textures
|
||||
@@ -502,6 +463,7 @@ void GLGSRender::end()
|
||||
}
|
||||
else
|
||||
{
|
||||
//LOG_ERROR(RSX, "No work is needed for this draw call! Muhahahahahahaha");
|
||||
skip_upload = true;
|
||||
}
|
||||
|
||||
@@ -843,14 +805,9 @@ bool GLGSRender::do_method(u32 cmd, u32 arg)
|
||||
{
|
||||
case NV4097_CLEAR_SURFACE:
|
||||
{
|
||||
if (arg & 0xF3)
|
||||
{
|
||||
//Only do all this if we have actual work to do
|
||||
init_buffers(true);
|
||||
synchronize_buffers();
|
||||
clear_surface(arg);
|
||||
}
|
||||
|
||||
init_buffers(true);
|
||||
synchronize_buffers();
|
||||
clear_surface(arg);
|
||||
return true;
|
||||
}
|
||||
case NV4097_TEXTURE_READ_SEMAPHORE_RELEASE:
|
||||
@@ -884,10 +841,8 @@ bool GLGSRender::load_program()
|
||||
return std::make_tuple(true, surface->get_native_pitch());
|
||||
};
|
||||
|
||||
RSXFragmentProgram fragment_program = get_current_fragment_program(rtt_lookup_func);
|
||||
if (!fragment_program.valid) return false;
|
||||
|
||||
RSXVertexProgram vertex_program = get_current_vertex_program();
|
||||
RSXFragmentProgram fragment_program = get_current_fragment_program(rtt_lookup_func);
|
||||
|
||||
u32 unnormalized_rtts = 0;
|
||||
|
||||
@@ -985,52 +940,29 @@ void GLGSRender::flip(int buffer)
|
||||
return;
|
||||
}
|
||||
|
||||
u32 buffer_width = display_buffers[buffer].width;
|
||||
u32 buffer_height = display_buffers[buffer].height;
|
||||
u32 buffer_pitch = display_buffers[buffer].pitch;
|
||||
u32 buffer_width = gcm_buffers[buffer].width;
|
||||
u32 buffer_height = gcm_buffers[buffer].height;
|
||||
u32 buffer_pitch = gcm_buffers[buffer].pitch;
|
||||
|
||||
// Calculate blit coordinates
|
||||
coordi aspect_ratio;
|
||||
areai screen_area = coordi({}, { (int)buffer_width, (int)buffer_height });
|
||||
sizei csize(m_frame->client_width(), m_frame->client_height());
|
||||
sizei new_size = csize;
|
||||
glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
|
||||
glDisable(GL_SCISSOR_TEST);
|
||||
glDisable(GL_DEPTH_TEST);
|
||||
glDisable(GL_STENCIL_TEST);
|
||||
|
||||
if (!g_cfg.video.stretch_to_display_area)
|
||||
{
|
||||
const double aq = (double)buffer_width / buffer_height;
|
||||
const double rq = (double)new_size.width / new_size.height;
|
||||
const double q = aq / rq;
|
||||
|
||||
if (q > 1.0)
|
||||
{
|
||||
new_size.height = int(new_size.height / q);
|
||||
aspect_ratio.y = (csize.height - new_size.height) / 2;
|
||||
}
|
||||
else if (q < 1.0)
|
||||
{
|
||||
new_size.width = int(new_size.width * q);
|
||||
aspect_ratio.x = (csize.width - new_size.width) / 2;
|
||||
}
|
||||
}
|
||||
|
||||
aspect_ratio.size = new_size;
|
||||
|
||||
// Find the source image
|
||||
rsx::tiled_region buffer_region = get_tiled_address(display_buffers[buffer].offset, CELL_GCM_LOCATION_LOCAL);
|
||||
rsx::tiled_region buffer_region = get_tiled_address(gcm_buffers[buffer].offset, CELL_GCM_LOCATION_LOCAL);
|
||||
u32 absolute_address = buffer_region.address + buffer_region.base;
|
||||
|
||||
gl::texture *render_target_texture = m_rtts.get_texture_from_render_target_if_applicable(absolute_address);
|
||||
|
||||
m_flip_fbo.recreate();
|
||||
__glcheck m_flip_fbo.recreate();
|
||||
m_flip_fbo.bind();
|
||||
|
||||
auto *flip_fbo = &m_flip_fbo;
|
||||
|
||||
if (render_target_texture)
|
||||
{
|
||||
buffer_width = render_target_texture->width();
|
||||
buffer_height = render_target_texture->height();
|
||||
|
||||
__glcheck m_flip_fbo.color = *render_target_texture;
|
||||
__glcheck m_flip_fbo.read_buffer(m_flip_fbo.color);
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -1063,14 +995,36 @@ void GLGSRender::flip(int buffer)
|
||||
__glcheck m_flip_fbo.read_buffer(m_flip_fbo.color);
|
||||
}
|
||||
|
||||
// Blit source image to the screen
|
||||
glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
|
||||
glDisable(GL_SCISSOR_TEST);
|
||||
glDisable(GL_DEPTH_TEST);
|
||||
glDisable(GL_STENCIL_TEST);
|
||||
areai screen_area = coordi({}, { (int)buffer_width, (int)buffer_height });
|
||||
|
||||
coordi aspect_ratio;
|
||||
|
||||
sizei csize(m_frame->client_width(), m_frame->client_height());
|
||||
sizei new_size = csize;
|
||||
|
||||
if (!g_cfg.video.stretch_to_display_area)
|
||||
{
|
||||
const double aq = (double)buffer_width / buffer_height;
|
||||
const double rq = (double)new_size.width / new_size.height;
|
||||
const double q = aq / rq;
|
||||
|
||||
if (q > 1.0)
|
||||
{
|
||||
new_size.height = int(new_size.height / q);
|
||||
aspect_ratio.y = (csize.height - new_size.height) / 2;
|
||||
}
|
||||
else if (q < 1.0)
|
||||
{
|
||||
new_size.width = int(new_size.width * q);
|
||||
aspect_ratio.x = (csize.width - new_size.width) / 2;
|
||||
}
|
||||
}
|
||||
|
||||
aspect_ratio.size = new_size;
|
||||
|
||||
gl::screen.clear(gl::buffers::color_depth_stencil);
|
||||
__glcheck m_flip_fbo.blit(gl::screen, screen_area, areai(aspect_ratio).flipped_vertical(), gl::buffers::color, gl::filter::linear);
|
||||
|
||||
__glcheck flip_fbo->blit(gl::screen, screen_area, areai(aspect_ratio).flipped_vertical(), gl::buffers::color, gl::filter::linear);
|
||||
|
||||
if (g_cfg.video.overlay)
|
||||
{
|
||||
@@ -1087,7 +1041,6 @@ void GLGSRender::flip(int buffer)
|
||||
m_frame->flip(m_context);
|
||||
rsx::thread::flip(buffer);
|
||||
|
||||
// Cleanup
|
||||
m_gl_texture_cache.clear_temporary_surfaces();
|
||||
|
||||
for (auto &tex : m_rtts.invalidated_resources)
|
||||
@@ -1098,9 +1051,7 @@ void GLGSRender::flip(int buffer)
|
||||
if (g_cfg.video.invalidate_surface_cache_every_frame)
|
||||
m_rtts.invalidate_surface_cache_data(nullptr);
|
||||
|
||||
m_vertex_cache->purge();
|
||||
|
||||
//If we are skipping the next frame, do not reset perf counters
|
||||
//If we are skipping the next frame, fo not reset perf counters
|
||||
if (skip_frame) return;
|
||||
|
||||
m_draw_calls = 0;
|
||||
|
||||
@@ -14,13 +14,6 @@
|
||||
|
||||
#pragma comment(lib, "opengl32.lib")
|
||||
|
||||
namespace gl
|
||||
{
|
||||
using vertex_cache = rsx::vertex_cache::default_vertex_cache<rsx::vertex_cache::uploaded_range<GLenum>, GLenum>;
|
||||
using weak_vertex_cache = rsx::vertex_cache::weak_vertex_cache<GLenum>;
|
||||
using null_vertex_cache = vertex_cache;
|
||||
}
|
||||
|
||||
struct work_item
|
||||
{
|
||||
std::condition_variable cv;
|
||||
@@ -64,7 +57,8 @@ private:
|
||||
s64 m_vertex_upload_time = 0;
|
||||
s64 m_textures_upload_time = 0;
|
||||
|
||||
std::unique_ptr<gl::vertex_cache> m_vertex_cache;
|
||||
//Compare to see if transform matrix have changed
|
||||
size_t m_transform_buffer_hash = 0;
|
||||
|
||||
GLint m_min_texbuffer_alignment = 256;
|
||||
GLint m_uniform_buffer_offset_align = 256;
|
||||
|
||||
@@ -173,8 +173,6 @@ OPENGL_PROC(PFNGLMULTIDRAWARRAYSPROC, MultiDrawArrays);
|
||||
OPENGL_PROC(PFNGLGETTEXTUREIMAGEEXTPROC, GetTextureImageEXT);
|
||||
OPENGL_PROC(PFNGLGETTEXTUREIMAGEPROC, GetTextureImage);
|
||||
|
||||
OPENGL_PROC(PFNGLCLEARBUFFERFVPROC, ClearBufferfv);
|
||||
|
||||
//Sampler Objects
|
||||
OPENGL_PROC(PFNGLGENSAMPLERSPROC, GenSamplers);
|
||||
OPENGL_PROC(PFNGLDELETESAMPLERSPROC, DeleteSamplers);
|
||||
|
||||
@@ -169,7 +169,6 @@ void GLGSRender::init_buffers(bool skip_reading)
|
||||
{
|
||||
LOG_ERROR(RSX, "Invalid framebuffer setup, w=%d, h=%d", clip_horizontal, clip_vertical);
|
||||
framebuffer_status_valid = false;
|
||||
return;
|
||||
}
|
||||
|
||||
const auto pitchs = get_pitchs();
|
||||
|
||||
@@ -192,7 +192,6 @@ struct gl_render_target_traits
|
||||
if (old_surface != nullptr && old_surface->get_compatible_internal_format() == internal_fmt)
|
||||
result->old_contents = old_surface;
|
||||
|
||||
result->set_cleared();
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -241,25 +240,19 @@ struct gl_render_target_traits
|
||||
static void prepare_ds_for_drawing(void *, gl::render_target*) {}
|
||||
static void prepare_ds_for_sampling(void *, gl::render_target*) {}
|
||||
|
||||
static void invalidate_rtt_surface_contents(void *, gl::render_target *rtt, gl::render_target* /*old*/, bool forced) { if (forced) rtt->set_cleared(false); }
|
||||
static void invalidate_depth_surface_contents(void *, gl::render_target *ds, gl::render_target* /*old*/, bool) { ds->set_cleared(false); }
|
||||
static void invalidate_rtt_surface_contents(void *, gl::render_target*) {}
|
||||
static void invalidate_depth_surface_contents(void *, gl::render_target *ds) { ds->set_cleared(false); }
|
||||
|
||||
static
|
||||
bool rtt_has_format_width_height(const std::unique_ptr<gl::render_target> &rtt, rsx::surface_color_format format, size_t width, size_t height, bool check_refs=false)
|
||||
bool rtt_has_format_width_height(const std::unique_ptr<gl::render_target> &rtt, rsx::surface_color_format format, size_t width, size_t height)
|
||||
{
|
||||
if (check_refs) //TODO
|
||||
return false;
|
||||
|
||||
auto internal_fmt = rsx::internals::sized_internal_format(format);
|
||||
return rtt->get_compatible_internal_format() == internal_fmt && rtt->width() == width && rtt->height() == height;
|
||||
}
|
||||
|
||||
static
|
||||
bool ds_has_format_width_height(const std::unique_ptr<gl::render_target> &rtt, rsx::surface_depth_format, size_t width, size_t height, bool check_refs=false)
|
||||
bool ds_has_format_width_height(const std::unique_ptr<gl::render_target> &rtt, rsx::surface_depth_format, size_t width, size_t height)
|
||||
{
|
||||
if (check_refs) //TODO
|
||||
return false;
|
||||
|
||||
// TODO: check format
|
||||
return rtt->width() == width && rtt->height() == height;
|
||||
}
|
||||
|
||||
@@ -198,13 +198,12 @@ namespace
|
||||
|
||||
struct vertex_buffer_visitor
|
||||
{
|
||||
vertex_buffer_visitor(u32 vtx_cnt, gl::ring_buffer& heap, gl::glsl::program* prog, gl::texture* attrib_buffer, u32 min_texbuffer_offset, gl::vertex_cache* vertex_cache)
|
||||
vertex_buffer_visitor(u32 vtx_cnt, gl::ring_buffer& heap, gl::glsl::program* prog, gl::texture* attrib_buffer, u32 min_texbuffer_offset)
|
||||
: vertex_count(vtx_cnt)
|
||||
, m_attrib_ring_info(heap)
|
||||
, m_program(prog)
|
||||
, m_gl_attrib_buffers(attrib_buffer)
|
||||
, m_min_texbuffer_alignment(min_texbuffer_offset)
|
||||
, m_vertex_cache(vertex_cache)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -214,30 +213,21 @@ namespace
|
||||
if (!m_program->uniforms.has_location(s_reg_table[vertex_array.index], &location))
|
||||
return;
|
||||
|
||||
GLenum gl_type = to_gl_internal_type(vertex_array.type, vertex_array.attribute_size);
|
||||
// Fill vertex_array
|
||||
u32 element_size = rsx::get_vertex_type_size_on_host(vertex_array.type, vertex_array.attribute_size);
|
||||
|
||||
u32 data_size = vertex_count * element_size;
|
||||
u32 gl_type = to_gl_internal_type(vertex_array.type, vertex_array.attribute_size);
|
||||
auto& texture = m_gl_attrib_buffers[vertex_array.index];
|
||||
const u32 element_size = rsx::get_vertex_type_size_on_host(vertex_array.type, vertex_array.attribute_size);
|
||||
const u32 data_size = vertex_count * element_size;
|
||||
|
||||
const uintptr_t local_addr = (uintptr_t)vertex_array.data.data();
|
||||
u32 buffer_offset = 0;
|
||||
auto mapping = m_attrib_ring_info.alloc_from_heap(data_size, m_min_texbuffer_alignment);
|
||||
gsl::byte* dst = static_cast<gsl::byte*>(mapping.first);
|
||||
buffer_offset = mapping.second;
|
||||
gsl::span<gsl::byte> dest_span(dst, data_size);
|
||||
|
||||
if (auto uploaded = m_vertex_cache->find_vertex_range(local_addr, gl_type, data_size))
|
||||
{
|
||||
buffer_offset = uploaded->offset_in_heap;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Fill vertex_array
|
||||
auto mapping = m_attrib_ring_info.alloc_from_heap(data_size, m_min_texbuffer_alignment);
|
||||
gsl::byte* dst = static_cast<gsl::byte*>(mapping.first);
|
||||
buffer_offset = mapping.second;
|
||||
gsl::span<gsl::byte> dest_span(dst, data_size);
|
||||
|
||||
m_vertex_cache->store_range(local_addr, gl_type, data_size, buffer_offset);
|
||||
write_vertex_array_data_to_buffer(dest_span, vertex_array.data, vertex_count, vertex_array.type, vertex_array.attribute_size, vertex_array.stride, rsx::get_vertex_type_size_on_host(vertex_array.type, vertex_array.attribute_size));
|
||||
prepare_buffer_for_writing(dst, vertex_array.type, vertex_array.attribute_size, vertex_count);
|
||||
}
|
||||
write_vertex_array_data_to_buffer(dest_span, vertex_array.data, vertex_count, vertex_array.type, vertex_array.attribute_size, vertex_array.stride, rsx::get_vertex_type_size_on_host(vertex_array.type, vertex_array.attribute_size));
|
||||
prepare_buffer_for_writing(dst, vertex_array.type, vertex_array.attribute_size, vertex_count);
|
||||
|
||||
texture.copy_from(m_attrib_ring_info, gl_type, buffer_offset, data_size);
|
||||
}
|
||||
@@ -273,7 +263,6 @@ namespace
|
||||
gl::glsl::program* m_program;
|
||||
gl::texture* m_gl_attrib_buffers;
|
||||
GLint m_min_texbuffer_alignment;
|
||||
gl::vertex_cache* m_vertex_cache;
|
||||
};
|
||||
|
||||
struct draw_command_visitor
|
||||
@@ -283,7 +272,6 @@ namespace
|
||||
|
||||
draw_command_visitor(gl::ring_buffer& index_ring_buffer, gl::ring_buffer& attrib_ring_buffer,
|
||||
gl::texture* gl_attrib_buffers, gl::glsl::program* program, GLint min_texbuffer_alignment,
|
||||
gl::vertex_cache* vertex_cache,
|
||||
std::function<attribute_storage(rsx::rsx_state, std::vector<std::pair<u32, u32>>)> gvb)
|
||||
: m_index_ring_buffer(index_ring_buffer)
|
||||
, m_attrib_ring_buffer(attrib_ring_buffer)
|
||||
@@ -291,7 +279,6 @@ namespace
|
||||
, m_program(program)
|
||||
, m_min_texbuffer_alignment(min_texbuffer_alignment)
|
||||
, get_vertex_buffers(gvb)
|
||||
, m_vertex_cache(vertex_cache)
|
||||
{
|
||||
for (u8 index = 0; index < rsx::limits::vertex_count; ++index) {
|
||||
if (rsx::method_registers.vertex_arrays_info[index].size() ||
|
||||
@@ -381,7 +368,7 @@ namespace
|
||||
gl::ring_buffer& m_index_ring_buffer;
|
||||
gl::ring_buffer& m_attrib_ring_buffer;
|
||||
gl::texture* m_gl_attrib_buffers;
|
||||
gl::vertex_cache* m_vertex_cache;
|
||||
|
||||
gl::glsl::program* m_program;
|
||||
GLint m_min_texbuffer_alignment;
|
||||
std::function<attribute_storage(rsx::rsx_state, std::vector<std::pair<u32, u32>>)>
|
||||
@@ -392,7 +379,7 @@ namespace
|
||||
u32 verts_allocated = max_index - min_index + 1;
|
||||
|
||||
vertex_buffer_visitor visitor(verts_allocated, m_attrib_ring_buffer,
|
||||
m_program, m_gl_attrib_buffers, m_min_texbuffer_alignment, m_vertex_cache);
|
||||
m_program, m_gl_attrib_buffers, m_min_texbuffer_alignment);
|
||||
const auto& vertex_buffers =
|
||||
get_vertex_buffers(rsx::method_registers, {{min_index, verts_allocated}});
|
||||
for (const auto& vbo : vertex_buffers) std::apply_visitor(visitor, vbo);
|
||||
@@ -465,12 +452,11 @@ std::tuple<u32, std::optional<std::tuple<GLenum, u32>>> GLGSRender::set_vertex_b
|
||||
{
|
||||
std::chrono::time_point<steady_clock> then = steady_clock::now();
|
||||
auto result = std::apply_visitor(draw_command_visitor(*m_index_ring_buffer, *m_attrib_ring_buffer,
|
||||
m_gl_attrib_buffers, m_program, m_min_texbuffer_alignment,
|
||||
m_vertex_cache.get(),
|
||||
[this](const auto& state, const auto& list) {
|
||||
return this->get_vertex_buffers(state, list, 0);
|
||||
}),
|
||||
get_draw_command(rsx::method_registers));
|
||||
m_gl_attrib_buffers, m_program, m_min_texbuffer_alignment,
|
||||
[this](const auto& state, const auto& list) {
|
||||
return this->get_vertex_buffers(state, list);
|
||||
}),
|
||||
get_draw_command(rsx::method_registers));
|
||||
|
||||
std::chrono::time_point<steady_clock> now = steady_clock::now();
|
||||
m_vertex_upload_time += std::chrono::duration_cast<std::chrono::microseconds>(now - then).count();
|
||||
|
||||
@@ -239,8 +239,6 @@ struct RSXFragmentProgram
|
||||
u8 textures_alpha_kill[16];
|
||||
u32 textures_zfunc[16];
|
||||
|
||||
bool valid;
|
||||
|
||||
rsx::texture_dimension_extended get_texture_dimension(u8 id) const
|
||||
{
|
||||
return (rsx::texture_dimension_extended)((texture_dimensions >> (id * 2)) & 0x3);
|
||||
@@ -265,7 +263,6 @@ struct RSXFragmentProgram
|
||||
, ctrl(0)
|
||||
, unnormalized_coords(0)
|
||||
, texture_dimensions(0)
|
||||
, valid(false)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
+126
-134
@@ -5,6 +5,7 @@
|
||||
#include "RSXThread.h"
|
||||
|
||||
#include "Emu/Cell/PPUCallback.h"
|
||||
#include "Emu/Cell/lv2/sys_rsx.h"
|
||||
|
||||
#include "Common/BufferUtils.h"
|
||||
#include "rsx_methods.h"
|
||||
@@ -34,55 +35,69 @@ namespace rsx
|
||||
|
||||
switch (location)
|
||||
{
|
||||
case CELL_GCM_CONTEXT_DMA_MEMORY_FRAME_BUFFER:
|
||||
case CELL_GCM_LOCATION_LOCAL:
|
||||
{
|
||||
// TODO: Don't use unnamed constants like 0xC0000000
|
||||
return 0xC0000000 + offset;
|
||||
}
|
||||
|
||||
case CELL_GCM_CONTEXT_DMA_MEMORY_HOST_BUFFER:
|
||||
case CELL_GCM_LOCATION_MAIN:
|
||||
{
|
||||
if (u32 result = RSXIOMem.RealAddr(offset))
|
||||
case CELL_GCM_CONTEXT_DMA_MEMORY_FRAME_BUFFER:
|
||||
case CELL_GCM_LOCATION_LOCAL:
|
||||
{
|
||||
return result;
|
||||
// TODO: Don't use unnamed constants like 0xC0000000
|
||||
return 0xC0000000 + offset;
|
||||
}
|
||||
|
||||
fmt::throw_exception("GetAddress(offset=0x%x, location=0x%x): RSXIO memory not mapped" HERE, offset, location);
|
||||
}
|
||||
|
||||
case CELL_GCM_CONTEXT_DMA_REPORT_LOCATION_LOCAL:
|
||||
return 0x40301400 + offset;
|
||||
|
||||
case CELL_GCM_CONTEXT_DMA_REPORT_LOCATION_MAIN:
|
||||
{
|
||||
if (u32 result = RSXIOMem.RealAddr(0x0e000000 + offset))
|
||||
case CELL_GCM_CONTEXT_DMA_MEMORY_HOST_BUFFER:
|
||||
case CELL_GCM_LOCATION_MAIN:
|
||||
{
|
||||
return result;
|
||||
if (u32 result = RSXIOMem.RealAddr(offset))
|
||||
{
|
||||
return result;
|
||||
}
|
||||
|
||||
fmt::throw_exception("GetAddress(offset=0x%x, location=0x%x): RSXIO memory not mapped" HERE, offset, location);
|
||||
|
||||
//if (fxm::get<GSRender>()->strict_ordering[offset >> 20])
|
||||
//{
|
||||
// _mm_mfence(); // probably doesn't have any effect on current implementation
|
||||
//}
|
||||
}
|
||||
|
||||
fmt::throw_exception("GetAddress(offset=0x%x, location=0x%x): RSXIO memory not mapped" HERE, offset, location);
|
||||
}
|
||||
case CELL_GCM_CONTEXT_DMA_REPORT_LOCATION_LOCAL:
|
||||
return 0x40301400 + offset; // not sure if this should be 0x40300000 or offset to the actual reports, lets try reports for now
|
||||
//return 0x100000 + offset; // TODO: Properly implement
|
||||
|
||||
case CELL_GCM_CONTEXT_DMA_TO_MEMORY_GET_NOTIFY0:
|
||||
fmt::throw_exception("Unimplemented CELL_GCM_CONTEXT_DMA_TO_MEMORY_GET_NOTIFY0 (offset=0x%x, location=0x%x)" HERE, offset, location);
|
||||
case CELL_GCM_CONTEXT_DMA_REPORT_LOCATION_MAIN:
|
||||
{
|
||||
if (u32 result = RSXIOMem.RealAddr(0x0e000000 + offset))
|
||||
{
|
||||
return result;
|
||||
}
|
||||
|
||||
case CELL_GCM_CONTEXT_DMA_NOTIFY_MAIN_0:
|
||||
fmt::throw_exception("Unimplemented CELL_GCM_CONTEXT_DMA_NOTIFY_MAIN_0 (offset=0x%x, location=0x%x)" HERE, offset, location);
|
||||
fmt::throw_exception("GetAddress(offset=0x%x, location=0x%x): RSXIO memory not mapped" HERE, offset, location);
|
||||
|
||||
case CELL_GCM_CONTEXT_DMA_SEMAPHORE_RW:
|
||||
case CELL_GCM_CONTEXT_DMA_SEMAPHORE_R:
|
||||
return 0x40300000 + offset;
|
||||
//if (fxm::get<GSRender>()->strict_ordering[offset >> 20])
|
||||
//{
|
||||
// _mm_mfence(); // probably doesn't have any effect on current implementation
|
||||
//}
|
||||
}
|
||||
|
||||
case CELL_GCM_CONTEXT_DMA_DEVICE_RW:
|
||||
return 0x40000000 + offset;
|
||||
case CELL_GCM_CONTEXT_DMA_TO_MEMORY_GET_NOTIFY0:
|
||||
fmt::throw_exception("Unimplemented CELL_GCM_CONTEXT_DMA_TO_MEMORY_GET_NOTIFY0 (offset=0x%x, location=0x%x)" HERE, offset, location);
|
||||
|
||||
case CELL_GCM_CONTEXT_DMA_DEVICE_R:
|
||||
return 0x40000000 + offset;
|
||||
case CELL_GCM_CONTEXT_DMA_NOTIFY_MAIN_0:
|
||||
fmt::throw_exception("Unimplemented CELL_GCM_CONTEXT_DMA_NOTIFY_MAIN_0 (offset=0x%x, location=0x%x)" HERE, offset, location);
|
||||
|
||||
default:
|
||||
fmt::throw_exception("Invalid location (offset=0x%x, location=0x%x)" HERE, offset, location);
|
||||
case CELL_GCM_CONTEXT_DMA_SEMAPHORE_RW:
|
||||
case CELL_GCM_CONTEXT_DMA_SEMAPHORE_R:
|
||||
return 0x40300000 + offset; // this offset also doesnt seem like its right, but it works for now so w/e
|
||||
//return 0x100 + offset; // TODO: Properly implement
|
||||
|
||||
case CELL_GCM_CONTEXT_DMA_DEVICE_RW:
|
||||
return 0x40000000 + offset;
|
||||
//fmt::throw_exception("Unimplemented CELL_GCM_CONTEXT_DMA_DEVICE_RW (offset=0x%x, location=0x%x)" HERE, offset, location);
|
||||
|
||||
case CELL_GCM_CONTEXT_DMA_DEVICE_R:
|
||||
return 0x40000000 + offset;
|
||||
//fmt::throw_exception("Unimplemented CELL_GCM_CONTEXT_DMA_DEVICE_R (offset=0x%x, location=0x%x)" HERE, offset, location);
|
||||
|
||||
default:
|
||||
fmt::throw_exception("Invalid location (offset=0x%x, location=0x%x)" HERE, offset, location);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -388,7 +403,7 @@ namespace rsx
|
||||
if (get_system_time() - start_time > vblank_count * 1000000 / 60)
|
||||
{
|
||||
vblank_count++;
|
||||
sys_rsx_context_attribute(0x55555555, 0xFED, 1, 0, 0, 0);
|
||||
sys_rsx_context_attribute(0x55555555, 0xFED, 1, 0, 0, 0);
|
||||
if (vblank_handler)
|
||||
{
|
||||
intr_thread->cmd_list
|
||||
@@ -403,16 +418,13 @@ namespace rsx
|
||||
|
||||
continue;
|
||||
}
|
||||
while (Emu.IsPaused())
|
||||
std::this_thread::sleep_for(10ms);
|
||||
while (Emu.IsPaused())
|
||||
std::this_thread::sleep_for(10ms);
|
||||
|
||||
std::this_thread::sleep_for(1ms); // hack
|
||||
}
|
||||
});
|
||||
|
||||
// Raise priority above other threads
|
||||
thread_ctrl::set_native_priority(1);
|
||||
|
||||
// TODO: exit condition
|
||||
while (!Emu.IsStopped())
|
||||
{
|
||||
@@ -507,7 +519,7 @@ namespace rsx
|
||||
u32 reg = ((cmd & RSX_METHOD_NON_INCREMENT_CMD_MASK) == RSX_METHOD_NON_INCREMENT_CMD) ? first_cmd : first_cmd + i;
|
||||
u32 value = args[i];
|
||||
|
||||
//LOG_NOTICE(RSX, "%s(0x%x) = 0x%x", get_method_name(reg).c_str(), reg, value);
|
||||
//LOG_WARNING(RSX, "%s(0x%x) = 0x%x", get_method_name(reg).c_str(), reg, value);
|
||||
|
||||
method_registers.decode(reg, value);
|
||||
|
||||
@@ -544,18 +556,15 @@ namespace rsx
|
||||
m_vblank_thread.reset();
|
||||
}
|
||||
|
||||
if (m_vertex_streaming_task.available_threads > 0)
|
||||
if (m_vertex_streaming_task.processing_threads.size() > 0)
|
||||
{
|
||||
for (auto &task : m_vertex_streaming_task.worker_threads)
|
||||
for (auto &thr : m_vertex_streaming_task.processing_threads)
|
||||
{
|
||||
if (!task.worker_thread)
|
||||
break;
|
||||
|
||||
task.worker_thread->join();
|
||||
task.worker_thread.reset();
|
||||
thr->join();
|
||||
thr.reset();
|
||||
}
|
||||
|
||||
m_vertex_streaming_task.available_threads = 0;
|
||||
m_vertex_streaming_task.processing_threads.resize(0);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -758,7 +767,7 @@ namespace rsx
|
||||
}
|
||||
|
||||
std::vector<std::variant<vertex_array_buffer, vertex_array_register, empty_vertex_array>>
|
||||
thread::get_vertex_buffers(const rsx::rsx_state& state, const std::vector<std::pair<u32, u32>>& vertex_ranges, const u64 consumed_attrib_mask) const
|
||||
thread::get_vertex_buffers(const rsx::rsx_state& state, const std::vector<std::pair<u32, u32>>& vertex_ranges) const
|
||||
{
|
||||
std::vector<std::variant<vertex_array_buffer, vertex_array_register, empty_vertex_array>> result;
|
||||
result.reserve(rsx::limits::vertex_count);
|
||||
@@ -766,10 +775,8 @@ namespace rsx
|
||||
u32 input_mask = state.vertex_attrib_input_mask();
|
||||
for (u8 index = 0; index < rsx::limits::vertex_count; ++index)
|
||||
{
|
||||
const bool enabled = !!(input_mask & (1 << index));
|
||||
const bool consumed = !!(consumed_attrib_mask & (1ull << index));
|
||||
|
||||
if (!enabled && !consumed)
|
||||
bool enabled = !!(input_mask & (1 << index));
|
||||
if (!enabled)
|
||||
continue;
|
||||
|
||||
if (state.vertex_arrays_info[index].size() > 0)
|
||||
@@ -986,17 +993,9 @@ namespace rsx
|
||||
RSXFragmentProgram thread::get_current_fragment_program(std::function<std::tuple<bool, u16>(u32, fragment_texture&, bool)> get_surface_info) const
|
||||
{
|
||||
RSXFragmentProgram result = {};
|
||||
|
||||
const u32 shader_program = rsx::method_registers.shader_program_address();
|
||||
if (shader_program == 0)
|
||||
return result;
|
||||
|
||||
const u32 program_location = (shader_program & 0x3) - 1;
|
||||
const u32 program_offset = (shader_program & ~0x3);
|
||||
|
||||
result.offset = program_offset;
|
||||
result.addr = vm::base(rsx::get_address(program_offset, program_location));
|
||||
result.valid = true;
|
||||
u32 shader_program = rsx::method_registers.shader_program_address();
|
||||
result.offset = shader_program & ~0x3;
|
||||
result.addr = vm::base(rsx::get_address(result.offset, (shader_program & 0x3) - 1));
|
||||
result.ctrl = rsx::method_registers.shader_control();
|
||||
result.unnormalized_coords = 0;
|
||||
result.front_back_color_enabled = !rsx::method_registers.two_side_light_en();
|
||||
@@ -1073,9 +1072,9 @@ namespace rsx
|
||||
rsx::method_registers.reset();
|
||||
}
|
||||
|
||||
void thread::init(u32 ioAddress, u32 ioSize, u32 ctrlAddress, u32 localAddress)
|
||||
void thread::init(const u32 ioAddress, const u32 ioSize, const u32 ctrlAddress, const u32 localAddress)
|
||||
{
|
||||
ctrl = vm::_ptr<RsxDmaControl>(ctrlAddress);
|
||||
ctrl = vm::_ptr<CellGcmControl>(ctrlAddress);
|
||||
this->ioAddress = ioAddress;
|
||||
this->ioSize = ioSize;
|
||||
local_mem_addr = localAddress;
|
||||
@@ -1141,8 +1140,7 @@ namespace rsx
|
||||
}
|
||||
}
|
||||
|
||||
void thread::post_vertex_stream_to_upload(gsl::span<const gsl::byte> src, gsl::span<gsl::byte> dst, rsx::vertex_base_type type, u32 vector_element_count,
|
||||
u32 attribute_src_stride, u8 dst_stride, u32 vertex_count, std::function<void(void *, rsx::vertex_base_type, u8, u32)> callback)
|
||||
void thread::post_vertex_stream_to_upload(gsl::span<const gsl::byte> src, gsl::span<gsl::byte> dst, rsx::vertex_base_type type, u32 vector_element_count, u32 attribute_src_stride, u8 dst_stride, std::function<void(void *, rsx::vertex_base_type, u8, u32)> callback)
|
||||
{
|
||||
upload_stream_packet packet;
|
||||
packet.dst_span = dst;
|
||||
@@ -1152,95 +1150,94 @@ namespace rsx
|
||||
packet.dst_stride = dst_stride;
|
||||
packet.vector_width = vector_element_count;
|
||||
packet.post_upload_func = callback;
|
||||
packet.vertex_count = vertex_count;
|
||||
|
||||
if (m_vertex_streaming_task.available_threads == 0)
|
||||
m_vertex_streaming_task.packets.push_back(packet);
|
||||
}
|
||||
|
||||
void thread::start_vertex_upload_task(u32 vertex_count)
|
||||
{
|
||||
if (m_vertex_streaming_task.processing_threads.size() == 0)
|
||||
{
|
||||
const u32 streaming_thread_count = (u32)g_cfg.video.vertex_upload_threads;
|
||||
m_vertex_streaming_task.available_threads = streaming_thread_count;
|
||||
m_vertex_streaming_task.processing_threads.resize(streaming_thread_count);
|
||||
|
||||
for (u32 n = 0; n < streaming_thread_count; ++n)
|
||||
{
|
||||
thread_ctrl::spawn(m_vertex_streaming_task.worker_threads[n].worker_thread, "Vertex Stream " + std::to_string(n), [this, n]()
|
||||
thread_ctrl::spawn(m_vertex_streaming_task.processing_threads[n], "Vertex Stream " + std::to_string(n), [this, n]()
|
||||
{
|
||||
auto &owner = m_vertex_streaming_task;
|
||||
auto &task = m_vertex_streaming_task.worker_threads[n];
|
||||
auto &task = m_vertex_streaming_task;
|
||||
const u32 index = n;
|
||||
|
||||
while (!Emu.IsStopped())
|
||||
{
|
||||
if (task.thread_status.load(std::memory_order_consume) != 0)
|
||||
if (task.remaining_packets != 0)
|
||||
{
|
||||
for (auto &packet: task.packets)
|
||||
//Wait for me!
|
||||
task.ready_threads--;
|
||||
|
||||
const size_t step = task.processing_threads.size();
|
||||
const size_t job_count = task.packets.size();
|
||||
//Process every nth packet
|
||||
|
||||
size_t current_job = index;
|
||||
|
||||
while (true)
|
||||
{
|
||||
write_vertex_array_data_to_buffer(packet.dst_span, packet.src_span, packet.vertex_count, packet.type, packet.vector_width, packet.src_stride, packet.dst_stride);
|
||||
if (current_job >= job_count)
|
||||
break;
|
||||
|
||||
auto &packet = task.packets[current_job];
|
||||
|
||||
write_vertex_array_data_to_buffer(packet.dst_span, packet.src_span, task.vertex_count, packet.type, packet.vector_width, packet.src_stride, packet.dst_stride);
|
||||
|
||||
if (packet.post_upload_func)
|
||||
packet.post_upload_func(packet.dst_span.data(), packet.type, (u8)packet.vector_width, packet.vertex_count);
|
||||
packet.post_upload_func(packet.dst_span.data(), packet.type, (u8)packet.vector_width, task.vertex_count);
|
||||
|
||||
owner.remaining_tasks--;
|
||||
_mm_sfence();
|
||||
task.remaining_packets--;
|
||||
current_job += step;
|
||||
}
|
||||
|
||||
task.packets.resize(0);
|
||||
task.thread_status.store(0);
|
||||
_mm_sfence();
|
||||
}
|
||||
_mm_mfence();
|
||||
|
||||
std::this_thread::yield();
|
||||
while (task.remaining_packets > 0 && !Emu.IsStopped())
|
||||
{
|
||||
_mm_lfence();
|
||||
std::this_thread::sleep_for(0us);
|
||||
}
|
||||
|
||||
_mm_sfence();
|
||||
task.ready_threads++;
|
||||
}
|
||||
else
|
||||
std::this_thread::sleep_for(0us);
|
||||
//thread_ctrl::wait();
|
||||
//busy_wait();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
//Increment job counter..
|
||||
m_vertex_streaming_task.remaining_tasks++;
|
||||
|
||||
//Assign this packet to a thread
|
||||
//Simple round robin based on first available thread
|
||||
upload_stream_worker *best_fit = nullptr;
|
||||
for (auto &worker : m_vertex_streaming_task.worker_threads)
|
||||
while (m_vertex_streaming_task.ready_threads != 0 && !Emu.IsStopped())
|
||||
{
|
||||
if (!worker.worker_thread)
|
||||
break;
|
||||
|
||||
if (worker.thread_status.load(std::memory_order_consume) == 0)
|
||||
{
|
||||
if (worker.packets.size() == 0)
|
||||
{
|
||||
worker.packets.push_back(packet);
|
||||
return;
|
||||
}
|
||||
|
||||
if (best_fit == nullptr)
|
||||
best_fit = &worker;
|
||||
else if (best_fit->packets.size() > worker.packets.size())
|
||||
best_fit = &worker;
|
||||
}
|
||||
_mm_lfence();
|
||||
busy_wait();
|
||||
}
|
||||
|
||||
best_fit->packets.push_back(packet);
|
||||
}
|
||||
|
||||
void thread::start_vertex_upload_task()
|
||||
{
|
||||
for (auto &worker : m_vertex_streaming_task.worker_threads)
|
||||
{
|
||||
if (!worker.worker_thread)
|
||||
break;
|
||||
|
||||
if (worker.thread_status.load(std::memory_order_consume) == 0 && worker.packets.size() > 0)
|
||||
{
|
||||
worker.thread_status.store(1);
|
||||
}
|
||||
}
|
||||
m_vertex_streaming_task.vertex_count = vertex_count;
|
||||
m_vertex_streaming_task.ready_threads = 0;
|
||||
m_vertex_streaming_task.remaining_packets = (int)m_vertex_streaming_task.packets.size();
|
||||
}
|
||||
|
||||
void thread::wait_for_vertex_upload_task()
|
||||
{
|
||||
while (m_vertex_streaming_task.remaining_tasks.load(std::memory_order_consume) != 0 && !Emu.IsStopped())
|
||||
while (m_vertex_streaming_task.remaining_packets > 0 && !Emu.IsStopped())
|
||||
{
|
||||
_mm_pause();
|
||||
_mm_lfence();
|
||||
busy_wait();
|
||||
}
|
||||
|
||||
m_vertex_streaming_task.packets.resize(0);
|
||||
}
|
||||
|
||||
bool thread::vertex_upload_task_ready()
|
||||
@@ -1248,12 +1245,7 @@ namespace rsx
|
||||
if (g_cfg.video.vertex_upload_threads < 2)
|
||||
return false;
|
||||
|
||||
//Not initialized
|
||||
if (m_vertex_streaming_task.available_threads == 0)
|
||||
return true;
|
||||
|
||||
//At least two threads are available
|
||||
return (m_vertex_streaming_task.remaining_tasks < (m_vertex_streaming_task.available_threads - 1));
|
||||
return (m_vertex_streaming_task.remaining_packets == 0 && m_vertex_streaming_task.ready_threads == 0);
|
||||
}
|
||||
|
||||
void thread::flip(int buffer)
|
||||
|
||||
+21
-27
@@ -22,8 +22,6 @@
|
||||
#include "Utilities/variant.hpp"
|
||||
#include "define_new_memleakdetect.h"
|
||||
|
||||
#include "Emu/Cell/lv2/sys_rsx.h"
|
||||
|
||||
extern u64 get_system_time();
|
||||
|
||||
extern bool user_asked_for_frame_capture;
|
||||
@@ -115,7 +113,7 @@ namespace rsx
|
||||
std::vector<u32> element_push_buffer;
|
||||
|
||||
public:
|
||||
RsxDmaControl* ctrl = nullptr;
|
||||
CellGcmControl* ctrl = nullptr;
|
||||
|
||||
Timer timer_sync;
|
||||
|
||||
@@ -131,23 +129,24 @@ namespace rsx
|
||||
public:
|
||||
std::shared_ptr<class ppu_thread> intr_thread;
|
||||
|
||||
// I hate this flag, but until hle is closer to lle, its needed
|
||||
bool isHLE{ false };
|
||||
|
||||
u32 ioAddress, ioSize;
|
||||
u32 flip_status;
|
||||
int flip_mode;
|
||||
int debug_level;
|
||||
int frequency_mode;
|
||||
|
||||
atomic_t<bool> requested_vsync{false};
|
||||
atomic_t<bool> enable_second_vhandler{false};
|
||||
|
||||
RsxDisplayInfo display_buffers[8];
|
||||
u32 display_buffers_count{0};
|
||||
u32 current_display_buffer{0};
|
||||
u32 tiles_addr;
|
||||
u32 zculls_addr;
|
||||
vm::ps3::ptr<CellGcmDisplayInfo> gcm_buffers = vm::null;
|
||||
u32 gcm_buffers_count;
|
||||
u32 gcm_current_buffer;
|
||||
u32 ctxt_addr;
|
||||
u32 label_addr;
|
||||
u32 nv406e_semaphore_addr;
|
||||
u32 nv4097_semaphore_index;
|
||||
|
||||
u32 local_mem_addr, main_mem_addr;
|
||||
bool strict_ordering[0x1000];
|
||||
|
||||
bool m_rtts_dirty;
|
||||
bool m_transform_constants_dirty;
|
||||
@@ -216,7 +215,7 @@ namespace rsx
|
||||
gsl::span<const gsl::byte> get_raw_vertex_buffer(const rsx::data_array_format_info&, u32 base_offset, const std::vector<std::pair<u32, u32>>& vertex_ranges) const;
|
||||
|
||||
std::vector<std::variant<vertex_array_buffer, vertex_array_register, empty_vertex_array>>
|
||||
get_vertex_buffers(const rsx::rsx_state& state, const std::vector<std::pair<u32, u32>>& vertex_ranges, const u64 consumed_attrib_mask) const;
|
||||
get_vertex_buffers(const rsx::rsx_state& state, const std::vector<std::pair<u32, u32>>& vertex_ranges) const;
|
||||
|
||||
std::variant<draw_array_command, draw_indexed_array_command, draw_inlined_array>
|
||||
get_draw_command(const rsx::rsx_state& state) const;
|
||||
@@ -247,30 +246,25 @@ namespace rsx
|
||||
gsl::span<gsl::byte> dst_span;
|
||||
rsx::vertex_base_type type;
|
||||
u32 vector_width;
|
||||
u32 vertex_count;
|
||||
u32 src_stride;
|
||||
u8 dst_stride;
|
||||
};
|
||||
|
||||
struct upload_stream_worker
|
||||
{
|
||||
std::shared_ptr<thread_ctrl> worker_thread;
|
||||
std::vector<upload_stream_packet> packets;
|
||||
std::atomic<int> thread_status = { 0 };
|
||||
};
|
||||
|
||||
struct upload_stream_task
|
||||
{
|
||||
std::array<upload_stream_worker, 16> worker_threads;
|
||||
int available_threads = 0;
|
||||
std::atomic<int> remaining_tasks = {0};
|
||||
std::vector<upload_stream_packet> packets;
|
||||
std::atomic<int> remaining_packets = { 0 };
|
||||
std::atomic<int> ready_threads = { 0 };
|
||||
std::atomic<u32> vertex_count;
|
||||
|
||||
std::vector<std::shared_ptr<thread_ctrl>> processing_threads;
|
||||
};
|
||||
|
||||
upload_stream_task m_vertex_streaming_task;
|
||||
void post_vertex_stream_to_upload(gsl::span<const gsl::byte> src, gsl::span<gsl::byte> dst, rsx::vertex_base_type type,
|
||||
u32 vector_element_count, u32 attribute_src_stride, u8 dst_stride, u32 vertex_count,
|
||||
u32 vector_element_count, u32 attribute_src_stride, u8 dst_stride,
|
||||
std::function<void(void *, rsx::vertex_base_type, u8, u32)> callback);
|
||||
void start_vertex_upload_task();
|
||||
void start_vertex_upload_task(u32 vertex_count);
|
||||
void wait_for_vertex_upload_task();
|
||||
bool vertex_upload_task_ready();
|
||||
|
||||
@@ -348,7 +342,7 @@ namespace rsx
|
||||
|
||||
public:
|
||||
void reset();
|
||||
void init(u32 ioAddress, u32 ioSize, u32 ctrlAddress, u32 localAddress);
|
||||
void init(const u32 ioAddress, const u32 ioSize, const u32 ctrlAddress, const u32 localAddress);
|
||||
|
||||
tiled_region get_tiled_address(u32 offset, u32 location);
|
||||
GcmTileInfo *find_tile(u32 offset, u32 location);
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user