Compare commits
8 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 668005c856 | |||
| 7efa53b218 | |||
| ad3fc60631 | |||
| c09cbeac15 | |||
| e854eb6ecd | |||
| e7841b5d9e | |||
| 76a49518e0 | |||
| 4a197e16a6 |
@@ -41,10 +41,6 @@
|
||||
/Vulkan/Vulkan-build
|
||||
/Vulkan/glslang-build
|
||||
|
||||
# Themes
|
||||
!/bin/GuiConfigs/
|
||||
/bin/GuiConfigs/*.ini
|
||||
|
||||
/bin/rpcs3.ini
|
||||
/bin/rpcs3.ipdb
|
||||
/bin/rpcs3.iobj
|
||||
@@ -75,7 +71,6 @@ rpcs3/git-version.h
|
||||
!/bin/dev_hdd0/game/
|
||||
/bin/dev_hdd0/game/*
|
||||
!/bin/dev_hdd0/game/TEST12345/
|
||||
/bin/dev_hdd0/disc/*
|
||||
|
||||
# Ignore other system generated files
|
||||
bin/dev_hdd0/*.txt
|
||||
|
||||
-13
@@ -62,24 +62,12 @@ before_install:
|
||||
brew update; brew update;
|
||||
brew install ccache glew llvm40;
|
||||
fi;
|
||||
# We need to update binutils to a newer version to link against the ffmpeg libs on.
|
||||
- if [ "$TRAVIS_OS_NAME" = "linux" ]; then
|
||||
sudo add-apt-repository ppa:jonathonf/binutils -y ;
|
||||
sudo apt-get update ;
|
||||
sudo apt-get install binutils -y;
|
||||
ld --version ;
|
||||
fi;
|
||||
|
||||
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
|
||||
- mkdir build
|
||||
- cd build
|
||||
- export CMAKE_PREFIX_PATH=~/Qt/5.9.1/gcc_64/lib/cmake
|
||||
- if [ "$TRAVIS_PULL_REQUEST" = false ]; then
|
||||
export CXXFLAGS="$CXXFLAGS -DBRANCH=$TRAVIS_REPO_SLUG/$TRAVIS_BRANCH";
|
||||
else
|
||||
export CXXFLAGS="$CXXFLAGS -DBRANCH=$TRAVIS_REPO_SLUG/$TRAVIS_BRANCH/#$TRAVIS_PULL_REQUEST";
|
||||
fi;
|
||||
- cmake .. -DCMAKE_INSTALL_PREFIX=/usr;
|
||||
- make -j 3
|
||||
- # AppImage generation
|
||||
@@ -138,7 +126,6 @@ addons:
|
||||
#- qtbase5-dev
|
||||
- libudev-dev
|
||||
- libevdev-dev
|
||||
- libpulse-dev
|
||||
coverity_scan:
|
||||
project:
|
||||
name: $TRAVIS_REPO_SLUG
|
||||
|
||||
Vendored
+1
-1
Submodule 3rdparty/ffmpeg updated: 7b7ae7b067...8dd84dc1ea
Vendored
+1
-1
Submodule 3rdparty/hidapi updated: 4c2750112e...66eed15b05
+2
-2
@@ -1,6 +1,6 @@
|
||||
# Getting Started
|
||||
|
||||
Before getting started using the emulator, read the [Quickstart Guide](https://rpcs3.net/quickstart) and the [FAQ](https://rpcs3.net/faq). After reading those, if you need support, visit our [Forums](https://forums.rpcs3.net).
|
||||
Before getting started using the emulator, read the [Quickstart Guide](https://rpcs3.net/quickstart) and the [FAQ](https://rpcs3.net/faq). After reading those, if you need support, visit our [Forums](http://www.emunewz.net/forum/forumdisplay.php?fid=172).
|
||||
|
||||
# Issue Reporting
|
||||
|
||||
@@ -13,7 +13,7 @@ Before getting started using the emulator, read the [Quickstart Guide](https://r
|
||||
- Use understandable English. It doesn't need to be perfect, but clear enough to understand your message.
|
||||
- While reporting issues, don't forget to include details about your system (OS, CPU, GPU, etc.), as well as the RPCS3.log file.
|
||||
|
||||
Submitting your test results for Commercial Games must be done on our forums. Please read the [Game Compatibility](https://github.com/RPCS3/rpcs3/wiki/Game-Compatibility) wiki page before doing so.
|
||||
Submitting your test results for Commercial Games must be done on our forums' [Commercial Games](http://www.emunewz.net/forum/forumdisplay.php?fid=193) section. If there's already a thread for the game you want to report post in it, otherwise please make a new thread following the [Guidelines for submitting new games](http://www.emunewz.net/forum/showthread.php?tid=174376).
|
||||
|
||||
# Contributing
|
||||
|
||||
|
||||
@@ -8,9 +8,9 @@ RPCS3
|
||||
The world's first open-source PlayStation 3 emulator/debugger written in C++ for Windows and Linux.
|
||||
|
||||
You can find some basic information in our [**website**](https://rpcs3.net/).
|
||||
For discussion about this emulator and PS3 emulation please visit our [**forums**](https://forums.rpcs3.net) and our [**Discord server**](https://discord.me/RPCS3).
|
||||
For discussion about this emulator and PS3 emulation please visit our [**forums**](http://www.emunewz.net/forum/forumdisplay.php?fid=172) and our [**Discord server**](https://discord.me/RPCS3).
|
||||
|
||||
[**Support Lead Developers Nekotekina and kd-11 on Patreon**](https://www.patreon.com/Nekotekina)
|
||||
[**Support Lead Developer Nekotekina on Patreon**](https://www.patreon.com/Nekotekina)
|
||||
|
||||
|
||||
## Development
|
||||
@@ -33,12 +33,12 @@ If you want to contribute please take a look at the [Coding Style](https://githu
|
||||
* GCC 5.1+ or Clang 3.5.0+ ([not GCC 6.1](https://github.com/RPCS3/rpcs3/issues/1691))
|
||||
* Debian & Ubuntu: `sudo apt-get install cmake build-essential libasound2-dev libopenal-dev libglew-dev zlib1g-dev libedit-dev libvulkan-dev libudev-dev git qt5-default`
|
||||
* Arch: `sudo pacman -S glew openal cmake llvm qt5-base`
|
||||
* Fedora: `sudo dnf install cmake qt5-devel vulkan-devel glew glew-devel`
|
||||
* Fedora: `sudo dnf install cmake qt5-devel vulkan-devel libGLEW`
|
||||
|
||||
### Mac OSX
|
||||
Mac OSX is not supported at this moment because it doesn't meet system requirements (OpenGL 4.3)
|
||||
* Xcode 6+ (tested with Xcode 6.4)
|
||||
* Install with Homebrew: `brew install glew llvm qt cmake`
|
||||
* Install with Homebrew: `brew install glew`
|
||||
|
||||
|
||||
## Building on Windows:
|
||||
@@ -66,10 +66,7 @@ To initialize the repository don't forget to execute `git submodule update --ini
|
||||
4) `cmake CMakeLists.txt && make GitVersion && make` </br>
|
||||
5) Run RPCS3 with `./bin/rpcs3` </br>
|
||||
|
||||
If you are on OSX and want to build with brew llvm and qt don't forget to add the following environment variables
|
||||
|
||||
* `LLVM_DIR=/usr/local/opt/llvm/` (or wherever llvm was installed).
|
||||
* `Qt5_DIR=/usr/local/opt/qt/lib/cmake/Qt5` (or wherever qt was installed).
|
||||
If you are on OSX and want to build with llvm don't forget to add `-DLLVM_DIR=...` (or wherever llvm brew was installed) to cmake invocation.
|
||||
|
||||
When using GDB, configure it to ignore SIGSEGV signal (`handle SIGSEGV nostop noprint`).
|
||||
|
||||
|
||||
+3
-25
@@ -48,11 +48,6 @@ namespace cfg
|
||||
static void decode(const YAML::Node& data, class _base& rhs);
|
||||
}
|
||||
|
||||
std::vector<std::string> cfg::make_int_range(s64 min, s64 max)
|
||||
{
|
||||
return {std::to_string(min), std::to_string(max)};
|
||||
}
|
||||
|
||||
bool cfg::try_to_int64(s64* out, const std::string& value, s64 min, s64 max)
|
||||
{
|
||||
// TODO: this could be rewritten without exceptions (but it should be as safe as possible and provide logs)
|
||||
@@ -87,8 +82,6 @@ bool cfg::try_to_int64(s64* out, const std::string& value, s64 min, s64 max)
|
||||
|
||||
bool cfg::try_to_enum_value(u64* out, decltype(&fmt_class_string<int>::format) func, const std::string& value)
|
||||
{
|
||||
u64 max = -1;
|
||||
|
||||
for (u64 i = 0;; i++)
|
||||
{
|
||||
std::string var;
|
||||
@@ -106,8 +99,6 @@ bool cfg::try_to_enum_value(u64* out, decltype(&fmt_class_string<int>::format) f
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
max = i;
|
||||
}
|
||||
|
||||
try
|
||||
@@ -117,22 +108,14 @@ bool cfg::try_to_enum_value(u64* out, decltype(&fmt_class_string<int>::format) f
|
||||
|
||||
if (pos != value.size())
|
||||
{
|
||||
if (out) cfg.error("cfg::try_to_enum_value('%s'): unexpected characters (pos=%zu)", value, pos);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (val > max)
|
||||
{
|
||||
if (out) cfg.error("cfg::try_to_enum_value('%s'): out of bounds(0..%u)", value, max);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (out) *out = val;
|
||||
return true;
|
||||
}
|
||||
catch (const std::exception& e)
|
||||
catch (...)
|
||||
{
|
||||
if (out) cfg.error("cfg::try_to_enum_value('%s'): invalid enum value: %s", value, e.what());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -285,19 +268,14 @@ std::string cfg::node::to_string() const
|
||||
YAML::Emitter out;
|
||||
cfg::encode(out, *this);
|
||||
|
||||
return {out.c_str(), out.size()};
|
||||
return{ out.c_str(), out.size() };
|
||||
}
|
||||
|
||||
bool cfg::node::from_string(const std::string& value) try
|
||||
bool cfg::node::from_string(const std::string& value)
|
||||
{
|
||||
cfg::decode(YAML::Load(value), *this);
|
||||
return true;
|
||||
}
|
||||
catch (const std::exception& e)
|
||||
{
|
||||
cfg.fatal("%s thrown: %s", typeid(e).name(), e.what());
|
||||
return false;
|
||||
}
|
||||
|
||||
void cfg::node::from_default()
|
||||
{
|
||||
|
||||
@@ -12,9 +12,6 @@
|
||||
|
||||
namespace cfg
|
||||
{
|
||||
// Format min and max values
|
||||
std::vector<std::string> make_int_range(s64 min, s64 max);
|
||||
|
||||
// Convert string to signed integer
|
||||
bool try_to_int64(s64* out, const std::string& value, s64 min, s64 max);
|
||||
|
||||
@@ -252,11 +249,6 @@ namespace cfg
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
std::vector<std::string> to_list() const override
|
||||
{
|
||||
return make_int_range(Min, Max);
|
||||
}
|
||||
};
|
||||
|
||||
// Alias for 32 bit int
|
||||
|
||||
+6
-66
@@ -93,7 +93,6 @@ static fs::error to_error(DWORD e)
|
||||
case ERROR_NEGATIVE_SEEK: return fs::error::inval;
|
||||
case ERROR_DIRECTORY: return fs::error::inval;
|
||||
case ERROR_INVALID_NAME: return fs::error::inval;
|
||||
case ERROR_SHARING_VIOLATION: return fs::error::acces;
|
||||
default: fmt::throw_exception("Unknown Win32 error: %u.", e);
|
||||
}
|
||||
}
|
||||
@@ -510,7 +509,7 @@ bool fs::remove_dir(const std::string& path)
|
||||
#endif
|
||||
}
|
||||
|
||||
bool fs::rename(const std::string& from, const std::string& to, bool overwrite)
|
||||
bool fs::rename(const std::string& from, const std::string& to)
|
||||
{
|
||||
const auto device = get_virtual_device(from);
|
||||
|
||||
@@ -525,43 +524,14 @@ bool fs::rename(const std::string& from, const std::string& to, bool overwrite)
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
const auto ws1 = to_wchar(from);
|
||||
const auto ws2 = to_wchar(to);
|
||||
|
||||
if (!MoveFileExW(ws1.get(), ws2.get(), overwrite ? MOVEFILE_REPLACE_EXISTING : 0))
|
||||
if (!MoveFileW(to_wchar(from).get(), to_wchar(to).get()))
|
||||
{
|
||||
DWORD error1 = GetLastError();
|
||||
|
||||
if (overwrite && error1 == ERROR_ACCESS_DENIED && is_dir(from) && is_dir(to))
|
||||
{
|
||||
if (RemoveDirectoryW(ws2.get()))
|
||||
{
|
||||
if (MoveFileW(ws1.get(), ws2.get()))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
error1 = GetLastError();
|
||||
CreateDirectoryW(ws2.get(), NULL); // TODO
|
||||
}
|
||||
else
|
||||
{
|
||||
error1 = GetLastError();
|
||||
}
|
||||
}
|
||||
|
||||
g_tls_error = to_error(error1);
|
||||
g_tls_error = to_error(GetLastError());
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
#else
|
||||
if (!overwrite && exists(to))
|
||||
{
|
||||
g_tls_error = fs::error::exist;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (::rename(from.c_str(), to.c_str()) != 0)
|
||||
{
|
||||
g_tls_error = to_error(errno);
|
||||
@@ -794,13 +764,7 @@ fs::file::file(const std::string& path, bs_t<open_mode> mode)
|
||||
disp = test(mode & fs::trunc) ? TRUNCATE_EXISTING : OPEN_EXISTING;
|
||||
}
|
||||
|
||||
DWORD share = FILE_SHARE_READ;
|
||||
if (!test(mode & fs::unshare))
|
||||
{
|
||||
share |= FILE_SHARE_WRITE | FILE_SHARE_DELETE;
|
||||
}
|
||||
|
||||
const HANDLE handle = CreateFileW(to_wchar(path).get(), access, share, NULL, disp, FILE_ATTRIBUTE_NORMAL, NULL);
|
||||
const HANDLE handle = CreateFileW(to_wchar(path).get(), access, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, NULL, disp, FILE_ATTRIBUTE_NORMAL, NULL);
|
||||
|
||||
if (handle == INVALID_HANDLE_VALUE)
|
||||
{
|
||||
@@ -808,7 +772,7 @@ fs::file::file(const std::string& path, bs_t<open_mode> mode)
|
||||
return;
|
||||
}
|
||||
|
||||
class windows_file final : public file_base, public get_native_handle
|
||||
class windows_file final : public file_base
|
||||
{
|
||||
const HANDLE m_handle;
|
||||
|
||||
@@ -915,11 +879,6 @@ fs::file::file(const std::string& path, bs_t<open_mode> mode)
|
||||
|
||||
return size.QuadPart;
|
||||
}
|
||||
|
||||
native_handle get() override
|
||||
{
|
||||
return m_handle;
|
||||
}
|
||||
};
|
||||
|
||||
m_file = std::make_unique<windows_file>(handle);
|
||||
@@ -943,7 +902,7 @@ fs::file::file(const std::string& path, bs_t<open_mode> mode)
|
||||
return;
|
||||
}
|
||||
|
||||
class unix_file final : public file_base, public get_native_handle
|
||||
class unix_file final : public file_base
|
||||
{
|
||||
const int m_fd;
|
||||
|
||||
@@ -1032,11 +991,6 @@ fs::file::file(const std::string& path, bs_t<open_mode> mode)
|
||||
|
||||
return file_info.st_size;
|
||||
}
|
||||
|
||||
native_handle get() override
|
||||
{
|
||||
return m_fd;
|
||||
}
|
||||
};
|
||||
|
||||
m_file = std::make_unique<unix_file>(fd);
|
||||
@@ -1112,20 +1066,6 @@ fs::file::file(const void* ptr, std::size_t size)
|
||||
m_file = std::make_unique<memory_stream>(ptr, size);
|
||||
}
|
||||
|
||||
fs::native_handle fs::file::get_handle() const
|
||||
{
|
||||
if (auto getter = dynamic_cast<get_native_handle*>(m_file.get()))
|
||||
{
|
||||
return getter->get();
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
return INVALID_HANDLE_VALUE;
|
||||
#else
|
||||
return -1;
|
||||
#endif
|
||||
}
|
||||
|
||||
void fs::dir::xnull() const
|
||||
{
|
||||
fmt::throw_exception<std::logic_error>("fs::dir is null");
|
||||
|
||||
+1
-18
@@ -10,12 +10,6 @@
|
||||
|
||||
namespace fs
|
||||
{
|
||||
#ifdef _WIN32
|
||||
using native_handle = void*;
|
||||
#else
|
||||
using native_handle = int;
|
||||
#endif
|
||||
|
||||
// File open mode flags
|
||||
enum class open_mode : u32
|
||||
{
|
||||
@@ -25,7 +19,6 @@ namespace fs
|
||||
create,
|
||||
trunc,
|
||||
excl,
|
||||
unshare,
|
||||
|
||||
__bitset_enum_max
|
||||
};
|
||||
@@ -36,7 +29,6 @@ namespace fs
|
||||
constexpr auto create = +open_mode::create; // Create file if it doesn't exist
|
||||
constexpr auto trunc = +open_mode::trunc; // Clear opened file if it's not empty
|
||||
constexpr auto excl = +open_mode::excl; // Failure if the file already exists (used with `create`)
|
||||
constexpr auto unshare = +open_mode::unshare; // Prevent opening the file twice
|
||||
|
||||
constexpr auto rewrite = open_mode::write + open_mode::create + open_mode::trunc;
|
||||
|
||||
@@ -63,12 +55,6 @@ namespace fs
|
||||
s64 ctime;
|
||||
};
|
||||
|
||||
// Native handle getter
|
||||
struct get_native_handle
|
||||
{
|
||||
virtual native_handle get() = 0;
|
||||
};
|
||||
|
||||
// File handle base
|
||||
struct file_base
|
||||
{
|
||||
@@ -159,7 +145,7 @@ namespace fs
|
||||
bool create_path(const std::string& path);
|
||||
|
||||
// Rename (move) file or directory
|
||||
bool rename(const std::string& from, const std::string& to, bool overwrite);
|
||||
bool rename(const std::string& from, const std::string& to);
|
||||
|
||||
// Copy file contents
|
||||
bool copy_file(const std::string& from, const std::string& to, bool overwrite);
|
||||
@@ -361,9 +347,6 @@ namespace fs
|
||||
if (seek(0), !read(result)) xfail();
|
||||
return result;
|
||||
}
|
||||
|
||||
// Get native handle if available
|
||||
native_handle get_handle() const;
|
||||
};
|
||||
|
||||
class dir final
|
||||
|
||||
+3
-3
@@ -90,13 +90,13 @@ extern void jit_finalize()
|
||||
// Helper class
|
||||
struct MemoryManager : llvm::RTDyldMemoryManager
|
||||
{
|
||||
std::unordered_map<std::string, u64>& m_link;
|
||||
std::unordered_map<std::string, std::uintptr_t>& m_link;
|
||||
|
||||
std::array<u8, 16>* m_tramps{};
|
||||
|
||||
u8* m_code_addr{}; // TODO
|
||||
|
||||
MemoryManager(std::unordered_map<std::string, u64>& table)
|
||||
MemoryManager(std::unordered_map<std::string, std::uintptr_t>& table)
|
||||
: m_link(table)
|
||||
{
|
||||
}
|
||||
@@ -371,7 +371,7 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
jit_compiler::jit_compiler(const std::unordered_map<std::string, u64>& _link, std::string _cpu)
|
||||
jit_compiler::jit_compiler(const std::unordered_map<std::string, std::uintptr_t>& _link, std::string _cpu)
|
||||
: m_link(std::move(_link))
|
||||
, m_cpu(std::move(_cpu))
|
||||
{
|
||||
|
||||
+18
-175
@@ -3,21 +3,16 @@
|
||||
#include "StrFmt.h"
|
||||
#include "sema.h"
|
||||
|
||||
#include "Utilities/sysinfo.h"
|
||||
#include "rpcs3_version.h"
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
|
||||
#ifdef _WIN32
|
||||
#define NOMINMAX
|
||||
#include <Windows.h>
|
||||
#else
|
||||
#include <chrono>
|
||||
#include <sys/mman.h>
|
||||
#endif
|
||||
|
||||
#include <zlib.h>
|
||||
|
||||
static std::string empty_string()
|
||||
{
|
||||
return {};
|
||||
@@ -49,38 +44,29 @@ void fmt_class_string<logs::level>::format(std::string& out, u64 arg)
|
||||
|
||||
namespace logs
|
||||
{
|
||||
constexpr std::size_t s_log_size = 128 * 1024 * 1024;
|
||||
constexpr std::size_t s_log_size_s = s_log_size / 2;
|
||||
constexpr std::size_t s_log_size_t = s_log_size / 4 + s_log_size_s;
|
||||
constexpr std::size_t s_log_size_e = s_log_size / 8 + s_log_size_t;
|
||||
constexpr std::size_t s_log_size_f = s_log_size / 16 + s_log_size_e;
|
||||
|
||||
class file_writer
|
||||
{
|
||||
// Could be memory-mapped file
|
||||
fs::file m_file;
|
||||
std::string m_name;
|
||||
|
||||
#ifdef _WIN32
|
||||
::HANDLE m_fmap;
|
||||
#endif
|
||||
atomic_t<std::size_t> m_pos{0};
|
||||
std::size_t m_size{0};
|
||||
uchar* m_fptr{};
|
||||
|
||||
public:
|
||||
file_writer(const std::string& name);
|
||||
|
||||
virtual ~file_writer();
|
||||
virtual ~file_writer() = default;
|
||||
|
||||
// Append raw data
|
||||
void log(logs::level sev, const char* text, std::size_t size);
|
||||
void log(const char* text, std::size_t size);
|
||||
};
|
||||
|
||||
struct file_listener : public file_writer, public listener
|
||||
{
|
||||
file_listener(const std::string& name);
|
||||
|
||||
virtual ~file_listener() = default;
|
||||
file_listener(const std::string& name)
|
||||
: file_writer(name)
|
||||
, listener()
|
||||
{
|
||||
const std::string& start = fmt::format("\xEF\xBB\xBF" "RPCS3 v%s\n", rpcs3::version.to_string());
|
||||
file_writer::log(start.data(), start.size());
|
||||
}
|
||||
|
||||
// Encode level, current thread name, channel name and write log message
|
||||
virtual void log(u64 stamp, const message& msg, const std::string& prefix, const std::string& text) override;
|
||||
@@ -151,26 +137,12 @@ namespace logs
|
||||
}
|
||||
};
|
||||
|
||||
struct stored_message
|
||||
{
|
||||
message m;
|
||||
u64 stamp;
|
||||
std::string prefix;
|
||||
std::string text;
|
||||
};
|
||||
|
||||
// Channel registry mutex
|
||||
semaphore<> g_mutex;
|
||||
|
||||
// Channel registry
|
||||
std::unordered_map<std::string, channel_info> g_channels;
|
||||
|
||||
// Messages for delayed listener initialization
|
||||
std::vector<stored_message> g_messages;
|
||||
|
||||
// Must be set to true in main()
|
||||
atomic_t<bool> g_init{false};
|
||||
|
||||
void reset()
|
||||
{
|
||||
semaphore_lock lock(g_mutex);
|
||||
@@ -187,17 +159,6 @@ namespace logs
|
||||
|
||||
g_channels[ch_name].set_level(value);
|
||||
}
|
||||
|
||||
// Must be called in main() to stop accumulating messages in g_messages
|
||||
void set_init()
|
||||
{
|
||||
if (!g_init)
|
||||
{
|
||||
semaphore_lock lock(g_mutex);
|
||||
g_messages.clear();
|
||||
g_init = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
logs::listener::~listener()
|
||||
@@ -209,19 +170,11 @@ void logs::listener::add(logs::listener* _new)
|
||||
// Get first (main) listener
|
||||
listener* lis = get_logger();
|
||||
|
||||
semaphore_lock lock(g_mutex);
|
||||
|
||||
// Install new listener at the end of linked list
|
||||
while (lis->m_next || !lis->m_next.compare_and_swap_test(nullptr, _new))
|
||||
{
|
||||
lis = lis->m_next;
|
||||
}
|
||||
|
||||
// Send initial messages
|
||||
for (const auto& msg : g_messages)
|
||||
{
|
||||
_new->log(msg.stamp, msg.m, msg.prefix, msg.text);
|
||||
}
|
||||
}
|
||||
|
||||
void logs::message::broadcast(const char* fmt, const fmt_type_info* sup, const u64* args)
|
||||
@@ -254,29 +207,12 @@ void logs::message::broadcast(const char* fmt, const fmt_type_info* sup, const u
|
||||
}
|
||||
|
||||
// Get text
|
||||
thread_local std::string text; text.clear();
|
||||
std::string text;
|
||||
fmt::raw_append(text, fmt, sup, args);
|
||||
std::string prefix = g_tls_log_prefix();
|
||||
|
||||
// Get first (main) listener
|
||||
listener* lis = get_logger();
|
||||
|
||||
if (!g_init)
|
||||
{
|
||||
semaphore_lock lock(g_mutex);
|
||||
|
||||
if (!g_init)
|
||||
{
|
||||
while (lis)
|
||||
{
|
||||
lis->log(stamp, *this, prefix, text);
|
||||
lis = lis->m_next;
|
||||
}
|
||||
|
||||
// Store message additionally
|
||||
g_messages.emplace_back(stored_message{*this, stamp, std::move(prefix), text});
|
||||
}
|
||||
}
|
||||
|
||||
// Send message to all listeners
|
||||
while (lis)
|
||||
@@ -289,28 +225,13 @@ void logs::message::broadcast(const char* fmt, const fmt_type_info* sup, const u
|
||||
[[noreturn]] extern void catch_all_exceptions();
|
||||
|
||||
logs::file_writer::file_writer(const std::string& name)
|
||||
: m_name(fs::get_config_dir() + name)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (!m_file.open(m_name, fs::read + fs::write + fs::create + fs::trunc + fs::unshare))
|
||||
if (!m_file.open(fs::get_config_dir() + name, fs::rewrite + fs::append))
|
||||
{
|
||||
fmt::throw_exception("Can't create file %s (error %s)", name, fs::g_tls_error);
|
||||
fmt::throw_exception("Can't create log file %s (error %s)", name, fs::g_tls_error);
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
m_fmap = CreateFileMappingW(m_file.get_handle(), 0, PAGE_READWRITE, s_log_size >> 32, s_log_size & 0xffffffff, 0);
|
||||
m_fptr = m_fmap ? (uchar*)MapViewOfFile(m_fmap, FILE_MAP_WRITE, 0, 0, 0) : nullptr;
|
||||
#else
|
||||
m_file.trunc(s_log_size);
|
||||
m_fptr = (uchar*)::mmap(0, s_log_size, PROT_READ | PROT_WRITE, MAP_SHARED, m_file.get_handle(), 0);
|
||||
#endif
|
||||
|
||||
verify(m_name.c_str()), m_fptr;
|
||||
std::memset(m_fptr, '\n', s_log_size);
|
||||
|
||||
// Rotate backups (TODO)
|
||||
fs::rename(m_name + ".gz", m_name + "1.gz", true);
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
@@ -318,92 +239,14 @@ logs::file_writer::file_writer(const std::string& name)
|
||||
}
|
||||
}
|
||||
|
||||
logs::file_writer::~file_writer()
|
||||
void logs::file_writer::log(const char* text, std::size_t size)
|
||||
{
|
||||
if (m_size == 0)
|
||||
{
|
||||
m_size = std::min<std::size_t>(+m_pos, s_log_size);
|
||||
}
|
||||
|
||||
// Compress
|
||||
z_stream zs{};
|
||||
if (deflateInit2(&zs, 9, Z_DEFLATED, 16 + 15, 9, Z_DEFAULT_STRATEGY) == Z_OK)
|
||||
{
|
||||
auto buf = std::make_unique<uchar[]>(s_log_size);
|
||||
zs.avail_in = ::narrow<u32>(m_size);
|
||||
zs.avail_out = s_log_size;
|
||||
zs.next_in = m_fptr;
|
||||
zs.next_out = buf.get();
|
||||
|
||||
if (deflate(&zs, Z_FINISH) != Z_STREAM_ERROR)
|
||||
{
|
||||
fs::file(m_name + ".gz", fs::rewrite).write(buf.get(), zs.total_out);
|
||||
}
|
||||
|
||||
if (deflateEnd(&zs) != Z_OK)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
UnmapViewOfFile(m_fptr);
|
||||
CloseHandle(m_fmap);
|
||||
m_file.seek(m_size);
|
||||
SetEndOfFile(m_file.get_handle());
|
||||
#else
|
||||
::munmap(m_fptr, s_log_size);
|
||||
m_file.trunc(m_size);
|
||||
#endif
|
||||
}
|
||||
|
||||
void logs::file_writer::log(logs::level sev, const char* text, std::size_t size)
|
||||
{
|
||||
// Adaptive log limit
|
||||
const auto lim =
|
||||
sev >= logs::level::success ? s_log_size_s :
|
||||
sev == logs::level::todo ? s_log_size_t :
|
||||
sev == logs::level::error ? s_log_size_e : s_log_size_f;
|
||||
|
||||
if (m_pos >= lim)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// Acquire memory
|
||||
const auto pos = m_pos.fetch_add(size);
|
||||
|
||||
// Write if possible
|
||||
if (pos + size <= s_log_size)
|
||||
{
|
||||
std::memcpy(m_fptr + pos, text, size);
|
||||
}
|
||||
else if (pos <= s_log_size)
|
||||
{
|
||||
m_size = pos;
|
||||
}
|
||||
}
|
||||
|
||||
logs::file_listener::file_listener(const std::string& name)
|
||||
: file_writer(name)
|
||||
, listener()
|
||||
{
|
||||
// Write UTF-8 BOM
|
||||
file_writer::log(logs::level::always, "\xEF\xBB\xBF", 3);
|
||||
|
||||
// Write initial message
|
||||
stored_message ver;
|
||||
ver.m.ch = nullptr;
|
||||
ver.m.sev = level::always;
|
||||
ver.stamp = 0;
|
||||
ver.text = fmt::format("RPCS3 v%s\n%s", rpcs3::version.to_string(), utils::get_system_info());
|
||||
file_writer::log(logs::level::always, ver.text.data(), ver.text.size());
|
||||
file_writer::log(logs::level::always, "\n", 1);
|
||||
g_messages.emplace_back(std::move(ver));
|
||||
m_file.write(text, size);
|
||||
}
|
||||
|
||||
void logs::file_listener::log(u64 stamp, const logs::message& msg, const std::string& prefix, const std::string& _text)
|
||||
{
|
||||
thread_local std::string text;
|
||||
std::string text; text.reserve(prefix.size() + _text.size() + 200);
|
||||
|
||||
// Used character: U+00B7 (Middle Dot)
|
||||
switch (msg.sev)
|
||||
@@ -432,7 +275,7 @@ void logs::file_listener::log(u64 stamp, const logs::message& msg, const std::st
|
||||
text += "} ";
|
||||
}
|
||||
|
||||
if (msg.ch && '\0' != *msg.ch->name)
|
||||
if ('\0' != *msg.ch->name)
|
||||
{
|
||||
text += msg.ch->name;
|
||||
text += msg.sev == level::todo ? " TODO: " : ": ";
|
||||
@@ -445,5 +288,5 @@ void logs::file_listener::log(u64 stamp, const logs::message& msg, const std::st
|
||||
text += _text;
|
||||
text += '\n';
|
||||
|
||||
file_writer::log(msg.sev, text.data(), text.size());
|
||||
file_writer::log(text.data(), text.size());
|
||||
}
|
||||
|
||||
@@ -257,8 +257,8 @@ struct fmt::cfmt_src
|
||||
|
||||
void skip(std::size_t extra)
|
||||
{
|
||||
sup += extra + 1;
|
||||
args += extra + 1;
|
||||
++sup += extra;
|
||||
++args += extra;
|
||||
}
|
||||
|
||||
std::size_t fmt_string(std::string& out, std::size_t extra) const
|
||||
|
||||
+4
-16
@@ -30,25 +30,13 @@ thread_local u64 g_tls_fault_spu = 0;
|
||||
|
||||
static void report_fatal_error(const std::string& msg)
|
||||
{
|
||||
static semaphore<> g_report_only_once;
|
||||
|
||||
g_report_only_once.wait();
|
||||
|
||||
std::string _msg = msg + "\n"
|
||||
"HOW TO REPORT ERRORS: https://github.com/RPCS3/rpcs3/wiki/How-to-ask-for-Support\n"
|
||||
"HOW TO REPORT ERRORS: Check the FAQ, README, other sources.\n"
|
||||
"Please, don't send incorrect reports. Thanks for understanding.\n";
|
||||
|
||||
#ifdef _WIN32
|
||||
_msg += "\nPress Yes or Enter to visit the URL above immediately.";
|
||||
const std::size_t buf_size = _msg.size() + 1;
|
||||
const int size = static_cast<int>(buf_size);
|
||||
std::unique_ptr<wchar_t[]> buffer(new wchar_t[buf_size]);
|
||||
MultiByteToWideChar(CP_UTF8, 0, _msg.c_str(), size, buffer.get(), size);
|
||||
|
||||
if (MessageBoxW(0, buffer.get(), L"Fatal error", MB_ICONERROR | MB_YESNO) == IDYES)
|
||||
{
|
||||
ShellExecuteW(0, L"open", L"https://github.com/RPCS3/rpcs3/wiki/How-to-ask-for-Support", 0, 0, SW_SHOWNORMAL);
|
||||
}
|
||||
_msg += "Press (Ctrl+C) to copy this message.";
|
||||
MessageBoxA(0, _msg.c_str(), "Fatal error", MB_ICONERROR); // TODO: unicode message
|
||||
#else
|
||||
std::printf("Fatal error: \n%s", _msg.c_str());
|
||||
#endif
|
||||
@@ -1248,7 +1236,7 @@ bool handle_access_violation(u32 addr, bool is_writing, x64_context* context)
|
||||
return true;
|
||||
}
|
||||
|
||||
if (vm::check_addr(addr, std::max<std::size_t>(1, d_size), vm::page_allocated | (is_writing ? vm::page_writable : vm::page_readable)))
|
||||
if (vm::check_addr(addr, std::max<std::size_t>(1, d_size)))
|
||||
{
|
||||
if (cpu)
|
||||
{
|
||||
|
||||
@@ -1,27 +0,0 @@
|
||||
#pragma once
|
||||
#include <stdint.h>
|
||||
|
||||
namespace rpcs3
|
||||
{
|
||||
template<typename T>
|
||||
static size_t hash_base(T value)
|
||||
{
|
||||
return static_cast<size_t>(value);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
static size_t hash_struct(const T& value)
|
||||
{
|
||||
// FNV 64-bit
|
||||
size_t result = 14695981039346656037ull;
|
||||
const unsigned char *bytes = reinterpret_cast<const unsigned char*>(&value);
|
||||
|
||||
for (size_t n = 0; n < sizeof(T); ++n)
|
||||
{
|
||||
result ^= bytes[n];
|
||||
result *= 1099511628211ull;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
+4
-10
@@ -32,6 +32,7 @@
|
||||
#define SAFE_BUFFERS
|
||||
#define NEVER_INLINE __attribute__((noinline))
|
||||
#define FORCE_INLINE __attribute__((always_inline)) inline
|
||||
#define thread_local __thread
|
||||
#endif
|
||||
|
||||
#define CHECK_SIZE(type, size) static_assert(sizeof(type) == size, "Invalid " #type " type size")
|
||||
@@ -918,7 +919,7 @@ struct error_code
|
||||
error_code() = default;
|
||||
|
||||
// Implementation must be provided specially
|
||||
static s32 error_report(const fmt_type_info* sup, u64 arg, const fmt_type_info* sup2, u64 arg2);
|
||||
static s32 error_report(const fmt_type_info* sup, u64 arg);
|
||||
|
||||
// Helper type
|
||||
enum class not_an_error : s32
|
||||
@@ -939,7 +940,7 @@ struct error_code
|
||||
|
||||
// Not an error constructor
|
||||
template<typename ET, typename = decltype(ET::__not_an_error)>
|
||||
error_code(const ET& value, std::nullptr_t = nullptr)
|
||||
error_code(const ET& value, int = 0)
|
||||
: value(static_cast<s32>(value))
|
||||
{
|
||||
}
|
||||
@@ -947,14 +948,7 @@ struct error_code
|
||||
// Error constructor
|
||||
template<typename ET, typename = std::enable_if_t<is_error<ET>::value>>
|
||||
error_code(const ET& value)
|
||||
: value(error_report(fmt::get_type_info<fmt_unveil_t<ET>>(), fmt_unveil<ET>::get(value), nullptr, 0))
|
||||
{
|
||||
}
|
||||
|
||||
// Error constructor (2 args)
|
||||
template<typename ET, typename T2, typename = std::enable_if_t<is_error<ET>::value>>
|
||||
error_code(const ET& value, const T2& value2)
|
||||
: value(error_report(fmt::get_type_info<fmt_unveil_t<ET>>(), fmt_unveil<ET>::get(value), fmt::get_type_info<fmt_unveil_t<T2>>(), fmt_unveil<T2>::get(value2)))
|
||||
: value(error_report(fmt::get_type_info<fmt_unveil_t<ET>>(), fmt_unveil<ET>::get(value)))
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
+1
-4
@@ -15,9 +15,6 @@ before_build:
|
||||
- git submodule update --init 3rdparty/ffmpeg 3rdparty/pugixml asmjit 3rdparty/GSL 3rdparty/libpng Vulkan/glslang Vulkan/Vulkan-LoaderAndValidationLayers Utilities/yaml-cpp 3rdparty/cereal 3rdparty/zlib 3rdparty/hidapi
|
||||
- 7z x zlib.7z -aos -oC:\rpcs3\ > null
|
||||
- 7z x vulkan.7z -aos -oC:\rpcs3\Vulkan > null
|
||||
- set BRANCH=%APPVEYOR_REPO_NAME%/%APPVEYOR_REPO_BRANCH%/#%APPVEYOR_PULL_REQUEST_NUMBER%
|
||||
- if "%APPVEYOR_PULL_REQUEST_NUMBER%"=="" (set BRANCH=%APPVEYOR_REPO_NAME%/%APPVEYOR_REPO_BRANCH%)
|
||||
- set CXXFLAGS=-DBRANCH=%BRANCH%
|
||||
- if %configuration%==Release (cmake -G "Visual Studio 15 Win64" -DZLIB_ROOT=C:/rpcs3/zlib/ -DVULKAN_PREBUILT=ON)
|
||||
else (7z x llvmlibs.7z -aos -oC:\rpcs3 > null && cmake -G "Visual Studio 15 Win64" -DLLVM_DIR=C:/rpcs3/llvm_build/lib/cmake/llvm -DZLIB_ROOT=C:/rpcs3/zlib/ -DVULKAN_PREBUILT=ON)
|
||||
|
||||
@@ -28,7 +25,7 @@ install:
|
||||
- if not exist llvmlibs.7z appveyor DownloadFile "https://drive.google.com/uc?export=download&id=0B8A6NaxhQAGRY2k3Q2Yya05lcm8" -FileName llvmlibs.7z
|
||||
- if not exist vulkan.7z appveyor DownloadFile "https://drive.google.com/uc?export=download&id=0B8A6NaxhQAGRaHYxV3VOS2d0a0U" -FileName vulkan.7z
|
||||
- if not exist zlib.7z appveyor DownloadFile "https://drive.google.com/uc?export=download&id=0B-HVE3xvheVFX05lRFdnZlh5aUU" -FileName zlib.7z
|
||||
- set QTDIR=C:\Qt\5.9.1\msvc2017_64
|
||||
- set QTDIR=C:\Qt\5.9\msvc2017_64
|
||||
- set OPENALDIR=C:\rpcs3\3rdparty\OpenAL
|
||||
- set PATH=C:\Program Files (x86)\MSBuild\15.0\Bin;%QTDIR%;%PATH%
|
||||
- set COMMIT_SHA=%APPVEYOR_REPO_COMMIT:~0,8%
|
||||
|
||||
@@ -1,248 +0,0 @@
|
||||
/*
|
||||
Kuroi (Dark) Theme for RPCS3
|
||||
by Ani @ https://github.com/AniLeo
|
||||
r1 (2017.08.15)
|
||||
*/
|
||||
|
||||
/*
|
||||
Color Scheme
|
||||
(Darker to Lighter)
|
||||
|
||||
Black
|
||||
> 292929
|
||||
> 323232
|
||||
> 333333
|
||||
> 3d3d3d
|
||||
> 404040
|
||||
> 444444
|
||||
|
||||
Light Grey
|
||||
> 828790
|
||||
> bdc3c7
|
||||
> ecf0f1
|
||||
|
||||
> b1b1b1
|
||||
> 7f8c8d
|
||||
|
||||
Green
|
||||
> 2ecc71
|
||||
|
||||
Red
|
||||
> e74c3c
|
||||
*/
|
||||
|
||||
/* Every widget */
|
||||
QWidget {
|
||||
background-color: #323232;
|
||||
color: #bdc3c7;
|
||||
alternate-background-color: #3d3d3d;
|
||||
}
|
||||
|
||||
/* Mouse tooltips */
|
||||
QToolTip {
|
||||
border: 1px solid #323232;
|
||||
background-color: #323232;
|
||||
color: #ecf0f1;
|
||||
}
|
||||
|
||||
/* Table headers */
|
||||
QHeaderView::section {
|
||||
background-color: #323232;
|
||||
color: #ecf0f1;
|
||||
padding-left: 4px;
|
||||
border: 1px solid #323232;
|
||||
}
|
||||
|
||||
/* Settings Dialog: Tabs */
|
||||
QTabBar::tab {
|
||||
color: #ecf0f1;
|
||||
border: 1px solid #444;
|
||||
border-bottom-style: none;
|
||||
background-color: #333333;
|
||||
padding-left: 16px;
|
||||
padding-right: 16px;
|
||||
padding-top: 4px;
|
||||
padding-bottom: 4px;
|
||||
margin-right: -2px;
|
||||
}
|
||||
QTabBar::tab:last {
|
||||
margin-right: 0px;
|
||||
}
|
||||
QTabBar::tab:!selected {
|
||||
color: #b1b1b1;
|
||||
border-bottom-style: solid;
|
||||
margin-top: 3px;
|
||||
background-color: #292929;
|
||||
}
|
||||
QTabBar::tab:hover {
|
||||
background-color: #333333;
|
||||
color: #ecf0f1;
|
||||
}
|
||||
|
||||
/* Checkboxes */
|
||||
QCheckBox::indicator {
|
||||
border-radius: 2px;
|
||||
border: 1px solid #ecf0f1;
|
||||
width: 10px;
|
||||
height: 10px;
|
||||
margin-top: 1px;
|
||||
}
|
||||
QCheckBox::indicator:checked {
|
||||
background-color: #2ecc71; /* Green */
|
||||
}
|
||||
QCheckBox::indicator:unchecked {
|
||||
background-color: #e74c3c; /* Red */
|
||||
}
|
||||
QCheckBox::indicator::disabled {
|
||||
background-color: #7f8c8d; /* Gray */
|
||||
}
|
||||
|
||||
/* Radio Buttons */
|
||||
QRadioButton::indicator {
|
||||
border-radius: 6px;
|
||||
border: 1px solid #ecf0f1;
|
||||
width: 10px;
|
||||
height: 10px;
|
||||
margin-top: 1px;
|
||||
}
|
||||
QRadioButton::indicator:checked {
|
||||
background-color: #2ecc71; /* Green */
|
||||
}
|
||||
QRadioButton::indicator:unchecked {
|
||||
background-color: #e74c3c; /* Red */
|
||||
}
|
||||
QRadioButton::indicator::disabled {
|
||||
background-color: #7f8c8d; /* Gray */
|
||||
}
|
||||
|
||||
/* Combo Boxes */
|
||||
QComboBox {
|
||||
background-color: #404040;
|
||||
color: #fff;
|
||||
border: 1px solid #1e1e1e;
|
||||
border-radius: 3px;
|
||||
padding-bottom: 2px;
|
||||
padding-left: 4px;
|
||||
}
|
||||
QComboBox::disabled {
|
||||
background-color: #828790;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
/* Group Boxes (Settings Dialog) */
|
||||
QGroupBox {
|
||||
margin-top: 17px;
|
||||
font-size: 13px;
|
||||
border: 1px solid #bdc3c7;
|
||||
border-radius: 4px;
|
||||
}
|
||||
QGroupBox::title {
|
||||
subcontrol-origin: margin;
|
||||
subcontrol-position: top center;
|
||||
padding: 5px 10px 5px 10px;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
/* Buttons */
|
||||
QPushButton {
|
||||
background-color: #404040;
|
||||
}
|
||||
QPushButton::disabled {
|
||||
background-color: #444444;
|
||||
color: #828790;
|
||||
}
|
||||
|
||||
/* Log and Debugger borders */
|
||||
QTextEdit {
|
||||
border: 1px solid #828790;
|
||||
}
|
||||
|
||||
/* For dock buttons to be visible */
|
||||
QDockWidget::close-button, QDockWidget::float-button {
|
||||
background-color: #bdc3c7;
|
||||
border: 1px solid #000;
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
/* Disable ugly borders */
|
||||
QTabWidget::pane {
|
||||
border: 0px solid #828790;
|
||||
}
|
||||
|
||||
/* Top menu bar */
|
||||
QMenuBar::item:selected {
|
||||
background: #444444;
|
||||
}
|
||||
QMenu::item {
|
||||
padding-left: 20px;
|
||||
padding-right: 15px;
|
||||
padding-top: 4px;
|
||||
padding-bottom: 4px;
|
||||
}
|
||||
QMenu::item:selected {
|
||||
background: #444444;
|
||||
border: 1px solid #bdc3c7;
|
||||
}
|
||||
QMenu::item:disabled {
|
||||
background-color: #444444;
|
||||
color: #828790;
|
||||
}
|
||||
|
||||
/* Libraries list */
|
||||
QListWidget::item:selected {
|
||||
background-color: #3d3d3d;
|
||||
color: #ecf0f1;
|
||||
}
|
||||
QListWidget::item:hover {
|
||||
background-color: #4c4b4b;
|
||||
color: #ecf0f1;
|
||||
}
|
||||
|
||||
/* Pad Settings: Controller Image */
|
||||
QLabel#l_controller {
|
||||
color: #bdc3c7;
|
||||
}
|
||||
|
||||
/* Game Grid Font */
|
||||
QLabel#gamegrid_font {
|
||||
font-weight: 600;
|
||||
font-size: 8pt;
|
||||
font-family: Lucida Grande;
|
||||
color: #ecf0f1;
|
||||
}
|
||||
|
||||
/* Slider on toolbar */
|
||||
QWidget#sizeSliderContainer {
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
/* Debug UI Settings buttons */
|
||||
QLabel#color_button {
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
/* Seachbar on main toolbar */
|
||||
QLineEdit#mw_searchbar {
|
||||
margin-left:14px;
|
||||
color: #ecf0f1;
|
||||
}
|
||||
|
||||
/* Uniform colors in Toolbar */
|
||||
QToolButton {
|
||||
background: transparent;
|
||||
color: transparent;
|
||||
}
|
||||
QToolButton::disabled {
|
||||
background-color: #828790;
|
||||
}
|
||||
QToolButton::hover {
|
||||
background-color: #444444;
|
||||
}
|
||||
|
||||
/* Set Theme UI colors */
|
||||
QLabel#gamelist_icon_background_color {
|
||||
background-color: #323232;
|
||||
}
|
||||
QLabel#gamelist_toolbar_icon_color {
|
||||
background-color: #e3e3e3;
|
||||
}
|
||||
+1
-1
Submodule llvm updated: a3b2103ffc...079c1f30fc
+11
-42
@@ -87,10 +87,7 @@ endif()
|
||||
if(NOT MSVC)
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fexceptions")
|
||||
# This hides our LLVM from mesa's LLVM, otherwise we get some unresolvable conflicts.
|
||||
if(NOT APPLE)
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wl,--exclude-libs,ALL")
|
||||
endif()
|
||||
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wl,--exclude-libs,ALL")
|
||||
if(WIN32)
|
||||
set(CMAKE_RC_COMPILER_INIT windres)
|
||||
enable_language(RC)
|
||||
@@ -104,23 +101,17 @@ if(NOT MSVC)
|
||||
|
||||
if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang")
|
||||
# This fixes 'some' of the st11range issues. See issue #2516
|
||||
if(APPLE)
|
||||
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,-image_base,0x10000 -Wl,-pagezero_size,0x10000")
|
||||
else()
|
||||
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -image-base=0x10000")
|
||||
endif()
|
||||
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -image-base=0x10000")
|
||||
endif()
|
||||
|
||||
# Some distros have the compilers set to use PIE by default, but RPCS3 doesn't work with PIE, so we need to disable it.
|
||||
if(APPLE)
|
||||
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,-no_pie")
|
||||
else()
|
||||
CHECK_C_COMPILER_FLAG("-no-pie" HAS_NO_PIE)
|
||||
CHECK_C_COMPILER_FLAG("-nopie" HAS_NOPIE)
|
||||
|
||||
if(HAS_NO_PIE)
|
||||
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -no-pie")
|
||||
elseif(HAS_NOPIE)
|
||||
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)
|
||||
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -nopie")
|
||||
endif()
|
||||
endif()
|
||||
@@ -136,7 +127,7 @@ endif()
|
||||
|
||||
if(${CMAKE_SYSTEM_NAME} MATCHES "Linux")
|
||||
#on some Linux distros shm_unlink and similar functions are in librt only
|
||||
set(ADDITIONAL_LIBS "rt" "X11")
|
||||
set(ADDITIONAL_LIBS "rt" "X11" "asound")
|
||||
elseif(NOT MSVC AND NOT CMAKE_CXX_FLAGS MATCHES "LIBICONV_PLUG")
|
||||
#it seems like glibc includes the iconv functions we use but other libc
|
||||
#implementations like the one on OSX don't seem implement them
|
||||
@@ -167,29 +158,9 @@ elseif(WIN32)
|
||||
set(PLATFORM_ARCH "Windows/x86_64")
|
||||
else()
|
||||
set(PLATFORM_ARCH "linux/x86_64")
|
||||
option(USE_ALSA "ALSA audio backend" ON)
|
||||
option(USE_PULSE "PulseAudio audio backend" ON)
|
||||
option(USE_LIBEVDEV "libevdev-based joystick support" ON)
|
||||
endif()
|
||||
|
||||
if(USE_ALSA)
|
||||
find_package(PkgConfig)
|
||||
pkg_check_modules(ALSA alsa)
|
||||
if(ALSA_FOUND)
|
||||
add_definitions(-DHAVE_ALSA)
|
||||
include_directories(SYSTEM ${ALSA_INCLUDE_DIRS})
|
||||
list(APPEND ADDITIONAL_LIBS ${ALSA_LDFLAGS})
|
||||
endif()
|
||||
endif()
|
||||
if(USE_PULSE)
|
||||
find_package(PkgConfig)
|
||||
pkg_check_modules(PULSE libpulse-simple)
|
||||
if(PULSE_FOUND)
|
||||
add_definitions(-DHAVE_PULSE)
|
||||
include_directories(SYSTEM ${PULSE_INCLUDE_DIRS})
|
||||
list(APPEND ADDITIONAL_LIBS ${PULSE_LDFLAGS})
|
||||
endif()
|
||||
endif()
|
||||
if(USE_LIBEVDEV)
|
||||
find_package(PkgConfig)
|
||||
pkg_check_modules(LIBEVDEV libevdev)
|
||||
@@ -350,9 +321,7 @@ if(WIN32)
|
||||
target_link_libraries(rpcs3 avformat.lib avcodec.lib avutil.lib swresample.lib swscale.lib png16_static ${OPENAL_LIBRARY} ${ADDITIONAL_LIBS})
|
||||
else()
|
||||
target_link_libraries(rpcs3 ${OPENAL_LIBRARY} ${GLEW_LIBRARY} ${OPENGL_LIBRARIES})
|
||||
if(APPLE)
|
||||
target_link_libraries(rpcs3 hidapi-mac "-framework CoreFoundation" "-framework IOKit")
|
||||
elseif(CMAKE_SYSTEM_NAME STREQUAL "Linux")
|
||||
if(CMAKE_SYSTEM_NAME STREQUAL "Linux")
|
||||
target_link_libraries(rpcs3 hidapi-hidraw udev vulkan)
|
||||
else()
|
||||
target_link_libraries(rpcs3 hidapi-libusb usb)
|
||||
|
||||
@@ -150,8 +150,8 @@ s64 decrypt_block(const fs::file* in, u8* out, EDAT_HEADER *edat, NPD_HEADER *np
|
||||
const int metadata_section_size = ((edat->flags & EDAT_COMPRESSED_FLAG) != 0 || (edat->flags & EDAT_FLAG_0x20) != 0) ? 0x20 : 0x10;
|
||||
const int metadata_offset = 0x100;
|
||||
|
||||
std::unique_ptr<u8[]> enc_data;
|
||||
std::unique_ptr<u8[]> dec_data;
|
||||
std::unique_ptr<u8> enc_data;
|
||||
std::unique_ptr<u8> dec_data;
|
||||
u8 hash[0x10] = { 0 };
|
||||
u8 key_result[0x10] = { 0 };
|
||||
u8 hash_result[0x14] = { 0 };
|
||||
@@ -315,7 +315,7 @@ int decrypt_data(const fs::file* in, const fs::file* out, EDAT_HEADER *edat, NPD
|
||||
{
|
||||
const int total_blocks = (int)((edat->file_size + edat->block_size - 1) / edat->block_size);
|
||||
u64 size_left = (int)edat->file_size;
|
||||
std::unique_ptr<u8[]> data(new u8[edat->block_size]);
|
||||
std::unique_ptr<u8> data(new u8[edat->block_size]);
|
||||
|
||||
for (int i = 0; i < total_blocks; i++)
|
||||
{
|
||||
@@ -427,8 +427,8 @@ int check_data(unsigned char *key, EDAT_HEADER *edat, NPD_HEADER *npd, const fs:
|
||||
|
||||
long bytes_read = 0;
|
||||
long bytes_to_read = metadata_size;
|
||||
std::unique_ptr<u8[]> metadata(new u8[metadata_size]);
|
||||
std::unique_ptr<u8[]> empty_metadata(new u8[metadata_size]);
|
||||
std::unique_ptr<u8> metadata(new u8[metadata_size]);
|
||||
std::unique_ptr<u8> empty_metadata(new u8[metadata_size]);
|
||||
|
||||
while (bytes_to_read > 0)
|
||||
{
|
||||
@@ -487,7 +487,7 @@ int check_data(unsigned char *key, EDAT_HEADER *edat, NPD_HEADER *npd, const fs:
|
||||
if ((edat->flags & EDAT_FLAG_0x20) != 0) //Sony failed again, they used buffer from 0x100 with half size of real metadata.
|
||||
{
|
||||
int metadata_buf_size = block_num * 0x10;
|
||||
std::unique_ptr<u8[]> metadata_buf(new u8[metadata_buf_size]);
|
||||
std::unique_ptr<u8> metadata_buf(new u8[metadata_buf_size]);
|
||||
f->seek(file_offset + metadata_offset);
|
||||
f->read(metadata_buf.get(), metadata_buf_size);
|
||||
sha1(metadata_buf.get(), metadata_buf_size, signature_hash);
|
||||
@@ -516,7 +516,7 @@ int check_data(unsigned char *key, EDAT_HEADER *edat, NPD_HEADER *npd, const fs:
|
||||
{
|
||||
// Setup header signature hash.
|
||||
memset(signature_hash, 0, 20);
|
||||
std::unique_ptr<u8[]> header_buf(new u8[0xD8]);
|
||||
std::unique_ptr<u8> header_buf(new u8[0xD8]);
|
||||
f->seek(file_offset);
|
||||
f->read(header_buf.get(), 0xD8);
|
||||
sha1(header_buf.get(), 0xD8, signature_hash );
|
||||
@@ -577,7 +577,7 @@ int validate_npd_hashes(const char* file_name, const u8* klicensee, NPD_HEADER *
|
||||
int dev_hash_result = 0;
|
||||
|
||||
const int file_name_length = (int) strlen(file_name);
|
||||
std::unique_ptr<u8[]> buf(new u8[0x30 + file_name_length]);
|
||||
std::unique_ptr<u8> buf(new u8[0x30 + file_name_length]);
|
||||
|
||||
// Build the title buffer (content_id + file_name).
|
||||
memcpy(buf.get(), npd->content_id, 0x30);
|
||||
|
||||
+11
-90
@@ -3,77 +3,19 @@
|
||||
#include "aes.h"
|
||||
#include "sha1.h"
|
||||
#include "key_vault.h"
|
||||
#include "Utilities/StrFmt.h"
|
||||
#include "unpkg.h"
|
||||
|
||||
bool pkg_install(const fs::file& pkg_f, const std::string& dir, atomic_t<double>& sync, const std::string& pkg_filepath)
|
||||
bool pkg_install(const fs::file& pkg_f, const std::string& dir, atomic_t<double>& sync)
|
||||
{
|
||||
const std::size_t BUF_SIZE = 8192 * 1024; // 8 MB
|
||||
std::vector<fs::file> filelist;
|
||||
u32 cur_file=0;
|
||||
|
||||
fs::file original_file(pkg_filepath);
|
||||
original_file.seek(pkg_f.pos());
|
||||
|
||||
filelist.push_back(std::move(original_file));
|
||||
|
||||
// Save current file offset (probably zero)
|
||||
const u64 start_offset = pkg_f.pos();
|
||||
u64 cur_offset = start_offset;
|
||||
u64 cur_file_offset = start_offset;
|
||||
|
||||
// Get basic PKG information
|
||||
PKGHeader header;
|
||||
|
||||
auto archive_seek = [&](const s64 new_offset, const fs::seek_mode damode = fs::seek_set)
|
||||
{
|
||||
if(damode == fs::seek_set) cur_offset = new_offset;
|
||||
else if (damode == fs::seek_cur) cur_offset += new_offset;
|
||||
|
||||
u64 _offset = 0;
|
||||
for (u32 i = 0; i < filelist.size(); i++)
|
||||
{
|
||||
if (cur_offset < (_offset + filelist[i].size()))
|
||||
{
|
||||
cur_file = i;
|
||||
cur_file_offset = cur_offset - _offset;
|
||||
filelist[i].seek(cur_file_offset);
|
||||
break;
|
||||
}
|
||||
_offset += filelist[i].size();
|
||||
}
|
||||
};
|
||||
|
||||
auto archive_read = [&](const void *data_ptr, const u64 num_bytes)
|
||||
{
|
||||
u64 num_bytes_left = filelist[cur_file].size() - cur_file_offset;
|
||||
//check if it continues in another file
|
||||
if (num_bytes > num_bytes_left)
|
||||
{
|
||||
filelist[cur_file].read((u8 *)data_ptr, num_bytes_left);
|
||||
if ((cur_file + 1) < filelist.size()) cur_file++;
|
||||
else
|
||||
{
|
||||
cur_offset += num_bytes_left;
|
||||
cur_file_offset = filelist[cur_file].size();
|
||||
return num_bytes_left;
|
||||
}
|
||||
u64 num_read = filelist[cur_file].read((u8 *)data_ptr + num_bytes_left, num_bytes - num_bytes_left);
|
||||
cur_offset += (num_read + num_bytes_left);
|
||||
cur_file_offset = num_read;
|
||||
return (num_read+num_bytes_left);
|
||||
}
|
||||
|
||||
u64 num_read = filelist[cur_file].read((u8 *)data_ptr, num_bytes);
|
||||
|
||||
cur_offset += num_read;
|
||||
cur_file_offset += num_read;
|
||||
|
||||
return num_read;
|
||||
};
|
||||
|
||||
|
||||
if (archive_read(&header, sizeof(header)) != sizeof(header))
|
||||
if (!pkg_f.read(header))
|
||||
{
|
||||
LOG_ERROR(LOADER, "PKG file is too short!");
|
||||
return false;
|
||||
@@ -109,29 +51,8 @@ bool pkg_install(const fs::file& pkg_f, const std::string& dir, atomic_t<double>
|
||||
|
||||
if (header.pkg_size > pkg_f.size())
|
||||
{
|
||||
//Check if multi-files pkg
|
||||
if (pkg_filepath.length() < 7 || pkg_filepath.substr(pkg_filepath.length() - 7).compare("_00.pkg") != 0)
|
||||
{
|
||||
LOG_ERROR(LOADER, "PKG file size mismatch (pkg_size=0x%llx)", header.pkg_size);
|
||||
return false;
|
||||
}
|
||||
|
||||
std::string name_wo_number = pkg_filepath.substr(0, pkg_filepath.length() - 7);
|
||||
u64 cursize = pkg_f.size();
|
||||
while (cursize != header.pkg_size)
|
||||
{
|
||||
std::string archive_filename = fmt::format("%s_%2d.pkg", name_wo_number, filelist.size());
|
||||
|
||||
fs::file archive_file(archive_filename);
|
||||
if (!archive_file)
|
||||
{
|
||||
LOG_ERROR(LOADER, "Missing part of the multi-files pkg: %s", archive_filename);
|
||||
return false;
|
||||
}
|
||||
|
||||
cursize += archive_file.size();
|
||||
filelist.push_back(std::move(archive_file));
|
||||
}
|
||||
LOG_ERROR(LOADER, "PKG file size mismatch (pkg_size=0x%llx)", header.pkg_size);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (header.data_size + header.data_offset > header.pkg_size)
|
||||
@@ -143,7 +64,7 @@ bool pkg_install(const fs::file& pkg_f, const std::string& dir, atomic_t<double>
|
||||
be_t<u32> drm_type{0};
|
||||
be_t<u32> content_type{0};
|
||||
|
||||
archive_seek(header.pkg_info_off);
|
||||
pkg_f.seek(header.pkg_info_off);
|
||||
|
||||
for (u32 i = 0; i < header.pkg_info_num; i++)
|
||||
{
|
||||
@@ -153,7 +74,7 @@ bool pkg_install(const fs::file& pkg_f, const std::string& dir, atomic_t<double>
|
||||
be_t<u32> size;
|
||||
} packet;
|
||||
|
||||
archive_read(&packet, sizeof(packet));
|
||||
pkg_f.read(packet);
|
||||
|
||||
// TODO
|
||||
switch (+packet.id)
|
||||
@@ -162,7 +83,7 @@ bool pkg_install(const fs::file& pkg_f, const std::string& dir, atomic_t<double>
|
||||
{
|
||||
if (packet.size == sizeof(drm_type))
|
||||
{
|
||||
archive_read(&drm_type, sizeof(drm_type));
|
||||
pkg_f.read(drm_type);
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -172,7 +93,7 @@ bool pkg_install(const fs::file& pkg_f, const std::string& dir, atomic_t<double>
|
||||
{
|
||||
if (packet.size == sizeof(content_type))
|
||||
{
|
||||
archive_read(&content_type, sizeof(content_type));
|
||||
pkg_f.read(content_type);
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -180,7 +101,7 @@ bool pkg_install(const fs::file& pkg_f, const std::string& dir, atomic_t<double>
|
||||
}
|
||||
}
|
||||
|
||||
archive_seek(packet.size, fs::seek_cur);
|
||||
pkg_f.seek(packet.size, fs::seek_cur);
|
||||
}
|
||||
|
||||
// Allocate buffer with BUF_SIZE size or more if required
|
||||
@@ -189,10 +110,10 @@ bool pkg_install(const fs::file& pkg_f, const std::string& dir, atomic_t<double>
|
||||
// Define decryption subfunction (`psp` arg selects the key for specific block)
|
||||
auto decrypt = [&](u64 offset, u64 size, const uchar* key) -> u64
|
||||
{
|
||||
archive_seek(start_offset + header.data_offset + offset);
|
||||
pkg_f.seek(start_offset + header.data_offset + offset);
|
||||
|
||||
// Read the data and set available size
|
||||
const u64 read = archive_read(buf.get(), size);
|
||||
const u64 read = pkg_f.read(buf.get(), size);
|
||||
|
||||
// Get block count
|
||||
const u64 blocks = (read + 15) / 16;
|
||||
|
||||
@@ -57,4 +57,4 @@ struct PKGEntry
|
||||
be_t<u32> pad; // Padding (zeros)
|
||||
};
|
||||
|
||||
bool pkg_install(const class fs::file& pkg_f, const std::string& dir, atomic_t<double>&, const std::string& pkg_filepath);
|
||||
bool pkg_install(const class fs::file& pkg_f, const std::string& dir, atomic_t<double>&);
|
||||
|
||||
@@ -118,7 +118,7 @@ void aesecb128_encrypt(unsigned char *key, unsigned char *in, unsigned char *out
|
||||
|
||||
bool hmac_hash_compare(unsigned char *key, int key_len, unsigned char *in, int in_len, unsigned char *hash, int hash_len)
|
||||
{
|
||||
std::unique_ptr<u8[]> out(new u8[key_len]);
|
||||
std::unique_ptr<u8> out(new u8[key_len]);
|
||||
|
||||
sha1_hmac(key, key_len, in, in_len, out.get());
|
||||
|
||||
@@ -132,7 +132,7 @@ void hmac_hash_forge(unsigned char *key, int key_len, unsigned char *in, int in_
|
||||
|
||||
bool cmac_hash_compare(unsigned char *key, int key_len, unsigned char *in, int in_len, unsigned char *hash, int hash_len)
|
||||
{
|
||||
std::unique_ptr<u8[]> out(new u8[key_len]);
|
||||
std::unique_ptr<u8> out(new u8[key_len]);
|
||||
|
||||
aes_context ctx;
|
||||
aes_setkey_enc(&ctx, key, 128);
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
|
||||
#include "ALSAThread.h"
|
||||
|
||||
#ifdef HAVE_ALSA
|
||||
#ifdef __linux__
|
||||
|
||||
#include <alsa/asoundlib.h>
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
#ifdef HAVE_ALSA
|
||||
#ifdef __linux__
|
||||
|
||||
#include "Emu/Audio/AudioThread.h"
|
||||
|
||||
|
||||
@@ -1,60 +0,0 @@
|
||||
#include "Emu/System.h"
|
||||
#include "PulseThread.h"
|
||||
|
||||
#ifdef HAVE_PULSE
|
||||
|
||||
#include <pulse/simple.h>
|
||||
#include <pulse/error.h>
|
||||
|
||||
PulseThread::PulseThread()
|
||||
{
|
||||
}
|
||||
|
||||
PulseThread::~PulseThread()
|
||||
{
|
||||
this->Close();
|
||||
}
|
||||
|
||||
void PulseThread::Play()
|
||||
{
|
||||
}
|
||||
|
||||
void PulseThread::Close()
|
||||
{
|
||||
if(this->connection) {
|
||||
pa_simple_free(this->connection);
|
||||
this->connection = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
void PulseThread::Stop()
|
||||
{
|
||||
}
|
||||
|
||||
void PulseThread::Open(const void* src, int size)
|
||||
{
|
||||
pa_sample_spec ss;
|
||||
ss.format = g_cfg.audio.convert_to_u16 ? PA_SAMPLE_S16LE : PA_SAMPLE_FLOAT32LE;
|
||||
ss.channels = g_cfg.audio.downmix_to_2ch ? 2 : 8;
|
||||
ss.rate = 48000;
|
||||
|
||||
int err;
|
||||
this->connection = pa_simple_new(NULL, "RPCS3", PA_STREAM_PLAYBACK, NULL, "Game", &ss, NULL, NULL, &err);
|
||||
if(!this->connection) {
|
||||
fprintf(stderr, "PulseAudio: Failed to initialize audio: %s\n", pa_strerror(err));
|
||||
}
|
||||
|
||||
this->AddData(src, size);
|
||||
}
|
||||
|
||||
void PulseThread::AddData(const void* src, int size)
|
||||
{
|
||||
if(this->connection) {
|
||||
int err;
|
||||
if(pa_simple_write(this->connection, src, size, &err) < 0) {
|
||||
fprintf(stderr, "PulseAudio: Failed to write audio stream: %s\n", pa_strerror(err));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -1,23 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#ifdef HAVE_PULSE
|
||||
#include <pulse/simple.h>
|
||||
#include "Emu/Audio/AudioThread.h"
|
||||
|
||||
class PulseThread : public AudioThread
|
||||
{
|
||||
public:
|
||||
PulseThread();
|
||||
virtual ~PulseThread() override;
|
||||
|
||||
virtual void Play() override;
|
||||
virtual void Open(const void* src, int size) override;
|
||||
virtual void Close() override;
|
||||
virtual void Stop() override;
|
||||
virtual void AddData(const void* src, int size) override;
|
||||
|
||||
private:
|
||||
pa_simple *connection = nullptr;
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -195,12 +195,6 @@ s32 cellAtracGetInternalErrorInfo(vm::ptr<CellAtracHandle> pHandle, vm::ptr<s32>
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
s32 cellAtracGetSamplingRate()
|
||||
{
|
||||
UNIMPLEMENTED_FUNC(cellAtrac);
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
DECLARE(ppu_module_manager::cellAtrac)("cellAtrac", []()
|
||||
{
|
||||
REG_FUNC(cellAtrac, cellAtracSetDataAndGetMemSize);
|
||||
@@ -233,6 +227,4 @@ DECLARE(ppu_module_manager::cellAtrac)("cellAtrac", []()
|
||||
REG_FUNC(cellAtrac, cellAtracResetPlayPosition);
|
||||
|
||||
REG_FUNC(cellAtrac, cellAtracGetInternalErrorInfo);
|
||||
|
||||
REG_FUNC(cellAtrac, cellAtracGetSamplingRate);
|
||||
});
|
||||
|
||||
@@ -203,12 +203,6 @@ s32 cellAtracMultiGetInternalErrorInfo(vm::ptr<CellAtracMultiHandle> pHandle, vm
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
s32 cellAtracMultiGetSamplingRate()
|
||||
{
|
||||
UNIMPLEMENTED_FUNC(cellAtracMulti);
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
DECLARE(ppu_module_manager::cellAtracMulti)("cellAtracMulti", []()
|
||||
{
|
||||
REG_FUNC(cellAtracMulti, cellAtracMultiSetDataAndGetMemSize);
|
||||
@@ -242,6 +236,4 @@ DECLARE(ppu_module_manager::cellAtracMulti)("cellAtracMulti", []()
|
||||
REG_FUNC(cellAtracMulti, cellAtracMultiResetPlayPosition);
|
||||
|
||||
REG_FUNC(cellAtracMulti, cellAtracMultiGetInternalErrorInfo);
|
||||
|
||||
REG_FUNC(cellAtracMulti, cellAtracMultiGetSamplingRate);
|
||||
});
|
||||
|
||||
@@ -11,39 +11,39 @@ logs::channel cellAvconfExt("cellAvconfExt");
|
||||
|
||||
vm::gvar<f32> g_gamma; // TODO
|
||||
|
||||
s32 cellAudioOutUnregisterDevice(u32 deviceNumber)
|
||||
s32 cellAudioOutUnregisterDevice()
|
||||
{
|
||||
cellAvconfExt.todo("cellAudioOutUnregisterDevice(deviceNumber=0x%x)", deviceNumber);
|
||||
UNIMPLEMENTED_FUNC(cellAvconfExt);
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
s32 cellAudioOutGetDeviceInfo2(u32 deviceNumber, u32 deviceIndex, vm::ptr<CellAudioOutDeviceInfo2> info)
|
||||
s32 cellAudioOutGetDeviceInfo2()
|
||||
{
|
||||
cellAvconfExt.todo("cellAudioOutGetDeviceInfo2(deviceNumber=0x%x, deviceIndex=0x%x, info=*0x%x)", deviceNumber, deviceIndex, info);
|
||||
UNIMPLEMENTED_FUNC(cellAvconfExt);
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
s32 cellVideoOutSetXVColor()
|
||||
{
|
||||
UNIMPLEMENTED_FUNC(cellAvconfExt);
|
||||
UNIMPLEMENTED_FUNC(cellAvconfExt);
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
s32 cellVideoOutSetupDisplay()
|
||||
{
|
||||
UNIMPLEMENTED_FUNC(cellAvconfExt);
|
||||
UNIMPLEMENTED_FUNC(cellAvconfExt);
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
s32 cellAudioInGetDeviceInfo(u32 deviceNumber, u32 deviceIndex, vm::ptr<CellAudioInDeviceInfo> info)
|
||||
s32 cellAudioInGetDeviceInfo()
|
||||
{
|
||||
cellAvconfExt.todo("cellAudioInGetDeviceInfo(deviceNumber=0x%x, deviceIndex=0x%x, info=*0x%x)", deviceNumber, deviceIndex, info);
|
||||
UNIMPLEMENTED_FUNC(cellAvconfExt);
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
s32 cellVideoOutConvertCursorColor(u32 videoOut, s32 displaybuffer_format, f32 gamma, s32 source_buffer_format, vm::ptr<void> src_addr, vm::ptr<u32> dest_addr, s32 num)
|
||||
s32 cellVideoOutConvertCursorColor()
|
||||
{
|
||||
cellAvconfExt.todo("cellVideoOutConvertCursorColor(videoOut=%d, displaybuffer_format=0x%x, gamma=0x%x, source_buffer_format=0x%x, src_addr=*0x%x, dest_addr=*0x%x, num=0x%x)", videoOut, displaybuffer_format, gamma, source_buffer_format, src_addr, dest_addr, num);
|
||||
UNIMPLEMENTED_FUNC(cellAvconfExt);
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
@@ -61,16 +61,16 @@ s32 cellVideoOutGetGamma(u32 videoOut, vm::ptr<f32> gamma)
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
s32 cellAudioInGetAvailableDeviceInfo(u32 count, vm::ptr<CellAudioInDeviceInfo> info)
|
||||
s32 cellAudioInGetAvailableDeviceInfo()
|
||||
{
|
||||
cellAvconfExt.todo("cellAudioInGetAvailableDeviceInfo(count=0x%x, info=*0x%x)", count, info);
|
||||
return 0; // number of available devices
|
||||
UNIMPLEMENTED_FUNC(cellAvconfExt);
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
s32 cellAudioOutGetAvailableDeviceInfo(u32 count, vm::ptr<CellAudioOutDeviceInfo2> info)
|
||||
s32 cellAudioOutGetAvailableDeviceInfo()
|
||||
{
|
||||
cellAvconfExt.todo("cellAudioOutGetAvailableDeviceInfo(count=0x%x, info=*0x%x)", count, info);
|
||||
return 0; // number of available devices
|
||||
UNIMPLEMENTED_FUNC(cellAvconfExt);
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
s32 cellVideoOutSetGamma(u32 videoOut, f32 gamma)
|
||||
@@ -92,37 +92,37 @@ s32 cellVideoOutSetGamma(u32 videoOut, f32 gamma)
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
s32 cellAudioOutRegisterDevice(u64 deviceType, vm::cptr<char> name, vm::ptr<CellAudioOutRegistrationOption> option, vm::ptr<CellAudioOutDeviceConfiguration> config)
|
||||
s32 cellAudioOutRegisterDevice()
|
||||
{
|
||||
cellAvconfExt.todo("cellAudioOutRegisterDevice(deviceType=0x%llx, name=%s, option=*0x%x, config=*0x%x)", deviceType, name, option, config);
|
||||
return 0; // device number
|
||||
}
|
||||
|
||||
s32 cellAudioOutSetDeviceMode(u32 deviceMode)
|
||||
{
|
||||
cellAvconfExt.todo("cellAudioOutSetDeviceMode(deviceMode=0x%x)", deviceMode);
|
||||
UNIMPLEMENTED_FUNC(cellAvconfExt);
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
s32 cellAudioInSetDeviceMode(u32 deviceMode)
|
||||
s32 cellAudioOutSetDeviceMode()
|
||||
{
|
||||
cellAvconfExt.todo("cellAudioInSetDeviceMode(deviceMode=0x%x)", deviceMode);
|
||||
UNIMPLEMENTED_FUNC(cellAvconfExt);
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
s32 cellAudioInRegisterDevice(u64 deviceType, vm::cptr<char> name, vm::ptr<CellAudioInRegistrationOption> option, vm::ptr<CellAudioInDeviceConfiguration> config)
|
||||
s32 cellAudioInSetDeviceMode()
|
||||
{
|
||||
cellAvconfExt.todo("cellAudioInRegisterDevice(deviceType=0x%llx, name=%s, option=*0x%x, config=*0x%x)", deviceType, name, option, config);
|
||||
return 0; // device number
|
||||
}
|
||||
|
||||
s32 cellAudioInUnregisterDevice(u32 deviceNumber)
|
||||
{
|
||||
cellAvconfExt.todo("cellAudioInUnregisterDevice(deviceNumber=0x%x)", deviceNumber);
|
||||
UNIMPLEMENTED_FUNC(cellAvconfExt);
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
s32 cellVideoOutGetScreenSize(u32 videoOut, vm::ptr<f32> screenSize)
|
||||
s32 cellAudioInRegisterDevice()
|
||||
{
|
||||
UNIMPLEMENTED_FUNC(cellAvconfExt);
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
s32 cellAudioInUnregisterDevice()
|
||||
{
|
||||
UNIMPLEMENTED_FUNC(cellAvconfExt);
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
s32 cellVideoOutGetScreenSize(u32 videoOut, vm::ptr<float> screenSize)
|
||||
{
|
||||
cellAvconfExt.warning("cellVideoOutGetScreenSize(videoOut=%d, screenSize=*0x%x)", videoOut, screenSize);
|
||||
|
||||
@@ -143,12 +143,6 @@ s32 cellVideoOutGetScreenSize(u32 videoOut, vm::ptr<f32> screenSize)
|
||||
return CELL_VIDEO_OUT_ERROR_VALUE_IS_NOT_SET;
|
||||
}
|
||||
|
||||
s32 cellVideoOutSetCopyControl(u32 videoOut, u32 control)
|
||||
{
|
||||
cellAvconfExt.todo("cellVideoOutSetCopyControl(videoOut=%d, control=0x%x)", videoOut, control);
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
|
||||
DECLARE(ppu_module_manager::cellAvconfExt)("cellSysutilAvconfExt", []()
|
||||
{
|
||||
@@ -174,5 +168,4 @@ DECLARE(ppu_module_manager::cellAvconfExt)("cellSysutilAvconfExt", []()
|
||||
REG_FUNC(cellSysutilAvconfExt, cellAudioInRegisterDevice);
|
||||
REG_FUNC(cellSysutilAvconfExt, cellAudioInUnregisterDevice);
|
||||
REG_FUNC(cellSysutilAvconfExt, cellVideoOutGetScreenSize);
|
||||
REG_FUNC(cellSysutilAvconfExt, cellVideoOutSetCopyControl);
|
||||
});
|
||||
|
||||
@@ -262,7 +262,7 @@ error_code cellGameBootCheck(vm::ptr<u32> type, vm::ptr<u32> attributes, vm::ptr
|
||||
return CELL_GAME_ERROR_BUSY;
|
||||
}
|
||||
}
|
||||
else if (category == "AP" || category == "AV" || category == "HG" || category == "AT" || category == "AM" || category == "SF")
|
||||
else if (category == "AP" || category == "AV" || category == "HG")
|
||||
{
|
||||
*type = CELL_GAME_GAMETYPE_HDD;
|
||||
*attributes = 0; // TODO
|
||||
@@ -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, false))
|
||||
if (fs::rename(prm->temp, vdir))
|
||||
{
|
||||
cellGame.success("cellGameContentPermit(): directory '%s' has been created", dir);
|
||||
}
|
||||
|
||||
@@ -484,7 +484,7 @@ s32 cellGcmSetDisplayBuffer(u8 id, u32 offset, u32 pitch, u32 width, u32 height)
|
||||
m_config->gcm_buffers[id].width = width;
|
||||
m_config->gcm_buffers[id].height = height;
|
||||
|
||||
if (id + 1u > render->display_buffers_count)
|
||||
if (id + 1 > render->display_buffers_count)
|
||||
{
|
||||
render->display_buffers_count = id + 1;
|
||||
}
|
||||
|
||||
@@ -65,12 +65,6 @@ s32 cellHttpSetProxy()
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
s32 cellHttpGetCookie()
|
||||
{
|
||||
UNIMPLEMENTED_FUNC(cellHttp);
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
s32 cellHttpGetProxy()
|
||||
{
|
||||
UNIMPLEMENTED_FUNC(cellHttp);
|
||||
@@ -707,7 +701,6 @@ DECLARE(ppu_module_manager::cellHttp)("cellHttp", []()
|
||||
REG_FUNC(cellHttp, cellHttpsInit);
|
||||
REG_FUNC(cellHttp, cellHttpsEnd);
|
||||
REG_FUNC(cellHttp, cellHttpSetProxy);
|
||||
REG_FUNC(cellHttp, cellHttpGetCookie);
|
||||
REG_FUNC(cellHttp, cellHttpGetProxy);
|
||||
|
||||
REG_FUNC(cellHttp, cellHttpInitCookie);
|
||||
|
||||
@@ -161,7 +161,7 @@ bool _L10nCodeParse(s32 code, HostCode& retCode)
|
||||
#ifdef _MSC_VER
|
||||
|
||||
// Use code page to transform std::string to std::wstring.
|
||||
s32 _OEM2Wide(HostCode oem_code, const std::string& src, std::wstring& dst)
|
||||
s32 _OEM2Wide(HostCode oem_code, const std::string src, std::wstring& dst)
|
||||
{
|
||||
//Such length returned should include the '\0' character.
|
||||
s32 length = MultiByteToWideChar(oem_code, 0, src.c_str(), -1, NULL, 0);
|
||||
@@ -178,7 +178,7 @@ s32 _OEM2Wide(HostCode oem_code, const std::string& src, std::wstring& dst)
|
||||
}
|
||||
|
||||
// Use Code page to transform std::wstring to std::string.
|
||||
s32 _Wide2OEM(HostCode oem_code, const std::wstring& src, std::string& dst)
|
||||
s32 _Wide2OEM(HostCode oem_code, const std::wstring src, std::string& dst)
|
||||
{
|
||||
//Such length returned should include the '\0' character.
|
||||
s32 length = WideCharToMultiByte(oem_code, 0, src.c_str(), -1, NULL, 0, NULL, NULL);
|
||||
@@ -195,7 +195,7 @@ s32 _Wide2OEM(HostCode oem_code, const std::wstring& src, std::string& dst)
|
||||
}
|
||||
|
||||
// Convert Codepage to Codepage (all char*)
|
||||
std::string _OemToOem(HostCode src_code, HostCode dst_code, const std::string& str)
|
||||
std::string _OemToOem(HostCode src_code, HostCode dst_code, const std::string str)
|
||||
{
|
||||
std::wstring wide; std::string result;
|
||||
_OEM2Wide(src_code, str, wide);
|
||||
|
||||
@@ -83,7 +83,7 @@ public:
|
||||
|
||||
virtual ~MsgDialogBase();
|
||||
virtual void Create(const std::string& msg) = 0;
|
||||
virtual void CreateOsk(const std::string& msg, char16_t* osk_text, u32 charlimit) = 0;
|
||||
virtual void CreateOsk(const std::string& msg, char16_t* osk_text) = 0;
|
||||
virtual void ProgressBarSetMsg(u32 progressBarIndex, const std::string& msg) = 0;
|
||||
virtual void ProgressBarReset(u32 progressBarIndex) = 0;
|
||||
virtual void ProgressBarInc(u32 progressBarIndex, u32 delta) = 0;
|
||||
|
||||
@@ -202,54 +202,6 @@ error_code cellNetCtlGetNatInfo(vm::ptr<CellNetCtlNatInfo> natInfo)
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
error_code cellNetCtlAddHandlerGameInt()
|
||||
{
|
||||
cellNetCtl.todo("cellNetCtlAddHandlerGameInt()");
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
error_code cellNetCtlConnectGameInt()
|
||||
{
|
||||
cellNetCtl.todo("cellNetCtlConnectGameInt()");
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
error_code cellNetCtlDelHandlerGameInt()
|
||||
{
|
||||
cellNetCtl.todo("cellNetCtlDelHandlerGameInt()");
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
error_code cellNetCtlDisconnectGameInt()
|
||||
{
|
||||
cellNetCtl.todo("cellNetCtlDisconnectGameInt()");
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
error_code cellNetCtlGetInfoGameInt()
|
||||
{
|
||||
cellNetCtl.todo("cellNetCtlGetInfoGameInt()");
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
error_code cellNetCtlGetScanInfoGameInt()
|
||||
{
|
||||
cellNetCtl.todo("cellNetCtlGetScanInfoGameInt()");
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
error_code cellNetCtlGetStateGameInt()
|
||||
{
|
||||
cellNetCtl.todo("cellNetCtlGetStateGameInt()");
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
error_code cellNetCtlScanGameInt()
|
||||
{
|
||||
cellNetCtl.todo("cellNetCtlScanGameInt()");
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
error_code cellGameUpdateInit()
|
||||
{
|
||||
cellNetCtl.todo("cellGameUpdateInit()");
|
||||
@@ -322,15 +274,6 @@ DECLARE(ppu_module_manager::cellNetCtl)("cellNetCtl", []()
|
||||
|
||||
REG_FUNC(cellNetCtl, cellNetCtlGetNatInfo);
|
||||
|
||||
REG_FUNC(cellNetCtl, cellNetCtlAddHandlerGameInt);
|
||||
REG_FUNC(cellNetCtl, cellNetCtlConnectGameInt);
|
||||
REG_FUNC(cellNetCtl, cellNetCtlDelHandlerGameInt);
|
||||
REG_FUNC(cellNetCtl, cellNetCtlDisconnectGameInt);
|
||||
REG_FUNC(cellNetCtl, cellNetCtlGetInfoGameInt);
|
||||
REG_FUNC(cellNetCtl, cellNetCtlGetScanInfoGameInt);
|
||||
REG_FUNC(cellNetCtl, cellNetCtlGetStateGameInt);
|
||||
REG_FUNC(cellNetCtl, cellNetCtlScanGameInt);
|
||||
|
||||
REG_FUNC(cellNetCtl, cellGameUpdateInit);
|
||||
REG_FUNC(cellNetCtl, cellGameUpdateTerm);
|
||||
|
||||
|
||||
@@ -14,21 +14,14 @@ s32 cellOskDialogLoadAsync(u32 container, vm::ptr<CellOskDialogParam> dialogPara
|
||||
{
|
||||
cellOskDialog.warning("cellOskDialogLoadAsync(container=0x%x, dialogParam=*0x%x, inputFieldInfo=*0x%x)", container, dialogParam, inputFieldInfo);
|
||||
|
||||
u32 maxLength = (inputFieldInfo->limit_length >= 512) ? 511 : (u32)inputFieldInfo->limit_length;
|
||||
|
||||
std::memset(s_osk_text, 0, sizeof(s_osk_text));
|
||||
|
||||
if (inputFieldInfo->init_text.addr() != 0)
|
||||
for (u32 i = 0; (i < maxLength) && (inputFieldInfo->init_text[i] != 0); i++)
|
||||
s_osk_text[i] = inputFieldInfo->init_text[i];
|
||||
|
||||
const auto osk = Emu.GetCallbacks().get_msg_dialog();
|
||||
bool result = false;
|
||||
|
||||
osk->on_close = [&](s32 status)
|
||||
{
|
||||
if (status != CELL_MSGDIALOG_BUTTON_OK) sysutil_send_system_cmd(CELL_SYSUTIL_OSKDIALOG_INPUT_CANCELED, 0);
|
||||
sysutil_send_system_cmd(CELL_SYSUTIL_OSKDIALOG_FINISHED, 0);
|
||||
sysutil_send_system_cmd(status == CELL_MSGDIALOG_BUTTON_OK ? CELL_SYSUTIL_OSKDIALOG_FINISHED : CELL_SYSUTIL_OSKDIALOG_INPUT_CANCELED, 0);
|
||||
result = true;
|
||||
};
|
||||
|
||||
@@ -39,7 +32,7 @@ s32 cellOskDialogLoadAsync(u32 container, vm::ptr<CellOskDialogParam> dialogPara
|
||||
|
||||
Emu.CallAfter([&]()
|
||||
{
|
||||
osk->CreateOsk("On Screen Keyboard", s_osk_text, maxLength);
|
||||
osk->CreateOsk("On Screen Keyboard", s_osk_text);
|
||||
});
|
||||
|
||||
sysutil_send_system_cmd(CELL_SYSUTIL_OSKDIALOG_LOADED, 0);
|
||||
|
||||
@@ -248,7 +248,7 @@ s32 cellPadGetData(u32 port_no, vm::ptr<CellPadData> data)
|
||||
}
|
||||
data->button[0] = 0x0; // always 0
|
||||
// bits 15-8 reserved, 7-4 = 0x7, 3-0: data->len/2;
|
||||
data->button[1] = (0x7 << 4) | std::min(data->len / 2, 15);
|
||||
data->button[1] = (0x7 << 4) | std::min(data->len / 2, 15) & 0xF;
|
||||
//lets still send new data anyway, not sure whats expected still
|
||||
data->button[CELL_PAD_BTN_OFFSET_DIGITAL1] = pad.m_digital_1;
|
||||
data->button[CELL_PAD_BTN_OFFSET_DIGITAL2] = pad.m_digital_2;
|
||||
|
||||
@@ -118,12 +118,6 @@ s32 cellSearchGetContentInfoDeveloperData()
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
s32 cellSearchGetContentInfoSharable()
|
||||
{
|
||||
UNIMPLEMENTED_FUNC(cellSearch);
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
s32 cellSearchCancel()
|
||||
{
|
||||
UNIMPLEMENTED_FUNC(cellSearch);
|
||||
@@ -156,7 +150,6 @@ DECLARE(ppu_module_manager::cellSearch)("cellSearchUtility", []()
|
||||
REG_FUNC(cellSearchUtility, cellSearchGetContentInfoPathMovieThumb);
|
||||
REG_FUNC(cellSearchUtility, cellSearchPrepareFile);
|
||||
REG_FUNC(cellSearchUtility, cellSearchGetContentInfoDeveloperData);
|
||||
REG_FUNC(cellSearchUtility, cellSearchGetContentInfoSharable);
|
||||
REG_FUNC(cellSearchUtility, cellSearchCancel);
|
||||
REG_FUNC(cellSearchUtility, cellSearchEnd);
|
||||
});
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
|
||||
logs::channel cellSpurs("cellSpurs");
|
||||
|
||||
error_code sys_spu_image_close(vm::ptr<sys_spu_image> img);
|
||||
s32 sys_spu_image_close(vm::ptr<sys_spu_image> img);
|
||||
|
||||
// TODO
|
||||
struct cell_error_t
|
||||
|
||||
@@ -585,36 +585,6 @@ s32 _ZN8cxmlutil7GetFileERKN4cxml7ElementEPKcPNS0_4FileE()
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
s32 _ZN16sysutil_cxmlutil11FixedMemory3EndEi()
|
||||
{
|
||||
UNIMPLEMENTED_FUNC(cellSysutil);
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
s32 _ZN16sysutil_cxmlutil11FixedMemory5BeginEi()
|
||||
{
|
||||
UNIMPLEMENTED_FUNC(cellSysutil);
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
s32 _ZN16sysutil_cxmlutil11FixedMemory8AllocateEN4cxml14AllocationTypeEPvS3_jPS3_Pj()
|
||||
{
|
||||
UNIMPLEMENTED_FUNC(cellSysutil);
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
s32 _ZN16sysutil_cxmlutil12PacketWriter5WriteEPKvjPv()
|
||||
{
|
||||
UNIMPLEMENTED_FUNC(cellSysutil);
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
s32 _ZN16sysutil_cxmlutil12PacketWriterC1EiiRN4cxml8DocumentE()
|
||||
{
|
||||
UNIMPLEMENTED_FUNC(cellSysutil);
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
s32 cellSysutil_E1EC7B6A(vm::ptr<u32> unk)
|
||||
{
|
||||
cellSysutil.todo("cellSysutil_E1EC7B6A(unk=*0x%x)", unk);
|
||||
@@ -705,12 +675,6 @@ DECLARE(ppu_module_manager::cellSysutil)("cellSysutil", []()
|
||||
REG_FUNC(cellSysutil, _ZN8cxmlutil16CheckElementNameERKN4cxml7ElementEPKc);
|
||||
REG_FUNC(cellSysutil, _ZN8cxmlutil16FindChildElementERKN4cxml7ElementEPKcS5_S5_);
|
||||
REG_FUNC(cellSysutil, _ZN8cxmlutil7GetFileERKN4cxml7ElementEPKcPNS0_4FileE);
|
||||
|
||||
REG_FUNC(cellSysutil, _ZN16sysutil_cxmlutil11FixedMemory3EndEi);
|
||||
REG_FUNC(cellSysutil, _ZN16sysutil_cxmlutil11FixedMemory5BeginEi);
|
||||
REG_FUNC(cellSysutil, _ZN16sysutil_cxmlutil11FixedMemory8AllocateEN4cxml14AllocationTypeEPvS3_jPS3_Pj);
|
||||
REG_FUNC(cellSysutil, _ZN16sysutil_cxmlutil12PacketWriter5WriteEPKvjPv);
|
||||
REG_FUNC(cellSysutil, _ZN16sysutil_cxmlutil12PacketWriterC1EiiRN4cxml8DocumentE);
|
||||
|
||||
|
||||
REG_FNID(cellSysutil, 0xE1EC7B6A, cellSysutil_E1EC7B6A);
|
||||
});
|
||||
|
||||
@@ -7,181 +7,129 @@
|
||||
|
||||
logs::channel cellSysutilAvc2("cellSysutilAvc2");
|
||||
|
||||
template<>
|
||||
void fmt_class_string<CellSysutilAvc2Error>::format(std::string& out, u64 arg)
|
||||
s32 cellSysutilAvc2GetPlayerInfo()
|
||||
{
|
||||
format_enum(out, arg, [](auto error)
|
||||
{
|
||||
switch (error)
|
||||
{
|
||||
STR_CASE(CELL_AVC2_ERROR_UNKNOWN);
|
||||
STR_CASE(CELL_AVC2_ERROR_NOT_SUPPORTED);
|
||||
STR_CASE(CELL_AVC2_ERROR_NOT_INITIALIZED);
|
||||
STR_CASE(CELL_AVC2_ERROR_ALREADY_INITIALIZED);
|
||||
STR_CASE(CELL_AVC2_ERROR_INVALID_ARGUMENT);
|
||||
STR_CASE(CELL_AVC2_ERROR_OUT_OF_MEMORY);
|
||||
STR_CASE(CELL_AVC2_ERROR_ERROR_BAD_ID);
|
||||
STR_CASE(CELL_AVC2_ERROR_INVALID_STATUS);
|
||||
STR_CASE(CELL_AVC2_ERROR_TIMEOUT);
|
||||
STR_CASE(CELL_AVC2_ERROR_NO_SESSION);
|
||||
STR_CASE(CELL_AVC2_ERROR_WINDOW_ALREADY_EXISTS);
|
||||
STR_CASE(CELL_AVC2_ERROR_TOO_MANY_WINDOWS);
|
||||
STR_CASE(CELL_AVC2_ERROR_TOO_MANY_PEER_WINDOWS);
|
||||
STR_CASE(CELL_AVC2_ERROR_WINDOW_NOT_FOUND);
|
||||
}
|
||||
|
||||
return unknown;
|
||||
});
|
||||
fmt::throw_exception("Unimplemented" HERE);
|
||||
}
|
||||
|
||||
error_code cellSysutilAvc2GetPlayerInfo(vm::cptr<SceNpMatching2RoomMemberId> player_id, vm::ptr<CellSysutilAvc2PlayerInfo> player_info)
|
||||
s32 cellSysutilAvc2JoinChat()
|
||||
{
|
||||
cellSysutilAvc2.todo("cellSysutilAvc2GetPlayerInfo(player_id=*0x%x, player_info=*0x%x)", player_id, player_info);
|
||||
return CELL_OK;
|
||||
fmt::throw_exception("Unimplemented" HERE);
|
||||
}
|
||||
|
||||
error_code cellSysutilAvc2JoinChat(vm::cptr<SceNpMatching2RoomId> room_id)
|
||||
s32 cellSysutilAvc2StopStreaming()
|
||||
{
|
||||
cellSysutilAvc2.todo("cellSysutilAvc2JoinChat(room_id=*0x%x)", room_id);
|
||||
return CELL_OK;
|
||||
fmt::throw_exception("Unimplemented" HERE);
|
||||
}
|
||||
|
||||
error_code cellSysutilAvc2StopStreaming()
|
||||
s32 cellSysutilAvc2ChangeVideoResolution()
|
||||
{
|
||||
cellSysutilAvc2.todo("cellSysutilAvc2StopStreaming()");
|
||||
return CELL_OK;
|
||||
fmt::throw_exception("Unimplemented" HERE);
|
||||
}
|
||||
|
||||
error_code cellSysutilAvc2ChangeVideoResolution(CellSysutilAvc2VideoResolution resolution)
|
||||
s32 cellSysutilAvc2ShowScreen()
|
||||
{
|
||||
cellSysutilAvc2.todo("cellSysutilAvc2ChangeVideoResolution(resolution=0x%x)", resolution);
|
||||
return CELL_OK;
|
||||
fmt::throw_exception("Unimplemented" HERE);
|
||||
}
|
||||
|
||||
error_code cellSysutilAvc2ShowScreen()
|
||||
s32 cellSysutilAvc2GetVideoMuting()
|
||||
{
|
||||
cellSysutilAvc2.todo("cellSysutilAvc2ShowScreen()");
|
||||
return CELL_OK;
|
||||
fmt::throw_exception("Unimplemented" HERE);
|
||||
}
|
||||
|
||||
error_code cellSysutilAvc2GetVideoMuting(vm::ptr<u8> muting)
|
||||
s32 cellSysutilAvc2GetWindowAttribute()
|
||||
{
|
||||
cellSysutilAvc2.todo("cellSysutilAvc2GetVideoMuting(muting=*0x%x)", muting);
|
||||
|
||||
*muting = 1;
|
||||
|
||||
return CELL_OK;
|
||||
fmt::throw_exception("Unimplemented" HERE);
|
||||
}
|
||||
|
||||
error_code cellSysutilAvc2GetWindowAttribute(SceNpMatching2RoomMemberId member_id, vm::ptr<CellSysutilAvc2WindowAttribute> attr)
|
||||
s32 cellSysutilAvc2StopStreaming2()
|
||||
{
|
||||
cellSysutilAvc2.todo("cellSysutilAvc2GetWindowAttribute(member_id=0x%x, attr=*0x%x)", member_id, attr);
|
||||
return CELL_OK;
|
||||
fmt::throw_exception("Unimplemented" HERE);
|
||||
}
|
||||
|
||||
error_code cellSysutilAvc2StopStreaming2(CellSysutilAvc2MediaType mediaType)
|
||||
s32 cellSysutilAvc2SetVoiceMuting()
|
||||
{
|
||||
cellSysutilAvc2.todo("cellSysutilAvc2StopStreaming2(mediaType=0x%x)", mediaType);
|
||||
return CELL_OK;
|
||||
fmt::throw_exception("Unimplemented" HERE);
|
||||
}
|
||||
|
||||
error_code cellSysutilAvc2SetVoiceMuting(u8 muting)
|
||||
{
|
||||
cellSysutilAvc2.todo("cellSysutilAvc2SetVoiceMuting(muting=0x%x)", muting);
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
error_code cellSysutilAvc2StartVoiceDetection()
|
||||
s32 cellSysutilAvc2StartVoiceDetection()
|
||||
{
|
||||
cellSysutilAvc2.todo("cellSysutilAvc2StartVoiceDetection()");
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
error_code cellSysutilAvc2UnloadAsync()
|
||||
s32 cellSysutilAvc2UnloadAsync()
|
||||
{
|
||||
cellSysutilAvc2.todo("cellSysutilAvc2UnloadAsync()");
|
||||
return CELL_OK;
|
||||
fmt::throw_exception("Unimplemented" HERE);
|
||||
}
|
||||
|
||||
error_code cellSysutilAvc2StopVoiceDetection()
|
||||
s32 cellSysutilAvc2StopVoiceDetection()
|
||||
{
|
||||
cellSysutilAvc2.todo("cellSysutilAvc2StopVoiceDetection()");
|
||||
return CELL_OK;
|
||||
fmt::throw_exception("Unimplemented" HERE);
|
||||
}
|
||||
|
||||
error_code cellSysutilAvc2GetAttribute(vm::ptr<CellSysutilAvc2Attribute> attr)
|
||||
s32 cellSysutilAvc2GetAttribute()
|
||||
{
|
||||
cellSysutilAvc2.todo("cellSysutilAvc2GetAttribute(attr=*0x%x)", attr);
|
||||
return CELL_OK;
|
||||
fmt::throw_exception("Unimplemented" HERE);
|
||||
}
|
||||
|
||||
error_code cellSysutilAvc2LoadAsync(SceNpMatching2ContextId ctx_id, u32 container, vm::ptr<CellSysutilAvc2Callback> callback_func, vm::ptr<void> user_data, vm::cptr<CellSysutilAvc2InitParam> init_param)
|
||||
s32 cellSysutilAvc2LoadAsync()
|
||||
{
|
||||
cellSysutilAvc2.todo("cellSysutilAvc2LoadAsync(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);
|
||||
}
|
||||
|
||||
error_code cellSysutilAvc2SetSpeakerVolumeLevel(f32 level)
|
||||
s32 cellSysutilAvc2SetSpeakerVolumeLevel()
|
||||
{
|
||||
cellSysutilAvc2.todo("cellSysutilAvc2SetSpeakerVolumeLevel(level=0x%x)", level);
|
||||
return CELL_OK;
|
||||
fmt::throw_exception("Unimplemented" HERE);
|
||||
}
|
||||
|
||||
error_code cellSysutilAvc2SetWindowString(SceNpMatching2RoomMemberId member_id, vm::cptr<char> string)
|
||||
s32 cellSysutilAvc2SetWindowString()
|
||||
{
|
||||
cellSysutilAvc2.todo("cellSysutilAvc2SetWindowString(member_id=0x%x, string=%s)", member_id, string);
|
||||
return CELL_OK;
|
||||
fmt::throw_exception("Unimplemented" HERE);
|
||||
}
|
||||
|
||||
error_code cellSysutilAvc2EstimateMemoryContainerSize(vm::cptr<CellSysutilAvc2InitParam> initparam, vm::ptr<u32> size)
|
||||
s32 cellSysutilAvc2EstimateMemoryContainerSize(vm::cptr<CellSysutilAvc2InitParam> initparam, vm::ptr<u32> size)
|
||||
{
|
||||
cellSysutilAvc2.todo("cellSysutilAvc2EstimateMemoryContainerSize(initparam=*0x%x, size=*0x%x)", initparam, size);
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
error_code cellSysutilAvc2SetVideoMuting(u8 muting)
|
||||
s32 cellSysutilAvc2SetVideoMuting()
|
||||
{
|
||||
cellSysutilAvc2.todo("cellSysutilAvc2SetVideoMuting(muting=0x%x)", muting);
|
||||
return CELL_OK;
|
||||
fmt::throw_exception("Unimplemented" HERE);
|
||||
}
|
||||
|
||||
error_code cellSysutilAvc2SetPlayerVoiceMuting(SceNpMatching2RoomMemberId member_id, u8 muting)
|
||||
s32 cellSysutilAvc2SetPlayerVoiceMuting()
|
||||
{
|
||||
cellSysutilAvc2.todo("cellSysutilAvc2SetPlayerVoiceMuting(member_id=0x%x, muting=0x%x)", member_id, muting);
|
||||
return CELL_OK;
|
||||
fmt::throw_exception("Unimplemented" HERE);
|
||||
}
|
||||
|
||||
error_code cellSysutilAvc2SetStreamingTarget()
|
||||
s32 cellSysutilAvc2SetStreamingTarget()
|
||||
{
|
||||
UNIMPLEMENTED_FUNC(cellSysutilAvc2);
|
||||
return CELL_OK;
|
||||
fmt::throw_exception("Unimplemented" HERE);
|
||||
}
|
||||
|
||||
error_code cellSysutilAvc2Unload()
|
||||
s32 cellSysutilAvc2Unload()
|
||||
{
|
||||
cellSysutilAvc2.todo("cellSysutilAvc2Unload()");
|
||||
return CELL_OK;
|
||||
fmt::throw_exception("Unimplemented" HERE);
|
||||
}
|
||||
|
||||
error_code cellSysutilAvc2DestroyWindow(SceNpMatching2RoomMemberId member_id)
|
||||
s32 cellSysutilAvc2DestroyWindow()
|
||||
{
|
||||
cellSysutilAvc2.todo("cellSysutilAvc2DestroyWindow(member_id=0x%x)", member_id);
|
||||
return CELL_OK;
|
||||
fmt::throw_exception("Unimplemented" HERE);
|
||||
}
|
||||
|
||||
error_code cellSysutilAvc2SetWindowPosition(SceNpMatching2RoomMemberId member_id, f32 x, f32 y, f32 z)
|
||||
s32 cellSysutilAvc2SetWindowPosition()
|
||||
{
|
||||
cellSysutilAvc2.todo("cellSysutilAvc2SetWindowPosition(member_id=0x%x, x=0x%x, y=0x%x, z=0x%x)", member_id, x, y, z);
|
||||
return CELL_OK;
|
||||
fmt::throw_exception("Unimplemented" HERE);
|
||||
}
|
||||
|
||||
error_code cellSysutilAvc2GetSpeakerVolumeLevel(vm::ptr<f32> level)
|
||||
s32 cellSysutilAvc2GetSpeakerVolumeLevel()
|
||||
{
|
||||
cellSysutilAvc2.todo("cellSysutilAvc2GetSpeakerVolumeLevel(level=*0x%x)", level);
|
||||
return CELL_OK;
|
||||
fmt::throw_exception("Unimplemented" HERE);
|
||||
}
|
||||
|
||||
error_code cellSysutilAvc2IsCameraAttached(vm::ptr<u8> status)
|
||||
s32 cellSysutilAvc2IsCameraAttached(vm::ptr<u8> status)
|
||||
{
|
||||
cellSysutilAvc2.todo("cellSysutilAvc2IsCameraAttached(status=*0x%x)", status);
|
||||
|
||||
@@ -190,43 +138,37 @@ error_code cellSysutilAvc2IsCameraAttached(vm::ptr<u8> status)
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
error_code cellSysutilAvc2MicRead(vm::ptr<void> ptr, vm::ptr<u32> pSize)
|
||||
s32 cellSysutilAvc2MicRead()
|
||||
{
|
||||
cellSysutilAvc2.todo("cellSysutilAvc2MicRead(ptr=*0x%x, pSize=*0x%x)", ptr, pSize);
|
||||
return CELL_OK;
|
||||
fmt::throw_exception("Unimplemented" HERE);
|
||||
}
|
||||
|
||||
error_code cellSysutilAvc2GetPlayerVoiceMuting(SceNpMatching2RoomMemberId member_id, vm::ptr<u8> muting)
|
||||
s32 cellSysutilAvc2GetPlayerVoiceMuting()
|
||||
{
|
||||
cellSysutilAvc2.todo("cellSysutilAvc2GetPlayerVoiceMuting(member_id=0x%x, muting=*0x%x)", member_id, muting);
|
||||
return CELL_OK;
|
||||
fmt::throw_exception("Unimplemented" HERE);
|
||||
}
|
||||
|
||||
error_code cellSysutilAvc2JoinChatRequest(vm::cptr<SceNpMatching2RoomId> room_id)
|
||||
s32 cellSysutilAvc2JoinChatRequest()
|
||||
{
|
||||
cellSysutilAvc2.todo("cellSysutilAvc2JoinChatRequest(room_id=*0x%x)", room_id);
|
||||
return CELL_OK;
|
||||
fmt::throw_exception("Unimplemented" HERE);
|
||||
}
|
||||
|
||||
error_code cellSysutilAvc2StartStreaming()
|
||||
s32 cellSysutilAvc2StartStreaming()
|
||||
{
|
||||
cellSysutilAvc2.todo("cellSysutilAvc2StartStreaming()");
|
||||
return CELL_OK;
|
||||
fmt::throw_exception("Unimplemented" HERE);
|
||||
}
|
||||
|
||||
error_code cellSysutilAvc2SetWindowAttribute(SceNpMatching2RoomMemberId member_id, vm::cptr<CellSysutilAvc2WindowAttribute> attr)
|
||||
s32 cellSysutilAvc2SetWindowAttribute()
|
||||
{
|
||||
cellSysutilAvc2.todo("cellSysutilAvc2SetWindowAttribute(member_id=0x%x, attr=*0x%x)", member_id, attr);
|
||||
return CELL_OK;
|
||||
fmt::throw_exception("Unimplemented" HERE);
|
||||
}
|
||||
|
||||
error_code cellSysutilAvc2GetWindowShowStatus(SceNpMatching2RoomMemberId member_id, vm::ptr<u8> visible)
|
||||
s32 cellSysutilAvc2GetWindowShowStatus()
|
||||
{
|
||||
cellSysutilAvc2.todo("cellSysutilAvc2GetWindowShowStatus(member_id=0x%x, visible=*0x%x)", member_id, visible);
|
||||
return CELL_OK;
|
||||
fmt::throw_exception("Unimplemented" HERE);
|
||||
}
|
||||
|
||||
error_code cellSysutilAvc2InitParam(u16 version, vm::ptr<CellSysutilAvc2InitParam> option)
|
||||
s32 cellSysutilAvc2InitParam(u16 version, vm::ptr<CellSysutilAvc2InitParam> option)
|
||||
{
|
||||
cellSysutilAvc2.warning("cellSysutilAvc2InitParam(version=%d, option=*0x%x)", version, option);
|
||||
|
||||
@@ -273,118 +215,99 @@ error_code cellSysutilAvc2InitParam(u16 version, vm::ptr<CellSysutilAvc2InitPara
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
error_code cellSysutilAvc2GetWindowSize(SceNpMatching2RoomMemberId member_id, vm::ptr<f32> width, vm::ptr<f32> height)
|
||||
s32 cellSysutilAvc2GetWindowSize()
|
||||
{
|
||||
cellSysutilAvc2.todo("cellSysutilAvc2GetWindowSize(member_id=0x%x, width=*0x%x, height=*0x%x)", member_id, width, height);
|
||||
return CELL_OK;
|
||||
fmt::throw_exception("Unimplemented" HERE);
|
||||
}
|
||||
|
||||
error_code cellSysutilAvc2SetStreamPriority(u8 priority)
|
||||
s32 cellSysutilAvc2SetStreamPriority()
|
||||
{
|
||||
cellSysutilAvc2.todo("cellSysutilAvc2SetStreamPriority(priority=0x%x)", priority);
|
||||
return CELL_OK;
|
||||
fmt::throw_exception("Unimplemented" HERE);
|
||||
}
|
||||
|
||||
error_code cellSysutilAvc2LeaveChatRequest()
|
||||
s32 cellSysutilAvc2LeaveChatRequest()
|
||||
{
|
||||
cellSysutilAvc2.todo("cellSysutilAvc2LeaveChatRequest()");
|
||||
return CELL_OK;
|
||||
fmt::throw_exception("Unimplemented" HERE);
|
||||
}
|
||||
|
||||
error_code cellSysutilAvc2IsMicAttached(vm::ptr<u8> status)
|
||||
s32 cellSysutilAvc2IsMicAttached()
|
||||
{
|
||||
cellSysutilAvc2.todo("cellSysutilAvc2IsMicAttached(status=*0x%x)", status);
|
||||
|
||||
*status = CELL_AVC2_MIC_STATUS_DETACHED;
|
||||
|
||||
return CELL_OK;
|
||||
fmt::throw_exception("Unimplemented" HERE);
|
||||
}
|
||||
|
||||
error_code cellSysutilAvc2CreateWindow(SceNpMatching2RoomMemberId member_id)
|
||||
s32 cellSysutilAvc2CreateWindow()
|
||||
{
|
||||
cellSysutilAvc2.todo("cellSysutilAvc2CreateWindow(member_id=0x%x)", member_id);
|
||||
return CELL_OK;
|
||||
fmt::throw_exception("Unimplemented" HERE);
|
||||
}
|
||||
|
||||
error_code cellSysutilAvc2GetSpeakerMuting(vm::ptr<u8> muting)
|
||||
s32 cellSysutilAvc2GetSpeakerMuting()
|
||||
{
|
||||
cellSysutilAvc2.todo("cellSysutilAvc2GetSpeakerMuting(muting=*0x%x)", muting);
|
||||
return CELL_OK;
|
||||
fmt::throw_exception("Unimplemented" HERE);
|
||||
}
|
||||
|
||||
error_code cellSysutilAvc2ShowWindow(SceNpMatching2RoomMemberId member_id)
|
||||
s32 cellSysutilAvc2ShowWindow()
|
||||
{
|
||||
cellSysutilAvc2.todo("cellSysutilAvc2ShowWindow(member_id=0x%x)", member_id);
|
||||
return CELL_OK;
|
||||
fmt::throw_exception("Unimplemented" HERE);
|
||||
}
|
||||
|
||||
error_code cellSysutilAvc2SetWindowSize(SceNpMatching2RoomMemberId member_id, f32 width, f32 height)
|
||||
s32 cellSysutilAvc2SetWindowSize()
|
||||
{
|
||||
cellSysutilAvc2.todo("cellSysutilAvc2SetWindowSize(member_id=0x%x, width=0x%x, height=0x%x)", member_id, width, height);
|
||||
return CELL_OK;
|
||||
fmt::throw_exception("Unimplemented" HERE);
|
||||
}
|
||||
|
||||
error_code cellSysutilAvc2EnumPlayers(vm::ptr<s32> players_num, vm::ptr<SceNpMatching2RoomMemberId> players_id)
|
||||
s32 cellSysutilAvc2EnumPlayers()
|
||||
{
|
||||
cellSysutilAvc2.todo("cellSysutilAvc2EnumPlayers(players_num=*0x%x, players_id=*0x%x)", players_num, players_id);
|
||||
return CELL_OK;
|
||||
fmt::throw_exception("Unimplemented" HERE);
|
||||
}
|
||||
|
||||
error_code cellSysutilAvc2GetWindowString(SceNpMatching2RoomMemberId member_id, vm::ptr<char> string, vm::ptr<u8> len)
|
||||
s32 cellSysutilAvc2GetWindowString()
|
||||
{
|
||||
cellSysutilAvc2.todo("cellSysutilAvc2GetWindowString(member_id=0x%x, string=*0x%x, len=*0x%x)", member_id, string, len);
|
||||
return CELL_OK;
|
||||
fmt::throw_exception("Unimplemented" HERE);
|
||||
}
|
||||
|
||||
error_code cellSysutilAvc2LeaveChat()
|
||||
s32 cellSysutilAvc2LeaveChat()
|
||||
{
|
||||
cellSysutilAvc2.todo("cellSysutilAvc2LeaveChat()");
|
||||
return CELL_OK;
|
||||
fmt::throw_exception("Unimplemented" HERE);
|
||||
}
|
||||
|
||||
error_code cellSysutilAvc2SetSpeakerMuting(u8 muting)
|
||||
s32 cellSysutilAvc2SetSpeakerMuting()
|
||||
{
|
||||
cellSysutilAvc2.todo("cellSysutilAvc2SetSpeakerMuting(muting=0x%x)", muting);
|
||||
return CELL_OK;
|
||||
fmt::throw_exception("Unimplemented" HERE);
|
||||
}
|
||||
|
||||
error_code cellSysutilAvc2Load(SceNpMatching2ContextId ctx_id, u32 container, vm::ptr<CellSysutilAvc2Callback> callback_func, vm::ptr<void> user_data, vm::cptr<CellSysutilAvc2InitParam> init_param)
|
||||
s32 cellSysutilAvc2Load(SceNpMatching2ContextId ctx_id, u32 container, vm::ptr<CellSysutilAvc2Callback> callback_func, vm::ptr<void> user_data, vm::cptr<CellSysutilAvc2InitParam> init_param)
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
error_code cellSysutilAvc2SetAttribute(vm::cptr<CellSysutilAvc2Attribute> attr)
|
||||
s32 cellSysutilAvc2SetAttribute(vm::cptr<CellSysutilAvc2Attribute> attr)
|
||||
{
|
||||
cellSysutilAvc2.todo("cellSysutilAvc2SetAttribute(attr=*0x%x)", attr);
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
error_code cellSysutilAvc2UnloadAsync2(CellSysutilAvc2MediaType mediaType)
|
||||
s32 cellSysutilAvc2UnloadAsync2()
|
||||
{
|
||||
cellSysutilAvc2.todo("cellSysutilAvc2UnloadAsync2(mediaType=0x%x)", mediaType);
|
||||
return CELL_OK;
|
||||
fmt::throw_exception("Unimplemented" HERE);
|
||||
}
|
||||
|
||||
error_code cellSysutilAvc2StartStreaming2(CellSysutilAvc2MediaType mediaType)
|
||||
s32 cellSysutilAvc2StartStreaming2()
|
||||
{
|
||||
cellSysutilAvc2.todo("cellSysutilAvc2StartStreaming2(mediaType=0x%x)", mediaType);
|
||||
return CELL_OK;
|
||||
fmt::throw_exception("Unimplemented" HERE);
|
||||
}
|
||||
|
||||
error_code cellSysutilAvc2HideScreen()
|
||||
s32 cellSysutilAvc2HideScreen()
|
||||
{
|
||||
cellSysutilAvc2.todo("cellSysutilAvc2HideScreen()");
|
||||
return CELL_OK;
|
||||
fmt::throw_exception("Unimplemented" HERE);
|
||||
}
|
||||
|
||||
error_code cellSysutilAvc2HideWindow(SceNpMatching2RoomMemberId member_id)
|
||||
s32 cellSysutilAvc2HideWindow()
|
||||
{
|
||||
cellSysutilAvc2.todo("cellSysutilAvc2HideWindow(member_id=0x%x)", member_id);
|
||||
return CELL_OK;
|
||||
fmt::throw_exception("Unimplemented" HERE);
|
||||
}
|
||||
|
||||
error_code cellSysutilAvc2GetVoiceMuting(vm::ptr<u8> muting)
|
||||
s32 cellSysutilAvc2GetVoiceMuting(vm::ptr<u8> muting)
|
||||
{
|
||||
cellSysutilAvc2.todo("cellSysutilAvc2GetVoiceMuting(muting=*0x%x)", muting);
|
||||
|
||||
@@ -393,22 +316,19 @@ error_code cellSysutilAvc2GetVoiceMuting(vm::ptr<u8> muting)
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
error_code cellSysutilAvc2GetScreenShowStatus(vm::ptr<u8> visible)
|
||||
s32 cellSysutilAvc2GetScreenShowStatus()
|
||||
{
|
||||
cellSysutilAvc2.todo("cellSysutilAvc2GetScreenShowStatus(visible=*0x%x)", visible);
|
||||
return CELL_OK;
|
||||
fmt::throw_exception("Unimplemented" HERE);
|
||||
}
|
||||
|
||||
error_code cellSysutilAvc2Unload2(CellSysutilAvc2MediaType mediaType)
|
||||
s32 cellSysutilAvc2Unload2()
|
||||
{
|
||||
cellSysutilAvc2.todo("cellSysutilAvc2Unload2(mediaType=0x%x)", mediaType);
|
||||
return CELL_OK;
|
||||
fmt::throw_exception("Unimplemented" HERE);
|
||||
}
|
||||
|
||||
error_code cellSysutilAvc2GetWindowPosition(SceNpMatching2RoomMemberId member_id, vm::ptr<f32> x, vm::ptr<f32> y, vm::ptr<f32> z)
|
||||
s32 cellSysutilAvc2GetWindowPosition()
|
||||
{
|
||||
cellSysutilAvc2.todo("cellSysutilAvc2GetWindowPosition(member_id=0x%x, x=*0x%x, y=*0x%x, z=*0x%x)", member_id, x, y, z);
|
||||
return CELL_OK;
|
||||
fmt::throw_exception("Unimplemented" HERE);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
namespace vm { using namespace ps3; }
|
||||
|
||||
// Error codes
|
||||
enum CellSysutilAvc2Error : u32
|
||||
enum
|
||||
{
|
||||
CELL_AVC2_ERROR_UNKNOWN = 0x8002b701,
|
||||
CELL_AVC2_ERROR_NOT_SUPPORTED = 0x8002b702,
|
||||
@@ -113,14 +113,6 @@ enum
|
||||
CELL_AVC2_CAMERA_STATUS_UNKNOWN = 3,
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
CELL_AVC2_MIC_STATUS_DETACHED = 0,
|
||||
CELL_AVC2_MIC_STATUS_ATTACHED_OFF = 1,
|
||||
CELL_AVC2_MIC_STATUS_ATTACHED_ON = 2,
|
||||
CELL_AVC2_MIC_STATUS_UNKNOWN = 3,
|
||||
};
|
||||
|
||||
typedef u32 CellSysutilAvc2AttributeId;
|
||||
typedef u32 CellSysutilAvc2WindowAttributeId;
|
||||
|
||||
@@ -151,7 +143,7 @@ struct CellSysutilAvc2VideoInitParam
|
||||
be_t<u16> max_video_windows;
|
||||
be_t<u16> max_video_framerate;
|
||||
be_t<u32> max_video_bitrate;
|
||||
be_t<CellSysutilAvc2CoordinatesForm> coordinates_form;
|
||||
CellSysutilAvc2CoordinatesForm coordinates_form;
|
||||
u8 video_stream_sharing;
|
||||
};
|
||||
|
||||
@@ -174,15 +166,15 @@ struct CellSysutilAvc2InitParam
|
||||
|
||||
struct CellSysutilAvc2RoomMemberList
|
||||
{
|
||||
vm::bptr<SceNpMatching2RoomMemberId> member_id;
|
||||
vm::ptr<SceNpMatching2RoomMemberId> member_id;
|
||||
u8 member_num;
|
||||
};
|
||||
|
||||
struct CellSysutilAvc2MemberIpAndPortList
|
||||
{
|
||||
vm::bptr<SceNpMatching2RoomMemberId> member_id;
|
||||
vm::bptr<u32> dst_addr; // in_addr
|
||||
vm::bptr<u16> dst_port; // in_port_t
|
||||
vm::ptr<SceNpMatching2RoomMemberId> member_id;
|
||||
vm::ptr<u32> dst_addr; // in_addr
|
||||
vm::ptr<u16> dst_port;
|
||||
be_t<SceNpMatching2RoomMemberId> my_member_id;
|
||||
u8 member_num;
|
||||
};
|
||||
@@ -191,7 +183,7 @@ union CellSysutilAvc2AttributeParam
|
||||
{
|
||||
be_t<u64> int_param;
|
||||
be_t<f32> float_param;
|
||||
vm::bptr<void> ptr_param;
|
||||
vm::ptr<void> ptr_param;
|
||||
};
|
||||
|
||||
struct CellSysutilAvc2Attribute
|
||||
@@ -204,7 +196,7 @@ union CellSysutilAvc2WindowAttributeParam
|
||||
{
|
||||
be_t<s32> int_vector[4];
|
||||
be_t<f32> float_vector[4];
|
||||
vm::bptr<void> ptr_vector[4];
|
||||
vm::ptr<void> ptr_vector[4];
|
||||
};
|
||||
|
||||
struct CellSysutilAvc2WindowAttribute
|
||||
@@ -212,12 +204,3 @@ struct CellSysutilAvc2WindowAttribute
|
||||
be_t<CellSysutilAvc2WindowAttributeId> attr_id;
|
||||
CellSysutilAvc2WindowAttributeParam attr_param;
|
||||
};
|
||||
|
||||
struct CellSysutilAvc2PlayerInfo
|
||||
{
|
||||
be_t<SceNpMatching2RoomMemberId> member_id;
|
||||
u8 joined;
|
||||
u8 connected;
|
||||
u8 mic_attached;
|
||||
u8 reserved[11];
|
||||
};
|
||||
|
||||
@@ -43,12 +43,6 @@ s32 cellUsbdRegisterLdd()
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
s32 cellUsbdRegisterCompositeLdd()
|
||||
{
|
||||
UNIMPLEMENTED_FUNC(cellUsbd);
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
s32 cellUsbdRegisterExtraLdd()
|
||||
{
|
||||
UNIMPLEMENTED_FUNC(cellUsbd);
|
||||
@@ -67,12 +61,6 @@ s32 cellUsbdUnregisterLdd()
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
s32 cellUsbdUnregisterCompositeLdd()
|
||||
{
|
||||
UNIMPLEMENTED_FUNC(cellUsbd);
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
s32 cellUsbdUnregisterExtraLdd()
|
||||
{
|
||||
UNIMPLEMENTED_FUNC(cellUsbd);
|
||||
@@ -163,13 +151,6 @@ s32 cellUsbdFreeMemory()
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
s32 cellUsbdResetDevice()
|
||||
{
|
||||
UNIMPLEMENTED_FUNC(cellUsbd);
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
|
||||
DECLARE(ppu_module_manager::cellUsbd)("cellUsbd", []()
|
||||
{
|
||||
REG_FUNC(cellUsbd, cellUsbdInit);
|
||||
@@ -180,11 +161,9 @@ DECLARE(ppu_module_manager::cellUsbd)("cellUsbd", []()
|
||||
REG_FUNC(cellUsbd, cellUsbdGetThreadPriority);
|
||||
|
||||
REG_FUNC(cellUsbd, cellUsbdRegisterLdd);
|
||||
REG_FUNC(cellUsbd, cellUsbdRegisterCompositeLdd);
|
||||
REG_FUNC(cellUsbd, cellUsbdRegisterExtraLdd);
|
||||
REG_FUNC(cellUsbd, cellUsbdRegisterExtraLdd2);
|
||||
REG_FUNC(cellUsbd, cellUsbdUnregisterLdd);
|
||||
REG_FUNC(cellUsbd, cellUsbdUnregisterCompositeLdd);
|
||||
REG_FUNC(cellUsbd, cellUsbdUnregisterExtraLdd);
|
||||
|
||||
REG_FUNC(cellUsbd, cellUsbdOpenPipe);
|
||||
@@ -205,6 +184,4 @@ DECLARE(ppu_module_manager::cellUsbd)("cellUsbd", []()
|
||||
|
||||
REG_FUNC(cellUsbd, cellUsbdAllocateMemory);
|
||||
REG_FUNC(cellUsbd, cellUsbdFreeMemory);
|
||||
|
||||
REG_FUNC(cellUsbd, cellUsbdResetDevice);
|
||||
});
|
||||
|
||||
@@ -128,24 +128,26 @@ error_code cellVideoOutGetResolution(u32 resolutionId, vm::ptr<CellVideoOutResol
|
||||
|
||||
error_code cellVideoOutConfigure(u32 videoOut, vm::ptr<CellVideoOutConfiguration> config, vm::ptr<CellVideoOutOption> option, u32 waitForEvent)
|
||||
{
|
||||
cellSysutil.todo("cellVideoOutConfigure(videoOut=%d, config=*0x%x, option=*0x%x, waitForEvent=%d)", videoOut, config, option, waitForEvent);
|
||||
cellSysutil.warning("cellVideoOutConfigure(videoOut=%d, config=*0x%x, option=*0x%x, waitForEvent=%d)", videoOut, config, option, waitForEvent);
|
||||
|
||||
if (!config)
|
||||
switch (videoOut)
|
||||
{
|
||||
return CELL_VIDEO_OUT_ERROR_ILLEGAL_PARAMETER;
|
||||
case CELL_VIDEO_OUT_PRIMARY:
|
||||
if (config->resolutionId != g_video_out_resolution_id.at(g_cfg.video.resolution)
|
||||
|| (config->format != CELL_VIDEO_OUT_BUFFER_COLOR_FORMAT_X8R8G8B8 &&
|
||||
config->format != CELL_VIDEO_OUT_BUFFER_COLOR_FORMAT_X8B8G8R8 &&
|
||||
config->format != CELL_VIDEO_OUT_BUFFER_COLOR_FORMAT_R16G16B16X16_FLOAT)
|
||||
|| (config->aspect != CELL_VIDEO_OUT_ASPECT_AUTO && config->aspect != g_video_out_aspect_id.at(g_cfg.video.aspect_ratio)))
|
||||
{
|
||||
return CELL_VIDEO_OUT_ERROR_ILLEGAL_CONFIGURATION;
|
||||
}
|
||||
return CELL_OK;
|
||||
|
||||
case CELL_VIDEO_OUT_SECONDARY:
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
if (!config->pitch)
|
||||
{
|
||||
return CELL_VIDEO_OUT_ERROR_PARAMETER_OUT_OF_RANGE;
|
||||
}
|
||||
|
||||
if (config->resolutionId == 0x92 || config->resolutionId == 0xa1)
|
||||
{
|
||||
return CELL_VIDEO_OUT_ERROR_ILLEGAL_CONFIGURATION;
|
||||
}
|
||||
|
||||
return CELL_OK;
|
||||
return CELL_VIDEO_OUT_ERROR_UNSUPPORTED_VIDEO_OUT;
|
||||
}
|
||||
|
||||
error_code cellVideoOutGetConfiguration(u32 videoOut, vm::ptr<CellVideoOutConfiguration> config, vm::ptr<CellVideoOutOption> option)
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -976,7 +976,7 @@ s32 sceNpManagerGetOnlineId(vm::ptr<SceNpOnlineId> onlineId)
|
||||
return SCE_NP_ERROR_OFFLINE;
|
||||
}
|
||||
|
||||
if (g_psn_connection_status != SCE_NP_MANAGER_STATUS_LOGGING_IN && g_psn_connection_status != SCE_NP_MANAGER_STATUS_ONLINE)
|
||||
if (g_psn_connection_status != SCE_NP_MANAGER_STATUS_LOGGING_IN || g_psn_connection_status != SCE_NP_MANAGER_STATUS_ONLINE)
|
||||
{
|
||||
return SCE_NP_ERROR_INVALID_STATE;
|
||||
}
|
||||
@@ -998,7 +998,7 @@ s32 sceNpManagerGetNpId(ppu_thread& ppu, vm::ptr<SceNpId> npId)
|
||||
return SCE_NP_ERROR_OFFLINE;
|
||||
}
|
||||
|
||||
if (g_psn_connection_status != SCE_NP_MANAGER_STATUS_LOGGING_IN && g_psn_connection_status != SCE_NP_MANAGER_STATUS_ONLINE)
|
||||
if (g_psn_connection_status != SCE_NP_MANAGER_STATUS_LOGGING_IN || g_psn_connection_status != SCE_NP_MANAGER_STATUS_ONLINE)
|
||||
{
|
||||
return SCE_NP_ERROR_INVALID_STATE;
|
||||
}
|
||||
@@ -1086,7 +1086,7 @@ s32 sceNpManagerGetAccountRegion(vm::ptr<SceNpCountryCode> countryCode, vm::ptr<
|
||||
return SCE_NP_ERROR_OFFLINE;
|
||||
}
|
||||
|
||||
if (g_psn_connection_status != SCE_NP_MANAGER_STATUS_LOGGING_IN && g_psn_connection_status != SCE_NP_MANAGER_STATUS_ONLINE)
|
||||
if (g_psn_connection_status != SCE_NP_MANAGER_STATUS_LOGGING_IN || g_psn_connection_status != SCE_NP_MANAGER_STATUS_ONLINE)
|
||||
{
|
||||
return SCE_NP_ERROR_INVALID_STATE;
|
||||
}
|
||||
@@ -1108,7 +1108,7 @@ s32 sceNpManagerGetAccountAge(vm::ptr<s32> age)
|
||||
return SCE_NP_ERROR_OFFLINE;
|
||||
}
|
||||
|
||||
if (g_psn_connection_status != SCE_NP_MANAGER_STATUS_LOGGING_IN && g_psn_connection_status != SCE_NP_MANAGER_STATUS_ONLINE)
|
||||
if (g_psn_connection_status != SCE_NP_MANAGER_STATUS_LOGGING_IN || g_psn_connection_status != SCE_NP_MANAGER_STATUS_ONLINE)
|
||||
{
|
||||
return SCE_NP_ERROR_INVALID_STATE;
|
||||
}
|
||||
@@ -1130,7 +1130,7 @@ s32 sceNpManagerGetContentRatingFlag(vm::ptr<s32> isRestricted, vm::ptr<s32> age
|
||||
return SCE_NP_ERROR_OFFLINE;
|
||||
}
|
||||
|
||||
if (g_psn_connection_status != SCE_NP_MANAGER_STATUS_LOGGING_IN && g_psn_connection_status != SCE_NP_MANAGER_STATUS_ONLINE)
|
||||
if (g_psn_connection_status != SCE_NP_MANAGER_STATUS_LOGGING_IN || g_psn_connection_status != SCE_NP_MANAGER_STATUS_ONLINE)
|
||||
{
|
||||
return SCE_NP_ERROR_INVALID_STATE;
|
||||
}
|
||||
@@ -1156,7 +1156,7 @@ s32 sceNpManagerGetChatRestrictionFlag(vm::ptr<s32> isRestricted)
|
||||
return SCE_NP_ERROR_OFFLINE;
|
||||
}
|
||||
|
||||
if (g_psn_connection_status != SCE_NP_MANAGER_STATUS_LOGGING_IN && g_psn_connection_status != SCE_NP_MANAGER_STATUS_ONLINE)
|
||||
if (g_psn_connection_status != SCE_NP_MANAGER_STATUS_LOGGING_IN || g_psn_connection_status != SCE_NP_MANAGER_STATUS_ONLINE)
|
||||
{
|
||||
return SCE_NP_ERROR_INVALID_STATE;
|
||||
}
|
||||
|
||||
@@ -368,19 +368,6 @@ s32 sceNpTssGetDataAsync()
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
s32 sceNpTssGetDataNoLimit()
|
||||
{
|
||||
UNIMPLEMENTED_FUNC(sceNpTus);
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
s32 sceNpTssGetDataNoLimitAsync()
|
||||
{
|
||||
UNIMPLEMENTED_FUNC(sceNpTus);
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
|
||||
DECLARE(ppu_module_manager::sceNpTus)("sceNpTus", []()
|
||||
{
|
||||
REG_FUNC(sceNpTus, sceNpTusInit);
|
||||
@@ -443,6 +430,4 @@ DECLARE(ppu_module_manager::sceNpTus)("sceNpTus", []()
|
||||
REG_FUNC(sceNpTus, sceNpTusDeleteMultiSlotDataVUserAsync);
|
||||
REG_FUNC(sceNpTus, sceNpTssGetData);
|
||||
REG_FUNC(sceNpTus, sceNpTssGetDataAsync);
|
||||
REG_FUNC(sceNpTus, sceNpTssGetDataNoLimit);
|
||||
REG_FUNC(sceNpTus, sceNpTssGetDataNoLimitAsync);
|
||||
});
|
||||
|
||||
@@ -31,7 +31,7 @@ struct ps3_fmt_src
|
||||
|
||||
void skip(std::size_t extra)
|
||||
{
|
||||
g_count += (u32)extra + 1;
|
||||
++g_count += (u32)extra;
|
||||
}
|
||||
|
||||
std::size_t fmt_string(std::string& out, std::size_t extra) const
|
||||
|
||||
@@ -1211,12 +1211,6 @@ namespace sys_net
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
s32 _sce_net_add_name_server()
|
||||
{
|
||||
UNIMPLEMENTED_FUNC(libnet);
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
s32 _sce_net_add_name_server_with_char()
|
||||
{
|
||||
UNIMPLEMENTED_FUNC(libnet);
|
||||
@@ -1348,7 +1342,6 @@ DECLARE(ppu_module_manager::libnet)("sys_net", []()
|
||||
REG_FUNC_(sys_netset_if_up);
|
||||
REG_FUNC_(sys_netset_open);
|
||||
|
||||
REG_FUNC_(_sce_net_add_name_server);
|
||||
REG_FUNC_(_sce_net_add_name_server_with_char);
|
||||
REG_FUNC_(_sce_net_flush_route);
|
||||
|
||||
|
||||
@@ -5,7 +5,6 @@
|
||||
#include "Emu/Cell/RawSPUThread.h"
|
||||
#include "Emu/Cell/lv2/sys_spu.h"
|
||||
#include "Crypto/unself.h"
|
||||
#include "Loader/ELF.h"
|
||||
#include "sysPrxForUser.h"
|
||||
|
||||
extern logs::channel sysPrxForUser;
|
||||
@@ -17,365 +16,46 @@ spu_printf_cb_t g_spu_printf_dgcb;
|
||||
spu_printf_cb_t g_spu_printf_atcb;
|
||||
spu_printf_cb_t g_spu_printf_dtcb;
|
||||
|
||||
struct spu_elf_ldr
|
||||
s32 sys_spu_elf_get_information(u32 elf_img, vm::ptr<u32> entry, vm::ptr<s32> nseg)
|
||||
{
|
||||
be_t<u32> _vtable;
|
||||
vm::bptr<void> src;
|
||||
be_t<u32> x8;
|
||||
be_t<u64> ehdr_off;
|
||||
be_t<u64> phdr_off;
|
||||
|
||||
s32 get_ehdr(vm::ptr<elf_ehdr<elf_be, u64>> out)
|
||||
{
|
||||
if (!src)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (_vtable == vm::cast(u32{1}))
|
||||
{
|
||||
vm::ptr<elf_ehdr<elf_be, u32>> ehdr = vm::cast(src.addr() + ehdr_off);
|
||||
std::memcpy(out.get_ptr(), ehdr.get_ptr(), 0x10); // Not needed?
|
||||
out->e_type = ehdr->e_type;
|
||||
out->e_machine = ehdr->e_machine;
|
||||
out->e_version = ehdr->e_version;
|
||||
out->e_entry = ehdr->e_entry;
|
||||
out->e_phoff = ehdr->e_phoff;
|
||||
out->e_shoff = ehdr->e_shoff;
|
||||
out->e_flags = ehdr->e_flags;
|
||||
out->e_ehsize = ehdr->e_ehsize;
|
||||
out->e_phentsize = ehdr->e_phentsize;
|
||||
out->e_phnum = ehdr->e_phnum;
|
||||
out->e_shentsize = ehdr->e_shentsize;
|
||||
out->e_shnum = ehdr->e_shnum;
|
||||
out->e_shstrndx = ehdr->e_shstrndx;
|
||||
}
|
||||
else
|
||||
{
|
||||
vm::ptr<elf_ehdr<elf_be, u64>> ehdr = vm::cast(src.addr() + ehdr_off);
|
||||
*out = *ehdr;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
s32 get_phdr(vm::ptr<elf_phdr<elf_be, u64>> out, u32 count)
|
||||
{
|
||||
if (!src)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (_vtable == vm::cast(u32{1}))
|
||||
{
|
||||
vm::ptr<elf_ehdr<elf_be, u32>> ehdr = vm::cast(src.addr() + ehdr_off);
|
||||
vm::ptr<elf_phdr<elf_be, u32>> phdr = vm::cast(src.addr() + (phdr_off ? +phdr_off : +ehdr->e_phoff));
|
||||
|
||||
for (; count; count--, phdr++, out++)
|
||||
{
|
||||
out->p_type = phdr->p_type;
|
||||
out->p_flags = phdr->p_flags;
|
||||
out->p_offset = phdr->p_offset;
|
||||
out->p_vaddr = phdr->p_vaddr;
|
||||
out->p_paddr = phdr->p_paddr;
|
||||
out->p_filesz = phdr->p_filesz;
|
||||
out->p_memsz = phdr->p_memsz;
|
||||
out->p_align = phdr->p_align;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
vm::ptr<elf_ehdr<elf_be, u64>> ehdr = vm::cast(src.addr() + ehdr_off);
|
||||
vm::ptr<elf_phdr<elf_be, u64>> phdr = vm::cast(src.addr() + (phdr_off ? +phdr_off : +ehdr->e_phoff));
|
||||
|
||||
std::memcpy(out.get_ptr(), phdr.get_ptr(), sizeof(*out) * count);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
};
|
||||
|
||||
struct spu_elf_info
|
||||
{
|
||||
u8 e_class;
|
||||
vm::bptr<spu_elf_ldr> ldr;
|
||||
|
||||
struct sce_hdr
|
||||
{
|
||||
be_t<u32> se_magic;
|
||||
be_t<u32> se_hver;
|
||||
be_t<u16> se_flags;
|
||||
be_t<u16> se_type;
|
||||
be_t<u32> se_meta;
|
||||
be_t<u64> se_hsize;
|
||||
be_t<u64> se_esize;
|
||||
} sce0;
|
||||
|
||||
struct self_hdr
|
||||
{
|
||||
be_t<u64> se_htype;
|
||||
be_t<u64> se_appinfooff;
|
||||
be_t<u64> se_elfoff;
|
||||
be_t<u64> se_phdroff;
|
||||
be_t<u64> se_shdroff;
|
||||
be_t<u64> se_secinfoff;
|
||||
be_t<u64> se_sceveroff;
|
||||
be_t<u64> se_controloff;
|
||||
be_t<u64> se_controlsize;
|
||||
be_t<u64> pad;
|
||||
} self;
|
||||
|
||||
// Doesn't exist there
|
||||
spu_elf_ldr _overlay;
|
||||
|
||||
error_code init(vm::ptr<void> src, s32 arg2 = 0)
|
||||
{
|
||||
if (!src)
|
||||
{
|
||||
return CELL_EINVAL;
|
||||
}
|
||||
|
||||
u32 ehdr_off = 0;
|
||||
u32 phdr_off = 0;
|
||||
|
||||
// Check SCE header if found
|
||||
std::memcpy(&sce0, src.get_ptr(), sizeof(sce0));
|
||||
|
||||
if (sce0.se_magic == 0x53434500 /* SCE\0 */)
|
||||
{
|
||||
if (sce0.se_hver != 2 || sce0.se_type != 1 || sce0.se_meta == 0)
|
||||
{
|
||||
return CELL_ENOEXEC;
|
||||
}
|
||||
|
||||
std::memcpy(&self, src.get_ptr(), sizeof(self));
|
||||
ehdr_off = static_cast<u32>(+self.se_elfoff);
|
||||
phdr_off = static_cast<u32>(+self.se_phdroff);
|
||||
|
||||
if (self.se_htype != 3 || !ehdr_off || !phdr_off)
|
||||
{
|
||||
return CELL_ENOEXEC;
|
||||
}
|
||||
}
|
||||
|
||||
// Check ELF header
|
||||
vm::ptr<elf_ehdr<elf_be, u32>> ehdr = vm::cast(src.addr() + ehdr_off);
|
||||
|
||||
if (ehdr->e_magic != "\177ELF"_u32 || ehdr->e_data != 2 /* BE */)
|
||||
{
|
||||
return CELL_ENOEXEC;
|
||||
}
|
||||
|
||||
if (ehdr->e_class != 1 && ehdr->e_class != 2)
|
||||
{
|
||||
return CELL_ENOEXEC;
|
||||
}
|
||||
|
||||
e_class = ehdr->e_class;
|
||||
ldr = vm::get_addr(&_overlay);
|
||||
ldr->_vtable = vm::cast(u32{e_class}); // TODO
|
||||
ldr->src = vm::static_ptr_cast<u8>(src);
|
||||
ldr->x8 = arg2;
|
||||
ldr->ehdr_off = ehdr_off;
|
||||
ldr->phdr_off = phdr_off;
|
||||
|
||||
return CELL_OK;
|
||||
}
|
||||
};
|
||||
|
||||
error_code sys_spu_elf_get_information(u32 elf_img, vm::ptr<u32> entry, vm::ptr<s32> nseg)
|
||||
{
|
||||
sysPrxForUser.warning("sys_spu_elf_get_information(elf_img=0x%x, entry=*0x%x, nseg=*0x%x)", elf_img, entry, nseg);
|
||||
|
||||
// Initialize ELF loader
|
||||
vm::var<spu_elf_info> info(spu_elf_info{});
|
||||
|
||||
if (auto res = info->init(vm::cast(elf_img)))
|
||||
{
|
||||
return res;
|
||||
}
|
||||
|
||||
// Reject SCE header
|
||||
if (info->sce0.se_magic == 0x53434500)
|
||||
{
|
||||
return CELL_ENOEXEC;
|
||||
}
|
||||
|
||||
// Load ELF header
|
||||
vm::var<elf_ehdr<elf_be, u64>> ehdr(elf_ehdr<elf_be, u64>{});
|
||||
|
||||
if (info->ldr->get_ehdr(ehdr) || ehdr->e_machine != elf_machine::spu || !ehdr->e_phnum)
|
||||
{
|
||||
return CELL_ENOEXEC;
|
||||
}
|
||||
|
||||
// Load program headers
|
||||
vm::var<elf_phdr<elf_be, u64>[]> phdr(ehdr->e_phnum);
|
||||
|
||||
if (info->ldr->get_phdr(phdr, ehdr->e_phnum))
|
||||
{
|
||||
return CELL_ENOEXEC;
|
||||
}
|
||||
|
||||
const s32 num_segs = sys_spu_image::get_nsegs<false>(phdr);
|
||||
|
||||
if (num_segs < 0)
|
||||
{
|
||||
return CELL_ENOEXEC;
|
||||
}
|
||||
|
||||
*entry = static_cast<u32>(ehdr->e_entry);
|
||||
*nseg = num_segs;
|
||||
sysPrxForUser.todo("sys_spu_elf_get_information(elf_img=0x%x, entry=*0x%x, nseg=*0x%x)", elf_img, entry, nseg);
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
error_code sys_spu_elf_get_segments(u32 elf_img, vm::ptr<sys_spu_segment> segments, s32 nseg)
|
||||
s32 sys_spu_elf_get_segments(u32 elf_img, vm::ptr<sys_spu_segment> segments, s32 nseg)
|
||||
{
|
||||
sysPrxForUser.warning("sys_spu_elf_get_segments(elf_img=0x%x, segments=*0x%x, nseg=0x%x)", elf_img, segments, nseg);
|
||||
|
||||
// Initialize ELF loader
|
||||
vm::var<spu_elf_info> info(spu_elf_info{});
|
||||
|
||||
if (auto res = info->init(vm::cast(elf_img)))
|
||||
{
|
||||
return res;
|
||||
}
|
||||
|
||||
// Load ELF header
|
||||
vm::var<elf_ehdr<elf_be, u64>> ehdr(elf_ehdr<elf_be, u64>{});
|
||||
|
||||
if (info->ldr->get_ehdr(ehdr) || ehdr->e_machine != elf_machine::spu || !ehdr->e_phnum)
|
||||
{
|
||||
return CELL_ENOEXEC;
|
||||
}
|
||||
|
||||
// Load program headers
|
||||
vm::var<elf_phdr<elf_be, u64>[]> phdr(ehdr->e_phnum);
|
||||
|
||||
if (info->ldr->get_phdr(phdr, ehdr->e_phnum))
|
||||
{
|
||||
return CELL_ENOEXEC;
|
||||
}
|
||||
|
||||
const s32 num_segs = sys_spu_image::fill<false>(segments, nseg, phdr, elf_img);
|
||||
|
||||
if (num_segs == -2)
|
||||
{
|
||||
return CELL_ENOMEM;
|
||||
}
|
||||
else if (num_segs < 0)
|
||||
{
|
||||
return CELL_ENOEXEC;
|
||||
}
|
||||
|
||||
sysPrxForUser.todo("sys_spu_elf_get_segments(elf_img=0x%x, segments=*0x%x, nseg=0x%x)", elf_img, segments, nseg);
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
error_code sys_spu_image_import(vm::ptr<sys_spu_image> img, u32 src, u32 type)
|
||||
s32 sys_spu_image_import(vm::ptr<sys_spu_image> img, u32 src, u32 type)
|
||||
{
|
||||
sysPrxForUser.warning("sys_spu_image_import(img=*0x%x, src=0x%x, type=%d)", img, src, type);
|
||||
|
||||
if (type != SYS_SPU_IMAGE_PROTECT && type != SYS_SPU_IMAGE_DIRECT)
|
||||
{
|
||||
return CELL_EINVAL;
|
||||
}
|
||||
// Load from memory (TODO)
|
||||
img->load(fs::file{vm::base(src), 0 - src});
|
||||
|
||||
// Initialize ELF loader
|
||||
vm::var<spu_elf_info> info(spu_elf_info{});
|
||||
|
||||
if (auto res = info->init(vm::cast(src)))
|
||||
{
|
||||
return res;
|
||||
}
|
||||
|
||||
// Reject SCE header
|
||||
if (info->sce0.se_magic == 0x53434500)
|
||||
{
|
||||
return CELL_ENOEXEC;
|
||||
}
|
||||
|
||||
// Load ELF header
|
||||
vm::var<elf_ehdr<elf_be, u64>> ehdr(elf_ehdr<elf_be, u64>{});
|
||||
|
||||
if (info->ldr->get_ehdr(ehdr) || ehdr->e_machine != elf_machine::spu || !ehdr->e_phnum)
|
||||
{
|
||||
return CELL_ENOEXEC;
|
||||
}
|
||||
|
||||
// Load program headers
|
||||
vm::var<elf_phdr<elf_be, u64>[]> phdr(ehdr->e_phnum);
|
||||
|
||||
if (info->ldr->get_phdr(phdr, ehdr->e_phnum))
|
||||
{
|
||||
return CELL_ENOEXEC;
|
||||
}
|
||||
|
||||
if (type == SYS_SPU_IMAGE_PROTECT)
|
||||
{
|
||||
u32 img_size = 0;
|
||||
|
||||
for (const auto& p : phdr)
|
||||
{
|
||||
if (p.p_type != 1 && p.p_type != 4)
|
||||
{
|
||||
return CELL_ENOEXEC;
|
||||
}
|
||||
|
||||
img_size = std::max<u32>(img_size, static_cast<u32>(p.p_offset + p.p_filesz));
|
||||
}
|
||||
|
||||
return _sys_spu_image_import(img, src, img_size, 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
s32 num_segs = sys_spu_image::get_nsegs(phdr);
|
||||
|
||||
if (num_segs < 0)
|
||||
{
|
||||
return CELL_ENOEXEC;
|
||||
}
|
||||
|
||||
img->nsegs = num_segs;
|
||||
img->entry_point = static_cast<u32>(ehdr->e_entry);
|
||||
|
||||
vm::ptr<sys_spu_segment> segs = vm::cast(vm::alloc(num_segs * sizeof(sys_spu_segment), vm::main));
|
||||
|
||||
if (!segs)
|
||||
{
|
||||
return CELL_ENOMEM;
|
||||
}
|
||||
|
||||
if (sys_spu_image::fill(segs, num_segs, phdr, src) != num_segs)
|
||||
{
|
||||
vm::dealloc(segs.addr());
|
||||
return CELL_ENOEXEC;
|
||||
}
|
||||
|
||||
img->type = SYS_SPU_IMAGE_TYPE_USER;
|
||||
img->segs = segs;
|
||||
return CELL_OK;
|
||||
}
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
error_code sys_spu_image_close(vm::ptr<sys_spu_image> img)
|
||||
s32 sys_spu_image_close(vm::ptr<sys_spu_image> img)
|
||||
{
|
||||
sysPrxForUser.warning("sys_spu_image_close(img=*0x%x)", img);
|
||||
|
||||
if (img->type == SYS_SPU_IMAGE_TYPE_USER)
|
||||
{
|
||||
//_sys_free(img->segs.addr());
|
||||
vm::dealloc_verbose_nothrow(img->segs.addr(), vm::main);
|
||||
}
|
||||
else if (img->type == SYS_SPU_IMAGE_TYPE_KERNEL)
|
||||
{
|
||||
// Call the syscall
|
||||
return _sys_spu_image_close(img);
|
||||
//return syscall_158(img);
|
||||
}
|
||||
else
|
||||
{
|
||||
return CELL_EINVAL;
|
||||
}
|
||||
|
||||
img->free();
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
@@ -383,7 +63,7 @@ s32 sys_raw_spu_load(s32 id, vm::cptr<char> path, vm::ptr<u32> entry)
|
||||
{
|
||||
sysPrxForUser.warning("sys_raw_spu_load(id=%d, path=%s, entry=*0x%x)", id, path, entry);
|
||||
|
||||
const fs::file elf_file = fs::file(vfs::get(path.get_ptr()));
|
||||
const fs::file elf_file = decrypt_self(fs::file(vfs::get(path.get_ptr())));
|
||||
|
||||
if (!elf_file)
|
||||
{
|
||||
@@ -393,10 +73,10 @@ s32 sys_raw_spu_load(s32 id, vm::cptr<char> path, vm::ptr<u32> entry)
|
||||
|
||||
sys_spu_image img;
|
||||
img.load(elf_file);
|
||||
img.deploy(RAW_SPU_BASE_ADDR + RAW_SPU_OFFSET * id, img.segs.get_ptr(), img.nsegs);
|
||||
img.deploy(RAW_SPU_BASE_ADDR + RAW_SPU_OFFSET * id);
|
||||
img.free();
|
||||
|
||||
*entry = img.entry_point;
|
||||
*entry = img.entry_point | 1;
|
||||
|
||||
return CELL_OK;
|
||||
}
|
||||
@@ -406,15 +86,15 @@ s32 sys_raw_spu_image_load(ppu_thread& ppu, s32 id, vm::ptr<sys_spu_image> img)
|
||||
sysPrxForUser.warning("sys_raw_spu_image_load(id=%d, img=*0x%x)", id, img);
|
||||
|
||||
// Load SPU segments
|
||||
img->deploy(RAW_SPU_BASE_ADDR + RAW_SPU_OFFSET * id, img->segs.get_ptr(), img->nsegs);
|
||||
img->deploy(RAW_SPU_BASE_ADDR + RAW_SPU_OFFSET * id);
|
||||
|
||||
// Use MMIO
|
||||
vm::write32(RAW_SPU_BASE_ADDR + RAW_SPU_OFFSET * id + RAW_SPU_PROB_OFFSET + SPU_NPC_offs, img->entry_point);
|
||||
vm::write32(RAW_SPU_BASE_ADDR + RAW_SPU_OFFSET * id + RAW_SPU_PROB_OFFSET + SPU_NPC_offs, img->entry_point | 1);
|
||||
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
error_code _sys_spu_printf_initialize(spu_printf_cb_t agcb, spu_printf_cb_t dgcb, spu_printf_cb_t atcb, spu_printf_cb_t dtcb)
|
||||
s32 _sys_spu_printf_initialize(spu_printf_cb_t agcb, spu_printf_cb_t dgcb, spu_printf_cb_t atcb, spu_printf_cb_t dtcb)
|
||||
{
|
||||
sysPrxForUser.warning("_sys_spu_printf_initialize(agcb=*0x%x, dgcb=*0x%x, atcb=*0x%x, dtcb=*0x%x)", agcb, dgcb, atcb, dtcb);
|
||||
|
||||
@@ -427,7 +107,7 @@ error_code _sys_spu_printf_initialize(spu_printf_cb_t agcb, spu_printf_cb_t dgcb
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
error_code _sys_spu_printf_finalize()
|
||||
s32 _sys_spu_printf_finalize()
|
||||
{
|
||||
sysPrxForUser.warning("_sys_spu_printf_finalize()");
|
||||
|
||||
@@ -439,7 +119,7 @@ error_code _sys_spu_printf_finalize()
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
error_code _sys_spu_printf_attach_group(ppu_thread& ppu, u32 group)
|
||||
s32 _sys_spu_printf_attach_group(ppu_thread& ppu, u32 group)
|
||||
{
|
||||
sysPrxForUser.warning("_sys_spu_printf_attach_group(group=0x%x)", group);
|
||||
|
||||
@@ -451,7 +131,7 @@ error_code _sys_spu_printf_attach_group(ppu_thread& ppu, u32 group)
|
||||
return g_spu_printf_agcb(ppu, group);
|
||||
}
|
||||
|
||||
error_code _sys_spu_printf_detach_group(ppu_thread& ppu, u32 group)
|
||||
s32 _sys_spu_printf_detach_group(ppu_thread& ppu, u32 group)
|
||||
{
|
||||
sysPrxForUser.warning("_sys_spu_printf_detach_group(group=0x%x)", group);
|
||||
|
||||
@@ -463,7 +143,7 @@ error_code _sys_spu_printf_detach_group(ppu_thread& ppu, u32 group)
|
||||
return g_spu_printf_dgcb(ppu, group);
|
||||
}
|
||||
|
||||
error_code _sys_spu_printf_attach_thread(ppu_thread& ppu, u32 thread)
|
||||
s32 _sys_spu_printf_attach_thread(ppu_thread& ppu, u32 thread)
|
||||
{
|
||||
sysPrxForUser.warning("_sys_spu_printf_attach_thread(thread=0x%x)", thread);
|
||||
|
||||
@@ -475,7 +155,7 @@ error_code _sys_spu_printf_attach_thread(ppu_thread& ppu, u32 thread)
|
||||
return g_spu_printf_atcb(ppu, thread);
|
||||
}
|
||||
|
||||
error_code _sys_spu_printf_detach_thread(ppu_thread& ppu, u32 thread)
|
||||
s32 _sys_spu_printf_detach_thread(ppu_thread& ppu, u32 thread)
|
||||
{
|
||||
sysPrxForUser.warning("_sys_spu_printf_detach_thread(thread=0x%x)", thread);
|
||||
|
||||
|
||||
@@ -11,7 +11,7 @@ public:
|
||||
}
|
||||
|
||||
private:
|
||||
u32 DisAsmBranchTarget(const s32 imm) override
|
||||
u32 DisAsmBranchTarget(const s32 imm)
|
||||
{
|
||||
return dump_pc + (imm & ~3);
|
||||
}
|
||||
|
||||
@@ -133,7 +133,7 @@ extern std::string ppu_get_syscall_name(u64 code)
|
||||
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_spu_image_get_segments";
|
||||
case 159: return "_sys_raw_spu_image_load";
|
||||
case 160: return "sys_raw_spu_create";
|
||||
case 161: return "sys_raw_spu_destroy";
|
||||
case 163: return "sys_raw_spu_read_puint_mb";
|
||||
|
||||
@@ -88,26 +88,12 @@ void ppu_module_manager::register_module(ppu_static_module* module)
|
||||
|
||||
ppu_static_function& ppu_module_manager::access_static_function(const char* module, u32 fnid)
|
||||
{
|
||||
auto& res = access().at(module)->functions[fnid];
|
||||
|
||||
if (res.name)
|
||||
{
|
||||
fmt::throw_exception("PPU FNID duplication in module %s (%s, 0x%x)", module, res.name, fnid);
|
||||
}
|
||||
|
||||
return res;
|
||||
return access().at(module)->functions[fnid];
|
||||
}
|
||||
|
||||
ppu_static_variable& ppu_module_manager::access_static_variable(const char* module, u32 vnid)
|
||||
{
|
||||
auto& res = access().at(module)->variables[vnid];
|
||||
|
||||
if (res.name)
|
||||
{
|
||||
fmt::throw_exception("PPU VNID duplication in module %s (%s, 0x%x)", module, res.name, vnid);
|
||||
}
|
||||
|
||||
return res;
|
||||
return access().at(module)->variables[vnid];
|
||||
}
|
||||
|
||||
const ppu_static_module* ppu_module_manager::get_module(const std::string& name)
|
||||
@@ -989,7 +975,7 @@ void ppu_load_exec(const ppu_exec_object& elf)
|
||||
if (prog.bin.size() > size || prog.bin.size() != prog.p_filesz)
|
||||
fmt::throw_exception("Invalid binary size (0x%llx, memsz=0x%x)", prog.bin.size(), size);
|
||||
|
||||
if (!vm::falloc(addr, size))
|
||||
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
|
||||
@@ -1305,9 +1291,9 @@ void ppu_load_exec(const ppu_exec_object& elf)
|
||||
{
|
||||
const std::string lle_dir = vfs::get("/dev_flash/sys/external/");
|
||||
|
||||
if (!fs::is_dir(lle_dir) || !fs::is_file(lle_dir + "libsysmodule.sprx"))
|
||||
if (!fs::is_dir(lle_dir))
|
||||
{
|
||||
LOG_ERROR(GENERAL, "PS3 firmware is not installed or the installed firmware is invalid."
|
||||
LOG_ERROR(GENERAL, "/dev_flash/sys/external/ directory does not exist!"
|
||||
"\nYou should install the PS3 Firmware (Menu: File -> Install Firmware)."
|
||||
"\nVisit https://rpcs3.net/ for Quickstart Guide and more information.");
|
||||
}
|
||||
|
||||
@@ -578,7 +578,7 @@ ppu_thread::~ppu_thread()
|
||||
ppu_thread::ppu_thread(const std::string& name, u32 prio, u32 stack)
|
||||
: cpu_thread(idm::last_id())
|
||||
, prio(prio)
|
||||
, stack_size(stack ? ::align(std::min<u32>(stack, 0x100000), 0x1000) : 0x4000)
|
||||
, stack_size(std::max<u32>(stack, 0x4000))
|
||||
, stack_addr(0)
|
||||
, start_time(get_system_time())
|
||||
, m_name(name)
|
||||
|
||||
@@ -41,7 +41,7 @@ struct TypeGen<T, std::enable_if_t<std::is_void<T>::value>>
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
struct TypeGen<T, std::enable_if_t<std::is_same<T, s64>::value || std::is_same<T, u64>::value || std::is_same<T, uptr>::value>>
|
||||
struct TypeGen<T, std::enable_if_t<std::is_same<T, s64>::value || std::is_same<T, u64>::value>>
|
||||
{
|
||||
static llvm::Type* get(llvm::LLVMContext& context) { return llvm::Type::getInt64Ty(context); }
|
||||
};
|
||||
|
||||
@@ -77,25 +77,6 @@ bool RawSPUThread::read_reg(const u32 addr, u32& value)
|
||||
value = status;
|
||||
return true;
|
||||
}
|
||||
|
||||
case Prxy_TagStatus_offs:
|
||||
{
|
||||
value = mfc_proxy.size() ? 0 : +mfc_prxy_mask;
|
||||
return true;
|
||||
}
|
||||
|
||||
case SPU_NPC_offs:
|
||||
{
|
||||
//npc = pc | ((ch_event_stat & SPU_EVENT_INTR_ENABLED) != 0);
|
||||
value = npc;
|
||||
return true;
|
||||
}
|
||||
|
||||
case SPU_RunCntl_offs:
|
||||
{
|
||||
value = run_ctrl;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
LOG_ERROR(SPU, "RawSPUThread[%d]: Read32(0x%x): unknown/illegal offset (0x%x)", index, addr, offset);
|
||||
@@ -149,15 +130,23 @@ bool RawSPUThread::write_reg(const u32 addr, const u32 value)
|
||||
case MFC_Class_CMD_offs:
|
||||
{
|
||||
g_tls_mfc[index].cmd = MFC(value & 0xff);
|
||||
do_dma_transfer(g_tls_mfc[index]);
|
||||
g_tls_mfc[index] = {};
|
||||
g_tls_mfc[index].cmd = MFC(MFC_PPU_DMA_CMD_ENQUEUE_SUCCESSFUL);
|
||||
|
||||
if (value & MFC_START_MASK)
|
||||
if (mfc_proxy.try_push(g_tls_mfc[index]))
|
||||
{
|
||||
try_start();
|
||||
}
|
||||
auto mfc = fxm::check_unlocked<mfc_thread>();
|
||||
|
||||
if (test(mfc->state, cpu_flag::stop) && mfc->state.test_and_reset(cpu_flag::stop))
|
||||
{
|
||||
mfc->notify();
|
||||
}
|
||||
|
||||
g_tls_mfc[index] = {};
|
||||
g_tls_mfc[index].cmd = MFC(MFC_PPU_DMA_CMD_ENQUEUE_SUCCESSFUL);
|
||||
}
|
||||
else
|
||||
{
|
||||
g_tls_mfc[index] = {};
|
||||
g_tls_mfc[index].cmd = MFC(MFC_PPU_DMA_QUEUE_FULL);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -183,7 +172,6 @@ bool RawSPUThread::write_reg(const u32 addr, const u32 value)
|
||||
|
||||
case Prxy_QueryMask_offs:
|
||||
{
|
||||
mfc_prxy_mask = value;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -166,7 +166,7 @@ void spu_recompiler::compile(spu_function_t& f)
|
||||
dis_asm.dump_pc = m_pos;
|
||||
dis_asm.disasm(m_pos);
|
||||
compiler.comment(dis_asm.last_opcode.c_str());
|
||||
log += dis_asm.last_opcode;
|
||||
log += dis_asm.last_opcode.c_str();
|
||||
log += '\n';
|
||||
}
|
||||
|
||||
|
||||
@@ -274,7 +274,6 @@ void SPUThread::cpu_init()
|
||||
srr0 = 0;
|
||||
ch_tag_upd = 0;
|
||||
ch_tag_mask = 0;
|
||||
mfc_prxy_mask = 0;
|
||||
ch_tag_stat.data.store({});
|
||||
ch_stall_mask = 0;
|
||||
ch_stall_stat.data.store({});
|
||||
|
||||
@@ -550,8 +550,6 @@ public:
|
||||
|
||||
spu_channel_4_t ch_in_mbox;
|
||||
|
||||
atomic_t<u32> mfc_prxy_mask;
|
||||
|
||||
spu_channel_t ch_out_mbox;
|
||||
spu_channel_t ch_out_intr_mbox;
|
||||
|
||||
|
||||
@@ -187,7 +187,7 @@ const std::array<ppu_function_t, 1024> s_ppu_syscall_table
|
||||
BIND_FUNC(sys_event_port_disconnect), //137 (0x089)
|
||||
BIND_FUNC(sys_event_port_send), //138 (0x08A)
|
||||
BIND_FUNC(sys_event_flag_get), //139 (0x08B)
|
||||
BIND_FUNC(sys_event_port_connect_ipc), //140 (0x08C)
|
||||
null_func,//BIND_FUNC(sys_event_port_connect_ipc) //140 (0x08C)
|
||||
BIND_FUNC(sys_timer_usleep), //141 (0x08D)
|
||||
BIND_FUNC(sys_timer_sleep), //142 (0x08E)
|
||||
null_func,//BIND_FUNC(sys_time_set_timezone) //143 (0x08F) ROOT
|
||||
@@ -206,7 +206,7 @@ const std::array<ppu_function_t, 1024> s_ppu_syscall_table
|
||||
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_spu_image_get_segments), //159 (0x09F)
|
||||
BIND_FUNC(_sys_raw_spu_image_load), //159 (0x09F)
|
||||
BIND_FUNC(sys_raw_spu_create), //160 (0x0A0)
|
||||
BIND_FUNC(sys_raw_spu_destroy), //161 (0x0A1)
|
||||
null_func, //162 (0x0A2) UNS
|
||||
|
||||
@@ -323,7 +323,7 @@ error_code sys_event_port_create(vm::ptr<u32> eport_id, s32 port_type, u64 name)
|
||||
{
|
||||
sys_event.warning("sys_event_port_create(eport_id=*0x%x, port_type=%d, name=0x%llx)", eport_id, port_type, name);
|
||||
|
||||
if (port_type != SYS_EVENT_PORT_LOCAL && port_type != 3)
|
||||
if (port_type != SYS_EVENT_PORT_LOCAL)
|
||||
{
|
||||
sys_event.error("sys_event_port_create(): unknown port type (%d)", port_type);
|
||||
return CELL_EINVAL;
|
||||
@@ -393,36 +393,6 @@ error_code sys_event_port_connect_local(u32 eport_id, u32 equeue_id)
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
error_code sys_event_port_connect_ipc(u32 eport_id, u64 ipc_key)
|
||||
{
|
||||
sys_event.warning("sys_event_port_connect_ipc(eport_id=0x%x, ipc_key=0x%x)", eport_id, ipc_key);
|
||||
|
||||
auto queue = lv2_event_queue::find(ipc_key);
|
||||
|
||||
writer_lock lock(id_manager::g_mutex);
|
||||
|
||||
const auto port = idm::check_unlocked<lv2_obj, lv2_event_port>(eport_id);
|
||||
|
||||
if (!port || !queue)
|
||||
{
|
||||
return CELL_ESRCH;
|
||||
}
|
||||
|
||||
if (port->type != 3)
|
||||
{
|
||||
return CELL_EINVAL;
|
||||
}
|
||||
|
||||
if (!port->queue.expired())
|
||||
{
|
||||
return CELL_EISCONN;
|
||||
}
|
||||
|
||||
port->queue = std::move(queue);
|
||||
|
||||
return CELL_ESRCH;
|
||||
}
|
||||
|
||||
error_code sys_event_port_disconnect(u32 eport_id)
|
||||
{
|
||||
sys_event.warning("sys_event_port_disconnect(eport_id=0x%x)", eport_id);
|
||||
|
||||
@@ -136,6 +136,5 @@ error_code sys_event_queue_drain(u32 event_queue_id);
|
||||
error_code sys_event_port_create(vm::ps3::ptr<u32> eport_id, s32 port_type, u64 name);
|
||||
error_code sys_event_port_destroy(u32 eport_id);
|
||||
error_code sys_event_port_connect_local(u32 event_port_id, u32 event_queue_id);
|
||||
error_code sys_event_port_connect_ipc(u32 eport_id, u64 ipc_key);
|
||||
error_code sys_event_port_disconnect(u32 eport_id);
|
||||
error_code sys_event_port_send(u32 event_port_id, u64 data1, u64 data2, u64 data3);
|
||||
|
||||
@@ -192,6 +192,7 @@ error_code sys_fs_open(vm::cptr<char> path, s32 flags, vm::ptr<u32> fd, s32 mode
|
||||
|
||||
if (!path[0])
|
||||
{
|
||||
sys_fs.error("sys_fs_open(%s) failed: path is invalid", path);
|
||||
return CELL_EINVAL;
|
||||
}
|
||||
|
||||
@@ -199,14 +200,16 @@ error_code sys_fs_open(vm::cptr<char> path, s32 flags, vm::ptr<u32> fd, s32 mode
|
||||
|
||||
if (local_path.empty())
|
||||
{
|
||||
return {CELL_ENOTMOUNTED, path};
|
||||
sys_fs.error("sys_fs_open(%s) failed: device not mounted", path);
|
||||
return CELL_ENOTMOUNTED;
|
||||
}
|
||||
|
||||
// TODO: other checks for path
|
||||
|
||||
if (fs::is_dir(local_path))
|
||||
{
|
||||
return {CELL_EISDIR, path};
|
||||
sys_fs.error("sys_fs_open(%s) failed: path is a directory", path);
|
||||
return CELL_EISDIR;
|
||||
}
|
||||
|
||||
bs_t<fs::open_mode> open_mode{};
|
||||
@@ -274,21 +277,20 @@ error_code sys_fs_open(vm::cptr<char> path, s32 flags, vm::ptr<u32> fd, s32 mode
|
||||
|
||||
if (!file)
|
||||
{
|
||||
sys_fs.error("sys_fs_open(%s): failed to open file (flags=%#o, mode=%#o)", path, flags, mode);
|
||||
|
||||
if (test(open_mode & fs::excl))
|
||||
{
|
||||
return not_an_error(CELL_EEXIST); // approximation
|
||||
return CELL_EEXIST; // approximation
|
||||
}
|
||||
|
||||
return {CELL_ENOENT, path};
|
||||
return CELL_ENOENT;
|
||||
}
|
||||
|
||||
if ((flags & CELL_FS_O_MSELF) && (!verify_mself(*fd, file)))
|
||||
{
|
||||
return {CELL_ENOTMSELF, path};
|
||||
}
|
||||
|
||||
const auto casted_arg = vm::static_ptr_cast<const u64>(arg);
|
||||
return CELL_ENOTMSELF;
|
||||
|
||||
const auto casted_arg = vm::static_ptr_cast<const u64>(arg);//static_cast<const be_t<u32> *>(arg.get_ptr());
|
||||
if (size == 8)
|
||||
{
|
||||
// check for sdata
|
||||
@@ -303,7 +305,8 @@ error_code sys_fs_open(vm::cptr<char> path, s32 flags, vm::ptr<u32> fd, s32 mode
|
||||
auto sdata_file = std::make_unique<EDATADecrypter>(std::move(file));
|
||||
if (!sdata_file->ReadHeader())
|
||||
{
|
||||
return {CELL_EFSSPECIFIC, path};
|
||||
sys_fs.error("sys_fs_open(%s): Error reading sdata header!", path);
|
||||
return CELL_EFSSPECIFIC;
|
||||
}
|
||||
|
||||
file.reset(std::move(sdata_file));
|
||||
@@ -322,14 +325,14 @@ error_code sys_fs_open(vm::cptr<char> path, s32 flags, vm::ptr<u32> fd, s32 mode
|
||||
auto sdata_file = std::make_unique<EDATADecrypter>(std::move(file), edatkeys->devKlic, edatkeys->rifKey);
|
||||
if (!sdata_file->ReadHeader())
|
||||
{
|
||||
return {CELL_EFSSPECIFIC, path};
|
||||
sys_fs.error("sys_fs_open(%s): Error reading edata header!", path);
|
||||
return CELL_EFSSPECIFIC;
|
||||
}
|
||||
|
||||
file.reset(std::move(sdata_file));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (const u32 id = idm::make<lv2_fs_object, lv2_file>(path.get_ptr(), std::move(file), mode, flags))
|
||||
{
|
||||
*fd = id;
|
||||
@@ -337,7 +340,7 @@ error_code sys_fs_open(vm::cptr<char> path, s32 flags, vm::ptr<u32> fd, s32 mode
|
||||
}
|
||||
|
||||
// Out of file descriptors
|
||||
return {CELL_EMFILE, path};
|
||||
return CELL_EMFILE;
|
||||
}
|
||||
|
||||
error_code sys_fs_read(u32 fd, vm::ptr<void> buf, u64 nbytes, vm::ptr<u64> nread)
|
||||
@@ -421,21 +424,24 @@ error_code sys_fs_opendir(vm::cptr<char> path, vm::ptr<u32> fd)
|
||||
|
||||
if (local_path.empty())
|
||||
{
|
||||
return {CELL_ENOTMOUNTED, path};
|
||||
sys_fs.error("sys_fs_opendir(%s) failed: device not mounted", path);
|
||||
return CELL_ENOTMOUNTED;
|
||||
}
|
||||
|
||||
// TODO: other checks for path
|
||||
|
||||
if (fs::is_file(local_path))
|
||||
{
|
||||
return {CELL_ENOTDIR, path};
|
||||
sys_fs.error("sys_fs_opendir(%s) failed: path is a file", path);
|
||||
return CELL_ENOTDIR;
|
||||
}
|
||||
|
||||
fs::dir dir(local_path);
|
||||
|
||||
if (!dir)
|
||||
{
|
||||
return {CELL_ENOENT, path};
|
||||
sys_fs.error("sys_fs_opendir(%s): failed to open directory", path);
|
||||
return CELL_ENOENT;
|
||||
}
|
||||
|
||||
if (const u32 id = idm::make<lv2_fs_object, lv2_dir>(path.get_ptr(), std::move(dir)))
|
||||
@@ -500,14 +506,16 @@ error_code sys_fs_stat(vm::cptr<char> path, vm::ptr<CellFsStat> sb)
|
||||
|
||||
if (local_path.empty())
|
||||
{
|
||||
return {CELL_ENOTMOUNTED, path};
|
||||
sys_fs.warning("sys_fs_stat(%s) failed: not mounted", path);
|
||||
return CELL_ENOTMOUNTED;
|
||||
}
|
||||
|
||||
fs::stat_t info;
|
||||
|
||||
if (!fs::stat(local_path, info))
|
||||
{
|
||||
return {CELL_ENOENT, path};
|
||||
sys_fs.error("sys_fs_stat(%s) failed: not found", path);
|
||||
return CELL_ENOENT;
|
||||
}
|
||||
|
||||
sb->mode = info.is_directory ? CELL_FS_S_IFDIR | 0777 : CELL_FS_S_IFREG | 0666;
|
||||
@@ -564,12 +572,12 @@ error_code sys_fs_mkdir(vm::cptr<char> path, s32 mode)
|
||||
|
||||
if (fs::is_dir(local_path))
|
||||
{
|
||||
return {CELL_EEXIST, path};
|
||||
return CELL_EEXIST;
|
||||
}
|
||||
|
||||
if (!fs::create_path(local_path))
|
||||
{
|
||||
return {CELL_EIO, path}; // ???
|
||||
return CELL_EIO; // ???
|
||||
}
|
||||
|
||||
sys_fs.notice("sys_fs_mkdir(): directory %s created", path);
|
||||
@@ -580,16 +588,9 @@ error_code sys_fs_rename(vm::cptr<char> from, vm::cptr<char> to)
|
||||
{
|
||||
sys_fs.warning("sys_fs_rename(from=%s, to=%s)", from, to);
|
||||
|
||||
if (!fs::rename(vfs::get(from.get_ptr()), vfs::get(to.get_ptr()), false))
|
||||
if (!fs::rename(vfs::get(from.get_ptr()), vfs::get(to.get_ptr())))
|
||||
{
|
||||
switch (auto error = fs::g_tls_error)
|
||||
{
|
||||
case fs::error::noent: return {CELL_ENOENT, from};
|
||||
case fs::error::exist: return {CELL_EEXIST, to};
|
||||
default: sys_fs.error("sys_fs_rename(): unknown error %s", error);
|
||||
}
|
||||
|
||||
return {CELL_EIO, from}; // ???
|
||||
return CELL_ENOENT; // ???
|
||||
}
|
||||
|
||||
sys_fs.notice("sys_fs_rename(): %s renamed to %s", from, to);
|
||||
@@ -604,11 +605,11 @@ error_code sys_fs_rmdir(vm::cptr<char> path)
|
||||
{
|
||||
switch (auto error = fs::g_tls_error)
|
||||
{
|
||||
case fs::error::noent: return {CELL_ENOENT, path};
|
||||
case fs::error::noent: return CELL_ENOENT;
|
||||
default: sys_fs.error("sys_fs_rmdir(): unknown error %s", error);
|
||||
}
|
||||
|
||||
return {CELL_EIO, path}; // ???
|
||||
return CELL_EIO; // ???
|
||||
}
|
||||
|
||||
sys_fs.notice("sys_fs_rmdir(): directory %s removed", path);
|
||||
@@ -623,11 +624,11 @@ error_code sys_fs_unlink(vm::cptr<char> path)
|
||||
{
|
||||
switch (auto error = fs::g_tls_error)
|
||||
{
|
||||
case fs::error::noent: return {CELL_ENOENT, path};
|
||||
case fs::error::noent: return CELL_ENOENT;
|
||||
default: sys_fs.error("sys_fs_unlink(): unknown error %s", error);
|
||||
}
|
||||
|
||||
return {CELL_EIO, path}; // ???
|
||||
return CELL_EIO; // ???
|
||||
}
|
||||
|
||||
sys_fs.notice("sys_fs_unlink(): file %s deleted", path);
|
||||
@@ -1005,7 +1006,8 @@ error_code sys_fs_lseek(u32 fd, s64 offset, s32 whence, vm::ptr<u64> pos)
|
||||
|
||||
if (whence >= 3)
|
||||
{
|
||||
return {CELL_EINVAL, whence};
|
||||
sys_fs.error("sys_fs_lseek(): invalid seek whence (%d)", whence);
|
||||
return CELL_EINVAL;
|
||||
}
|
||||
|
||||
const auto file = idm::get<lv2_fs_object, lv2_file>(fd);
|
||||
@@ -1106,11 +1108,11 @@ error_code sys_fs_truncate(vm::cptr<char> path, u64 size)
|
||||
{
|
||||
switch (auto error = fs::g_tls_error)
|
||||
{
|
||||
case fs::error::noent: return {CELL_ENOENT, path};
|
||||
case fs::error::noent: return CELL_ENOENT;
|
||||
default: sys_fs.error("sys_fs_truncate(): unknown error %s", error);
|
||||
}
|
||||
|
||||
return {CELL_EIO, path}; // ???
|
||||
return CELL_EIO; // ???
|
||||
}
|
||||
|
||||
return CELL_OK;
|
||||
@@ -1173,11 +1175,11 @@ error_code sys_fs_disk_free(vm::ps3::cptr<char> path, vm::ptr<u64> total_free, v
|
||||
{
|
||||
switch (auto error = fs::g_tls_error)
|
||||
{
|
||||
case fs::error::noent: return {CELL_ENOENT, path};
|
||||
case fs::error::noent: return CELL_ENOENT;
|
||||
default: sys_fs.error("sys_fs_disk_free(): unknown error %s", error);
|
||||
}
|
||||
|
||||
return {CELL_EIO, path}; // ???
|
||||
return CELL_EIO; // ???
|
||||
}
|
||||
|
||||
*total_free = info.total_free;
|
||||
@@ -1194,11 +1196,11 @@ error_code sys_fs_utime(vm::ps3::cptr<char> path, vm::ps3::cptr<CellFsUtimbuf> t
|
||||
{
|
||||
switch (auto error = fs::g_tls_error)
|
||||
{
|
||||
case fs::error::noent: return {CELL_ENOENT, path};
|
||||
case fs::error::noent: return CELL_ENOENT;
|
||||
default: sys_fs.error("sys_fs_utime(): unknown error %s", error);
|
||||
}
|
||||
|
||||
return {CELL_EIO, path}; // ???
|
||||
return CELL_EIO; // ???
|
||||
}
|
||||
|
||||
return CELL_OK;
|
||||
|
||||
@@ -116,7 +116,9 @@ error_code prx_load_module(std::string path, u64 flags, vm::ptr<sys_prx_load_mod
|
||||
return not_an_error(idm::last_id());
|
||||
}
|
||||
|
||||
const ppu_prx_object obj = decrypt_self(fs::file(vfs::get(path)), fxm::get_always<LoadedNpdrmKeys_t>()->devKlic.data());
|
||||
const auto loadedkeys = fxm::get_always<LoadedNpdrmKeys_t>();
|
||||
|
||||
const ppu_prx_object obj = decrypt_self(fs::file(vfs::get(path)), loadedkeys->devKlic.data());
|
||||
|
||||
if (obj != elf_error::ok)
|
||||
{
|
||||
|
||||
@@ -328,30 +328,7 @@ s32 sys_rsx_context_attribute(s32 context_id, u32 package_id, u64 a3, u64 a4, u6
|
||||
break;
|
||||
|
||||
case 0x301: // Depth-buffer (Z-cull)
|
||||
{
|
||||
//a4 high = region = (1 << 0) | (zFormat << 4) | (aaFormat << 8);
|
||||
//a4 low = size = ((width >> 6) << 22) | ((height >> 6) << 6);
|
||||
//a5 high = start = cullStart&(~0xFFF);
|
||||
//a5 low = offset = offset;
|
||||
//a6 high = status0 = (zcullDir << 1) | (zcullFormat << 2) | ((sFunc & 0xF) << 12) | (sRef << 16) | (sMask << 24);
|
||||
//a6 low = status1 = (0x2000 << 0) | (0x20 << 16);
|
||||
|
||||
auto &zcull = render->zculls[a3];
|
||||
zcull.zFormat = ((a4 >> 32) >> 4) & 0xF;
|
||||
zcull.aaFormat = ((a4 >> 32) >> 8) & 0xF;
|
||||
zcull.width = ((a4 & 0xFFFFFFFF) >> 22) << 6;
|
||||
zcull.height = (((a4 & 0xFFFFFFFF) >> 6) & 0xFF) << 6;
|
||||
zcull.cullStart = (a5 >> 32);
|
||||
zcull.offset = (a5 & 0xFFFFFFFF);
|
||||
zcull.zcullDir = ((a6 >> 32) >> 1) & 0x1;
|
||||
zcull.zcullFormat = ((a6 >> 32) >> 2) & 0x3FF;
|
||||
zcull.sFunc = ((a6 >> 32) >> 12) & 0xF;
|
||||
zcull.sRef = ((a6 >> 32) >> 16) & 0xFF;
|
||||
zcull.sMask = ((a6 >> 32) >> 24) & 0xFF;
|
||||
zcull.binded = (a6 & 0xFFFFFFFF) != 0;
|
||||
}
|
||||
break;
|
||||
|
||||
break;
|
||||
case 0x302: // something with zcull
|
||||
break;
|
||||
case 0x600: // Framebuffer setup
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
#include "Emu/System.h"
|
||||
#include "Emu/IdManager.h"
|
||||
#include "Crypto/unself.h"
|
||||
#include "Crypto/unedat.h"
|
||||
#include "Crypto/sha1.h"
|
||||
#include "Loader/ELF.h"
|
||||
#include "Utilities/bin_patch.h"
|
||||
@@ -21,13 +20,20 @@ logs::channel sys_spu("sys_spu");
|
||||
|
||||
void sys_spu_image::load(const fs::file& stream)
|
||||
{
|
||||
const spu_exec_object obj{stream, 0, elf_opt::no_sections + elf_opt::no_data};
|
||||
const spu_exec_object obj{stream};
|
||||
|
||||
if (obj != elf_error::ok)
|
||||
{
|
||||
fmt::throw_exception("Failed to load SPU image: %s" HERE, obj.get_error());
|
||||
}
|
||||
|
||||
this->type = SYS_SPU_IMAGE_TYPE_KERNEL;
|
||||
this->entry_point = obj.header.e_entry;
|
||||
this->segs.set(vm::alloc(65 * 4096, vm::main));
|
||||
this->nsegs = 0;
|
||||
|
||||
const u32 addr = this->segs.addr() + 4096;
|
||||
|
||||
for (const auto& shdr : obj.shdrs)
|
||||
{
|
||||
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);
|
||||
@@ -37,30 +43,37 @@ void sys_spu_image::load(const fs::file& stream)
|
||||
{
|
||||
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 && prog.p_type != SYS_SPU_SEGMENT_TYPE_INFO)
|
||||
if (prog.p_type == SYS_SPU_SEGMENT_TYPE_COPY)
|
||||
{
|
||||
auto& seg = segs[nsegs++];
|
||||
seg.type = prog.p_type;
|
||||
seg.ls = prog.p_vaddr;
|
||||
seg.addr = addr + prog.p_vaddr;
|
||||
seg.size = std::min(prog.p_filesz, prog.p_memsz);
|
||||
std::memcpy(vm::base(seg.addr), prog.bin.data(), seg.size);
|
||||
|
||||
if (prog.p_memsz > prog.p_filesz)
|
||||
{
|
||||
auto& zero = segs[nsegs++];
|
||||
zero.type = SYS_SPU_SEGMENT_TYPE_FILL;
|
||||
zero.ls = prog.p_vaddr + prog.p_filesz;
|
||||
zero.addr = 0;
|
||||
zero.size = prog.p_memsz - seg.size;
|
||||
}
|
||||
}
|
||||
else if (prog.p_type == SYS_SPU_SEGMENT_TYPE_INFO)
|
||||
{
|
||||
auto& seg = segs[nsegs++];
|
||||
seg.type = SYS_SPU_SEGMENT_TYPE_INFO;
|
||||
seg.ls = prog.p_vaddr;
|
||||
seg.addr = 0;
|
||||
seg.size = prog.p_filesz;
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG_ERROR(SPU, "Unknown program type (0x%x)", prog.p_type);
|
||||
}
|
||||
}
|
||||
|
||||
const u32 mem_size = nsegs * sizeof(sys_spu_segment) + ::size32(stream);
|
||||
|
||||
type = SYS_SPU_IMAGE_TYPE_KERNEL;
|
||||
entry_point = obj.header.e_entry;
|
||||
nsegs = sys_spu_image::get_nsegs(obj.progs);
|
||||
segs = vm::cast(vm::alloc(mem_size, vm::main));
|
||||
|
||||
const u32 src = segs.addr() + nsegs * sizeof(sys_spu_segment);
|
||||
|
||||
stream.seek(0);
|
||||
stream.read(vm::base(src), stream.size());
|
||||
|
||||
if (nsegs < 0 || sys_spu_image::fill(segs, nsegs, obj.progs, src) != nsegs)
|
||||
{
|
||||
fmt::throw_exception("Failed to load SPU segments (%d)" HERE, nsegs);
|
||||
}
|
||||
|
||||
vm::page_protect(segs.addr(), ::align(mem_size, 4096), 0, 0, vm::page_writable);
|
||||
}
|
||||
|
||||
void sys_spu_image::free()
|
||||
@@ -71,7 +84,7 @@ void sys_spu_image::free()
|
||||
}
|
||||
}
|
||||
|
||||
void sys_spu_image::deploy(u32 loc, sys_spu_segment* segs, u32 nsegs)
|
||||
void sys_spu_image::deploy(u32 loc)
|
||||
{
|
||||
// Segment info dump
|
||||
std::string dump;
|
||||
@@ -81,19 +94,19 @@ void sys_spu_image::deploy(u32 loc, sys_spu_segment* segs, u32 nsegs)
|
||||
sha1_starts(&sha);
|
||||
u8 sha1_hash[20];
|
||||
|
||||
for (u32 i = 0; i < nsegs; i++)
|
||||
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);
|
||||
|
||||
sha1_update(&sha, (uchar*)&seg.type, sizeof(seg.type));
|
||||
|
||||
// Hash big-endian values
|
||||
sha1_update(&sha, (uchar*)&seg.type, sizeof(seg.type));
|
||||
sha1_update(&sha, (uchar*)&seg.size, sizeof(seg.size));
|
||||
|
||||
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.size, sizeof(seg.size));
|
||||
sha1_update(&sha, (uchar*)&seg.ls, sizeof(seg.ls));
|
||||
sha1_update(&sha, vm::g_base_addr + seg.addr, seg.size);
|
||||
}
|
||||
@@ -105,15 +118,9 @@ void sys_spu_image::deploy(u32 loc, sys_spu_segment* segs, u32 nsegs)
|
||||
}
|
||||
|
||||
std::fill_n(vm::_ptr<u32>(loc + seg.ls), seg.size / 4, seg.addr);
|
||||
sha1_update(&sha, (uchar*)&seg.size, sizeof(seg.size));
|
||||
sha1_update(&sha, (uchar*)&seg.ls, sizeof(seg.ls));
|
||||
sha1_update(&sha, (uchar*)&seg.addr, sizeof(seg.addr));
|
||||
}
|
||||
else if (seg.type == SYS_SPU_SEGMENT_TYPE_INFO)
|
||||
{
|
||||
const be_t<u32> size = seg.size + 0x14; // Workaround
|
||||
sha1_update(&sha, (uchar*)&size, sizeof(size));
|
||||
}
|
||||
}
|
||||
|
||||
sha1_finish(&sha, sha1_hash);
|
||||
@@ -151,24 +158,22 @@ 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, vm::ptr<u32> entry_point, vm::ptr<s32> nsegs)
|
||||
error_code _sys_spu_image_get_information(vm::ptr<sys_spu_image> img, u32 ptr1, u32 ptr2)
|
||||
{
|
||||
sys_spu.warning("_sys_spu_image_get_information(img=*0x%x, entry_point=*0x%x, nsegs=*0x%x)", img, entry_point, nsegs);
|
||||
sys_spu.todo("_sys_spu_image_get_information(img=*0x%x, 1=*0x%x, 2=*0x%x)", img, ptr1, ptr2);
|
||||
|
||||
*entry_point = img->entry_point;
|
||||
*nsegs = img->nsegs;
|
||||
return CELL_OK;
|
||||
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);
|
||||
|
||||
const fs::file elf_file = decrypt_self(fs::file(vfs::get(path.get_ptr())), fxm::get_always<LoadedNpdrmKeys_t>()->devKlic.data());
|
||||
const fs::file elf_file = decrypt_self(fs::file(vfs::get(path.get_ptr())));
|
||||
|
||||
if (!elf_file)
|
||||
{
|
||||
sys_spu.error("sys_spu_image_open() error: failed to open %s!", path);
|
||||
sys_spu.error("sys_spu_image_open() error: %s not found!", path);
|
||||
return CELL_ENOENT;
|
||||
}
|
||||
|
||||
@@ -177,29 +182,25 @@ 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 size, u32 arg4)
|
||||
error_code _sys_spu_image_import(vm::ptr<sys_spu_image> img, u32 src, u32 arg3, u32 arg4)
|
||||
{
|
||||
sys_spu.warning("_sys_spu_image_import(img=*0x%x, src=*0x%x, size=0x%x, arg4=0x%x)", img, src, size, arg4);
|
||||
sys_spu.todo("_sys_spu_image_import(img=*0x%x, src=*0x%x, arg3=0x%x, arg4=0x%x)", img, src, arg3, arg4);
|
||||
|
||||
img->load(fs::file{vm::base(src), size});
|
||||
return CELL_OK;
|
||||
fmt::throw_exception("Unimplemented syscall: _sys_spu_image_import");
|
||||
}
|
||||
|
||||
error_code _sys_spu_image_close(vm::ptr<sys_spu_image> img)
|
||||
{
|
||||
sys_spu.warning("_sys_spu_image_close(img=*0x%x)", img);
|
||||
sys_spu.todo("_sys_spu_image_close(img=*0x%x)", img);
|
||||
|
||||
vm::dealloc(img->segs.addr(), vm::main);
|
||||
return CELL_OK;
|
||||
fmt::throw_exception("Unimplemented syscall: _sys_spu_image_close");
|
||||
}
|
||||
|
||||
error_code _sys_spu_image_get_segments(vm::ptr<sys_spu_image> img, vm::ptr<sys_spu_segment> segments, s32 nseg)
|
||||
error_code _sys_raw_spu_image_load(vm::ptr<sys_spu_image> img, u32 ptr, u32 arg3)
|
||||
{
|
||||
sys_spu.error("_sys_spu_image_get_segments(img=*0x%x, segments=*0x%x, nseg=%d)", img, segments, nseg);
|
||||
sys_spu.todo("_sys_raw_spu_image_load(img=*0x%x, ptr=*0x%x, arg3=0x%x)", img, ptr, arg3);
|
||||
|
||||
// TODO: apply SPU patches
|
||||
std::memcpy(segments.get_ptr(), img->segs.get_ptr(), sizeof(sys_spu_segment) * nseg);
|
||||
return CELL_OK;
|
||||
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)
|
||||
@@ -241,8 +242,7 @@ error_code sys_spu_thread_initialize(vm::ptr<u32> thread, u32 group_id, u32 spu_
|
||||
|
||||
group->threads[spu_num] = std::move(spu);
|
||||
group->args[spu_num] = {arg->arg1, arg->arg2, arg->arg3, arg->arg4};
|
||||
group->imgs[spu_num] = std::make_pair(*img, std::vector<sys_spu_segment>());
|
||||
group->imgs[spu_num].second.assign(img->segs.get_ptr(), img->segs.get_ptr() + img->nsegs);
|
||||
group->imgs[spu_num] = *img;
|
||||
|
||||
if (++group->init == group->num)
|
||||
{
|
||||
@@ -384,9 +384,9 @@ error_code sys_spu_thread_group_start(ppu_thread& ppu, u32 id)
|
||||
auto& args = group->args[thread->index];
|
||||
auto& img = group->imgs[thread->index];
|
||||
|
||||
sys_spu_image::deploy(thread->offset, img.second.data(), img.first.nsegs);
|
||||
img.deploy(thread->offset);
|
||||
|
||||
thread->pc = img.first.entry_point;
|
||||
thread->pc = img.entry_point;
|
||||
thread->cpu_init();
|
||||
thread->gpr[3] = v128::from64(0, args[0]);
|
||||
thread->gpr[4] = v128::from64(0, args[1]);
|
||||
|
||||
@@ -112,92 +112,9 @@ struct sys_spu_image
|
||||
vm::ps3::bptr<sys_spu_segment> segs;
|
||||
be_t<s32> nsegs;
|
||||
|
||||
template <bool CountInfo = true, typename Phdrs>
|
||||
static s32 get_nsegs(const Phdrs& phdrs)
|
||||
{
|
||||
s32 num_segs = 0;
|
||||
|
||||
for (const auto& phdr : phdrs)
|
||||
{
|
||||
if (phdr.p_type != 1 && phdr.p_type != 4)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (phdr.p_type == 1 && phdr.p_filesz != phdr.p_memsz && phdr.p_filesz)
|
||||
{
|
||||
num_segs += 2;
|
||||
}
|
||||
else if (phdr.p_type == 1 || CountInfo)
|
||||
{
|
||||
num_segs += 1;
|
||||
}
|
||||
}
|
||||
|
||||
return num_segs;
|
||||
}
|
||||
|
||||
template <bool WriteInfo = true, typename Phdrs>
|
||||
static s32 fill(vm::ps3::ptr<sys_spu_segment> segs, s32 nsegs, const Phdrs& phdrs, u32 src)
|
||||
{
|
||||
s32 num_segs = 0;
|
||||
|
||||
for (const auto& phdr : phdrs)
|
||||
{
|
||||
if (phdr.p_type == 1)
|
||||
{
|
||||
if (phdr.p_filesz)
|
||||
{
|
||||
if (num_segs >= nsegs)
|
||||
{
|
||||
return -2;
|
||||
}
|
||||
|
||||
auto* seg = &segs[num_segs++];
|
||||
seg->type = SYS_SPU_SEGMENT_TYPE_COPY;
|
||||
seg->ls = static_cast<u32>(phdr.p_vaddr);
|
||||
seg->size = static_cast<u32>(phdr.p_filesz);
|
||||
seg->addr = static_cast<u32>(phdr.p_offset + src);
|
||||
}
|
||||
|
||||
if (phdr.p_memsz > phdr.p_filesz)
|
||||
{
|
||||
if (num_segs >= nsegs)
|
||||
{
|
||||
return -2;
|
||||
}
|
||||
|
||||
auto* seg = &segs[num_segs++];
|
||||
seg->type = SYS_SPU_SEGMENT_TYPE_FILL;
|
||||
seg->ls = static_cast<u32>(phdr.p_vaddr + phdr.p_filesz);
|
||||
seg->size = static_cast<u32>(phdr.p_memsz - phdr.p_filesz);
|
||||
seg->addr = 0;
|
||||
}
|
||||
}
|
||||
else if (WriteInfo && phdr.p_type == 4)
|
||||
{
|
||||
if (num_segs >= nsegs)
|
||||
{
|
||||
return -2;
|
||||
}
|
||||
|
||||
auto* seg = &segs[num_segs++];
|
||||
seg->type = SYS_SPU_SEGMENT_TYPE_INFO;
|
||||
seg->size = 0x20;
|
||||
seg->addr = static_cast<u32>(phdr.p_offset + 0x14 + src);
|
||||
}
|
||||
else if (phdr.p_type != 4)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
return num_segs;
|
||||
}
|
||||
|
||||
void load(const fs::file& stream);
|
||||
void free();
|
||||
static void deploy(u32 loc, sys_spu_segment* segs, u32 nsegs);
|
||||
void deploy(u32 loc);
|
||||
};
|
||||
|
||||
enum : u32
|
||||
@@ -236,7 +153,7 @@ struct lv2_spu_group
|
||||
cond_variable cv; // used to signal waiting PPU thread
|
||||
|
||||
std::array<std::shared_ptr<SPUThread>, 256> threads; // SPU Threads
|
||||
std::array<std::pair<sys_spu_image, std::vector<sys_spu_segment>>, 256> imgs; // SPU Images
|
||||
std::array<sys_spu_image, 256> imgs; // SPU Images
|
||||
std::array<std::array<u64, 4>, 256> args; // SPU Thread Arguments
|
||||
|
||||
std::weak_ptr<lv2_event_queue> ep_run; // port for SYS_SPU_THREAD_GROUP_EVENT_RUN events
|
||||
@@ -286,11 +203,11 @@ 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, vm::ps3::ptr<u32> entry_point, vm::ps3::ptr<s32> nsegs);
|
||||
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 size, u32 arg4);
|
||||
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_spu_image_get_segments(vm::ps3::ptr<sys_spu_image> img, vm::ps3::ptr<sys_spu_segment> segments, s32 nseg);
|
||||
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);
|
||||
@@ -298,7 +215,7 @@ error_code sys_spu_thread_group_destroy(u32 id);
|
||||
error_code sys_spu_thread_group_start(ppu_thread&, u32 id);
|
||||
error_code sys_spu_thread_group_suspend(u32 id);
|
||||
error_code sys_spu_thread_group_resume(u32 id);
|
||||
error_code sys_spu_thread_group_yield(u32 id);
|
||||
error_code sys_spu_thread_group_yield(u32 id);
|
||||
error_code sys_spu_thread_group_terminate(u32 id, s32 value);
|
||||
error_code sys_spu_thread_group_join(ppu_thread&, u32 id, vm::ps3::ptr<u32> cause, vm::ps3::ptr<u32> status);
|
||||
error_code sys_spu_thread_group_set_priority(u32 id, s32 priority);
|
||||
|
||||
+1
-8
@@ -26,9 +26,7 @@ public:
|
||||
// Get object location
|
||||
std::weak_ptr<T>& wptr = g_ipc.m_map[ipc_key];
|
||||
|
||||
std::shared_ptr<T> old;
|
||||
|
||||
if ((out && !(old = wptr.lock())) || wptr.expired())
|
||||
if ((out && !(*out = wptr.lock())) || wptr.expired())
|
||||
{
|
||||
// Call a function which must return the object
|
||||
if (out)
|
||||
@@ -44,11 +42,6 @@ public:
|
||||
return true;
|
||||
}
|
||||
|
||||
if (out)
|
||||
{
|
||||
*out = std::move(old);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@@ -50,7 +50,6 @@ void idm::init()
|
||||
{
|
||||
// Allocate
|
||||
g_map.resize(id_manager::typeinfo::get_count());
|
||||
idm::clear();
|
||||
}
|
||||
|
||||
void idm::clear()
|
||||
@@ -76,7 +75,6 @@ void fxm::init()
|
||||
{
|
||||
// Allocate
|
||||
g_vec.resize(id_manager::typeinfo::get_count());
|
||||
fxm::clear();
|
||||
}
|
||||
|
||||
void fxm::clear()
|
||||
|
||||
+4
-15
@@ -6,7 +6,6 @@
|
||||
#include "Utilities/VirtualMemory.h"
|
||||
#include "Emu/CPU/CPUThread.h"
|
||||
#include "Emu/Cell/lv2/sys_memory.h"
|
||||
#include "Emu/RSX/GSRender.h"
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <Windows.h>
|
||||
@@ -657,7 +656,6 @@ namespace vm
|
||||
if (found != m_map.end())
|
||||
{
|
||||
const u32 size = found->second;
|
||||
const auto rsxthr = fxm::get<GSRender>();
|
||||
|
||||
// Remove entry
|
||||
m_map.erase(found);
|
||||
@@ -665,9 +663,6 @@ namespace vm
|
||||
// Unmap "real" memory pages
|
||||
_page_unmap(addr, size);
|
||||
|
||||
// Notify rsx to invalidate range
|
||||
if (rsxthr != nullptr) rsxthr->on_notify_memory_unmapped(addr, size);
|
||||
|
||||
// Write supplementary info if necessary
|
||||
if (sup_out) *sup_out = m_sup[addr];
|
||||
|
||||
@@ -680,8 +675,10 @@ namespace vm
|
||||
return 0;
|
||||
}
|
||||
|
||||
u32 block_t::imp_used(const vm::writer_lock&)
|
||||
u32 block_t::used()
|
||||
{
|
||||
reader_lock lock;
|
||||
|
||||
u32 result = 0;
|
||||
|
||||
for (auto& entry : m_map)
|
||||
@@ -692,13 +689,6 @@ namespace vm
|
||||
return result;
|
||||
}
|
||||
|
||||
u32 block_t::used()
|
||||
{
|
||||
writer_lock lock(0);
|
||||
|
||||
return imp_used(lock);
|
||||
}
|
||||
|
||||
std::shared_ptr<block_t> map(u32 addr, u32 size, u64 flags)
|
||||
{
|
||||
writer_lock lock(0);
|
||||
@@ -744,7 +734,7 @@ namespace vm
|
||||
{
|
||||
if (*it && (*it)->addr == addr)
|
||||
{
|
||||
if (must_be_empty && (!it->unique() || (*it)->imp_used(lock)))
|
||||
if (must_be_empty && (!it->unique() || (*it)->used()))
|
||||
{
|
||||
return *it;
|
||||
}
|
||||
@@ -797,7 +787,6 @@ namespace vm
|
||||
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
|
||||
std::make_shared<block_t>(0x30000000, 0x10000000), // main extend
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -156,9 +156,6 @@ namespace vm
|
||||
// Unmap memory at specified location previously returned by alloc(), return size
|
||||
u32 dealloc(u32 addr, u32* sup_out = nullptr);
|
||||
|
||||
// Internal
|
||||
u32 imp_used(const vm::writer_lock&);
|
||||
|
||||
// Get allocated memory count
|
||||
u32 used();
|
||||
};
|
||||
|
||||
@@ -96,16 +96,6 @@ namespace vm
|
||||
{
|
||||
return m_size / SIZE_32(T);
|
||||
}
|
||||
|
||||
auto begin() const
|
||||
{
|
||||
return *this + 0;
|
||||
}
|
||||
|
||||
auto end() const
|
||||
{
|
||||
return *this + get_count();
|
||||
}
|
||||
};
|
||||
|
||||
// LE variable
|
||||
|
||||
@@ -51,22 +51,21 @@ std::string CgBinaryDisasm::GetScaMaskDisasm()
|
||||
std::string CgBinaryDisasm::GetDSTDisasm(bool isSca)
|
||||
{
|
||||
std::string ret;
|
||||
std::string mask = GetMaskDisasm(isSca);
|
||||
|
||||
switch ((isSca && d3.sca_dst_tmp != 0x3f) ? 0x1f : d3.dst)
|
||||
switch (isSca ? 0x1f : d3.dst)
|
||||
{
|
||||
case 0x1f:
|
||||
ret += (isSca ? fmt::format("R%d", d3.sca_dst_tmp) : fmt::format("R%d", d0.dst_tmp)) + mask;
|
||||
ret += isSca ? fmt::format("R%d", d3.sca_dst_tmp) + GetScaMaskDisasm() : fmt::format("R%d", d0.dst_tmp) + GetVecMaskDisasm();
|
||||
break;
|
||||
|
||||
default:
|
||||
if (d3.dst > 15)
|
||||
LOG_ERROR(RSX, "dst index out of range: %u", d3.dst);
|
||||
|
||||
ret += fmt::format("o[%d]", d3.dst) + mask;
|
||||
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) + mask;
|
||||
ret += fmt::format(" R%d", d0.dst_tmp) + GetVecMaskDisasm();
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
@@ -610,12 +610,12 @@ bool is_primitive_native(rsx::primitive_type draw_mode)
|
||||
case rsx::primitive_type::line_strip:
|
||||
case rsx::primitive_type::triangles:
|
||||
case rsx::primitive_type::triangle_strip:
|
||||
case rsx::primitive_type::quad_strip:
|
||||
return true;
|
||||
case rsx::primitive_type::line_loop:
|
||||
case rsx::primitive_type::polygon:
|
||||
case rsx::primitive_type::triangle_fan:
|
||||
case rsx::primitive_type::quads:
|
||||
case rsx::primitive_type::quad_strip:
|
||||
return false;
|
||||
}
|
||||
fmt::throw_exception("Wrong primitive type" HERE);
|
||||
@@ -641,6 +641,8 @@ u32 get_index_count(rsx::primitive_type draw_mode, u32 initial_index_count)
|
||||
return (initial_index_count - 2) * 3;
|
||||
case rsx::primitive_type::quads:
|
||||
return (6 * initial_index_count) / 4;
|
||||
case rsx::primitive_type::quad_strip:
|
||||
return (6 * (initial_index_count - 2)) / 2;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
@@ -689,6 +691,18 @@ void write_index_array_for_non_indexed_non_native_primitive_to_buffer(char* dst,
|
||||
}
|
||||
return;
|
||||
case rsx::primitive_type::quad_strip:
|
||||
for (unsigned i = 0; i < (count - 2) / 2; i++)
|
||||
{
|
||||
// First triangle
|
||||
typedDst[6 * i] = 2 * i;
|
||||
typedDst[6 * i + 1] = 2 * i + 1;
|
||||
typedDst[6 * i + 2] = 2 * i + 2;
|
||||
// Second triangle
|
||||
typedDst[6 * i + 3] = 2 * i + 2;
|
||||
typedDst[6 * i + 4] = 2 * i + 1;
|
||||
typedDst[6 * i + 5] = 2 * i + 3;
|
||||
}
|
||||
return;
|
||||
case rsx::primitive_type::points:
|
||||
case rsx::primitive_type::lines:
|
||||
case rsx::primitive_type::line_strip:
|
||||
|
||||
@@ -1,347 +0,0 @@
|
||||
#pragma once
|
||||
#include <sstream>
|
||||
|
||||
#include "ShaderParam.h"
|
||||
|
||||
namespace program_common
|
||||
{
|
||||
static void insert_compare_op(std::ostream& OS)
|
||||
{
|
||||
OS << "bool comparison_passes(float a, float b, uint func)\n";
|
||||
OS << "{\n";
|
||||
OS << " switch (func)\n";
|
||||
OS << " {\n";
|
||||
OS << " default:\n";
|
||||
OS << " case 0: return false; //never\n";
|
||||
OS << " case 1: return (a < b); //less\n";
|
||||
OS << " case 2: return (a == b); //equal\n";
|
||||
OS << " case 3: return (a <= b); //lequal\n";
|
||||
OS << " case 4: return (a > b); //greater\n";
|
||||
OS << " case 5: return (a != b); //nequal\n";
|
||||
OS << " case 6: return (a >= b); //gequal\n";
|
||||
OS << " case 7: return true; //always\n";
|
||||
OS << " }\n";
|
||||
OS << "}\n\n";
|
||||
}
|
||||
|
||||
static void insert_fog_declaration(std::ostream& OS, const std::string wide_vector_type, const std::string input_coord, bool declare = false)
|
||||
{
|
||||
std::string template_body;
|
||||
|
||||
if (!declare)
|
||||
template_body += "$T fetch_fog_value(uint mode)\n";
|
||||
else
|
||||
template_body += "$T fetch_fog_value(uint mode, $T $I)\n";
|
||||
|
||||
template_body += "{\n";
|
||||
template_body += " $T result = $T(0., 0., 0., 0.);\n";
|
||||
template_body += " switch(mode)\n";
|
||||
template_body += " {\n";
|
||||
template_body += " default:\n";
|
||||
template_body += " return result;\n";
|
||||
template_body += " case 0:\n";
|
||||
template_body += " //linear\n";
|
||||
template_body += " result = $T(fog_param1 * $I.x + (fog_param0 - 1.), fog_param1 * $I.x + (fog_param0 - 1.), 0., 0.);\n";
|
||||
template_body += " break;\n";
|
||||
template_body += " case 1:\n";
|
||||
template_body += " //exponential\n";
|
||||
template_body += " result = $T(11.084 * (fog_param1 * $I.x + fog_param0 - 1.5), exp(11.084 * (fog_param1 * $I.x + fog_param0 - 1.5)), 0., 0.);\n";
|
||||
template_body += " break;\n";
|
||||
template_body += " case 2:\n";
|
||||
template_body += " //exponential2\n";
|
||||
template_body += " result = $T(4.709 * (fog_param1 * $I.x + fog_param0 - 1.5), exp(-pow(4.709 * (fog_param1 * $I.x + fog_param0 - 1.5), 2.)), 0., 0.);\n";
|
||||
template_body += " break;\n";
|
||||
template_body += " case 3:\n";
|
||||
template_body += " //exponential_abs\n";
|
||||
template_body += " result = $T(11.084 * (fog_param1 * abs($I.x) + fog_param0 - 1.5), exp(11.084 * (fog_param1 * abs($I.x) + fog_param0 - 1.5)), 0., 0.);\n";
|
||||
template_body += " break;\n";
|
||||
template_body += " case 4:\n";
|
||||
template_body += " //exponential2_abs\n";
|
||||
template_body += " result = $T(4.709 * (fog_param1 * abs($I.x) + fog_param0 - 1.5), exp(-pow(4.709 * (fog_param1 * abs($I.x) + fog_param0 - 1.5), 2.)), 0., 0.);\n";
|
||||
template_body += " break;\n";
|
||||
template_body += " case 5:\n";
|
||||
template_body += " //linear_abs\n";
|
||||
template_body += " result = $T(fog_param1 * abs($I.x) + (fog_param0 - 1.), fog_param1 * abs($I.x) + (fog_param0 - 1.), 0., 0.);\n";
|
||||
template_body += " break;\n";
|
||||
template_body += " }\n";
|
||||
template_body += "\n";
|
||||
template_body += " result.y = clamp(result.y, 0., 1.);\n";
|
||||
template_body += " return result;\n";
|
||||
template_body += "}\n\n";
|
||||
|
||||
std::pair<std::string, std::string> replacements[] =
|
||||
{std::make_pair("$T", wide_vector_type),
|
||||
std::make_pair("$I", input_coord)};
|
||||
|
||||
OS << fmt::replace_all(template_body, replacements);
|
||||
}
|
||||
}
|
||||
|
||||
namespace glsl
|
||||
{
|
||||
enum program_domain
|
||||
{
|
||||
glsl_vertex_program = 0,
|
||||
glsl_fragment_program = 1
|
||||
};
|
||||
|
||||
enum glsl_rules
|
||||
{
|
||||
glsl_rules_opengl4,
|
||||
glsl_rules_rpirv
|
||||
};
|
||||
|
||||
static std::string getFloatTypeNameImpl(size_t elementCount)
|
||||
{
|
||||
switch (elementCount)
|
||||
{
|
||||
default:
|
||||
abort();
|
||||
case 1:
|
||||
return "float";
|
||||
case 2:
|
||||
return "vec2";
|
||||
case 3:
|
||||
return "vec3";
|
||||
case 4:
|
||||
return "vec4";
|
||||
}
|
||||
}
|
||||
|
||||
static std::string compareFunctionImpl(COMPARE f, const std::string &Op0, const std::string &Op1)
|
||||
{
|
||||
switch (f)
|
||||
{
|
||||
case COMPARE::FUNCTION_SEQ:
|
||||
return "equal(" + Op0 + ", " + Op1 + ")";
|
||||
case COMPARE::FUNCTION_SGE:
|
||||
return "greaterThanEqual(" + Op0 + ", " + Op1 + ")";
|
||||
case COMPARE::FUNCTION_SGT:
|
||||
return "greaterThan(" + Op0 + ", " + Op1 + ")";
|
||||
case COMPARE::FUNCTION_SLE:
|
||||
return "lessThanEqual(" + Op0 + ", " + Op1 + ")";
|
||||
case COMPARE::FUNCTION_SLT:
|
||||
return "lessThan(" + Op0 + ", " + Op1 + ")";
|
||||
case COMPARE::FUNCTION_SNE:
|
||||
return "notEqual(" + Op0 + ", " + Op1 + ")";
|
||||
}
|
||||
fmt::throw_exception("Unknown compare function" HERE);
|
||||
}
|
||||
|
||||
static void insert_vertex_input_fetch(std::stringstream& OS, glsl_rules rules, bool glsl4_compliant=true)
|
||||
{
|
||||
std::string vertex_id_name = (rules == glsl_rules_opengl4) ? "gl_VertexID" : "gl_VertexIndex";
|
||||
|
||||
//Actually decode a vertex attribute from a raw byte stream
|
||||
OS << "struct attribute_desc\n";
|
||||
OS << "{\n";
|
||||
OS << " int type;\n";
|
||||
OS << " int attribute_size;\n";
|
||||
OS << " int starting_offset;\n";
|
||||
OS << " int stride;\n";
|
||||
OS << " int swap_bytes;\n";
|
||||
OS << " int is_volatile;\n";
|
||||
OS << " int frequency;\n";
|
||||
OS << " int divisor;\n";
|
||||
OS << " int modulo;\n";
|
||||
OS << "};\n\n";
|
||||
|
||||
OS << "uint get_bits(uvec4 v, int swap)\n";
|
||||
OS << "{\n";
|
||||
OS << " if (swap != 0) return (v.w | v.z << 8 | v.y << 16 | v.x << 24);\n";
|
||||
OS << " return (v.x | v.y << 8 | v.z << 16 | v.w << 24);\n";
|
||||
OS << "}\n\n";
|
||||
|
||||
OS << "uint get_bits(uvec2 v, int swap)\n";
|
||||
OS << "{\n";
|
||||
OS << " if (swap != 0) return (v.y | v.x << 8);\n";
|
||||
OS << " return (v.x | v.y << 8);\n";
|
||||
OS << "}\n\n";
|
||||
|
||||
OS << "int preserve_sign_s16(uint bits)\n";
|
||||
OS << "{\n";
|
||||
OS << " //convert raw 16 bit value into signed 32-bit integer counterpart\n";
|
||||
OS << " uint sign = bits & 0x8000;\n";
|
||||
OS << " if (sign != 0) return int(bits | 0xFFFF0000);\n";
|
||||
OS << " return int(bits);\n";
|
||||
OS << "}\n\n";
|
||||
|
||||
//For intel GPUs which cannot access vectors in indexed mode (driver bug? or glsl version too low?)
|
||||
if (!glsl4_compliant)
|
||||
{
|
||||
OS << "void mov(inout vec4 vector, in int index, in float scalar)\n";
|
||||
OS << "{\n";
|
||||
OS << " switch(index)\n";
|
||||
OS << " {\n";
|
||||
OS << " case 0: vector.x = scalar; return;\n";
|
||||
OS << " case 1: vector.y = scalar; return;\n";
|
||||
OS << " case 2: vector.z = scalar; return;\n";
|
||||
OS << " case 3: vector.w = scalar; return;\n";
|
||||
OS << " }\n";
|
||||
OS << "}\n";
|
||||
}
|
||||
else
|
||||
{
|
||||
OS << "#define mov(v, i, s) v[i] = s\n";
|
||||
}
|
||||
|
||||
OS << "#define get_s16(v, s) preserve_sign_s16(get_bits(v, s))\n\n";
|
||||
|
||||
OS << "vec4 fetch_attribute(attribute_desc desc, int vertex_id, usamplerBuffer input_stream)\n";
|
||||
OS << "{\n";
|
||||
OS << " vec4 result = vec4(0., 0., 0., 1.);\n";
|
||||
OS << " vec4 scale = vec4(1.);\n";
|
||||
OS << " uvec4 tmp;\n";
|
||||
OS << " uint bits;\n";
|
||||
OS << " bool reverse_order = false;\n";
|
||||
OS << "\n";
|
||||
OS << " int first_byte = (vertex_id * desc.stride) + desc.starting_offset;\n";
|
||||
OS << " for (int n = 0; n < 4; n++)\n";
|
||||
OS << " {\n";
|
||||
OS << " if (n == desc.attribute_size) break;\n";
|
||||
OS << "\n";
|
||||
OS << " switch (desc.type)\n";
|
||||
OS << " {\n";
|
||||
OS << " case 0:\n";
|
||||
OS << " //signed normalized 16-bit\n";
|
||||
OS << " tmp.x = texelFetch(input_stream, first_byte++).x;\n";
|
||||
OS << " tmp.y = texelFetch(input_stream, first_byte++).x;\n";
|
||||
OS << " mov(result, n, get_s16(tmp.xy, desc.swap_bytes));\n";
|
||||
OS << " mov(scale, n, 32767.);\n";
|
||||
OS << " break;\n";
|
||||
OS << " case 1:\n";
|
||||
OS << " //float\n";
|
||||
OS << " tmp.x = texelFetch(input_stream, first_byte++).x;\n";
|
||||
OS << " tmp.y = texelFetch(input_stream, first_byte++).x;\n";
|
||||
OS << " tmp.z = texelFetch(input_stream, first_byte++).x;\n";
|
||||
OS << " tmp.w = texelFetch(input_stream, first_byte++).x;\n";
|
||||
OS << " mov(result, n, uintBitsToFloat(get_bits(tmp, desc.swap_bytes)));\n";
|
||||
OS << " break;\n";
|
||||
OS << " case 2:\n";
|
||||
OS << " //half\n";
|
||||
OS << " tmp.x = texelFetch(input_stream, first_byte++).x;\n";
|
||||
OS << " tmp.y = texelFetch(input_stream, first_byte++).x;\n";
|
||||
OS << " mov(result, n, unpackHalf2x16(uint(get_bits(tmp.xy, desc.swap_bytes))).x);\n";
|
||||
OS << " break;\n";
|
||||
OS << " case 3:\n";
|
||||
OS << " //unsigned byte\n";
|
||||
OS << " mov(result, n, texelFetch(input_stream, first_byte++).x);\n";
|
||||
OS << " mov(scale, n, 255.);\n";
|
||||
OS << " reverse_order = (desc.swap_bytes != 0);\n";
|
||||
OS << " break;\n";
|
||||
OS << " case 4:\n";
|
||||
OS << " //signed word\n";
|
||||
OS << " tmp.x = texelFetch(input_stream, first_byte++).x;\n";
|
||||
OS << " tmp.y = texelFetch(input_stream, first_byte++).x;\n";
|
||||
OS << " mov(result, n, get_s16(tmp.xy, desc.swap_bytes));\n";
|
||||
OS << " break;\n";
|
||||
OS << " case 5:\n";
|
||||
OS << " //cmp\n";
|
||||
OS << " tmp.x = texelFetch(input_stream, first_byte++).x;\n";
|
||||
OS << " tmp.y = texelFetch(input_stream, first_byte++).x;\n";
|
||||
OS << " tmp.z = texelFetch(input_stream, first_byte++).x;\n";
|
||||
OS << " tmp.w = texelFetch(input_stream, first_byte++).x;\n";
|
||||
OS << " bits = get_bits(tmp, desc.swap_bytes);\n";
|
||||
OS << " result.x = preserve_sign_s16((bits & 0x7FF) << 5);\n";
|
||||
OS << " result.y = preserve_sign_s16(((bits >> 11) & 0x7FF) << 5);\n";
|
||||
OS << " result.z = preserve_sign_s16(((bits >> 22) & 0x3FF) << 6);\n";
|
||||
OS << " result.w = 1.;\n";
|
||||
OS << " scale = vec4(32767., 32767., 32767., 1.);\n";
|
||||
OS << " break;\n";
|
||||
OS << " case 6:\n";
|
||||
OS << " //ub256\n";
|
||||
OS << " mov(result, n, float(texelFetch(input_stream, first_byte++).x));\n";
|
||||
OS << " reverse_order = (desc.swap_bytes != 0);\n";
|
||||
OS << " break;\n";
|
||||
OS << " }\n";
|
||||
OS << " }\n\n";
|
||||
OS << " result /= scale;\n";
|
||||
OS << " return (reverse_order)? result.wzyx: result;\n";
|
||||
OS << "}\n\n";
|
||||
|
||||
OS << "attribute_desc fetch_desc(int location)\n";
|
||||
OS << "{\n";
|
||||
OS << " attribute_desc result;\n";
|
||||
OS << " int attribute_flags = input_attributes[location].w;\n";
|
||||
OS << " result.type = input_attributes[location].x;\n";
|
||||
OS << " result.attribute_size = input_attributes[location].y;\n";
|
||||
OS << " result.starting_offset = input_attributes[location].z;\n";
|
||||
OS << " result.stride = attribute_flags & 0xFF;\n";
|
||||
OS << " result.swap_bytes = (attribute_flags >> 8) & 0x1;\n";
|
||||
OS << " result.is_volatile = (attribute_flags >> 9) & 0x1;\n";
|
||||
OS << " result.frequency = (attribute_flags >> 10) & 0x3;\n";
|
||||
OS << " result.modulo = (attribute_flags >> 12) & 0x1;\n";
|
||||
OS << " result.divisor = (attribute_flags >> 13) & 0xFFFF;\n";
|
||||
OS << " return result;\n";
|
||||
OS << "}\n\n";
|
||||
|
||||
OS << "vec4 read_location(int location)\n";
|
||||
OS << "{\n";
|
||||
OS << " attribute_desc desc = fetch_desc(location);\n";
|
||||
OS << "\n";
|
||||
OS << " int vertex_id = " << vertex_id_name << " - int(vertex_base_index);\n";
|
||||
OS << " if (desc.frequency == 0)\n";
|
||||
OS << " vertex_id = 0;\n";
|
||||
OS << " else if (desc.frequency > 1)\n";
|
||||
OS << " {\n";
|
||||
OS << " //if a vertex modifier is active; vertex_base must be 0 and is ignored\n";
|
||||
OS << " if (desc.modulo != 0)\n";
|
||||
OS << " vertex_id = " << vertex_id_name << " % desc.divisor;\n";
|
||||
OS << " else\n";
|
||||
OS << " vertex_id = " << vertex_id_name << " / desc.divisor;\n";
|
||||
OS << " }\n";
|
||||
OS << "\n";
|
||||
OS << " if (desc.is_volatile != 0)\n";
|
||||
OS << " return fetch_attribute(desc, vertex_id, volatile_input_stream);\n";
|
||||
OS << " else\n";
|
||||
OS << " return fetch_attribute(desc, vertex_id, persistent_input_stream);\n";
|
||||
OS << "}\n\n";
|
||||
}
|
||||
|
||||
static void insert_glsl_legacy_function(std::ostream& OS, glsl::program_domain domain)
|
||||
{
|
||||
OS << "vec4 lit_legacy(vec4 val)";
|
||||
OS << "{\n";
|
||||
OS << " vec4 clamped_val = val;\n";
|
||||
OS << " clamped_val.x = max(val.x, 0.);\n";
|
||||
OS << " clamped_val.y = max(val.y, 0.);\n";
|
||||
OS << " vec4 result;\n";
|
||||
OS << " result.x = 1.;\n";
|
||||
OS << " result.w = 1.;\n";
|
||||
OS << " result.y = clamped_val.x;\n";
|
||||
OS << " result.z = clamped_val.x > 0. ? exp(clamped_val.w * log(max(clamped_val.y, 1.E-10))) : 0.;\n";
|
||||
OS << " return result;\n";
|
||||
OS << "}\n\n";
|
||||
|
||||
if (domain == glsl::program_domain::glsl_vertex_program)
|
||||
return;
|
||||
|
||||
program_common::insert_compare_op(OS);
|
||||
|
||||
//NOTE: After testing with GOW, the w component is either the original depth or wraps around to the x component
|
||||
//Since component.r == depth_value with some precision loss, just use the precise depth value for now (further testing needed)
|
||||
OS << "vec4 decodeLinearDepth(float depth_value)\n";
|
||||
OS << "{\n";
|
||||
OS << " uint value = uint(depth_value * 16777215);\n";
|
||||
OS << " uint b = (value & 0xff);\n";
|
||||
OS << " uint g = (value >> 8) & 0xff;\n";
|
||||
OS << " uint r = (value >> 16) & 0xff;\n";
|
||||
OS << " return vec4(float(r)/255., float(g)/255., float(b)/255., depth_value);\n";
|
||||
OS << "}\n\n";
|
||||
|
||||
OS << "vec4 texture2DReconstruct(sampler2D tex, vec2 coord)\n";
|
||||
OS << "{\n";
|
||||
OS << " return decodeLinearDepth(texture(tex, coord.xy).r);\n";
|
||||
OS << "}\n\n";
|
||||
|
||||
OS << "vec4 texture2DReconstruct(sampler2DRect tex, vec2 coord)\n";
|
||||
OS << "{\n";
|
||||
OS << " return decodeLinearDepth(texture(tex, coord.xy).r);\n";
|
||||
OS << "}\n\n";
|
||||
}
|
||||
|
||||
static void insert_fog_declaration(std::ostream& OS)
|
||||
{
|
||||
program_common::insert_fog_declaration(OS, "vec4", "fog_c");
|
||||
}
|
||||
}
|
||||
@@ -28,7 +28,7 @@ bool vertex_program_compare::operator()(const RSXVertexProgram &binary1, const R
|
||||
return false;
|
||||
if (binary1.data.size() != binary2.data.size())
|
||||
return false;
|
||||
if (!binary1.skip_vertex_input_check && !binary2.skip_vertex_input_check && binary1.rsx_vertex_inputs != binary2.rsx_vertex_inputs)
|
||||
if (binary1.rsx_vertex_inputs != binary2.rsx_vertex_inputs)
|
||||
return false;
|
||||
|
||||
const qword *instBuffer1 = (const qword*)binary1.data.data();
|
||||
@@ -107,20 +107,12 @@ size_t fragment_program_hash::operator()(const RSXFragmentProgram& program) cons
|
||||
bool fragment_program_compare::operator()(const RSXFragmentProgram& binary1, const RSXFragmentProgram& binary2) const
|
||||
{
|
||||
if (binary1.texture_dimensions != binary2.texture_dimensions || binary1.unnormalized_coords != binary2.unnormalized_coords ||
|
||||
binary1.height != binary2.height || binary1.origin_mode != binary2.origin_mode || binary1.pixel_center_mode != binary2.pixel_center_mode ||
|
||||
binary1.back_color_diffuse_output != binary2.back_color_diffuse_output || binary1.back_color_specular_output != binary2.back_color_specular_output ||
|
||||
binary1.front_back_color_enabled != binary2.front_back_color_enabled ||
|
||||
binary1.front_back_color_enabled != binary2.front_back_color_enabled || binary1.alpha_func != binary2.alpha_func ||
|
||||
binary1.shadow_textures != binary2.shadow_textures || binary1.redirected_textures != binary2.redirected_textures)
|
||||
return false;
|
||||
|
||||
for (u8 index = 0; index < 16; ++index)
|
||||
{
|
||||
if (binary1.textures_alpha_kill[index] != binary2.textures_alpha_kill[index])
|
||||
return false;
|
||||
|
||||
if (binary1.textures_zfunc[index] != binary2.textures_zfunc[index])
|
||||
return false;
|
||||
}
|
||||
|
||||
const qword *instBuffer1 = (const qword*)binary1.addr;
|
||||
const qword *instBuffer2 = (const qword*)binary2.addr;
|
||||
size_t instIndex = 0;
|
||||
|
||||
@@ -5,7 +5,6 @@
|
||||
#include "Emu/Memory/vm.h"
|
||||
|
||||
#include "Utilities/GSL.h"
|
||||
#include "Utilities/hash.h"
|
||||
|
||||
enum class SHADER_TYPE
|
||||
{
|
||||
@@ -94,9 +93,9 @@ class program_state_cache
|
||||
size_t operator()(const pipeline_key &key) const
|
||||
{
|
||||
size_t hashValue = 0;
|
||||
hashValue ^= rpcs3::hash_base<unsigned>(key.vertex_program_id);
|
||||
hashValue ^= rpcs3::hash_base<unsigned>(key.fragment_program_id);
|
||||
hashValue ^= rpcs3::hash_struct<pipeline_properties>(key.properties);
|
||||
hashValue ^= std::hash<unsigned>()(key.vertex_program_id);
|
||||
hashValue ^= std::hash<unsigned>()(key.fragment_program_id);
|
||||
hashValue ^= std::hash<pipeline_properties>()(key.properties);
|
||||
return hashValue;
|
||||
}
|
||||
};
|
||||
@@ -111,7 +110,6 @@ class program_state_cache
|
||||
|
||||
protected:
|
||||
size_t m_next_id = 0;
|
||||
bool m_cache_miss_flag;
|
||||
binary_to_vertex_program m_vertex_shader_cache;
|
||||
binary_to_fragment_program m_fragment_shader_cache;
|
||||
std::unordered_map <pipeline_key, pipeline_storage_type, pipeline_key_hash, pipeline_key_compare> m_storage;
|
||||
@@ -199,10 +197,7 @@ public:
|
||||
{
|
||||
const auto I = m_storage.find(key);
|
||||
if (I != m_storage.end())
|
||||
{
|
||||
m_cache_miss_flag = false;
|
||||
return I->second;
|
||||
}
|
||||
}
|
||||
|
||||
LOG_NOTICE(RSX, "Add program :");
|
||||
@@ -210,9 +205,6 @@ public:
|
||||
LOG_NOTICE(RSX, "*** fp id = %d", fragment_program.id);
|
||||
|
||||
m_storage[key] = backend_traits::build_pipeline(vertex_program, fragment_program, pipelineProperties, std::forward<Args>(args)...);
|
||||
m_cache_miss_flag = true;
|
||||
|
||||
LOG_SUCCESS(RSX, "New program compiled successfully");
|
||||
return m_storage[key];
|
||||
}
|
||||
|
||||
|
||||
@@ -43,7 +43,7 @@ std::string VertexProgramDecompiler::GetDST(bool isSca)
|
||||
|
||||
std::string mask = GetMask(isSca);
|
||||
|
||||
switch ((isSca && d3.sca_dst_tmp != 0x3f) ? 0x1f : d3.dst)
|
||||
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;
|
||||
@@ -209,7 +209,6 @@ std::string VertexProgramDecompiler::Format(const std::string& code)
|
||||
{ "$awm", std::bind(std::mem_fn(&VertexProgramDecompiler::AddAddrRegWithoutMask), this) },
|
||||
{ "$am", std::bind(std::mem_fn(&VertexProgramDecompiler::AddAddrMask), this) },
|
||||
{ "$a", std::bind(std::mem_fn(&VertexProgramDecompiler::AddAddrReg), this) },
|
||||
{ "$vm", std::bind(std::mem_fn(&VertexProgramDecompiler::GetVecMask), this) },
|
||||
|
||||
{ "$t", std::bind(std::mem_fn(&VertexProgramDecompiler::GetTex), this) },
|
||||
|
||||
@@ -374,7 +373,7 @@ void VertexProgramDecompiler::SetDSTSca(const std::string& code)
|
||||
SetDST(true, code);
|
||||
}
|
||||
|
||||
std::string VertexProgramDecompiler::NotZeroPositive(const std::string& code)
|
||||
std::string VertexProgramDecompiler::NotZeroPositive(const std::string code)
|
||||
{
|
||||
return "max(" + code + ", 1.E-10)";
|
||||
}
|
||||
@@ -607,9 +606,8 @@ std::string VertexProgramDecompiler::Decompile()
|
||||
case RSX_VEC_OPCODE_MAX: SetDSTVec("max($0, $1)"); break;
|
||||
case RSX_VEC_OPCODE_SLT: SetDSTVec(getFloatTypeName(4) + "(" + compareFunction(COMPARE::FUNCTION_SLT, "$0", "$1") + ")"); break;
|
||||
case RSX_VEC_OPCODE_SGE: SetDSTVec(getFloatTypeName(4) + "(" + compareFunction(COMPARE::FUNCTION_SGE, "$0", "$1") + ")"); break;
|
||||
// Note: ARL uses the vec mask to determine channels and ignores the src input mask
|
||||
// Tested with SH3, BLES00574 (G-Force) and NPUB90415 (Dead Space 2 Demo)
|
||||
case RSX_VEC_OPCODE_ARL: AddCode("$ifcond $awm$vm = " + getIntTypeName(4) + "($0)$vm;"); break;
|
||||
// Note: It looks like ARL opcode ignore input/output swizzle mask (SH3)
|
||||
case RSX_VEC_OPCODE_ARL: AddCode("$ifcond $awm = " + getIntTypeName(4) + "($0);"); break;
|
||||
case RSX_VEC_OPCODE_FRC: SetDSTVec(getFunction(FUNCTION::FUNCTION_FRACT)); break;
|
||||
case RSX_VEC_OPCODE_FLR: SetDSTVec("floor($0)"); break;
|
||||
case RSX_VEC_OPCODE_SEQ: SetDSTVec(getFloatTypeName(4) + "(" + compareFunction(COMPARE::FUNCTION_SEQ, "$0", "$1") + ")"); break;
|
||||
|
||||
@@ -61,7 +61,7 @@ struct VertexProgramDecompiler
|
||||
const std::vector<u32>& m_data;
|
||||
ParamArray m_parr;
|
||||
|
||||
std::string NotZeroPositive(const std::string& code);
|
||||
std::string NotZeroPositive(const std::string code);
|
||||
std::string GetMask(bool is_sca);
|
||||
std::string GetVecMask();
|
||||
std::string GetScaMask();
|
||||
|
||||
@@ -42,7 +42,7 @@ namespace
|
||||
fmt::throw_exception("Wrong vector size %d" HERE, size);
|
||||
}
|
||||
|
||||
u32 get_vertex_count(const std::vector<std::pair<u32, u32> >& first_count_commands)
|
||||
u32 get_vertex_count(const std::vector<std::pair<u32, u32> > first_count_commands)
|
||||
{
|
||||
u32 vertex_count = 0;
|
||||
for (const auto &pair : first_count_commands)
|
||||
@@ -89,7 +89,7 @@ void D3D12GSRender::upload_and_bind_scale_offset_matrix(size_t descriptorIndex)
|
||||
void *mapped_buffer = m_buffer_data.map<void>(CD3DX12_RANGE(heap_offset, heap_offset + 512));
|
||||
fill_scale_offset_data(mapped_buffer, true);
|
||||
fill_user_clip_data((char*)mapped_buffer + 64);
|
||||
fill_fragment_state_buffer((char *)mapped_buffer + 128, current_fragment_program);
|
||||
fill_fragment_state_buffer((char *)mapped_buffer + 128, m_fragment_program);
|
||||
m_buffer_data.unmap(CD3DX12_RANGE(heap_offset, heap_offset + 512));
|
||||
|
||||
D3D12_CONSTANT_BUFFER_VIEW_DESC constant_buffer_view_desc = {
|
||||
@@ -124,7 +124,7 @@ void D3D12GSRender::upload_and_bind_vertex_shader_constants(size_t descriptor_in
|
||||
D3D12_CONSTANT_BUFFER_VIEW_DESC D3D12GSRender::upload_fragment_shader_constants()
|
||||
{
|
||||
// Get constant from fragment program
|
||||
size_t buffer_size = m_pso_cache.get_fragment_constants_buffer_size(current_fragment_program);
|
||||
size_t buffer_size = m_pso_cache.get_fragment_constants_buffer_size(m_fragment_program);
|
||||
// Multiple of 256 never 0
|
||||
buffer_size = (buffer_size + 255) & ~255;
|
||||
|
||||
@@ -132,7 +132,7 @@ D3D12_CONSTANT_BUFFER_VIEW_DESC D3D12GSRender::upload_fragment_shader_constants(
|
||||
|
||||
size_t offset = 0;
|
||||
float *mapped_buffer = m_buffer_data.map<float>(CD3DX12_RANGE(heap_offset, heap_offset + buffer_size));
|
||||
m_pso_cache.fill_fragment_constants_buffer({ mapped_buffer, ::narrow<int>(buffer_size) }, current_fragment_program);
|
||||
m_pso_cache.fill_fragment_constants_buffer({ mapped_buffer, ::narrow<int>(buffer_size) }, m_fragment_program);
|
||||
m_buffer_data.unmap(CD3DX12_RANGE(heap_offset, heap_offset + buffer_size));
|
||||
|
||||
return {
|
||||
|
||||
@@ -124,8 +124,6 @@ void insert_d3d12_legacy_function(std::ostream& OS, bool is_fragment_program)
|
||||
if (!is_fragment_program)
|
||||
return;
|
||||
|
||||
program_common::insert_compare_op(OS);
|
||||
|
||||
OS << "uint packSnorm2x16(float2 val)";
|
||||
OS << "{\n";
|
||||
OS << " uint high_bits = round(clamp(val.x, -1., 1.) * 32767.);\n";
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
#include "../Common/ShaderParam.h"
|
||||
#include "../Common/GLSLCommon.h"
|
||||
|
||||
std::string getFloatTypeNameImp(size_t elementCount);
|
||||
std::string getFunctionImp(FUNCTION f);
|
||||
|
||||
@@ -304,7 +304,7 @@ D3D12_PRIMITIVE_TOPOLOGY get_primitive_topology(rsx::primitive_type draw_mode)
|
||||
case rsx::primitive_type::triangle_strip: return D3D_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP;
|
||||
case rsx::primitive_type::triangle_fan: return D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST;
|
||||
case rsx::primitive_type::quads: return D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST;
|
||||
case rsx::primitive_type::quad_strip: return D3D_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP;
|
||||
case rsx::primitive_type::quad_strip: return D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST;
|
||||
case rsx::primitive_type::polygon: return D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST;
|
||||
}
|
||||
fmt::throw_exception("Invalid draw mode (0x%x)" HERE, (u32)draw_mode);
|
||||
|
||||
@@ -42,12 +42,8 @@ void D3D12FragmentDecompiler::insertHeader(std::stringstream & OS)
|
||||
OS << " float4 userClipFactor[2];\n";
|
||||
OS << " float fog_param0;\n";
|
||||
OS << " float fog_param1;\n";
|
||||
OS << " uint alpha_test;\n";
|
||||
OS << " float alpha_ref;\n";
|
||||
OS << " uint alpha_func;\n";
|
||||
OS << " uint fog_mode;\n";
|
||||
OS << " uint window_origin;\n";
|
||||
OS << " uint window_height;\n";
|
||||
OS << " int isAlphaTested;\n";
|
||||
OS << " float alphaRef;\n";
|
||||
OS << " float4 texture_parameters[16];\n";
|
||||
OS << "};\n";
|
||||
}
|
||||
@@ -155,6 +151,38 @@ void D3D12FragmentDecompiler::insertConstants(std::stringstream & OS)
|
||||
|
||||
namespace
|
||||
{
|
||||
// Note: It's not clear whether fog is computed per pixel or per vertex.
|
||||
// But it makes more sense to compute exp of interpoled value than to interpolate exp values.
|
||||
void insert_fog_declaration(std::stringstream & OS, rsx::fog_mode mode)
|
||||
{
|
||||
switch (mode)
|
||||
{
|
||||
case rsx::fog_mode::linear:
|
||||
OS << " float4 fogc = float4(fog_param1 * In.fogc.x + (fog_param0 - 1.), fog_param1 * In.fogc.x + (fog_param0 - 1.), 0., 0.);\n";
|
||||
break;
|
||||
case rsx::fog_mode::exponential:
|
||||
OS << " float4 fogc = float4(11.084 * (fog_param1 * In.fogc.x + fog_param0 - 1.5), exp(11.084 * (fog_param1 * In.fogc.x + fog_param0 - 1.5)), 0., 0.);\n";
|
||||
break;
|
||||
case rsx::fog_mode::exponential2:
|
||||
OS << " float4 fogc = float4(4.709 * (fog_param1 * In.fogc.x + fog_param0 - 1.5), exp(-pow(4.709 * (fog_param1 * In.fogc.x + fog_param0 - 1.5), 2.)), 0., 0.);\n";
|
||||
break;
|
||||
case rsx::fog_mode::linear_abs:
|
||||
OS << " float4 fogc = float4(fog_param1 * abs(In.fogc.x) + (fog_param0 - 1.), fog_param1 * abs(In.fogc.x) + (fog_param0 - 1.), 0., 0.);\n";
|
||||
break;
|
||||
case rsx::fog_mode::exponential_abs:
|
||||
OS << " float4 fogc = float4(11.084 * (fog_param1 * abs(In.fogc.x) + fog_param0 - 1.5), exp(11.084 * (fog_param1 * abs(In.fogc.x) + fog_param0 - 1.5)), 0., 0.);\n";
|
||||
break;
|
||||
case rsx::fog_mode::exponential2_abs:
|
||||
OS << " float4 fogc = float4(4.709 * (fog_param1 * abs(In.fogc.x) + fog_param0 - 1.5), exp(-pow(4.709 * (fog_param1 * abs(In.fogc.x) + fog_param0 - 1.5), 2.)), 0., 0.);\n";
|
||||
break;
|
||||
default:
|
||||
OS << " float4 fogc = float4(0., 0., 0., 0.);\n";
|
||||
return;
|
||||
}
|
||||
|
||||
OS << " fogc.y = saturate(fogc.y);\n";
|
||||
}
|
||||
|
||||
std::string insert_texture_fetch(const RSXFragmentProgram& prog, int index)
|
||||
{
|
||||
std::string tex_name = "tex" + std::to_string(index) + ".Sample";
|
||||
@@ -177,18 +205,6 @@ void D3D12FragmentDecompiler::insertMainStart(std::stringstream & OS)
|
||||
{
|
||||
insert_d3d12_legacy_function(OS, true);
|
||||
|
||||
for (const ParamType &PT : m_parr.params[PF_PARAM_IN])
|
||||
{
|
||||
for (const ParamItem &PI : PT.items)
|
||||
{
|
||||
if (PI.name == "fogc")
|
||||
{
|
||||
program_common::insert_fog_declaration(OS, "float4", "fogc", true);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const std::set<std::string> output_value =
|
||||
{
|
||||
"r0", "r1", "r2", "r3", "r4",
|
||||
@@ -215,7 +231,7 @@ void D3D12FragmentDecompiler::insertMainStart(std::stringstream & OS)
|
||||
}
|
||||
if (PI.name == "fogc")
|
||||
{
|
||||
OS << " float4 fogc = fetch_fog_value(fog_mode, In.fogc);\n";
|
||||
insert_fog_declaration(OS, m_prog.fog_equation);
|
||||
continue;
|
||||
}
|
||||
if (PI.name == "ssa")
|
||||
@@ -223,9 +239,10 @@ void D3D12FragmentDecompiler::insertMainStart(std::stringstream & OS)
|
||||
OS << " " << PT.type << " " << PI.name << " = In." << PI.name << ";\n";
|
||||
}
|
||||
}
|
||||
|
||||
OS << " float4 wpos = In.Position;\n";
|
||||
OS << " if (window_origin != 0) wpos.y = window_height - wpos.y;\n";
|
||||
// A bit unclean, but works.
|
||||
OS << " " << "float4 wpos = In.Position;\n";
|
||||
if (m_prog.origin_mode == rsx::window_origin::bottom)
|
||||
OS << " wpos.y = (" << std::to_string(m_prog.height) << " - wpos.y);\n";
|
||||
OS << " float4 ssa = is_front_face ? float4(1., 1., 1., 1.) : float4(-1., -1., -1., -1.);\n";
|
||||
|
||||
// Declare output
|
||||
@@ -346,7 +363,7 @@ void D3D12FragmentDecompiler::insertMainEnd(std::stringstream & OS)
|
||||
}
|
||||
}
|
||||
|
||||
OS << " if (alpha_test != 0 && !comparison_passes(Out." << first_output_name << ".a, alpha_ref, alpha_func)) discard;\n";
|
||||
OS << make_comparison_test(m_prog.alpha_func, "isAlphaTested && ", "Out." + first_output_name + ".a", "alphaRef");
|
||||
|
||||
}
|
||||
OS << " return Out;\n";
|
||||
|
||||
@@ -329,7 +329,7 @@ void D3D12GSRender::end()
|
||||
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 (!current_fragment_program.valid)
|
||||
if (!m_fragment_program.valid)
|
||||
{
|
||||
rsx::thread::end();
|
||||
return;
|
||||
|
||||
@@ -61,6 +61,8 @@ private:
|
||||
data_cache m_texture_cache;
|
||||
bool invalidate_address(u32 addr);
|
||||
|
||||
RSXVertexProgram m_vertex_program;
|
||||
RSXFragmentProgram m_fragment_program;
|
||||
PipelineStateObjectCache m_pso_cache;
|
||||
std::tuple<ComPtr<ID3D12PipelineState>, size_t, size_t> m_current_pso;
|
||||
|
||||
|
||||
@@ -53,10 +53,10 @@ void D3D12GSRender::load_program()
|
||||
return std::make_tuple(true, native_pitch);
|
||||
};
|
||||
|
||||
get_current_vertex_program();
|
||||
get_current_fragment_program(rtt_lookup_func);
|
||||
m_vertex_program = get_current_vertex_program();
|
||||
m_fragment_program = get_current_fragment_program(rtt_lookup_func);
|
||||
|
||||
if (!current_fragment_program.valid)
|
||||
if (!m_fragment_program.valid)
|
||||
return;
|
||||
|
||||
D3D12PipelineProperties prop = {};
|
||||
@@ -308,12 +308,12 @@ void D3D12GSRender::load_program()
|
||||
}
|
||||
}
|
||||
|
||||
m_current_pso = m_pso_cache.getGraphicPipelineState(current_vertex_program, current_fragment_program, prop, m_device.Get(), m_shared_root_signature.Get());
|
||||
m_current_pso = m_pso_cache.getGraphicPipelineState(m_vertex_program, m_fragment_program, prop, m_device.Get(), m_shared_root_signature.Get());
|
||||
return;
|
||||
}
|
||||
|
||||
std::pair<std::string, std::string> D3D12GSRender::get_programs() const
|
||||
{
|
||||
return std::make_pair(m_pso_cache.get_transform_program(current_vertex_program).content, m_pso_cache.get_shader_program(current_fragment_program).content);
|
||||
return std::make_pair(m_pso_cache.get_transform_program(m_vertex_program).content, m_pso_cache.get_shader_program(m_fragment_program).content);
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -298,9 +298,6 @@ void D3D12GSRender::copy_render_target_to_dma_location()
|
||||
int clip_w = rsx::method_registers.surface_clip_width();
|
||||
int clip_h = rsx::method_registers.surface_clip_height();
|
||||
|
||||
if (clip_w == 0 || clip_h == 0)
|
||||
return;
|
||||
|
||||
size_t depth_row_pitch = align(clip_w * 4, 256);
|
||||
size_t depth_buffer_offset_in_heap = 0;
|
||||
|
||||
|
||||
@@ -1,6 +1,22 @@
|
||||
#include "stdafx.h"
|
||||
#include "GLCommonDecompiler.h"
|
||||
|
||||
std::string getFloatTypeNameImpl(size_t elementCount)
|
||||
{
|
||||
switch (elementCount)
|
||||
{
|
||||
default:
|
||||
abort();
|
||||
case 1:
|
||||
return "float";
|
||||
case 2:
|
||||
return "vec2";
|
||||
case 3:
|
||||
return "vec3";
|
||||
case 4:
|
||||
return "vec4";
|
||||
}
|
||||
}
|
||||
|
||||
std::string getFunctionImpl(FUNCTION f)
|
||||
{
|
||||
@@ -68,3 +84,55 @@ std::string getFunctionImpl(FUNCTION f)
|
||||
return "texture2DReconstruct($t, $0.xy * $t_coord_scale)";
|
||||
}
|
||||
}
|
||||
|
||||
std::string compareFunctionImpl(COMPARE f, const std::string &Op0, const std::string &Op1)
|
||||
{
|
||||
switch (f)
|
||||
{
|
||||
case COMPARE::FUNCTION_SEQ:
|
||||
return "equal(" + Op0 + ", " + Op1 + ")";
|
||||
case COMPARE::FUNCTION_SGE:
|
||||
return "greaterThanEqual(" + Op0 + ", " + Op1 + ")";
|
||||
case COMPARE::FUNCTION_SGT:
|
||||
return "greaterThan(" + Op0 + ", " + Op1 + ")";
|
||||
case COMPARE::FUNCTION_SLE:
|
||||
return "lessThanEqual(" + Op0 + ", " + Op1 + ")";
|
||||
case COMPARE::FUNCTION_SLT:
|
||||
return "lessThan(" + Op0 + ", " + Op1 + ")";
|
||||
case COMPARE::FUNCTION_SNE:
|
||||
return "notEqual(" + Op0 + ", " + Op1 + ")";
|
||||
}
|
||||
fmt::throw_exception("Unknown compare function" HERE);
|
||||
}
|
||||
|
||||
void insert_glsl_legacy_function(std::ostream& OS, gl::glsl::program_domain domain)
|
||||
{
|
||||
OS << "vec4 lit_legacy(vec4 val)";
|
||||
OS << "{\n";
|
||||
OS << " vec4 clamped_val = val;\n";
|
||||
OS << " clamped_val.x = max(val.x, 0);\n";
|
||||
OS << " clamped_val.y = max(val.y, 0);\n";
|
||||
OS << " vec4 result;\n";
|
||||
OS << " result.x = 1.0;\n";
|
||||
OS << " result.w = 1.;\n";
|
||||
OS << " result.y = clamped_val.x;\n";
|
||||
OS << " result.z = clamped_val.x > 0.0 ? exp(clamped_val.w * log(max(clamped_val.y, 1.E-10))) : 0.0;\n";
|
||||
OS << " return result;\n";
|
||||
OS << "}\n\n";
|
||||
|
||||
if (domain != gl::glsl::program_domain::glsl_fragment_program)
|
||||
return;
|
||||
|
||||
//NOTE: We lose precision if we just store depth value into 8-bit textures i.e (depth, 0, 0)
|
||||
//NOTE2: After testing with GOW, the w component is either the original depth or wraps around to the x component
|
||||
//Since component.r == depth_value with some precision loss, just use the precise depth value for now (further testing needed)
|
||||
OS << "vec4 texture2DReconstruct(sampler2D tex, vec2 coord)\n";
|
||||
OS << "{\n";
|
||||
OS << " float depth_value = texture(tex, coord.xy).r;\n";
|
||||
OS << " uint value = uint(depth_value * 16777215);\n";
|
||||
OS << " uint b = (value & 0xff);\n";
|
||||
OS << " uint g = (value >> 8) & 0xff;\n";
|
||||
OS << " uint r = (value >> 16) & 0xff;\n";
|
||||
OS << " return vec4(float(r)/255., float(g)/255., float(b)/255., depth_value);\n";
|
||||
OS << "}\n\n";
|
||||
}
|
||||
|
||||
@@ -1,7 +1,10 @@
|
||||
#pragma once
|
||||
|
||||
#include "../Common/ShaderParam.h"
|
||||
#include "../Common/GLSLCommon.h"
|
||||
#include "GLHelpers.h"
|
||||
#include <ostream>
|
||||
|
||||
std::string getFloatTypeNameImpl(size_t elementCount);
|
||||
std::string getFunctionImpl(FUNCTION f);
|
||||
std::string compareFunctionImpl(COMPARE f, const std::string &Op0, const std::string &Op1);
|
||||
void insert_glsl_legacy_function(std::ostream& OS, gl::glsl::program_domain domain);
|
||||
|
||||
@@ -3,13 +3,13 @@
|
||||
#include "Emu/Memory/Memory.h"
|
||||
#include "Emu/System.h"
|
||||
#include "GLFragmentProgram.h"
|
||||
#include "../Common/ProgramStateCache.h"
|
||||
|
||||
#include "GLCommonDecompiler.h"
|
||||
#include "../GCM.h"
|
||||
|
||||
std::string GLFragmentDecompilerThread::getFloatTypeName(size_t elementCount)
|
||||
{
|
||||
return glsl::getFloatTypeNameImpl(elementCount);
|
||||
return getFloatTypeNameImpl(elementCount);
|
||||
}
|
||||
|
||||
std::string GLFragmentDecompilerThread::getFunction(FUNCTION f)
|
||||
@@ -24,7 +24,7 @@ std::string GLFragmentDecompilerThread::saturate(const std::string & code)
|
||||
|
||||
std::string GLFragmentDecompilerThread::compareFunction(COMPARE f, const std::string &Op0, const std::string &Op1)
|
||||
{
|
||||
return glsl::compareFunctionImpl(f, Op0, Op1);
|
||||
return compareFunctionImpl(f, Op0, Op1);
|
||||
}
|
||||
|
||||
void GLFragmentDecompilerThread::insertHeader(std::stringstream & OS)
|
||||
@@ -145,16 +145,45 @@ void GLFragmentDecompilerThread::insertConstants(std::stringstream & OS)
|
||||
OS << " float fog_param1;\n";
|
||||
OS << " uint alpha_test;\n";
|
||||
OS << " float alpha_ref;\n";
|
||||
OS << " uint alpha_func;\n";
|
||||
OS << " uint fog_mode;\n";
|
||||
OS << " uint window_origin;\n";
|
||||
OS << " uint window_height;\n";
|
||||
OS << " vec4 texture_parameters[16];\n"; //sampling: x,y scaling and (unused) offsets data
|
||||
OS << "};\n";
|
||||
}
|
||||
|
||||
|
||||
namespace
|
||||
{
|
||||
// Note: It's not clear whether fog is computed per pixel or per vertex.
|
||||
// But it makes more sense to compute exp of interpoled value than to interpolate exp values.
|
||||
void insert_fog_declaration(std::stringstream & OS, rsx::fog_mode mode)
|
||||
{
|
||||
switch (mode)
|
||||
{
|
||||
case rsx::fog_mode::linear:
|
||||
OS << " vec4 fogc = vec4(fog_param1 * fog_c.x + (fog_param0 - 1.), fog_param1 * fog_c.x + (fog_param0 - 1.), 0., 0.);\n";
|
||||
break;
|
||||
case rsx::fog_mode::exponential:
|
||||
OS << " vec4 fogc = vec4(11.084 * (fog_param1 * fog_c.x + fog_param0 - 1.5), exp(11.084 * (fog_param1 * fog_c.x + fog_param0 - 1.5)), 0., 0.);\n";
|
||||
break;
|
||||
case rsx::fog_mode::exponential2:
|
||||
OS << " vec4 fogc = vec4(4.709 * (fog_param1 * fog_c.x + fog_param0 - 1.5), exp(-pow(4.709 * (fog_param1 * fog_c.x + fog_param0 - 1.5), 2.)), 0., 0.);\n";
|
||||
break;
|
||||
case rsx::fog_mode::linear_abs:
|
||||
OS << " vec4 fogc = vec4(fog_param1 * abs(fog_c.x) + (fog_param0 - 1.), fog_param1 * abs(fog_c.x) + (fog_param0 - 1.), 0., 0.);\n";
|
||||
break;
|
||||
case rsx::fog_mode::exponential_abs:
|
||||
OS << " vec4 fogc = vec4(11.084 * (fog_param1 * abs(fog_c.x) + fog_param0 - 1.5), exp(11.084 * (fog_param1 * abs(fog_c.x) + fog_param0 - 1.5)), 0., 0.);\n";
|
||||
break;
|
||||
case rsx::fog_mode::exponential2_abs:
|
||||
OS << " vec4 fogc = vec4(4.709 * (fog_param1 * abs(fog_c.x) + fog_param0 - 1.5), exp(-pow(4.709 * (fog_param1 * abs(fog_c.x) + fog_param0 - 1.5), 2.)), 0., 0.);\n";
|
||||
break;
|
||||
default:
|
||||
OS << " vec4 fogc = vec4(0.);\n";
|
||||
return;
|
||||
}
|
||||
|
||||
OS << " fogc.y = clamp(fogc.y, 0., 1.);\n";
|
||||
}
|
||||
|
||||
void insert_texture_scale(std::stringstream & OS, const RSXFragmentProgram& prog, int index)
|
||||
{
|
||||
std::string vec_type = "vec2";
|
||||
@@ -192,20 +221,7 @@ namespace
|
||||
|
||||
void GLFragmentDecompilerThread::insertMainStart(std::stringstream & OS)
|
||||
{
|
||||
glsl::insert_glsl_legacy_function(OS, glsl::glsl_fragment_program);
|
||||
|
||||
//TODO: Generate input mask during parse stage to avoid this
|
||||
for (const ParamType& PT : m_parr.params[PF_PARAM_IN])
|
||||
{
|
||||
for (const ParamItem& PI : PT.items)
|
||||
{
|
||||
if (PI.name == "fogc")
|
||||
{
|
||||
glsl::insert_fog_declaration(OS);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
insert_glsl_legacy_function(OS, gl::glsl::glsl_fragment_program);
|
||||
|
||||
const std::set<std::string> output_values =
|
||||
{
|
||||
@@ -225,7 +241,6 @@ void GLFragmentDecompilerThread::insertMainStart(std::stringstream & OS)
|
||||
}
|
||||
}
|
||||
|
||||
OS << "//FP_HASH=" << fmt::format("%llX", program_hash_util::fragment_program_hash()(m_prog)) << "\n";
|
||||
OS << "void fs_main(" << parameters << ")\n";
|
||||
OS << "{\n";
|
||||
|
||||
@@ -246,7 +261,11 @@ void GLFragmentDecompilerThread::insertMainStart(std::stringstream & OS)
|
||||
|
||||
OS << " vec4 ssa = gl_FrontFacing ? vec4(1.) : vec4(-1.);\n";
|
||||
OS << " vec4 wpos = gl_FragCoord;\n";
|
||||
OS << " if (window_origin != 0) wpos.y = window_height - wpos.y;\n";
|
||||
|
||||
//Flip wpos in Y
|
||||
//We could optionally export wpos from the VS, but this is so much easier
|
||||
if (m_prog.origin_mode == rsx::window_origin::bottom)
|
||||
OS << " wpos.y = " << std::to_string(m_prog.height) << " - wpos.y;\n";
|
||||
|
||||
for (const ParamType& PT : m_parr.params[PF_PARAM_UNIFORM])
|
||||
{
|
||||
@@ -307,7 +326,7 @@ void GLFragmentDecompilerThread::insertMainStart(std::stringstream & OS)
|
||||
|
||||
if (PI.name == "fogc")
|
||||
{
|
||||
OS << " vec4 fogc = fetch_fog_value(fog_mode);\n";
|
||||
insert_fog_declaration(OS, m_prog.fog_equation);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
@@ -375,7 +394,7 @@ void GLFragmentDecompilerThread::insertMainEnd(std::stringstream & OS)
|
||||
}
|
||||
}
|
||||
|
||||
OS << " if (alpha_test != 0 && !comparison_passes(" << first_output_name << ".a, alpha_ref, alpha_func)) discard;\n";
|
||||
OS << make_comparison_test(m_prog.alpha_func, "alpha_test != 0 && ", first_output_name + ".a", "alpha_ref");
|
||||
}
|
||||
|
||||
OS << "}\n\n";
|
||||
|
||||
+160
-378
@@ -24,7 +24,8 @@ namespace
|
||||
|
||||
GLGSRender::GLGSRender() : GSRender()
|
||||
{
|
||||
m_shaders_cache.reset(new gl::shader_cache(m_prog_buffer, "opengl", "v1"));
|
||||
//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());
|
||||
@@ -32,6 +33,34 @@ GLGSRender::GLGSRender() : GSRender()
|
||||
m_vertex_cache.reset(new gl::weak_vertex_cache());
|
||||
}
|
||||
|
||||
u32 GLGSRender::enable(u32 condition, u32 cap)
|
||||
{
|
||||
if (condition)
|
||||
{
|
||||
glEnable(cap);
|
||||
}
|
||||
else
|
||||
{
|
||||
glDisable(cap);
|
||||
}
|
||||
|
||||
return condition;
|
||||
}
|
||||
|
||||
u32 GLGSRender::enable(u32 condition, u32 cap, u32 index)
|
||||
{
|
||||
if (condition)
|
||||
{
|
||||
glEnablei(cap, index);
|
||||
}
|
||||
else
|
||||
{
|
||||
glDisablei(cap, index);
|
||||
}
|
||||
|
||||
return condition;
|
||||
}
|
||||
|
||||
extern CellGcmContextData current_context;
|
||||
|
||||
namespace
|
||||
@@ -165,9 +194,6 @@ void GLGSRender::begin()
|
||||
if (skip_frame)
|
||||
return;
|
||||
|
||||
if (conditional_render_enabled && conditional_render_test_failed)
|
||||
return;
|
||||
|
||||
init_buffers();
|
||||
|
||||
if (!framebuffer_status_valid)
|
||||
@@ -180,105 +206,87 @@ void GLGSRender::begin()
|
||||
bool color_mask_r = rsx::method_registers.color_mask_r();
|
||||
bool color_mask_a = rsx::method_registers.color_mask_a();
|
||||
|
||||
gl_state.color_mask(color_mask_r, color_mask_g, color_mask_b, color_mask_a);
|
||||
gl_state.depth_mask(rsx::method_registers.depth_write_enabled());
|
||||
gl_state.stencil_mask(rsx::method_registers.stencil_mask());
|
||||
__glcheck glColorMask(color_mask_r, color_mask_g, color_mask_b, color_mask_a);
|
||||
__glcheck glDepthMask(rsx::method_registers.depth_write_enabled());
|
||||
__glcheck glStencilMask(rsx::method_registers.stencil_mask());
|
||||
|
||||
if (gl_state.enable(rsx::method_registers.depth_test_enabled(), GL_DEPTH_TEST))
|
||||
if (__glcheck enable(rsx::method_registers.depth_test_enabled(), GL_DEPTH_TEST))
|
||||
{
|
||||
gl_state.depth_func(comparison_op(rsx::method_registers.depth_func()));
|
||||
|
||||
float range_near = rsx::method_registers.clip_min();
|
||||
float range_far = rsx::method_registers.clip_max();
|
||||
|
||||
if (g_cfg.video.strict_rendering_mode)
|
||||
gl_state.depth_range(range_near, range_far);
|
||||
else
|
||||
{
|
||||
//Workaround to preserve depth precision but respect z direction
|
||||
//Ni no Kuni sets a very restricted z range (0.9x - 1.) and depth reads / tests are broken
|
||||
if (range_near <= range_far)
|
||||
gl_state.depth_range(0.f, 1.f);
|
||||
else
|
||||
gl_state.depth_range(1.f, 0.f);
|
||||
}
|
||||
__glcheck glDepthFunc(comparison_op(rsx::method_registers.depth_func()));
|
||||
}
|
||||
|
||||
if (glDepthBoundsEXT && (gl_state.enable(rsx::method_registers.depth_bounds_test_enabled(), GL_DEPTH_BOUNDS_TEST_EXT)))
|
||||
if (glDepthBoundsEXT && (__glcheck enable(rsx::method_registers.depth_bounds_test_enabled(), GL_DEPTH_BOUNDS_TEST_EXT)))
|
||||
{
|
||||
gl_state.depth_bounds(rsx::method_registers.depth_bounds_min(), rsx::method_registers.depth_bounds_max());
|
||||
__glcheck glDepthBoundsEXT(rsx::method_registers.depth_bounds_min(), rsx::method_registers.depth_bounds_max());
|
||||
}
|
||||
|
||||
gl_state.enable(rsx::method_registers.dither_enabled(), GL_DITHER);
|
||||
//__glcheck glDepthRange(rsx::method_registers.clip_min(), rsx::method_registers.clip_max());
|
||||
__glcheck enable(rsx::method_registers.dither_enabled(), GL_DITHER);
|
||||
|
||||
if (gl_state.enable(rsx::method_registers.blend_enabled(), GL_BLEND))
|
||||
if (__glcheck enable(rsx::method_registers.blend_enabled(), GL_BLEND))
|
||||
{
|
||||
glBlendFuncSeparate(blend_factor(rsx::method_registers.blend_func_sfactor_rgb()),
|
||||
__glcheck glBlendFuncSeparate(blend_factor(rsx::method_registers.blend_func_sfactor_rgb()),
|
||||
blend_factor(rsx::method_registers.blend_func_dfactor_rgb()),
|
||||
blend_factor(rsx::method_registers.blend_func_sfactor_a()),
|
||||
blend_factor(rsx::method_registers.blend_func_dfactor_a()));
|
||||
|
||||
auto blend_colors = rsx::get_constant_blend_colors();
|
||||
glBlendColor(blend_colors[0], blend_colors[1], blend_colors[2], blend_colors[3]);
|
||||
__glcheck glBlendColor(blend_colors[0], blend_colors[1], blend_colors[2], blend_colors[3]);
|
||||
|
||||
glBlendEquationSeparate(blend_equation(rsx::method_registers.blend_equation_rgb()),
|
||||
__glcheck glBlendEquationSeparate(blend_equation(rsx::method_registers.blend_equation_rgb()),
|
||||
blend_equation(rsx::method_registers.blend_equation_a()));
|
||||
}
|
||||
|
||||
if (gl_state.enable(rsx::method_registers.stencil_test_enabled(), GL_STENCIL_TEST))
|
||||
if (__glcheck enable(rsx::method_registers.stencil_test_enabled(), GL_STENCIL_TEST))
|
||||
{
|
||||
glStencilFunc(comparison_op(rsx::method_registers.stencil_func()),
|
||||
rsx::method_registers.stencil_func_ref(),
|
||||
__glcheck glStencilFunc(comparison_op(rsx::method_registers.stencil_func()), rsx::method_registers.stencil_func_ref(),
|
||||
rsx::method_registers.stencil_func_mask());
|
||||
|
||||
glStencilOp(stencil_op(rsx::method_registers.stencil_op_fail()), stencil_op(rsx::method_registers.stencil_op_zfail()),
|
||||
__glcheck glStencilOp(stencil_op(rsx::method_registers.stencil_op_fail()), stencil_op(rsx::method_registers.stencil_op_zfail()),
|
||||
stencil_op(rsx::method_registers.stencil_op_zpass()));
|
||||
|
||||
if (rsx::method_registers.two_sided_stencil_test_enabled())
|
||||
{
|
||||
glStencilMaskSeparate(GL_BACK, rsx::method_registers.back_stencil_mask());
|
||||
|
||||
glStencilFuncSeparate(GL_BACK, comparison_op(rsx::method_registers.back_stencil_func()),
|
||||
__glcheck glStencilMaskSeparate(GL_BACK, rsx::method_registers.back_stencil_mask());
|
||||
__glcheck glStencilFuncSeparate(GL_BACK, comparison_op(rsx::method_registers.back_stencil_func()),
|
||||
rsx::method_registers.back_stencil_func_ref(), rsx::method_registers.back_stencil_func_mask());
|
||||
|
||||
glStencilOpSeparate(GL_BACK, stencil_op(rsx::method_registers.back_stencil_op_fail()),
|
||||
__glcheck glStencilOpSeparate(GL_BACK, stencil_op(rsx::method_registers.back_stencil_op_fail()),
|
||||
stencil_op(rsx::method_registers.back_stencil_op_zfail()), stencil_op(rsx::method_registers.back_stencil_op_zpass()));
|
||||
}
|
||||
}
|
||||
|
||||
gl_state.enablei(rsx::method_registers.blend_enabled_surface_1(), GL_BLEND, 1);
|
||||
gl_state.enablei(rsx::method_registers.blend_enabled_surface_2(), GL_BLEND, 2);
|
||||
gl_state.enablei(rsx::method_registers.blend_enabled_surface_3(), GL_BLEND, 3);
|
||||
__glcheck enable(rsx::method_registers.blend_enabled_surface_1(), GL_BLEND, 1);
|
||||
__glcheck enable(rsx::method_registers.blend_enabled_surface_2(), GL_BLEND, 2);
|
||||
__glcheck enable(rsx::method_registers.blend_enabled_surface_3(), GL_BLEND, 3);
|
||||
|
||||
if (gl_state.enable(rsx::method_registers.logic_op_enabled(), GL_COLOR_LOGIC_OP))
|
||||
if (__glcheck enable(rsx::method_registers.logic_op_enabled(), GL_COLOR_LOGIC_OP))
|
||||
{
|
||||
gl_state.logic_op(logic_op(rsx::method_registers.logic_operation()));
|
||||
__glcheck glLogicOp(logic_op(rsx::method_registers.logic_operation()));
|
||||
}
|
||||
|
||||
gl_state.line_width(rsx::method_registers.line_width());
|
||||
gl_state.enable(rsx::method_registers.line_smooth_enabled(), GL_LINE_SMOOTH);
|
||||
|
||||
gl_state.enable(rsx::method_registers.poly_offset_point_enabled(), GL_POLYGON_OFFSET_POINT);
|
||||
gl_state.enable(rsx::method_registers.poly_offset_line_enabled(), GL_POLYGON_OFFSET_LINE);
|
||||
gl_state.enable(rsx::method_registers.poly_offset_fill_enabled(), GL_POLYGON_OFFSET_FILL);
|
||||
|
||||
gl_state.polygon_offset(rsx::method_registers.poly_offset_scale(), rsx::method_registers.poly_offset_bias());
|
||||
|
||||
if (gl_state.enable(rsx::method_registers.cull_face_enabled(), GL_CULL_FACE))
|
||||
{
|
||||
gl_state.cull_face(cull_face(rsx::method_registers.cull_face_mode()));
|
||||
}
|
||||
|
||||
gl_state.front_face(front_face(rsx::method_registers.front_face_mode()));
|
||||
__glcheck glLineWidth(rsx::method_registers.line_width());
|
||||
__glcheck enable(rsx::method_registers.line_smooth_enabled(), GL_LINE_SMOOTH);
|
||||
|
||||
//TODO
|
||||
//NV4097_SET_ANISO_SPREAD
|
||||
|
||||
__glcheck enable(rsx::method_registers.poly_offset_point_enabled(), GL_POLYGON_OFFSET_POINT);
|
||||
__glcheck enable(rsx::method_registers.poly_offset_line_enabled(), GL_POLYGON_OFFSET_LINE);
|
||||
__glcheck enable(rsx::method_registers.poly_offset_fill_enabled(), GL_POLYGON_OFFSET_FILL);
|
||||
|
||||
__glcheck glPolygonOffset(rsx::method_registers.poly_offset_scale(),
|
||||
rsx::method_registers.poly_offset_bias());
|
||||
|
||||
//NV4097_SET_SPECULAR_ENABLE
|
||||
//NV4097_SET_TWO_SIDE_LIGHT_EN
|
||||
//NV4097_SET_FLAT_SHADE_OP
|
||||
//NV4097_SET_EDGE_FLAG
|
||||
|
||||
if (__glcheck enable(rsx::method_registers.cull_face_enabled(), GL_CULL_FACE))
|
||||
{
|
||||
__glcheck glCullFace(cull_face(rsx::method_registers.cull_face_mode()));
|
||||
}
|
||||
|
||||
__glcheck glFrontFace(front_face(rsx::method_registers.front_face_mode()));
|
||||
|
||||
//NV4097_SET_COLOR_KEY_COLOR
|
||||
//NV4097_SET_SHADER_CONTROL
|
||||
@@ -319,12 +327,18 @@ namespace
|
||||
|
||||
void GLGSRender::end()
|
||||
{
|
||||
if (skip_frame || !framebuffer_status_valid || (conditional_render_enabled && conditional_render_test_failed) || !check_program_state())
|
||||
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())
|
||||
{
|
||||
rsx::thread::end();
|
||||
return;
|
||||
}
|
||||
|
||||
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();
|
||||
|
||||
if (manually_flush_ring_buffers)
|
||||
{
|
||||
//Use approximations to reseve space. This path is mostly for debug purposes anyway
|
||||
@@ -336,32 +350,6 @@ void GLGSRender::end()
|
||||
m_index_ring_buffer->reserve_storage_on_heap(16 * 1024);
|
||||
}
|
||||
|
||||
//Do vertex upload before RTT prep / texture lookups to give the driver time to push data
|
||||
u32 vertex_draw_count;
|
||||
u32 actual_vertex_count;
|
||||
u32 vertex_base;
|
||||
std::optional<std::tuple<GLenum, u32> > indexed_draw_info;
|
||||
std::tie(vertex_draw_count, actual_vertex_count, vertex_base, indexed_draw_info) = set_vertex_buffer();
|
||||
|
||||
std::chrono::time_point<steady_clock> program_start = steady_clock::now();
|
||||
//Load program here since it is dependent on vertex state
|
||||
|
||||
load_program(vertex_base, actual_vertex_count);
|
||||
|
||||
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();
|
||||
|
||||
if (manually_flush_ring_buffers)
|
||||
{
|
||||
m_attrib_ring_buffer->unmap();
|
||||
m_index_ring_buffer->unmap();
|
||||
}
|
||||
else
|
||||
{
|
||||
//DMA push; not needed with MAP_COHERENT
|
||||
//glMemoryBarrier(GL_CLIENT_MAPPED_BUFFER_BARRIER_BIT);
|
||||
}
|
||||
|
||||
//Check if depth buffer is bound and valid
|
||||
//If ds is not initialized clear it; it seems new depth textures should have depth cleared
|
||||
auto copy_rtt_contents = [](gl::render_target *surface)
|
||||
@@ -410,9 +398,9 @@ void GLGSRender::end()
|
||||
|
||||
if (clear_depth)
|
||||
{
|
||||
gl_state.depth_mask(GL_TRUE);
|
||||
gl_state.clear_depth(1.0);
|
||||
gl_state.clear_stencil(255);
|
||||
glDepthMask(GL_TRUE);
|
||||
glClearDepth(1.0);
|
||||
glClearStencil(255);
|
||||
mask |= GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT;
|
||||
}
|
||||
|
||||
@@ -430,7 +418,7 @@ void GLGSRender::end()
|
||||
}
|
||||
|
||||
if (clear_depth)
|
||||
gl_state.depth_mask(rsx::method_registers.depth_write_enabled());
|
||||
glDepthMask(rsx::method_registers.depth_write_enabled());
|
||||
|
||||
ds->set_cleared();
|
||||
}
|
||||
@@ -486,12 +474,12 @@ void GLGSRender::end()
|
||||
int texture_index = i + rsx::limits::fragment_textures_count;
|
||||
int location;
|
||||
|
||||
if (!rsx::method_registers.vertex_textures[i].enabled())
|
||||
/* if (!rsx::method_registers.vertex_textures[i].enabled())
|
||||
{
|
||||
//glActiveTexture(GL_TEXTURE0 + texture_index);
|
||||
//glBindTexture(GL_TEXTURE_2D, 0);
|
||||
glActiveTexture(GL_TEXTURE0 + texture_index);
|
||||
glBindTexture(GL_TEXTURE_2D, 0);
|
||||
continue;
|
||||
}
|
||||
} */
|
||||
|
||||
if (m_program->uniforms.has_location("vtex" + std::to_string(i), &location))
|
||||
{
|
||||
@@ -503,6 +491,20 @@ void GLGSRender::end()
|
||||
std::chrono::time_point<steady_clock> textures_end = steady_clock::now();
|
||||
m_textures_upload_time += (u32)std::chrono::duration_cast<std::chrono::microseconds>(textures_end - textures_start).count();
|
||||
|
||||
u32 vertex_draw_count = m_last_vertex_count;
|
||||
std::optional<std::tuple<GLenum, u32> > indexed_draw_info;
|
||||
bool skip_upload = false;
|
||||
|
||||
if (!is_probable_instanced_draw())
|
||||
{
|
||||
std::tie(vertex_draw_count, indexed_draw_info) = set_vertex_buffer();
|
||||
m_last_vertex_count = vertex_draw_count;
|
||||
}
|
||||
else
|
||||
{
|
||||
skip_upload = true;
|
||||
}
|
||||
|
||||
std::chrono::time_point<steady_clock> draw_start = steady_clock::now();
|
||||
|
||||
if (g_cfg.video.debug_output)
|
||||
@@ -510,38 +512,49 @@ void GLGSRender::end()
|
||||
m_program->validate();
|
||||
}
|
||||
|
||||
if (indexed_draw_info)
|
||||
if (manually_flush_ring_buffers)
|
||||
{
|
||||
const GLenum index_type = std::get<0>(indexed_draw_info.value());
|
||||
const u32 index_offset = std::get<1>(indexed_draw_info.value());
|
||||
m_attrib_ring_buffer->unmap();
|
||||
m_index_ring_buffer->unmap();
|
||||
}
|
||||
|
||||
if (__glcheck gl_state.enable(rsx::method_registers.restart_index_enabled(), GL_PRIMITIVE_RESTART))
|
||||
if (indexed_draw_info || (skip_upload && m_last_draw_indexed == true))
|
||||
{
|
||||
if (__glcheck enable(rsx::method_registers.restart_index_enabled(), GL_PRIMITIVE_RESTART))
|
||||
{
|
||||
GLenum index_type = (skip_upload)? m_last_ib_type: std::get<0>(indexed_draw_info.value());
|
||||
__glcheck glPrimitiveRestartIndex((index_type == GL_UNSIGNED_SHORT)? 0xffff: 0xffffffff);
|
||||
}
|
||||
|
||||
__glcheck glDrawElements(gl::draw_mode(rsx::method_registers.current_draw_clause.primitive), vertex_draw_count, index_type, (GLvoid *)(uintptr_t)index_offset);
|
||||
m_last_draw_indexed = true;
|
||||
|
||||
if (!skip_upload)
|
||||
{
|
||||
m_last_ib_type = std::get<0>(indexed_draw_info.value());
|
||||
m_last_index_offset = std::get<1>(indexed_draw_info.value());
|
||||
}
|
||||
|
||||
__glcheck glDrawElements(gl::draw_mode(rsx::method_registers.current_draw_clause.primitive), vertex_draw_count, m_last_ib_type, (GLvoid *)(std::ptrdiff_t)m_last_index_offset);
|
||||
}
|
||||
else
|
||||
{
|
||||
glDrawArrays(gl::draw_mode(rsx::method_registers.current_draw_clause.primitive), 0, vertex_draw_count);
|
||||
draw_fbo.draw_arrays(rsx::method_registers.current_draw_clause.primitive, vertex_draw_count);
|
||||
m_last_draw_indexed = false;
|
||||
}
|
||||
|
||||
m_attrib_ring_buffer->notify();
|
||||
m_index_ring_buffer->notify();
|
||||
m_vertex_state_buffer->notify();
|
||||
m_scale_offset_buffer->notify();
|
||||
m_fragment_constants_buffer->notify();
|
||||
m_transform_constants_buffer->notify();
|
||||
|
||||
std::chrono::time_point<steady_clock> draw_end = steady_clock::now();
|
||||
m_draw_time += (u32)std::chrono::duration_cast<std::chrono::microseconds>(draw_end - draw_start).count();
|
||||
|
||||
m_draw_calls++;
|
||||
|
||||
if (zcull_task_queue.active_query &&
|
||||
zcull_task_queue.active_query->active)
|
||||
zcull_task_queue.active_query->num_draws++;
|
||||
|
||||
synchronize_buffers();
|
||||
|
||||
rsx::thread::end();
|
||||
}
|
||||
|
||||
@@ -580,9 +593,6 @@ void GLGSRender::on_init_thread()
|
||||
|
||||
gl::init();
|
||||
|
||||
//Enable adaptive vsync if vsync is requested
|
||||
gl::set_swapinterval(g_cfg.video.vsync ? -1 : 0);
|
||||
|
||||
if (g_cfg.video.debug_output)
|
||||
gl::enable_debugging();
|
||||
|
||||
@@ -627,21 +637,13 @@ void GLGSRender::on_init_thread()
|
||||
|
||||
const u32 texture_index_offset = rsx::limits::fragment_textures_count + rsx::limits::vertex_textures_count;
|
||||
|
||||
//Array stream buffer
|
||||
for (int index = 0; index < rsx::limits::vertex_count; ++index)
|
||||
{
|
||||
auto &tex = m_gl_persistent_stream_buffer;
|
||||
auto &tex = m_gl_attrib_buffers[index];
|
||||
tex.create();
|
||||
tex.set_target(gl::texture::target::textureBuffer);
|
||||
glActiveTexture(GL_TEXTURE0 + texture_index_offset);
|
||||
tex.bind();
|
||||
}
|
||||
|
||||
//Register stream buffer
|
||||
{
|
||||
auto &tex = m_gl_volatile_stream_buffer;
|
||||
tex.create();
|
||||
tex.set_target(gl::texture::target::textureBuffer);
|
||||
glActiveTexture(GL_TEXTURE0 + texture_index_offset + 1);
|
||||
glActiveTexture(GL_TEXTURE0 + texture_index_offset + index);
|
||||
tex.bind();
|
||||
}
|
||||
|
||||
@@ -660,7 +662,7 @@ void GLGSRender::on_init_thread()
|
||||
m_attrib_ring_buffer.reset(new gl::legacy_ring_buffer());
|
||||
m_transform_constants_buffer.reset(new gl::legacy_ring_buffer());
|
||||
m_fragment_constants_buffer.reset(new gl::legacy_ring_buffer());
|
||||
m_vertex_state_buffer.reset(new gl::legacy_ring_buffer());
|
||||
m_scale_offset_buffer.reset(new gl::legacy_ring_buffer());
|
||||
m_index_ring_buffer.reset(new gl::legacy_ring_buffer());
|
||||
}
|
||||
else
|
||||
@@ -668,7 +670,7 @@ void GLGSRender::on_init_thread()
|
||||
m_attrib_ring_buffer.reset(new gl::ring_buffer());
|
||||
m_transform_constants_buffer.reset(new gl::ring_buffer());
|
||||
m_fragment_constants_buffer.reset(new gl::ring_buffer());
|
||||
m_vertex_state_buffer.reset(new gl::ring_buffer());
|
||||
m_scale_offset_buffer.reset(new gl::ring_buffer());
|
||||
m_index_ring_buffer.reset(new gl::ring_buffer());
|
||||
}
|
||||
|
||||
@@ -676,7 +678,7 @@ void GLGSRender::on_init_thread()
|
||||
m_index_ring_buffer->create(gl::buffer::target::element_array, 64 * 0x100000);
|
||||
m_transform_constants_buffer->create(gl::buffer::target::uniform, 16 * 0x100000);
|
||||
m_fragment_constants_buffer->create(gl::buffer::target::uniform, 16 * 0x100000);
|
||||
m_vertex_state_buffer->create(gl::buffer::target::uniform, 16 * 0x100000);
|
||||
m_scale_offset_buffer->create(gl::buffer::target::uniform, 16 * 0x100000);
|
||||
|
||||
m_vao.element_array_buffer = *m_index_ring_buffer;
|
||||
|
||||
@@ -695,17 +697,6 @@ void GLGSRender::on_init_thread()
|
||||
m_gl_sampler_states[i].bind(i);
|
||||
}
|
||||
|
||||
//Occlusion query
|
||||
for (u32 i = 0; i < occlusion_query_count; ++i)
|
||||
{
|
||||
auto &query = occlusion_query_data[i];
|
||||
glGenQueries(1, &query.handle);
|
||||
|
||||
query.pending = false;
|
||||
query.active = false;
|
||||
query.result = 0;
|
||||
}
|
||||
|
||||
//Clip planes are shader controlled; enable all planes driver-side
|
||||
glEnable(GL_CLIP_DISTANCE0 + 0);
|
||||
glEnable(GL_CLIP_DISTANCE0 + 1);
|
||||
@@ -715,13 +706,11 @@ void GLGSRender::on_init_thread()
|
||||
glEnable(GL_CLIP_DISTANCE0 + 5);
|
||||
|
||||
m_gl_texture_cache.initialize(this);
|
||||
|
||||
m_shaders_cache->load();
|
||||
}
|
||||
|
||||
void GLGSRender::on_exit()
|
||||
{
|
||||
glFinish();
|
||||
glDisable(GL_VERTEX_PROGRAM_POINT_SIZE);
|
||||
|
||||
m_prog_buffer.clear();
|
||||
|
||||
@@ -745,8 +734,10 @@ void GLGSRender::on_exit()
|
||||
m_vao.remove();
|
||||
}
|
||||
|
||||
m_gl_persistent_stream_buffer.remove();
|
||||
m_gl_volatile_stream_buffer.remove();
|
||||
for (gl::texture &tex : m_gl_attrib_buffers)
|
||||
{
|
||||
tex.remove();
|
||||
}
|
||||
|
||||
for (auto &sampler : m_gl_sampler_states)
|
||||
{
|
||||
@@ -768,9 +759,9 @@ void GLGSRender::on_exit()
|
||||
m_fragment_constants_buffer->remove();
|
||||
}
|
||||
|
||||
if (m_vertex_state_buffer)
|
||||
if (m_scale_offset_buffer)
|
||||
{
|
||||
m_vertex_state_buffer->remove();
|
||||
m_scale_offset_buffer->remove();
|
||||
}
|
||||
|
||||
if (m_index_ring_buffer)
|
||||
@@ -781,15 +772,6 @@ void GLGSRender::on_exit()
|
||||
m_text_printer.close();
|
||||
m_gl_texture_cache.close();
|
||||
|
||||
for (u32 i = 0; i < occlusion_query_count; ++i)
|
||||
{
|
||||
auto &query = occlusion_query_data[i];
|
||||
query.active = false;
|
||||
query.pending = false;
|
||||
|
||||
glDeleteQueries(1, &query.handle);
|
||||
}
|
||||
|
||||
return GSRender::on_exit();
|
||||
}
|
||||
|
||||
@@ -808,8 +790,8 @@ void GLGSRender::clear_surface(u32 arg)
|
||||
u32 max_depth_value = get_max_depth_value(surface_depth_format);
|
||||
u32 clear_depth = rsx::method_registers.z_clear_value(surface_depth_format == rsx::surface_depth_format::z24s8);
|
||||
|
||||
gl_state.depth_mask(GL_TRUE);
|
||||
gl_state.clear_depth(f32(clear_depth) / max_depth_value);
|
||||
glDepthMask(GL_TRUE);
|
||||
glClearDepth(double(clear_depth) / max_depth_value);
|
||||
mask |= GLenum(gl::buffers::depth);
|
||||
|
||||
gl::render_target *ds = std::get<1>(m_rtts.m_bound_depth_stencil);
|
||||
@@ -824,8 +806,8 @@ void GLGSRender::clear_surface(u32 arg)
|
||||
{
|
||||
u8 clear_stencil = rsx::method_registers.stencil_clear_value();
|
||||
|
||||
gl_state.stencil_mask(rsx::method_registers.stencil_mask());
|
||||
gl_state.clear_stencil(clear_stencil);
|
||||
__glcheck glStencilMask(rsx::method_registers.stencil_mask());
|
||||
glClearStencil(clear_stencil);
|
||||
|
||||
mask |= GLenum(gl::buffers::stencil);
|
||||
}
|
||||
@@ -837,8 +819,8 @@ void GLGSRender::clear_surface(u32 arg)
|
||||
u8 clear_g = rsx::method_registers.clear_color_g();
|
||||
u8 clear_b = rsx::method_registers.clear_color_b();
|
||||
|
||||
gl_state.color_mask(arg & 0xf0);
|
||||
gl_state.clear_color(clear_r, clear_g, clear_b, clear_a);
|
||||
glColorMask(((arg & 0x20) ? 1 : 0), ((arg & 0x40) ? 1 : 0), ((arg & 0x80) ? 1 : 0), ((arg & 0x10) ? 1 : 0));
|
||||
glClearColor(clear_r / 255.f, clear_g / 255.f, clear_b / 255.f, clear_a / 255.f);
|
||||
|
||||
mask |= GLenum(gl::buffers::color);
|
||||
|
||||
@@ -871,12 +853,6 @@ bool GLGSRender::do_method(u32 cmd, u32 arg)
|
||||
|
||||
return true;
|
||||
}
|
||||
case NV4097_CLEAR_ZCULL_SURFACE:
|
||||
{
|
||||
// NOP
|
||||
// Clearing zcull memory does not modify depth/stencil buffers 'bound' to the zcull region
|
||||
return true;
|
||||
}
|
||||
case NV4097_TEXTURE_READ_SEMAPHORE_RELEASE:
|
||||
case NV4097_BACK_END_WRITE_SEMAPHORE_RELEASE:
|
||||
flush_draw_buffers = true;
|
||||
@@ -886,7 +862,7 @@ bool GLGSRender::do_method(u32 cmd, u32 arg)
|
||||
return false;
|
||||
}
|
||||
|
||||
bool GLGSRender::check_program_state()
|
||||
bool GLGSRender::load_program()
|
||||
{
|
||||
auto rtt_lookup_func = [this](u32 texaddr, rsx::fragment_texture &tex, bool is_depth) -> std::tuple<bool, u16>
|
||||
{
|
||||
@@ -908,19 +884,12 @@ bool GLGSRender::check_program_state()
|
||||
return std::make_tuple(true, surface->get_native_pitch());
|
||||
};
|
||||
|
||||
get_current_fragment_program(rtt_lookup_func);
|
||||
RSXFragmentProgram fragment_program = get_current_fragment_program(rtt_lookup_func);
|
||||
if (!fragment_program.valid) return false;
|
||||
|
||||
if (current_fragment_program.valid == false)
|
||||
return false;
|
||||
RSXVertexProgram vertex_program = get_current_vertex_program();
|
||||
|
||||
get_current_vertex_program();
|
||||
return true;
|
||||
}
|
||||
|
||||
void GLGSRender::load_program(u32 vertex_base, u32 vertex_count)
|
||||
{
|
||||
auto &fragment_program = current_fragment_program;
|
||||
auto &vertex_program = current_vertex_program;
|
||||
u32 unnormalized_rtts = 0;
|
||||
|
||||
for (auto &vtx : vertex_program.rsx_vertex_inputs)
|
||||
{
|
||||
@@ -934,39 +903,31 @@ void GLGSRender::load_program(u32 vertex_base, u32 vertex_count)
|
||||
}
|
||||
}
|
||||
|
||||
vertex_program.skip_vertex_input_check = true; //not needed for us since decoding is done server side
|
||||
void* pipeline_properties = nullptr;
|
||||
|
||||
m_program = &m_prog_buffer.getGraphicPipelineState(vertex_program, fragment_program, pipeline_properties);
|
||||
auto old_program = m_program;
|
||||
m_program = &m_prog_buffer.getGraphicPipelineState(vertex_program, fragment_program, nullptr);
|
||||
m_program->use();
|
||||
|
||||
if (m_prog_buffer.check_cache_missed())
|
||||
m_shaders_cache->store(pipeline_properties, vertex_program, fragment_program);
|
||||
|
||||
u8 *buf;
|
||||
u32 vertex_state_offset;
|
||||
u32 scale_offset_offset;
|
||||
u32 vertex_constants_offset;
|
||||
u32 fragment_constants_offset;
|
||||
|
||||
const u32 fragment_constants_size = (const u32)m_prog_buffer.get_fragment_constants_buffer_size(fragment_program);
|
||||
const u32 fragment_buffer_size = fragment_constants_size + (18 * 4 * sizeof(float));
|
||||
const u32 fragment_buffer_size = fragment_constants_size + (17 * 4 * sizeof(float));
|
||||
|
||||
if (manually_flush_ring_buffers)
|
||||
{
|
||||
m_vertex_state_buffer->reserve_storage_on_heap(512);
|
||||
m_scale_offset_buffer->reserve_storage_on_heap(512);
|
||||
m_fragment_constants_buffer->reserve_storage_on_heap(align(fragment_buffer_size, 256));
|
||||
if (m_transform_constants_dirty) m_transform_constants_buffer->reserve_storage_on_heap(8192);
|
||||
}
|
||||
|
||||
// Vertex state
|
||||
auto mapping = m_vertex_state_buffer->alloc_from_heap(512, m_uniform_buffer_offset_align);
|
||||
// Scale offset
|
||||
auto mapping = m_scale_offset_buffer->alloc_from_heap(512, m_uniform_buffer_offset_align);
|
||||
buf = static_cast<u8*>(mapping.first);
|
||||
vertex_state_offset = mapping.second;
|
||||
scale_offset_offset = mapping.second;
|
||||
fill_scale_offset_data(buf, false);
|
||||
fill_user_clip_data(buf + 64);
|
||||
*(reinterpret_cast<u32*>(buf + 128)) = rsx::method_registers.transform_branch_bits();
|
||||
*(reinterpret_cast<u32*>(buf + 132)) = vertex_base;
|
||||
fill_vertex_layout_state(m_vertex_layout, vertex_count, reinterpret_cast<s32*>(buf + 144));
|
||||
fill_user_clip_data((char *)buf + 64);
|
||||
|
||||
if (m_transform_constants_dirty)
|
||||
{
|
||||
@@ -975,6 +936,7 @@ void GLGSRender::load_program(u32 vertex_base, u32 vertex_count)
|
||||
buf = static_cast<u8*>(mapping.first);
|
||||
vertex_constants_offset = mapping.second;
|
||||
fill_vertex_program_constants_data(buf);
|
||||
*(reinterpret_cast<u32*>(buf + (468 * 4 * sizeof(float)))) = rsx::method_registers.transform_branch_bits();
|
||||
}
|
||||
|
||||
// Fragment constants
|
||||
@@ -987,20 +949,21 @@ void GLGSRender::load_program(u32 vertex_base, u32 vertex_count)
|
||||
// Fragment state
|
||||
fill_fragment_state_buffer(buf+fragment_constants_size, fragment_program);
|
||||
|
||||
m_vertex_state_buffer->bind_range(0, vertex_state_offset, 512);
|
||||
m_scale_offset_buffer->bind_range(0, scale_offset_offset, 512);
|
||||
m_fragment_constants_buffer->bind_range(2, fragment_constants_offset, fragment_buffer_size);
|
||||
|
||||
if (m_transform_constants_dirty) m_transform_constants_buffer->bind_range(1, vertex_constants_offset, 8192);
|
||||
|
||||
if (manually_flush_ring_buffers)
|
||||
{
|
||||
m_vertex_state_buffer->unmap();
|
||||
m_scale_offset_buffer->unmap();
|
||||
m_fragment_constants_buffer->unmap();
|
||||
|
||||
if (m_transform_constants_dirty) m_transform_constants_buffer->unmap();
|
||||
}
|
||||
|
||||
m_transform_constants_dirty = false;
|
||||
return true;
|
||||
}
|
||||
|
||||
void GLGSRender::flip(int buffer)
|
||||
@@ -1101,8 +1064,10 @@ void GLGSRender::flip(int buffer)
|
||||
}
|
||||
|
||||
// Blit source image to the screen
|
||||
// Disable scissor test (affects blit)
|
||||
glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
|
||||
glDisable(GL_SCISSOR_TEST);
|
||||
glDisable(GL_DEPTH_TEST);
|
||||
glDisable(GL_STENCIL_TEST);
|
||||
|
||||
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);
|
||||
@@ -1161,12 +1126,6 @@ bool GLGSRender::on_access_violation(u32 address, bool is_writing)
|
||||
return m_gl_texture_cache.flush_section(address);
|
||||
}
|
||||
|
||||
void GLGSRender::on_notify_memory_unmapped(u32 address_base, u32 size)
|
||||
{
|
||||
if (m_gl_texture_cache.invalidate_range(address_base, size, false))
|
||||
m_gl_texture_cache.purge_dirty();
|
||||
}
|
||||
|
||||
void GLGSRender::do_local_task()
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(queue_guard);
|
||||
@@ -1224,180 +1183,3 @@ bool GLGSRender::scaled_image_from_memory(rsx::blit_src_info& src, rsx::blit_dst
|
||||
{
|
||||
return m_gl_texture_cache.upload_scaled_image(src, dst, interpolate, m_rtts);
|
||||
}
|
||||
|
||||
void GLGSRender::check_zcull_status(bool framebuffer_swap, bool force_read)
|
||||
{
|
||||
if (g_cfg.video.disable_zcull_queries)
|
||||
return;
|
||||
|
||||
bool testing_enabled = zcull_pixel_cnt_enabled || zcull_stats_enabled;
|
||||
|
||||
if (framebuffer_swap)
|
||||
{
|
||||
zcull_surface_active = false;
|
||||
const u32 zeta_address = depth_surface_info.address;
|
||||
|
||||
if (zeta_address)
|
||||
{
|
||||
//Find zeta address in bound zculls
|
||||
for (int i = 0; i < rsx::limits::zculls_count; i++)
|
||||
{
|
||||
if (zculls[i].binded)
|
||||
{
|
||||
const u32 rsx_address = rsx::get_address(zculls[i].offset, CELL_GCM_LOCATION_LOCAL);
|
||||
if (rsx_address == zeta_address)
|
||||
{
|
||||
zcull_surface_active = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
occlusion_query_info* query = nullptr;
|
||||
|
||||
if (zcull_task_queue.task_stack.size() > 0)
|
||||
query = zcull_task_queue.active_query;
|
||||
|
||||
if (query && query->active)
|
||||
{
|
||||
if (force_read || (!zcull_rendering_enabled || !testing_enabled || !zcull_surface_active))
|
||||
{
|
||||
glEndQuery(GL_ANY_SAMPLES_PASSED);
|
||||
query->active = false;
|
||||
query->pending = true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (zcull_rendering_enabled && testing_enabled && zcull_surface_active)
|
||||
{
|
||||
//Find query
|
||||
u32 free_index = synchronize_zcull_stats();
|
||||
query = &occlusion_query_data[free_index];
|
||||
zcull_task_queue.add(query);
|
||||
|
||||
glBeginQuery(GL_ANY_SAMPLES_PASSED, query->handle);
|
||||
query->active = true;
|
||||
query->result = 0;
|
||||
query->num_draws = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void GLGSRender::clear_zcull_stats(u32 type)
|
||||
{
|
||||
if (g_cfg.video.disable_zcull_queries)
|
||||
return;
|
||||
|
||||
if (type == CELL_GCM_ZPASS_PIXEL_CNT)
|
||||
{
|
||||
if (zcull_task_queue.active_query &&
|
||||
zcull_task_queue.active_query->active &&
|
||||
zcull_task_queue.active_query->num_draws > 0)
|
||||
{
|
||||
//discard active query results
|
||||
check_zcull_status(false, true);
|
||||
zcull_task_queue.active_query->pending = false;
|
||||
|
||||
//re-enable cull stats if stats are enabled
|
||||
check_zcull_status(false, false);
|
||||
zcull_task_queue.active_query->num_draws = 0;
|
||||
}
|
||||
|
||||
current_zcull_stats.clear();
|
||||
}
|
||||
}
|
||||
|
||||
u32 GLGSRender::get_zcull_stats(u32 type)
|
||||
{
|
||||
if (g_cfg.video.disable_zcull_queries)
|
||||
return 0u;
|
||||
|
||||
if (zcull_task_queue.active_query &&
|
||||
zcull_task_queue.active_query->active &&
|
||||
current_zcull_stats.zpass_pixel_cnt == 0 &&
|
||||
type == CELL_GCM_ZPASS_PIXEL_CNT)
|
||||
{
|
||||
//The zcull unit is still bound as the read is happening and there are no results ready
|
||||
check_zcull_status(false, true); //close current query
|
||||
check_zcull_status(false, false); //start new query since stat counting is still active
|
||||
}
|
||||
|
||||
switch (type)
|
||||
{
|
||||
case CELL_GCM_ZPASS_PIXEL_CNT:
|
||||
{
|
||||
if (current_zcull_stats.zpass_pixel_cnt > 0)
|
||||
return UINT16_MAX;
|
||||
|
||||
synchronize_zcull_stats(true);
|
||||
return (current_zcull_stats.zpass_pixel_cnt > 0)? UINT16_MAX : 0;
|
||||
}
|
||||
case CELL_GCM_ZCULL_STATS:
|
||||
case CELL_GCM_ZCULL_STATS1:
|
||||
case CELL_GCM_ZCULL_STATS2:
|
||||
//TODO
|
||||
return UINT16_MAX;
|
||||
case CELL_GCM_ZCULL_STATS3:
|
||||
{
|
||||
//Some kind of inverse value
|
||||
if (current_zcull_stats.zpass_pixel_cnt > 0)
|
||||
return 0;
|
||||
|
||||
synchronize_zcull_stats(true);
|
||||
return (current_zcull_stats.zpass_pixel_cnt > 0) ? 0 : UINT16_MAX;
|
||||
}
|
||||
default:
|
||||
LOG_ERROR(RSX, "Unknown zcull stat type %d", type);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
u32 GLGSRender::synchronize_zcull_stats(bool hard_sync)
|
||||
{
|
||||
if (!zcull_rendering_enabled || zcull_task_queue.pending == 0)
|
||||
return 0;
|
||||
|
||||
u32 result = UINT16_MAX;
|
||||
GLint count, status;
|
||||
|
||||
for (auto &query : zcull_task_queue.task_stack)
|
||||
{
|
||||
if (query == nullptr || query->active)
|
||||
continue;
|
||||
|
||||
glGetQueryObjectiv(query->handle, GL_QUERY_RESULT_AVAILABLE, &status);
|
||||
|
||||
if (status == GL_FALSE && !hard_sync)
|
||||
continue;
|
||||
|
||||
glGetQueryObjectiv(query->handle, GL_QUERY_RESULT, &count);
|
||||
query->pending = false;
|
||||
query = nullptr;
|
||||
|
||||
current_zcull_stats.zpass_pixel_cnt += count;
|
||||
zcull_task_queue.pending--;
|
||||
}
|
||||
|
||||
for (u32 i = 0; i < occlusion_query_count; ++i)
|
||||
{
|
||||
auto &query = occlusion_query_data[i];
|
||||
if (!query.pending && !query.active)
|
||||
{
|
||||
result = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (result == UINT16_MAX && !hard_sync)
|
||||
return synchronize_zcull_stats(true);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void GLGSRender::notify_zcull_info_changed()
|
||||
{
|
||||
check_zcull_status(false, false);
|
||||
}
|
||||
|
||||
+12
-304
@@ -19,8 +19,6 @@ 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;
|
||||
|
||||
using shader_cache = rsx::shaders_cache<void*, GLProgramBuffer>;
|
||||
}
|
||||
|
||||
struct work_item
|
||||
@@ -52,13 +50,12 @@ private:
|
||||
|
||||
gl::texture_cache m_gl_texture_cache;
|
||||
|
||||
gl::texture m_gl_persistent_stream_buffer;
|
||||
gl::texture m_gl_volatile_stream_buffer;
|
||||
gl::texture m_gl_attrib_buffers[rsx::limits::vertex_count];
|
||||
|
||||
std::unique_ptr<gl::ring_buffer> m_attrib_ring_buffer;
|
||||
std::unique_ptr<gl::ring_buffer> m_fragment_constants_buffer;
|
||||
std::unique_ptr<gl::ring_buffer> m_transform_constants_buffer;
|
||||
std::unique_ptr<gl::ring_buffer> m_vertex_state_buffer;
|
||||
std::unique_ptr<gl::ring_buffer> m_scale_offset_buffer;
|
||||
std::unique_ptr<gl::ring_buffer> m_index_ring_buffer;
|
||||
|
||||
u32 m_draw_calls = 0;
|
||||
@@ -68,7 +65,6 @@ private:
|
||||
s64 m_textures_upload_time = 0;
|
||||
|
||||
std::unique_ptr<gl::vertex_cache> m_vertex_cache;
|
||||
std::unique_ptr<gl::shader_cache> m_shaders_cache;
|
||||
|
||||
GLint m_min_texbuffer_alignment = 256;
|
||||
GLint m_uniform_buffer_offset_align = 256;
|
||||
@@ -87,6 +83,11 @@ private:
|
||||
|
||||
bool flush_draw_buffers = false;
|
||||
|
||||
bool m_last_draw_indexed;
|
||||
GLenum m_last_ib_type;
|
||||
size_t m_last_index_offset;
|
||||
u32 m_last_vertex_count;
|
||||
|
||||
public:
|
||||
gl::fbo draw_fbo;
|
||||
|
||||
@@ -100,306 +101,21 @@ private:
|
||||
//vaos are mandatory for core profile
|
||||
gl::vao m_vao;
|
||||
|
||||
//occlusion query
|
||||
bool zcull_surface_active = false;
|
||||
|
||||
struct occlusion_query_info
|
||||
{
|
||||
GLuint handle;
|
||||
GLint result;
|
||||
GLint num_draws;
|
||||
bool pending;
|
||||
bool active;
|
||||
};
|
||||
|
||||
struct
|
||||
{
|
||||
u32 zpass_pixel_cnt;
|
||||
u32 zcull_stats;
|
||||
u32 zcull_stats1;
|
||||
u32 zcull_stats2;
|
||||
u32 zcull_stats3;
|
||||
|
||||
void clear()
|
||||
{
|
||||
zpass_pixel_cnt = zcull_stats = zcull_stats1 = zcull_stats2 = zcull_stats3 = 0;
|
||||
}
|
||||
}
|
||||
current_zcull_stats;
|
||||
|
||||
struct occlusion_task
|
||||
{
|
||||
std::vector<occlusion_query_info*> task_stack;
|
||||
occlusion_query_info* active_query = nullptr;
|
||||
u32 pending = 0;
|
||||
|
||||
//Add one query to the task
|
||||
void add(occlusion_query_info* query)
|
||||
{
|
||||
active_query = query;
|
||||
|
||||
if (task_stack.size() > 0 && pending == 0)
|
||||
task_stack.resize(0);
|
||||
|
||||
const auto empty_slots = task_stack.size() - pending;
|
||||
if (empty_slots >= 4)
|
||||
{
|
||||
for (auto &_query : task_stack)
|
||||
{
|
||||
if (_query == nullptr)
|
||||
{
|
||||
_query = query;
|
||||
pending++;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
task_stack.push_back(query);
|
||||
pending++;
|
||||
}
|
||||
}
|
||||
zcull_task_queue = {};
|
||||
|
||||
const u32 occlusion_query_count = 128;
|
||||
std::array<occlusion_query_info, 128> occlusion_query_data = {};
|
||||
|
||||
public:
|
||||
GLGSRender();
|
||||
|
||||
private:
|
||||
|
||||
struct
|
||||
{
|
||||
const u32 DEPTH_BOUNDS_MIN = 0xFFFF0001;
|
||||
const u32 DEPTH_BOUNDS_MAX = 0xFFFF0002;
|
||||
const u32 DEPTH_RANGE_MIN = 0xFFFF0003;
|
||||
const u32 DEPTH_RANGE_MAX = 0xFFFF0004;
|
||||
|
||||
std::unordered_map<GLenum, u32> properties = {};
|
||||
std::unordered_map<GLenum, std::array<u32, 4>> indexed_properties = {};
|
||||
|
||||
bool enable(u32 test, GLenum cap)
|
||||
{
|
||||
auto found = properties.find(cap);
|
||||
if (found != properties.end() && found->second == test)
|
||||
return !!test;
|
||||
|
||||
properties[cap] = test;
|
||||
|
||||
if (test)
|
||||
glEnable(cap);
|
||||
else
|
||||
glDisable(cap);
|
||||
|
||||
return !!test;
|
||||
}
|
||||
|
||||
bool enablei(u32 test, GLenum cap, u32 index)
|
||||
{
|
||||
auto found = indexed_properties.find(cap);
|
||||
const bool exists = found != indexed_properties.end();
|
||||
|
||||
if (!exists)
|
||||
{
|
||||
indexed_properties[cap] = {};
|
||||
indexed_properties[cap][index] = test;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (found->second[index] == test)
|
||||
return !!test;
|
||||
|
||||
found->second[index] = test;
|
||||
}
|
||||
|
||||
if (test)
|
||||
glEnablei(cap, index);
|
||||
else
|
||||
glDisablei(cap, index);
|
||||
|
||||
return !!test;
|
||||
}
|
||||
|
||||
const bool test_property(GLenum property, u32 test) const
|
||||
{
|
||||
auto found = properties.find(property);
|
||||
if (found == properties.end())
|
||||
return false;
|
||||
|
||||
return (found->second == test);
|
||||
}
|
||||
|
||||
void depth_func(GLenum func)
|
||||
{
|
||||
if (!test_property(GL_DEPTH_FUNC, func))
|
||||
{
|
||||
glDepthFunc(func);
|
||||
properties[GL_DEPTH_FUNC] = func;
|
||||
}
|
||||
}
|
||||
|
||||
void depth_mask(GLboolean mask)
|
||||
{
|
||||
if (!test_property(GL_DEPTH_WRITEMASK, mask))
|
||||
{
|
||||
glDepthMask(mask);
|
||||
properties[GL_DEPTH_WRITEMASK] = mask;
|
||||
}
|
||||
}
|
||||
|
||||
void clear_depth(GLfloat depth)
|
||||
{
|
||||
u32 value = (u32&)depth;
|
||||
if (!test_property(GL_DEPTH_CLEAR_VALUE, value))
|
||||
{
|
||||
glClearDepth(depth);
|
||||
properties[GL_DEPTH_CLEAR_VALUE] = value;
|
||||
}
|
||||
}
|
||||
|
||||
void stencil_mask(GLuint mask)
|
||||
{
|
||||
if (!test_property(GL_STENCIL_WRITEMASK, mask))
|
||||
{
|
||||
glStencilMask(mask);
|
||||
properties[GL_STENCIL_WRITEMASK] = mask;
|
||||
}
|
||||
}
|
||||
|
||||
void clear_stencil(GLint stencil)
|
||||
{
|
||||
u32 value = (u32&)stencil;
|
||||
if (!test_property(GL_STENCIL_CLEAR_VALUE, value))
|
||||
{
|
||||
glClearStencil(stencil);
|
||||
properties[GL_STENCIL_CLEAR_VALUE] = value;
|
||||
}
|
||||
}
|
||||
|
||||
void color_mask(u32 mask)
|
||||
{
|
||||
if (!test_property(GL_COLOR_WRITEMASK, mask))
|
||||
{
|
||||
glColorMask(((mask & 0x20) ? 1 : 0), ((mask & 0x40) ? 1 : 0), ((mask & 0x80) ? 1 : 0), ((mask & 0x10) ? 1 : 0));
|
||||
properties[GL_COLOR_WRITEMASK] = mask;
|
||||
}
|
||||
}
|
||||
|
||||
void color_mask(bool r, bool g, bool b, bool a)
|
||||
{
|
||||
u32 mask = 0;
|
||||
if (r) mask |= 0x20;
|
||||
if (g) mask |= 0x40;
|
||||
if (b) mask |= 0x80;
|
||||
if (a) mask |= 0x10;
|
||||
|
||||
color_mask(mask);
|
||||
}
|
||||
|
||||
void clear_color(u8 r, u8 g, u8 b, u8 a)
|
||||
{
|
||||
u32 value = (u32)r | (u32)g << 8 | (u32)b << 16 | (u32)a << 24;
|
||||
if (!test_property(GL_COLOR_CLEAR_VALUE, value))
|
||||
{
|
||||
glClearColor(r / 255.f, g / 255.f, b / 255.f, a / 255.f);
|
||||
properties[GL_COLOR_CLEAR_VALUE] = value;
|
||||
}
|
||||
}
|
||||
|
||||
void depth_bounds(float min, float max)
|
||||
{
|
||||
u32 depth_min = (u32&)min;
|
||||
u32 depth_max = (u32&)max;
|
||||
|
||||
if (!test_property(DEPTH_BOUNDS_MIN, depth_min) || !test_property(DEPTH_BOUNDS_MAX, depth_max))
|
||||
{
|
||||
glDepthBoundsEXT(min, max);
|
||||
|
||||
properties[DEPTH_BOUNDS_MIN] = depth_min;
|
||||
properties[DEPTH_BOUNDS_MAX] = depth_max;
|
||||
}
|
||||
}
|
||||
|
||||
void depth_range(float min, float max)
|
||||
{
|
||||
u32 depth_min = (u32&)min;
|
||||
u32 depth_max = (u32&)max;
|
||||
|
||||
if (!test_property(DEPTH_RANGE_MIN, depth_min) || !test_property(DEPTH_RANGE_MAX, depth_max))
|
||||
{
|
||||
glDepthRange(min, max);
|
||||
|
||||
properties[DEPTH_RANGE_MIN] = depth_min;
|
||||
properties[DEPTH_RANGE_MAX] = depth_max;
|
||||
}
|
||||
}
|
||||
|
||||
void logic_op(GLenum op)
|
||||
{
|
||||
if (!test_property(GL_COLOR_LOGIC_OP, op))
|
||||
{
|
||||
glLogicOp(op);
|
||||
properties[GL_COLOR_LOGIC_OP] = op;
|
||||
}
|
||||
}
|
||||
|
||||
void line_width(GLfloat width)
|
||||
{
|
||||
u32 value = (u32&)width;
|
||||
|
||||
if (!test_property(GL_LINE_WIDTH, value))
|
||||
{
|
||||
glLineWidth(width);
|
||||
properties[GL_LINE_WIDTH] = value;
|
||||
}
|
||||
}
|
||||
|
||||
void front_face(GLenum face)
|
||||
{
|
||||
if (!test_property(GL_FRONT_FACE, face))
|
||||
{
|
||||
glFrontFace(face);
|
||||
properties[GL_FRONT_FACE] = face;
|
||||
}
|
||||
}
|
||||
|
||||
void cull_face(GLenum mode)
|
||||
{
|
||||
if (!test_property(GL_CULL_FACE_MODE, mode))
|
||||
{
|
||||
glCullFace(mode);
|
||||
properties[GL_CULL_FACE_MODE] = mode;
|
||||
}
|
||||
}
|
||||
|
||||
void polygon_offset(float factor, float units)
|
||||
{
|
||||
u32 _units = (u32&)units;
|
||||
u32 _factor = (u32&)factor;
|
||||
|
||||
if (!test_property(GL_POLYGON_OFFSET_UNITS, _units) || !test_property(GL_POLYGON_OFFSET_FACTOR, _factor))
|
||||
{
|
||||
glPolygonOffset(factor, units);
|
||||
|
||||
properties[GL_POLYGON_OFFSET_UNITS] = _units;
|
||||
properties[GL_POLYGON_OFFSET_FACTOR] = _factor;
|
||||
}
|
||||
}
|
||||
}
|
||||
gl_state;
|
||||
static u32 enable(u32 enable, u32 cap);
|
||||
static u32 enable(u32 enable, u32 cap, u32 index);
|
||||
|
||||
// Return element to draw and in case of indexed draw index type and offset in index buffer
|
||||
std::tuple<u32, u32, u32, std::optional<std::tuple<GLenum, u32> > > set_vertex_buffer();
|
||||
rsx::vertex_input_layout m_vertex_layout = {};
|
||||
std::tuple<u32, std::optional<std::tuple<GLenum, u32> > > set_vertex_buffer();
|
||||
|
||||
void clear_surface(u32 arg);
|
||||
void init_buffers(bool skip_reading = false);
|
||||
|
||||
bool check_program_state();
|
||||
void load_program(u32 vertex_base, u32 vertex_count);
|
||||
|
||||
public:
|
||||
bool load_program();
|
||||
void init_buffers(bool skip_reading = false);
|
||||
void read_buffers();
|
||||
void write_buffers();
|
||||
void set_viewport();
|
||||
@@ -408,9 +124,6 @@ public:
|
||||
work_item& post_flush_request(u32 address, gl::texture_cache::cached_texture_section *section);
|
||||
|
||||
bool scaled_image_from_memory(rsx::blit_src_info& src_info, rsx::blit_dst_info& dst_info, bool interpolate) override;
|
||||
|
||||
void check_zcull_status(bool framebuffer_swap, bool force_read);
|
||||
u32 synchronize_zcull_stats(bool hard_sync = false);
|
||||
|
||||
protected:
|
||||
void begin() override;
|
||||
@@ -424,12 +137,7 @@ protected:
|
||||
|
||||
void do_local_task() override;
|
||||
|
||||
void notify_zcull_info_changed() override;
|
||||
void clear_zcull_stats(u32 type) override;
|
||||
u32 get_zcull_stats(u32 type) override;
|
||||
|
||||
bool on_access_violation(u32 address, bool is_writing) override;
|
||||
void on_notify_memory_unmapped(u32 address_base, u32 size) override;
|
||||
|
||||
virtual std::array<std::vector<gsl::byte>, 4> copy_render_targets_to_memory() override;
|
||||
virtual std::array<std::vector<gsl::byte>, 2> copy_depth_stencil_buffer_to_memory() override;
|
||||
|
||||
@@ -19,7 +19,7 @@ namespace gl
|
||||
case rsx::primitive_type::triangle_strip: return GL_TRIANGLE_STRIP;
|
||||
case rsx::primitive_type::triangle_fan: return GL_TRIANGLE_FAN;
|
||||
case rsx::primitive_type::quads: return GL_TRIANGLES;
|
||||
case rsx::primitive_type::quad_strip: return GL_TRIANGLE_STRIP;
|
||||
case rsx::primitive_type::quad_strip: return GL_TRIANGLES;
|
||||
case rsx::primitive_type::polygon: return GL_TRIANGLES;
|
||||
}
|
||||
fmt::throw_exception("unknow primitive type" HERE);
|
||||
@@ -543,9 +543,9 @@ namespace gl
|
||||
case rsx::primitive_type::triangles:
|
||||
case rsx::primitive_type::triangle_strip:
|
||||
case rsx::primitive_type::triangle_fan:
|
||||
case rsx::primitive_type::quad_strip:
|
||||
return true;
|
||||
case rsx::primitive_type::quads:
|
||||
case rsx::primitive_type::quad_strip:
|
||||
case rsx::primitive_type::polygon:
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -82,7 +82,6 @@ namespace gl
|
||||
bool ARB_texture_barrier_supported = false;
|
||||
bool NV_texture_barrier_supported = false;
|
||||
bool initialized = false;
|
||||
bool vendor_INTEL = false;
|
||||
|
||||
void initialize()
|
||||
{
|
||||
@@ -155,17 +154,8 @@ namespace gl
|
||||
}
|
||||
|
||||
//Workaround for intel drivers which have terrible capability reporting
|
||||
std::string vendor_string;
|
||||
if (const char* raw_string = (const char*)glGetString(GL_VENDOR))
|
||||
{
|
||||
vendor_string = raw_string;
|
||||
std::transform(vendor_string.begin(), vendor_string.end(), vendor_string.begin(), ::tolower);
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG_ERROR(RSX, "Failed to get vendor string from driver. Are we missing a context?");
|
||||
vendor_string = "intel"; //lowest acceptable value
|
||||
}
|
||||
std::string vendor_string = (const char*)glGetString(GL_VENDOR);
|
||||
std::transform(vendor_string.begin(), vendor_string.end(), vendor_string.begin(), ::tolower);
|
||||
|
||||
if (vendor_string.find("intel") != std::string::npos)
|
||||
{
|
||||
@@ -175,8 +165,6 @@ namespace gl
|
||||
glGetIntegerv(GL_MAJOR_VERSION, &version_major);
|
||||
glGetIntegerv(GL_MINOR_VERSION, &version_minor);
|
||||
|
||||
vendor_INTEL = true;
|
||||
|
||||
//Texture buffers moved into core at GL 3.3
|
||||
if (version_major > 3 || (version_major == 3 && version_minor >= 3))
|
||||
ARB_texture_buffer_supported = true;
|
||||
@@ -838,7 +826,7 @@ namespace gl
|
||||
buffer::create();
|
||||
|
||||
glBindBuffer((GLenum)m_target, m_id);
|
||||
glBufferStorage((GLenum)m_target, size, data, GL_MAP_WRITE_BIT | GL_MAP_PERSISTENT_BIT | GL_CLIENT_STORAGE_BIT | GL_MAP_COHERENT_BIT);
|
||||
glBufferStorage((GLenum)m_target, size, data, GL_MAP_WRITE_BIT | GL_MAP_PERSISTENT_BIT | GL_MAP_COHERENT_BIT);
|
||||
m_memory_mapping = glMapBufferRange((GLenum)m_target, 0, size, GL_MAP_WRITE_BIT | GL_MAP_PERSISTENT_BIT | GL_MAP_COHERENT_BIT);
|
||||
|
||||
verify(HERE), m_memory_mapping != nullptr;
|
||||
@@ -2046,6 +2034,12 @@ namespace gl
|
||||
|
||||
namespace glsl
|
||||
{
|
||||
enum program_domain
|
||||
{
|
||||
glsl_vertex_program = 0,
|
||||
glsl_fragment_program = 1
|
||||
};
|
||||
|
||||
class compilation_exception : public exception
|
||||
{
|
||||
public:
|
||||
@@ -2544,7 +2538,7 @@ namespace gl
|
||||
error_msg = buf.get();
|
||||
}
|
||||
|
||||
LOG_ERROR(RSX, "Validation failed: %s", error_msg.c_str());
|
||||
throw validation_exception(error_msg);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -183,13 +183,6 @@ OPENGL_PROC(PFNGLSAMPLERPARAMETERIPROC, SamplerParameteri);
|
||||
OPENGL_PROC(PFNGLSAMPLERPARAMETERFPROC, SamplerParameterf);
|
||||
OPENGL_PROC(PFNGLSAMPLERPARAMETERFVPROC, SamplerParameterfv);
|
||||
|
||||
//Occlusion Query
|
||||
OPENGL_PROC(PFNGLGENQUERIESPROC, GenQueries);
|
||||
OPENGL_PROC(PFNGLDELETEQUERIESPROC, DeleteQueries);
|
||||
OPENGL_PROC(PFNGLGETQUERYOBJECTIVPROC, GetQueryObjectiv);
|
||||
OPENGL_PROC(PFNGLBEGINQUERYPROC, BeginQuery);
|
||||
OPENGL_PROC(PFNGLENDQUERYPROC, EndQuery);
|
||||
|
||||
//Texture Buffers
|
||||
OPENGL_PROC(PFNGLTEXTUREBUFFERRANGEEXTPROC, TextureBufferRangeEXT);
|
||||
OPENGL_PROC(PFNGLTEXTUREBUFFERRANGEPROC, TextureBufferRange);
|
||||
@@ -219,8 +212,6 @@ OPENGL_PROC(PFNGLTEXTUREBARRIERPROC, TextureBarrier);
|
||||
OPENGL_PROC(PFNGLTEXTUREBARRIERNVPROC, TextureBarrierNV);
|
||||
//...
|
||||
|
||||
WGL_PROC(PFNWGLSWAPINTERVALEXTPROC, SwapIntervalEXT);
|
||||
|
||||
#if !defined(__GNUG__) || defined(__MINGW32__)
|
||||
OPENGL_PROC(PFNGLBLENDCOLORPROC, BlendColor);
|
||||
OPENGL_PROC(PFNGLBLENDEQUATIONPROC, BlendEquation);
|
||||
|
||||
@@ -54,11 +54,24 @@ struct GLTraits
|
||||
result.uniforms[location] = (i + rsx::limits::fragment_textures_count);
|
||||
}
|
||||
|
||||
const int stream_buffer_start = rsx::limits::fragment_textures_count + rsx::limits::vertex_textures_count;
|
||||
//We use texture buffers for vertex attributes. Bind these here as well
|
||||
//as they are guaranteed to be fixed (1 to 1 mapping)
|
||||
std::array<const char*, 16> s_reg_table =
|
||||
{
|
||||
"in_pos_buffer", "in_weight_buffer", "in_normal_buffer",
|
||||
"in_diff_color_buffer", "in_spec_color_buffer",
|
||||
"in_fog_buffer",
|
||||
"in_point_size_buffer", "in_7_buffer",
|
||||
"in_tc0_buffer", "in_tc1_buffer", "in_tc2_buffer", "in_tc3_buffer",
|
||||
"in_tc4_buffer", "in_tc5_buffer", "in_tc6_buffer", "in_tc7_buffer"
|
||||
};
|
||||
|
||||
//Bind locations 0 and 1 to the stream buffers
|
||||
result.uniforms[0] = stream_buffer_start;
|
||||
result.uniforms[1] = stream_buffer_start + 1;
|
||||
for (int i = 0; i < rsx::limits::vertex_count; ++i)
|
||||
{
|
||||
int location;
|
||||
if (result.uniforms.has_location(s_reg_table[i], &location))
|
||||
result.uniforms[location] = (i + rsx::limits::fragment_textures_count + rsx::limits::vertex_textures_count);
|
||||
}
|
||||
|
||||
LOG_NOTICE(RSX, "*** prog id = %d", result.id());
|
||||
LOG_NOTICE(RSX, "*** vp id = %d", vertexProgramData.id);
|
||||
@@ -73,32 +86,4 @@ struct GLTraits
|
||||
|
||||
class GLProgramBuffer : public program_state_cache<GLTraits>
|
||||
{
|
||||
public:
|
||||
|
||||
u64 get_hash(void*&)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
u64 get_hash(RSXVertexProgram &prog)
|
||||
{
|
||||
return program_hash_util::vertex_program_hash()(prog);
|
||||
}
|
||||
|
||||
u64 get_hash(RSXFragmentProgram &prog)
|
||||
{
|
||||
return program_hash_util::fragment_program_hash()(prog);
|
||||
}
|
||||
|
||||
template <typename... Args>
|
||||
void add_pipeline_entry(RSXVertexProgram &vp, RSXFragmentProgram &fp, void* &props, Args&& ...args)
|
||||
{
|
||||
vp.skip_vertex_input_check = true;
|
||||
getGraphicPipelineState(vp, fp, props, std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
bool check_cache_missed() const
|
||||
{
|
||||
return m_cache_miss_flag;
|
||||
}
|
||||
};
|
||||
|
||||
@@ -161,7 +161,6 @@ void GLGSRender::init_buffers(bool skip_reading)
|
||||
synchronize_buffers();
|
||||
|
||||
m_rtts_dirty = false;
|
||||
zcull_surface_active = false;
|
||||
|
||||
const u16 clip_horizontal = rsx::method_registers.surface_clip_width();
|
||||
const u16 clip_vertical = rsx::method_registers.surface_clip_height();
|
||||
@@ -246,8 +245,6 @@ void GLGSRender::init_buffers(bool skip_reading)
|
||||
framebuffer_status_valid = draw_fbo.check();
|
||||
if (!framebuffer_status_valid) return;
|
||||
|
||||
check_zcull_status(true, false);
|
||||
|
||||
draw_fbo.bind();
|
||||
set_viewport();
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user