Merge RPCS3 upstream, and revert tonight's frame-generation work

Catches up 98 commits from RPCS3/rpcs3. Seven files conflicted:

PPUTranslator.cpp -- upstream fixed the ARM64 float-to-int saturation
inversion independently, and the two fixes are the same fix. Took upstream's
ordering so it stops re-conflicting, kept one line of the reasoning.

rpcn_types.h, rpcn_client.cpp -- our hand-rolled protocol 31 bump was a
stopgap to stop the server refusing us. Upstream's trophy sync (cb175278b) is
the real implementation, so it replaces ours outright.

nv0039.cpp -- upstream refactored the strided copy and extracted
validate_buffer_notify; ours was the older code plus a profiler include. Took
upstream's, re-added the include.

VKQueryPool.cpp -- both sides had real changes. Upstream added a lock around
the pool cache; ours has the bounded occlusion-query wait and the render-pass
fix for the Adreno device loss. Kept ours, re-applied their lock.

VKResourceManager.cpp -- upstream moved GC completion onto a
driver_manager_thread, which supersedes our flush parameter and offloader
dispatch entirely. Took theirs; no callers passed the second argument.

VKGSRender.cpp -- our flush-site counter and their driver-manager drain are
independent. Both kept.

Upstream also began attaching 3D and array levels through DSA, which
EXT_direct_state_access has no NamedFramebufferTextureLayer for, so the GLES
shim gains one that binds and uses the non-DSA entry point.

Reverted in the same commit, because they are what is on the tester's device
and it is broken: the sync-fd handoff, the SUBOPTIMAL acquire fix, the
cross-device ownership barrier, the generated-frame acquire semaphore, and the
deferred-present guard in frame_context_cleanup. Each was defensible on its
own reading of the code and the result was worse every time -- slower, judder
described as nauseating, and rendering faults that outlast switching frame
generation off. Five attempts is enough to stop treating the next theory as
better than the last.

What stays fixed is everything outside the present path. What goes back is the
state before tonight: frame generation is slow and does not release its memory
when switched off.
This commit is contained in:
jpolo1224
2026-08-20 00:01:42 -04:00
137 changed files with 8985 additions and 6689 deletions
+2 -2
View File
@@ -37,7 +37,7 @@ if [ "$DEPLOY_APPIMAGE" = "true" ]; then
# Download translations
mkdir -p "./AppDir/usr/translations"
ZIP_URL=$(curl -fsSL "https://api.github.com/repos/RPCS3/rpcs3_translations/releases/latest" \
ZIP_URL=$(curl -fsSL --retry 3 --retry-delay 60 "https://api.github.com/repos/RPCS3/rpcs3_translations/releases/latest" \
| grep "browser_download_url" \
| grep "RPCS3-languages.zip" \
| cut -d '"' -f 4)
@@ -45,7 +45,7 @@ if [ "$DEPLOY_APPIMAGE" = "true" ]; then
echo "Failed to find RPCS3-languages.zip in the latest release. Continuing without translations."
else
echo "Downloading translations from: $ZIP_URL"
curl -L -o translations.zip "$ZIP_URL" || {
curl -fsSL --retry 3 --retry-delay 60 -o translations.zip "$ZIP_URL" || {
echo "Failed to download translations.zip. Continuing without translations."
exit 0
}
+1 -1
View File
@@ -29,7 +29,7 @@ rm -rf "rpcs3.app/Contents/Frameworks/QtPdf.framework" \
mkdir -p "rpcs3.app/Contents/translations"
ZIP_URL="https://github.com/RPCS3/rpcs3_translations/releases/latest/download/RPCS3-languages.zip"
echo "Downloading translations from: $ZIP_URL"
if curl -fsSL "$ZIP_URL" -o "translations.zip"; then
if curl -fsSL --retry 3 --retry-delay 60 "$ZIP_URL" -o "translations.zip"; then
echo "Successfully downloaded translations."
if unzip -o translations.zip -d "rpcs3.app/Contents/translations" >/dev/null 2>&1; then
rm -f translations.zip
+2 -2
View File
@@ -28,7 +28,7 @@ curl -fsSL 'https://api.rpcs3.net/config/?api=v1' | iconv -f ISO-8859-1 -t UTF-8
# Download translations
mkdir -p ./bin/share/qt6/translations
ZIP_URL=$(curl -fsSL "https://api.github.com/repos/RPCS3/rpcs3_translations/releases/latest" \
ZIP_URL=$(curl -fsSL --retry 3 --retry-delay 60 "https://api.github.com/repos/RPCS3/rpcs3_translations/releases/latest" \
| grep "browser_download_url" \
| grep "RPCS3-languages.zip" \
| cut -d '"' -f 4)
@@ -36,7 +36,7 @@ if [ -z "$ZIP_URL" ]; then
echo "Failed to find RPCS3-languages.zip in the latest release. Continuing without translations."
else
echo "Downloading translations from: $ZIP_URL"
curl -L -o translations.zip "$ZIP_URL" || {
curl -fsSL --retry 3 --retry-delay 60 -o translations.zip "$ZIP_URL" || {
echo "Failed to download translations.zip. Continuing without translations."
exit 0
}
+2 -2
View File
@@ -18,7 +18,7 @@ curl -fsSL 'https://api.rpcs3.net/config/?api=v1' | iconv -t UTF-8 1> ./bin/GuiC
# Download translations
mkdir -p ./bin/qt6/translations
ZIP_URL=$(curl -fsSL "https://api.github.com/repos/RPCS3/rpcs3_translations/releases/latest" \
ZIP_URL=$(curl -fsSL --retry 3 --retry-delay 60 "https://api.github.com/repos/RPCS3/rpcs3_translations/releases/latest" \
| grep "browser_download_url" \
| grep "RPCS3-languages.zip" \
| cut -d '"' -f 4)
@@ -26,7 +26,7 @@ if [ -z "$ZIP_URL" ]; then
echo "Failed to find RPCS3-languages.zip in the latest release. Continuing without translations."
else
echo "Downloading translations from: $ZIP_URL"
curl -L -o translations.zip "$ZIP_URL" || {
curl -fsSL --retry 3 --retry-delay 60 -o translations.zip "$ZIP_URL" || {
echo "Failed to download translations.zip. Continuing without translations."
exit 0
}
+4 -4
View File
@@ -30,23 +30,23 @@ jobs:
matrix:
include:
- os: ubuntu-24.04
docker_img: "rpcs3/rpcs3-ci-jammy:2.0"
docker_img: "rpcs3/rpcs3-ci-jammy:2.1"
build_sh: "/rpcs3/.ci/build-linux.sh"
compiler: clang
UPLOAD_COMMIT_HASH: d812f1254a1157c80fd402f94446310560f54e5f
UPLOAD_REPO_FULL_NAME: "rpcs3/rpcs3-binaries-linux"
- os: ubuntu-24.04
docker_img: "rpcs3/rpcs3-ci-jammy:2.0"
docker_img: "rpcs3/rpcs3-ci-jammy:2.1"
build_sh: "/rpcs3/.ci/build-linux.sh"
compiler: gcc
- os: ubuntu-24.04-arm
docker_img: "rpcs3/rpcs3-ci-jammy-aarch64:2.0"
docker_img: "rpcs3/rpcs3-ci-jammy-aarch64:2.1"
build_sh: "/rpcs3/.ci/build-linux-aarch64.sh"
compiler: clang
UPLOAD_COMMIT_HASH: a1d35836e8d45bfc6f63c26f0a3e5d46ef622fe1
UPLOAD_REPO_FULL_NAME: "rpcs3/rpcs3-binaries-linux-arm64"
- os: ubuntu-24.04-arm
docker_img: "rpcs3/rpcs3-ci-jammy-aarch64:2.0"
docker_img: "rpcs3/rpcs3-ci-jammy-aarch64:2.1"
build_sh: "/rpcs3/.ci/build-linux-aarch64.sh"
compiler: gcc
name: RPCS3 Linux ${{ matrix.os }} ${{ matrix.compiler }}
-1
View File
@@ -19,7 +19,6 @@
armsx3_lsfg_initialize;
armsx3_lsfg_create_context_ahb;
armsx3_lsfg_present;
armsx3_lsfg_present_fenced;
armsx3_lsfg_destroy_context;
armsx3_lsfg_wait_idle;
armsx3_lsfg_finalize;
+2 -22
View File
@@ -184,22 +184,6 @@ extern "C" int32_t armsx3_lsfg_create_context_ahb(void* in0, void* in1, void* co
extern "C" int armsx3_lsfg_present(int32_t ctx, int in_sem, const int* out_sems, uint32_t out_count)
{
// Forwarded rather than duplicated. Asking for no fence descriptor is exactly what this
// always did, and keeping one body means the two entry points cannot drift.
return armsx3_lsfg_present_fenced(ctx, in_sem, out_sems, out_count, nullptr);
}
extern "C" int armsx3_lsfg_present_fenced(int32_t ctx, int in_sem, const int* out_sems,
uint32_t out_count, int* out_fence_fd)
{
if (out_fence_fd)
{
// Written before anything that can fail. Every path out of here leaves the caller with a
// value it can act on, so it can never read an uninitialised int and close a descriptor
// belonging to something else -- which on Android is somebody's socket or an open asset.
*out_fence_fd = -1;
}
if (!g_initialized)
{
set_error("not initialized");
@@ -214,17 +198,13 @@ extern "C" int armsx3_lsfg_present_fenced(int32_t ctx, int in_sem, const int* ou
outs.push_back(out_sems ? out_sems[i] : -1);
}
// framegen writes the descriptor itself and leaves it at -1 when it cannot produce one, so a
// null out_fence_fd degrades to the plain present without a second code path here.
if (g_performance)
{
ARMSX3_LSFG_GUARD(LSFG_3_1P::presentContextFenced(ctx, in_sem, outs, out_fence_fd),
ARMSX3_LSFG_ERR_VULKAN)
ARMSX3_LSFG_GUARD(LSFG_3_1P::presentContext(ctx, in_sem, outs), ARMSX3_LSFG_ERR_VULKAN)
}
else
{
ARMSX3_LSFG_GUARD(LSFG_3_1::presentContextFenced(ctx, in_sem, outs, out_fence_fd),
ARMSX3_LSFG_ERR_VULKAN)
ARMSX3_LSFG_GUARD(LSFG_3_1::presentContext(ctx, in_sem, outs), ARMSX3_LSFG_ERR_VULKAN)
}
return ARMSX3_LSFG_OK;
+1 -24
View File
@@ -29,7 +29,7 @@ extern "C" {
// Bump when anything below changes shape. The loader refuses a library whose version it does not
// recognise, so a stale libarmsx3_lsfg.so on a user's device fails loudly at load instead of
// quietly passing mismatched structs.
#define ARMSX3_LSFG_ABI_VERSION 3u
#define ARMSX3_LSFG_ABI_VERSION 2u
// Mark the exported surface explicitly.
//
@@ -103,29 +103,6 @@ ARMSX3_LSFG_API int32_t armsx3_lsfg_create_context_ahb(void* in0, void* in1, voi
// each out_sems[i] is signalled when output image i is ready. Pass -1 for an unused slot.
ARMSX3_LSFG_API int armsx3_lsfg_present(int32_t ctx, int in_sem, const int* out_sems, uint32_t out_count);
// Generate frames for one presented pair, and hand back a fence for the result.
//
// Identical to armsx3_lsfg_present in every respect except that *out_fence_fd receives a sync file
// descriptor that becomes readable once the generation this call submitted has finished. The
// caller owns that fd and must close(2) it.
//
// This is the answer to armsx3_lsfg_wait_idle() below being the only completion signal on offer.
// framegen renders on its OWN VkDevice, so the caller cannot wait on its queues; before this
// entry point existed the only way to know the generated images were ready -- and, more
// importantly, that framegen had finished READING the caller's input images -- was a
// vkDeviceWaitIdle on framegen's device, once per presented frame. A sync fd can be waited on
// with poll(2) instead, which parks a thread rather than draining a GPU.
//
// *out_fence_fd is set to -1 whenever a descriptor is not available: an older library, a driver
// without VK_KHR_external_fence_fd, or work that had already completed by the time it was asked
// for. -1 is not an error and the return code is still ARMSX3_LSFG_OK -- the caller must fall
// back to armsx3_lsfg_wait_idle(), which is always correct.
//
// Added in ABI 3. Resolve it with dlsym rather than assuming it: this is the one entry point a
// caller can do without.
ARMSX3_LSFG_API int armsx3_lsfg_present_fenced(int32_t ctx, int in_sem, const int* out_sems,
uint32_t out_count, int* out_fence_fd);
ARMSX3_LSFG_API int armsx3_lsfg_destroy_context(int32_t ctx);
// Read the user's own Lossless.dll and keep the shaders it contains.
+57 -3
View File
@@ -724,15 +724,24 @@ struct coord3_base
struct { T width, height, depth; };
};
constexpr coord3_base() : position{}, size{}
constexpr coord3_base()
: position{}, size{}
{
}
constexpr coord3_base(const position3_base<T>& position, const size3_base<T>& size) : position{ position }, size{ size }
constexpr coord3_base(const position3_base<T>& position, const size3_base<T>& size)
: position{ position }, size{ size }
{
}
constexpr coord3_base(T x, T y, T z, T width, T height, T depth) : x{ x }, y{ y }, z{ z }, width{ width }, height{ height }, depth{ depth }
constexpr coord3_base(T x, T y, T z, T width, T height, T depth)
: x{ x }, y{ y }, z{ z }, width{ width }, height{ height }, depth{ depth }
{
}
constexpr coord3_base(const area_base<T>& area, T z = 0, T depth = 1)
: x{ area.x1 }, y{ area.y1 }, z{ z }
, width{ area.x2 - area.x1 }, height{ area.y2 - area.y1 }, depth{ depth }
{
}
@@ -755,6 +764,51 @@ struct coord3_base
{
return{ static_cast<NT>(x), static_cast<NT>(y), static_cast<NT>(z), static_cast<NT>(width), static_cast<NT>(height), static_cast<NT>(depth) };
}
void flip_horizontal()
requires std::is_signed_v<T>
{
auto x2 = x + width;
x = x2;
width = -width;
}
void flip_vertical()
requires std::is_signed_v<T>
{
auto y2 = y + height;
y = y2;
height = -height;
}
bool is_flipped() const
requires std::is_signed_v<T>
{
return width < 0 || height < 0 || depth < 0;
}
area_base<T> to_area() const
{
return { x, y, x + width, y + height };
}
T abs_width() const
requires std::is_signed_v<T>
{
return width < 0 ? -width : width;
}
T abs_height() const
requires std::is_signed_v<T>
{
return height < 0 ? -height : height;
}
T abs_depth() const
requires std::is_signed_v<T>
{
return depth < 0 ? -depth : depth;
}
};
+150 -142
View File
File diff suppressed because it is too large Load Diff
+1 -1
View File
@@ -54,7 +54,7 @@ struct NPD_HEADER
struct EDAT_HEADER
{
s32 flags;
s32 block_size;
u32 block_size;
u64 file_size;
};
+60 -31
View File
@@ -2,6 +2,7 @@
#include "aes.h"
#include "sha1.h"
#include "key_vault.h"
#include "util/asm.hpp"
#include "util/logs.hpp"
#include "Utilities/StrUtil.h"
#include "Utilities/Thread.h"
@@ -190,7 +191,8 @@ bool package_reader::read_header()
m_file = fs::make_gather(std::move(filelist));
}
if (m_header.data_size + m_header.data_offset > m_header.pkg_size)
if ((m_header.data_size + m_header.data_offset) > m_header.pkg_size ||
m_header.data_size > (u64{umax} - m_header.data_offset)) // Check for overflow
{
pkg_log.error("PKG data size mismatch (data_size=0x%llx, data_offset=0x%llx, file_size=0x%llx)", m_header.data_size, m_header.data_offset, m_header.pkg_size);
return false;
@@ -203,7 +205,7 @@ bool package_reader::read_metadata()
{
// Read title ID and use it as an installation directory
m_install_dir.resize(9);
archive_read_block(55, &m_install_dir.front(), m_install_dir.size());
archive_read_block(55, {reinterpret_cast<u8*>(m_install_dir.data()), m_install_dir.size()}, m_install_dir.size());
// Read package metadata
@@ -548,7 +550,7 @@ bool package_reader::read_entries(std::vector<PKGEntry>& entries)
entries.clear();
entries.resize(m_header.file_count + BUF_PADDING / sizeof(PKGEntry) + 1);
const usz read_size = decrypt(0, m_header.file_count * sizeof(PKGEntry), m_header.pkg_platform == PKG_PLATFORM_TYPE_PSP_PSVITA ? PKG_AES_KEY2 : m_dec_key.data(), entries.data());
const usz read_size = decrypt(0, m_header.file_count * sizeof(PKGEntry), m_header.pkg_platform == PKG_PLATFORM_TYPE_PSP_PSVITA ? PKG_AES_KEY2 : m_dec_key.data(), std::span<u8>{reinterpret_cast<u8*>(entries.data()), entries.size() * sizeof(PKGEntry)});
if (read_size < m_header.file_count * sizeof(PKGEntry))
{
@@ -620,7 +622,7 @@ bool package_reader::read_param_sfo()
std::string name_buf(entry.name_size + BUF_PADDING, '\0');
if (usz read_size = decrypt(entry.name_offset, entry.name_size, is_psp ? PKG_AES_KEY2 : m_dec_key.data(), name_buf.data()); read_size < entry.name_size)
if (usz read_size = decrypt(entry.name_offset, entry.name_size, is_psp ? PKG_AES_KEY2 : m_dec_key.data(), std::span<u8>{reinterpret_cast<u8*>(name_buf.data()), name_buf.size()}); read_size < entry.name_size)
{
pkg_log.error("PKG name could not be read (size=0x%x, offset=0x%x)", entry.name_size, entry.name_offset);
continue;
@@ -643,7 +645,7 @@ bool package_reader::read_param_sfo()
data_buf.resize(block_size + BUF_PADDING);
if (decrypt(entry.file_offset + pos, block_size, is_psp ? PKG_AES_KEY2 : m_dec_key.data(), data_buf.data()) != block_size)
if (decrypt(entry.file_offset + pos, block_size, is_psp ? PKG_AES_KEY2 : m_dec_key.data(), data_buf) != block_size)
{
pkg_log.error("Failed to decrypt PARAM.SFO file");
return false;
@@ -956,7 +958,7 @@ bool package_reader::fill_data(std::map<std::string, install_entry*>& all_instal
const bool is_psp = (entry.type & PKG_FILE_ENTRY_PSP) != 0u;
if (const usz read_size = decrypt(entry.name_offset, entry.name_size, is_psp ? PKG_AES_KEY2 : m_dec_key.data(), name_buf.data()); read_size < entry.name_size)
if (const usz read_size = decrypt(entry.name_offset, entry.name_size, is_psp ? PKG_AES_KEY2 : m_dec_key.data(), std::span<u8>{reinterpret_cast<u8*>(name_buf.data()), name_buf.size()}); read_size < entry.name_size)
{
num_failures++;
pkg_log.error("PKG name could not be read (size=0x%x, offset=0x%x)", entry.name_size, entry.name_offset);
@@ -1135,7 +1137,7 @@ void package_reader::extract_worker()
const install_entry& m_entry;
usz m_pos;
explicit pkg_file_reader(std::function<u64(u64, void* buffer, u64)> read_func, const install_entry& entry) noexcept
explicit pkg_file_reader(std::function<u64(u64, void*, u64)> read_func, const install_entry& entry) noexcept
: m_read_func(std::move(read_func))
, m_entry(entry)
, m_pos(0)
@@ -1204,6 +1206,9 @@ void package_reader::extract_worker()
read_cache.clear();
// 16MB buffer
std::vector<u8> buffer(std::min<usz>(entry.file_size, 1u << 24) + BUF_PADDING);
auto reader = std::make_unique<pkg_file_reader>([&, cache_off = u64{umax}](usz pos, void* ptr, usz size) mutable -> u64
{
if (pos >= entry.file_size || !size)
@@ -1211,6 +1216,7 @@ void package_reader::extract_worker()
return 0;
}
const usz original_size = size;
size = std::min<u64>(entry.file_size - pos, size);
u64 size_cache_end = 0;
@@ -1245,7 +1251,7 @@ void package_reader::extract_worker()
read_cache.resize(block_size + BUF_PADDING);
cache_off = pos;
const usz advance_size = decrypt(entry.file_offset + pos, block_size, is_psp ? PKG_AES_KEY2 : m_dec_key.data(), read_cache.data());
const usz advance_size = decrypt(entry.file_offset + pos, block_size, is_psp ? PKG_AES_KEY2 : m_dec_key.data(), read_cache);
if (!advance_size)
{
@@ -1263,8 +1269,13 @@ void package_reader::extract_worker()
while (read_size < size)
{
const u64 block_size = std::min<u64>(BUF_SIZE, size - read_size);
const u64 available_buffer_size = buffer.size() - read_size;
const usz advance_size = decrypt(entry.file_offset + pos, block_size, is_psp ? PKG_AES_KEY2 : m_dec_key.data(), static_cast<u8*>(ptr) + read_size);
ensure(buffer.data() == ptr);
ensure(buffer.size() == original_size + BUF_PADDING);
ensure(available_buffer_size >= block_size);
const usz advance_size = decrypt(entry.file_offset + pos, block_size, is_psp ? PKG_AES_KEY2 : m_dec_key.data(), std::span<u8>{static_cast<u8*>(ptr) + read_size, available_buffer_size});
if (!advance_size)
{
@@ -1299,9 +1310,6 @@ void package_reader::extract_worker()
break;
}
// 16MB buffer
std::vector<u8> buffer(std::min<usz>(entry.file_size, 1u << 24) + BUF_PADDING);
while (usz read_size = final_data.read(buffer.data(), buffer.size() - BUF_PADDING))
{
// Check what actually landed.
@@ -1498,14 +1506,16 @@ u64 package_reader::archive_read(void* data_ptr, const u64 num_bytes)
return m_file ? m_file.read(data_ptr, num_bytes) : 0;
}
std::span<const char> package_reader::archive_read_block(u64 offset, void* data_ptr, u64 num_bytes)
std::span<const char> package_reader::archive_read_block(u64 offset, std::span<u8> dst, u64 num_bytes)
{
const usz read_n = m_file.read_at(offset, data_ptr, num_bytes);
ensure(dst.size() >= num_bytes);
return {static_cast<const char*>(data_ptr), read_n};
const usz read_n = m_file.read_at(offset, dst.data(), num_bytes);
return {reinterpret_cast<const char*>(dst.data()), read_n};
}
usz package_reader::decrypt(u64 offset, u64 size, const uchar* key, void* local_buf)
usz package_reader::decrypt(u64 offset, u64 size, const uchar* key, std::span<u8> local_buf)
{
if (!m_is_valid)
{
@@ -1517,15 +1527,26 @@ usz package_reader::decrypt(u64 offset, u64 size, const uchar* key, void* local_
return 0;
}
ensure(local_buf.size() >= size);
// Read the data and set available size
const auto data_span = archive_read_block(m_header.data_offset + offset, local_buf, size);
ensure(data_span.data() == static_cast<void*>(local_buf));
ensure(data_span.data() == static_cast<void*>(local_buf.data()));
ensure(data_span.size() <= size);
// Get block count
const u64 blocks = (data_span.size() + 15) / 16;
const auto out_data = reinterpret_cast<u8*>(local_buf);
// Clear padding
if (data_span.size() < local_buf.size())
{
std::memset(&local_buf[data_span.size()], 0, local_buf.size() - data_span.size());
}
if (m_header.pkg_type == PKG_RELEASE_TYPE_DEBUG)
// Get block count. Round up.
const u64 blocks = utils::aligned_div<u64>(data_span.size(), sizeof(u128));
const u64 read_size = blocks * sizeof(u128);
switch (m_header.pkg_type)
{
case PKG_RELEASE_TYPE_DEBUG:
{
// Debug key
be_t<u64> input[8] =
@@ -1539,7 +1560,7 @@ usz package_reader::decrypt(u64 offset, u64 size, const uchar* key, void* local_
for (u64 i = 0; i < blocks; i++)
{
// Initialize stream cipher for current position
input[7] = offset / 16 + i;
input[7] = offset / sizeof(u128) + i;
struct sha1_hash
{
@@ -1548,11 +1569,13 @@ usz package_reader::decrypt(u64 offset, u64 size, const uchar* key, void* local_
sha1(reinterpret_cast<const u8*>(input), sizeof(input), hash.data);
const u128 v = read_from_ptr_unsafe<u128>(out_data, i * 16);
write_to_ptr_unsafe<u128>(out_data, i * 16, v ^ read_from_ptr<u128>(hash.data));
const u128 v = read_from_ptr<u128>(local_buf, i * sizeof(u128));
write_to_ptr<u128>(local_buf, i * sizeof(u128), v ^ read_from_ptr<u128>(hash.data));
}
break;
}
else if (m_header.pkg_type == PKG_RELEASE_TYPE_RELEASE)
case PKG_RELEASE_TYPE_RELEASE:
{
aes_context ctx;
@@ -1560,7 +1583,7 @@ usz package_reader::decrypt(u64 offset, u64 size, const uchar* key, void* local_
aes_setkey_enc(&ctx, key, 128);
// Initialize stream cipher for start position
be_t<u128> input = m_header.klicensee.value() + offset / 16;
be_t<u128> input = m_header.klicensee.value() + offset / sizeof(u128);
// Increment stream position for every block
for (u64 i = 0; i < blocks; i++, input++)
@@ -1569,19 +1592,25 @@ usz package_reader::decrypt(u64 offset, u64 size, const uchar* key, void* local_
aes_crypt_ecb(&ctx, AES_ENCRYPT, reinterpret_cast<const u8*>(&input), reinterpret_cast<u8*>(&key));
const u128 v = read_from_ptr_unsafe<u128>(out_data, i * 16);
write_to_ptr_unsafe<u128>(out_data, i * 16, v ^ key);
const u128 v = read_from_ptr<u128>(local_buf, i * sizeof(u128));
write_to_ptr<u128>(local_buf, i * sizeof(u128), v ^ key);
}
break;
}
else
default:
{
pkg_log.error("Unknown release type (0x%x)", m_header.pkg_type);
break;
}
}
if (blocks * 16 != size)
if (read_size > size)
{
// Put NTS and other zeroes on unaligned reads
std::memset(out_data + size, 0, blocks * 16 - size);
const u64 pad_size = read_size - size;
ensure(local_buf.size() >= (size + pad_size));
std::memset(&local_buf[size], 0, pad_size);
}
// Return the amount of data written in buf
+2 -2
View File
@@ -401,8 +401,8 @@ private:
u64 archive_read(void* data_ptr, u64 num_bytes);
bool set_install_path();
bool fill_data(std::map<std::string, install_entry*>& all_install_entries);
std::span<const char> archive_read_block(u64 offset, void* data_ptr, u64 num_bytes);
usz decrypt(u64 offset, u64 size, const uchar* key, void* local_buf);
std::span<const char> archive_read_block(u64 offset, std::span<u8> dst, u64 num_bytes);
usz decrypt(u64 offset, u64 size, const uchar* key, std::span<u8> local_buf);
void extract_worker();
std::deque<install_entry> m_install_entries;
+95 -75
View File
@@ -90,7 +90,7 @@ inline void Write64(const fs::file& f, const be_t<u64> data)
f.write(&data, sizeof(data));
}
void WriteEhdr(const fs::file& f, Elf64_Ehdr& ehdr)
void WriteEhdr(const fs::file& f, const Elf64_Ehdr& ehdr)
{
Write32(f, ehdr.e_magic);
Write8(f, ehdr.e_class);
@@ -113,7 +113,7 @@ void WriteEhdr(const fs::file& f, Elf64_Ehdr& ehdr)
Write16(f, ehdr.e_shstrndx);
}
void WritePhdr(const fs::file& f, Elf64_Phdr& phdr)
void WritePhdr(const fs::file& f, const Elf64_Phdr& phdr)
{
Write32(f, phdr.p_type);
Write32(f, phdr.p_flags);
@@ -125,7 +125,7 @@ void WritePhdr(const fs::file& f, Elf64_Phdr& phdr)
Write64(f, phdr.p_align);
}
void WriteShdr(const fs::file& f, Elf64_Shdr& shdr)
void WriteShdr(const fs::file& f, const Elf64_Shdr& shdr)
{
Write32(f, shdr.sh_name);
Write32(f, shdr.sh_type);
@@ -139,7 +139,7 @@ void WriteShdr(const fs::file& f, Elf64_Shdr& shdr)
Write64(f, shdr.sh_entsize);
}
void WriteEhdr(const fs::file& f, Elf32_Ehdr& ehdr)
void WriteEhdr(const fs::file& f, const Elf32_Ehdr& ehdr)
{
Write32(f, ehdr.e_magic);
Write8(f, ehdr.e_class);
@@ -162,7 +162,7 @@ void WriteEhdr(const fs::file& f, Elf32_Ehdr& ehdr)
Write16(f, ehdr.e_shstrndx);
}
void WritePhdr(const fs::file& f, Elf32_Phdr& phdr)
void WritePhdr(const fs::file& f, const Elf32_Phdr& phdr)
{
Write32(f, phdr.p_type);
Write32(f, phdr.p_offset);
@@ -174,7 +174,7 @@ void WritePhdr(const fs::file& f, Elf32_Phdr& phdr)
Write32(f, phdr.p_align);
}
void WriteShdr(const fs::file& f, Elf32_Shdr& shdr)
void WriteShdr(const fs::file& f, const Elf32_Shdr& shdr)
{
Write32(f, shdr.sh_name);
Write32(f, shdr.sh_type);
@@ -683,7 +683,7 @@ bool SCEDecrypter::LoadMetadata(const u8 erk[32], const u8 riv[16])
// Load the metadata section headers.
meta_shdr.clear();
for (unsigned int i = 0; i < meta_hdr.section_count; i++)
for (u32 i = 0; i < meta_hdr.section_count; i++)
{
const usz shdr_offset = sizeof(meta_hdr) + sizeof(MetadataSectionHeader) * i;
ensure(metadata_headers.size() > shdr_offset);
@@ -693,10 +693,11 @@ bool SCEDecrypter::LoadMetadata(const u8 erk[32], const u8 riv[16])
}
// Copy the decrypted data keys.
data_keys.resize(meta_hdr.key_count * 0x10);
data_keys.resize(static_cast<u64>(meta_hdr.key_count) * 0x10);
const usz data_keys_offset = sizeof(meta_hdr) + meta_hdr.section_count * sizeof(MetadataSectionHeader);
ensure(metadata_headers.size() >= (data_keys_offset + data_keys.size()));
ensure(data_keys.size() <= (usz{umax} - data_keys_offset)); // Check for overflow
std::memcpy(data_keys.data(), metadata_headers.data() + data_keys_offset, data_keys.size());
return true;
@@ -708,9 +709,9 @@ bool SCEDecrypter::DecryptData()
usz data_buf_length = 0;
// Calculate the total data size.
for (unsigned int i = 0; i < meta_hdr.section_count; i++)
for (const MetadataSectionHeader& hdr : meta_shdr)
{
data_buf_length += ::narrow<u32>(meta_shdr[i].data_size);
data_buf_length += ::narrow<u32>(hdr.data_size);
}
// Allocate a buffer to store decrypted data.
@@ -719,52 +720,55 @@ bool SCEDecrypter::DecryptData()
// Set initial offset.
u32 data_buf_offset = 0;
// Parse the metadata section headers to find the offsets of encrypted data.
for (unsigned int i = 0; i < meta_hdr.section_count; i++)
{
usz ctr_nc_off = 0;
u8 ctr_stream_block[0x10];
u8 data_key[0x10];
u8 data_iv[0x10];
// Tmp buffer
std::vector<u8> buf;
u8 ctr_stream_block[0x10];
// Parse the metadata section headers to find the offsets of encrypted data.
for (const MetadataSectionHeader& hdr : meta_shdr)
{
// Check if this is an encrypted section.
if (meta_shdr[i].encrypted == 3)
if (hdr.encrypted == 3)
{
// Make sure the key and iv are not out of boundaries.
if ((meta_shdr[i].key_idx <= meta_hdr.key_count - 1) && (meta_shdr[i].iv_idx <= meta_hdr.key_count))
if ((hdr.key_idx < meta_hdr.key_count) && (hdr.iv_idx <= meta_hdr.key_count))
{
// Get the key and iv from the previously stored key buffer.
std::memcpy(data_key, data_keys.data() + meta_shdr[i].key_idx * 0x10, 0x10);
std::memcpy(data_iv, data_keys.data() + meta_shdr[i].iv_idx * 0x10, 0x10);
// Allocate a buffer to hold the data.
auto buf = std::make_unique<u8[]>(meta_shdr[i].data_size);
const std::array<u8, 0x10> data_key = read_from_ptr<std::array<u8, 0x10>>(data_keys, static_cast<usz>(hdr.key_idx) * 0x10);
std::array<u8, 0x10> data_iv = read_from_ptr<std::array<u8, 0x10>>(data_keys, static_cast<usz>(hdr.iv_idx) * 0x10);
// Seek to the section data offset and read the encrypted data.
sce_f.seek(meta_shdr[i].data_offset);
sce_f.read(buf.get(), meta_shdr[i].data_size);
buf.resize(hdr.data_size);
sce_f.seek(hdr.data_offset);
sce_f.read(buf.data(), buf.size());
// Zero out our ctr nonce.
std::memset(ctr_stream_block, 0, sizeof(ctr_stream_block));
// Perform AES-CTR encryption on the data blocks.
aes_setkey_enc(&aes, data_key, 128);
aes_crypt_ctr(&aes, meta_shdr[i].data_size, &ctr_nc_off, data_iv, ctr_stream_block, buf.get(), buf.get());
usz ctr_nc_off = 0;
aes_setkey_enc(&aes, data_key.data(), 128);
aes_crypt_ctr(&aes, buf.size(), &ctr_nc_off, data_iv.data(), ctr_stream_block, buf.data(), buf.data());
// Copy the decrypted data.
std::memcpy(data_buf.data() + data_buf_offset, buf.get(), meta_shdr[i].data_size);
ensure(data_buf.size() >= (buf.size() + data_buf_offset));
ensure(buf.size() <= (usz{umax} - static_cast<usz>(data_buf_offset))); // Check for overflow
std::memcpy(data_buf.data() + data_buf_offset, buf.data(), buf.size());
}
}
else
{
auto buf = std::make_unique<u8[]>(meta_shdr[i].data_size);
sce_f.seek(meta_shdr[i].data_offset);
sce_f.read(buf.get(), meta_shdr[i].data_size);
std::memcpy(data_buf.data() + data_buf_offset, buf.get(), meta_shdr[i].data_size);
buf.resize(hdr.data_size);
sce_f.seek(hdr.data_offset);
sce_f.read(buf.data(), buf.size());
ensure(data_buf.size() >= (buf.size() + data_buf_offset));
ensure(buf.size() <= (usz{umax} - static_cast<usz>(data_buf_offset))); // Check for overflow
std::memcpy(data_buf.data() + data_buf_offset, buf.data(), buf.size());
}
// Advance the buffer's offset.
data_buf_offset += ::narrow<u32>(meta_shdr[i].data_size);
data_buf_offset += ::narrow<u32>(hdr.data_size);
}
return true;
@@ -779,9 +783,8 @@ std::vector<fs::file> SCEDecrypter::MakeFile()
u32 data_buf_offset = 0;
// Write data.
for (u32 i = 0; i < meta_hdr.section_count; i++)
for (const MetadataSectionHeader& hdr : meta_shdr)
{
const MetadataSectionHeader& hdr = meta_shdr[i];
const u8* src = data_buf.data() + data_buf_offset;
fs::file out_f = fs::make_stream<std::vector<u8>>();
@@ -860,13 +863,13 @@ bool SELFDecrypter::LoadHeaders(bool isElf32, SelfAdditionalInfo* out_info)
if (isElf32)
{
phdr32_arr.clear();
if(elf32_hdr.e_phoff == 0 && elf32_hdr.e_phnum)
if (elf32_hdr.e_phoff == 0 && elf32_hdr.e_phnum)
{
self_log.error("ELF program header offset is null!");
return false;
}
self_f.seek(m_ext_hdr.phdr_offset);
for(u32 i = 0; i < elf32_hdr.e_phnum; ++i)
for (u32 i = 0; i < elf32_hdr.e_phnum; ++i)
{
phdr32_arr.emplace_back();
phdr32_arr.back().Load(self_f);
@@ -895,7 +898,7 @@ bool SELFDecrypter::LoadHeaders(bool isElf32, SelfAdditionalInfo* out_info)
m_seg_ext_hdr.clear();
self_f.seek(m_ext_hdr.segment_ext_hdr_offset);
for(u32 i = 0; i < (isElf32 ? elf32_hdr.e_phnum : elf64_hdr.e_phnum); ++i)
for (u32 i = 0; i < (isElf32 ? elf32_hdr.e_phnum : elf64_hdr.e_phnum); ++i)
{
if (self_f.pos() >= self_size)
{
@@ -961,7 +964,7 @@ bool SELFDecrypter::LoadHeaders(bool isElf32, SelfAdditionalInfo* out_info)
self_f.seek(m_ext_hdr.shdr_offset);
for(u32 i = 0; i < elf32_hdr.e_shnum; ++i)
for (u32 i = 0; i < elf32_hdr.e_shnum; ++i)
{
shdr32_arr.emplace_back();
shdr32_arr.back().Load(self_f);
@@ -978,7 +981,7 @@ bool SELFDecrypter::LoadHeaders(bool isElf32, SelfAdditionalInfo* out_info)
self_f.seek(m_ext_hdr.shdr_offset);
for(u32 i = 0; i < elf64_hdr.e_shnum; ++i)
for (u32 i = 0; i < elf64_hdr.e_shnum; ++i)
{
shdr64_arr.emplace_back();
shdr64_arr.back().Load(self_f);
@@ -1013,13 +1016,21 @@ void SELFDecrypter::ShowHeaders(bool isElf32)
self_log.notice("----------------------------------------------------");
self_log.notice("ELF program headers");
self_log.notice("----------------------------------------------------");
for(unsigned int i = 0; i < ((isElf32) ? phdr32_arr.size() : phdr64_arr.size()); i++)
isElf32 ? phdr32_arr[i].Show() : phdr64_arr[i].Show();
if (isElf32)
{
for (const Elf32_Phdr& hdr : phdr32_arr)
hdr.Show();
}
else
{
for (const Elf64_Phdr& hdr : phdr64_arr)
hdr.Show();
}
self_log.notice("----------------------------------------------------");
self_log.notice("Section info");
self_log.notice("----------------------------------------------------");
for(unsigned int i = 0; i < m_seg_ext_hdr.size(); i++)
m_seg_ext_hdr[i].Show();
for (const segment_ext_header& hdr : m_seg_ext_hdr)
hdr.Show();
self_log.notice("----------------------------------------------------");
self_log.notice("SCE version info");
self_log.notice("----------------------------------------------------");
@@ -1027,13 +1038,21 @@ void SELFDecrypter::ShowHeaders(bool isElf32)
self_log.notice("----------------------------------------------------");
self_log.notice("Control info");
self_log.notice("----------------------------------------------------");
for(unsigned int i = 0; i < m_supplemental_hdr_arr.size(); i++)
m_supplemental_hdr_arr[i].Show();
for (const supplemental_header& hdr : m_supplemental_hdr_arr)
hdr.Show();
self_log.notice("----------------------------------------------------");
self_log.notice("ELF section headers");
self_log.notice("----------------------------------------------------");
for(unsigned int i = 0; i < ((isElf32) ? shdr32_arr.size() : shdr64_arr.size()); i++)
isElf32 ? shdr32_arr[i].Show() : shdr64_arr[i].Show();
if (isElf32)
{
for (const Elf32_Shdr& hdr : shdr32_arr)
hdr.Show();
}
else
{
for (const Elf64_Shdr& hdr : shdr64_arr)
hdr.Show();
}
self_log.notice("----------------------------------------------------");
}
@@ -1180,7 +1199,7 @@ bool SELFDecrypter::LoadMetadata(const u8* klic_key)
// Load the metadata section headers.
meta_shdr.clear();
for (unsigned int i = 0; i < meta_hdr.section_count; i++)
for (u32 i = 0; i < meta_hdr.section_count; i++)
{
const usz shdr_offset = sizeof(meta_hdr) + sizeof(MetadataSectionHeader) * i;
ensure(metadata_headers.size() > shdr_offset);
@@ -1190,10 +1209,11 @@ bool SELFDecrypter::LoadMetadata(const u8* klic_key)
}
// Copy the decrypted data keys.
data_keys.resize(meta_hdr.key_count * 0x10);
data_keys.resize(static_cast<u64>(meta_hdr.key_count) * 0x10);
const usz data_keys_offset = sizeof(meta_hdr) + meta_hdr.section_count * sizeof(MetadataSectionHeader);
ensure(metadata_headers.size() >= (data_keys_offset + data_keys.size()));
ensure(data_keys.size() <= (usz{umax} - data_keys_offset)); // Check for overflow
std::memcpy(data_keys.data(), metadata_headers.data() + data_keys_offset, data_keys.size());
return true;
@@ -1205,12 +1225,12 @@ bool SELFDecrypter::DecryptData()
usz data_buf_length = 0;
// Calculate the total data size.
for (unsigned int i = 0; i < meta_hdr.section_count; i++)
for (const MetadataSectionHeader& hdr : meta_shdr)
{
if (meta_shdr[i].encrypted == 3)
if (hdr.encrypted == 3)
{
if ((meta_shdr[i].key_idx <= meta_hdr.key_count - 1) && (meta_shdr[i].iv_idx <= meta_hdr.key_count))
data_buf_length += ::narrow<u32>(meta_shdr[i].data_size);
if ((hdr.key_idx < meta_hdr.key_count) && (hdr.iv_idx <= meta_hdr.key_count))
data_buf_length += ::narrow<u32>(hdr.data_size);
}
}
@@ -1220,43 +1240,43 @@ bool SELFDecrypter::DecryptData()
// Set initial offset.
u32 data_buf_offset = 0;
// Parse the metadata section headers to find the offsets of encrypted data.
for (unsigned int i = 0; i < meta_hdr.section_count; i++)
{
usz ctr_nc_off = 0;
u8 ctr_stream_block[0x10];
u8 data_key[0x10];
u8 data_iv[0x10];
// Tmp buffer
std::vector<u8> buf;
u8 ctr_stream_block[0x10];
// Parse the metadata section headers to find the offsets of encrypted data.
for (const MetadataSectionHeader& hdr : meta_shdr)
{
// Check if this is an encrypted section.
if (meta_shdr[i].encrypted == 3)
if (hdr.encrypted == 3)
{
// Make sure the key and iv are not out of boundaries.
if((meta_shdr[i].key_idx <= meta_hdr.key_count - 1) && (meta_shdr[i].iv_idx <= meta_hdr.key_count))
if ((hdr.key_idx < meta_hdr.key_count) && (hdr.iv_idx <= meta_hdr.key_count))
{
// Get the key and iv from the previously stored key buffer.
std::memcpy(data_key, data_keys.data() + meta_shdr[i].key_idx * 0x10, 0x10);
std::memcpy(data_iv, data_keys.data() + meta_shdr[i].iv_idx * 0x10, 0x10);
// Allocate a buffer to hold the data.
auto buf = std::make_unique<u8[]>(meta_shdr[i].data_size);
const std::array<u8, 0x10> data_key = read_from_ptr<std::array<u8, 0x10>>(data_keys, static_cast<usz>(hdr.key_idx) * 0x10);
std::array<u8, 0x10> data_iv = read_from_ptr<std::array<u8, 0x10>>(data_keys, static_cast<usz>(hdr.iv_idx) * 0x10);
// Seek to the section data offset and read the encrypted data.
self_f.seek(meta_shdr[i].data_offset);
self_f.read(buf.get(), meta_shdr[i].data_size);
buf.resize(hdr.data_size);
self_f.seek(hdr.data_offset);
self_f.read(buf.data(), buf.size());
// Zero out our ctr nonce.
std::memset(ctr_stream_block, 0, sizeof(ctr_stream_block));
// Perform AES-CTR encryption on the data blocks.
aes_setkey_enc(&aes, data_key, 128);
aes_crypt_ctr(&aes, meta_shdr[i].data_size, &ctr_nc_off, data_iv, ctr_stream_block, buf.get(), buf.get());
usz ctr_nc_off = 0;
aes_setkey_enc(&aes, data_key.data(), 128);
aes_crypt_ctr(&aes, buf.size(), &ctr_nc_off, data_iv.data(), ctr_stream_block, buf.data(), buf.data());
// Copy the decrypted data.
std::memcpy(data_buf.data() + data_buf_offset, buf.get(), meta_shdr[i].data_size);
ensure(data_buf.size() >= (buf.size() + data_buf_offset));
ensure(buf.size() <= (usz{umax} - static_cast<usz>(data_buf_offset))); // Check for overflow
std::memcpy(data_buf.data() + data_buf_offset, buf.data(), buf.size());
// Advance the buffer's offset.
data_buf_offset += ::narrow<u32>(meta_shdr[i].data_size);
data_buf_offset += ::narrow<u32>(hdr.data_size);
}
}
}
+37 -23
View File
@@ -482,7 +482,7 @@ public:
private:
template<typename EHdr, typename SHdr, typename PHdr>
void WriteElf(fs::file& e, EHdr ehdr, SHdr shdr, PHdr phdr)
void WriteElf(fs::file& e, EHdr ehdr, const std::vector<SHdr>& shdrs, const std::vector<PHdr>& phdrs)
{
// Set initial offset.
u32 data_buf_offset = 0;
@@ -491,32 +491,35 @@ private:
WriteEhdr(e, ehdr);
// Write program headers.
for (u32 i = 0; i < ehdr.e_phnum; ++i)
for (const PHdr& phdr : phdrs)
{
WritePhdr(e, phdr[i]);
WritePhdr(e, phdr);
}
for (unsigned int i = 0; i < meta_hdr.section_count; i++)
// Tmp buffer
std::vector<u8> decomp_buf;
for (const MetadataSectionHeader& hdr : meta_shdr)
{
// PHDR type.
if (meta_shdr[i].type == 2)
if (hdr.type == 2)
{
// Decompress if necessary.
if (meta_shdr[i].compressed == 2)
{
const auto filesz = phdr[meta_shdr[i].program_idx].p_filesz;
const PHdr& phdr = ::at32(phdrs, hdr.program_idx);
// Create a pointer to a buffer for decompression.
std::unique_ptr<u8[]> decomp_buf(new u8[filesz]);
// Decompress if necessary.
if (hdr.compressed == 2)
{
const auto filesz = phdr.p_filesz;
decomp_buf.resize(filesz);
// Create a buffer separate from data_buf to uncompress.
std::vector<u8> zlib_buf = data_buf;
uLongf decomp_buf_length = ::narrow<uLongf>(filesz);
ensure(data_buf.size() > data_buf_offset);
const std::vector<u8> zlib_buf(data_buf.cbegin() + data_buf_offset, data_buf.cend());
// Use zlib uncompress on the new buffer.
// decomp_buf_length changes inside the call to uncompress
const int rv = uncompress(decomp_buf.get(), &decomp_buf_length, zlib_buf.data() + data_buf_offset, ::size32(zlib_buf));
uLongf decomp_buf_length = ::narrow<uLongf>(filesz);
const int rv = uncompress(decomp_buf.data(), &decomp_buf_length, zlib_buf.data(), ::size32(zlib_buf));
// Check for errors (TODO: Probably safe to remove this once these changes have passed testing.)
switch (rv)
@@ -527,19 +530,30 @@ private:
default: break;
}
ensure(decomp_buf_length <= decomp_buf.size());
// Warn if the final data is smaller than expected
if (decomp_buf_length < decomp_buf.size())
{
self_log.warning("zlib uncompress returned a buffer of less size than expected (size=%d, expected=%d)", decomp_buf_length, decomp_buf.size());
}
// Seek to the program header data offset and write the data.
e.seek(phdr[meta_shdr[i].program_idx].p_offset);
e.write(decomp_buf.get(), filesz);
e.seek(phdr.p_offset);
e.write(decomp_buf.data(), decomp_buf_length);
}
else
{
// Seek to the program header data offset and write the data.
e.seek(phdr[meta_shdr[i].program_idx].p_offset);
e.write(data_buf.data() + data_buf_offset, meta_shdr[i].data_size);
ensure(data_buf.size() >= (hdr.data_size + data_buf_offset));
ensure(hdr.data_size <= (u64{umax} - static_cast<u64>(data_buf_offset))); // Check for overflow
e.seek(phdr.p_offset);
e.write(data_buf.data() + data_buf_offset, hdr.data_size);
}
// Advance the data buffer offset by data size.
data_buf_offset += ::narrow<u32>(meta_shdr[i].data_size);
data_buf_offset += ::narrow<u32>(hdr.data_size);
}
}
@@ -548,9 +562,9 @@ private:
{
e.seek(ehdr.e_shoff);
for (u32 i = 0; i < ehdr.e_shnum; ++i)
for (const SHdr& shdr : shdrs)
{
WriteShdr(e, shdr[i]);
WriteShdr(e, shdr);
}
}
}
+70 -2
View File
@@ -8,6 +8,10 @@
#include "Utilities/JIT.h"
#include "util/v128.hpp"
#ifdef ARCH_X64
#include <immintrin.h>
#endif
#ifdef _MSC_VER
#pragma warning(push, 0)
#else
@@ -43,6 +47,13 @@
#pragma GCC diagnostic pop
#endif
// MSVC can use intrinsics without compiling for its target feature
#if defined(_MSC_VER) || !defined(ARCH_X64)
#define GNUC_X64_TARGET(x)
#else
#define GNUC_X64_TARGET(x) [[gnu::target(x)]]
#endif
#include <functional>
#include <unordered_map>
#include <source_location>
@@ -3807,13 +3818,25 @@ public:
}
template <typename T1, typename T2>
value_t<u8[16]> gf2p8affineqb(T1 a, T2 b, u8 c)
GNUC_X64_TARGET("gfni") value_t<u8[16]> gf2p8affineqb(T1 a, T2 b, u8 c)
{
value_t<u8[16]> result;
const auto data0 = a.eval(m_ir);
const auto data1 = b.eval(m_ir);
#ifdef ARCH_X64
const auto [a_is_const, a_data] = get_const_vector(data0, -1);
const auto [b_is_const, b_data] = get_const_vector(data1, -1);
if (a_is_const && b_is_const)
{
const auto affine = _mm_xor_si128(_mm_gf2p8affine_epi64_epi8(a_data, b_data, 0), _mm_set1_epi8(c));
result.value = llvm::ConstantDataVector::get(m_context, llvm::ArrayRef(static_cast<v128>(affine)._u8.m_data, 16));
return result;
}
#endif
const auto immediate = (llvm_const_int<u8>{c});
const auto imm8 = immediate.eval(m_ir);
@@ -3829,6 +3852,24 @@ public:
const auto data0 = a.eval(m_ir);
const auto data1 = b.eval(m_ir);
const auto data2 = c.eval(m_ir);
#ifdef ARCH_X64
const auto [a_is_const, a_data] = get_const_vector(data0, -1);
const auto [b_is_const, b_data] = get_const_vector(data1, -1);
const auto [c_is_const, c_data] = get_const_vector(data2, -1);
if (a_is_const && b_is_const && c_is_const)
{
__m128i dpbusd;
if (utils::has_avx512_icl())
dpbusd = _mm_wrapper_dpbusd_avx512vnni(a_data, b_data, c_data);
else
dpbusd = _mm_wrapper_dpbusd_avxvnni(a_data, b_data, c_data);
result.value = llvm::ConstantDataVector::get(m_context, llvm::ArrayRef(static_cast<v128>(dpbusd)._u32.m_data, 4));
return result;
}
#endif
result.value = m_ir->CreateCall(get_intrinsic(llvm::Intrinsic::x86_avx512_vpdpbusd_128),
{data0, m_ir->CreateBitCast(data1, get_type<u8[16]>()), m_ir->CreateBitCast(data2, get_type<u8[16]>())});
@@ -4197,13 +4238,27 @@ template <typename T1, typename T2, typename T3>
}
template <typename T1, typename T2, typename T3>
value_t<f32[4]> vfixupimmps(T1 a, T2 b, T3 c, u8 d, u8 e)
GNUC_X64_TARGET("avx512vl") value_t<f32[4]> vfixupimmps(T1 a, T2 b, T3 c, u8 d, u8 e)
{
value_t<f32[4]> result;
const auto data0 = a.eval(m_ir);
const auto data1 = b.eval(m_ir);
const auto data2 = c.eval(m_ir);
#ifdef ARCH_X64
const auto [a_is_const, a_data] = get_const_vector(data0, -1);
const auto [b_is_const, b_data] = get_const_vector(data1, -1);
const auto [c_is_const, c_data] = get_const_vector(data2, -1);
if (a_is_const && b_is_const && c_is_const)
{
const auto vfixup = _mm_mask_fixupimm_ps(a_data, e, b_data, c_data, 0); // flag reporting doesn't matter for constants
result.value = llvm::ConstantDataVector::get(m_context, llvm::ArrayRef(static_cast<v128>(vfixup)._f.m_data, 4));
return result;
}
#endif
const auto immediate = (llvm_const_int<u32>{d});
const auto imm32 = immediate.eval(m_ir);
const auto immediate2 = (llvm_const_int<u8>{e});
@@ -4314,6 +4369,19 @@ private:
// Custom intrinsic table
std::unordered_map<std::string_view, std::function<llvm::Value*(llvm::CallInst*)>> m_intrinsics;
#ifdef ARCH_X64
// LLVM uses the same intrinsic despite different encodings
GNUC_X64_TARGET("avx512vnni,avx512vl") __m128i _mm_wrapper_dpbusd_avx512vnni(__m128i a, __m128i b, __m128i c)
{
return _mm_dpbusd_epi32(a, b, c);
}
GNUC_X64_TARGET("avxvnni") __m128i _mm_wrapper_dpbusd_avxvnni(__m128i a, __m128i b, __m128i c)
{
return _mm_dpbusd_avx_epi32(a, b, c);
}
#endif
public:
// Call custom intrinsic by name
template <typename RT, typename... Args>
+10 -9
View File
@@ -502,8 +502,8 @@ error_code cellGifDecDecodeData(vm::ptr<GifDecoder> mainHandle, vm::cptr<GifStre
}
//Decode GIF file. (TODO: Is there any faster alternative? Can we do it without external libraries?)
int width, height, actual_components;
auto image = std::unique_ptr<unsigned char,decltype(&::free)>
int width = 0, height = 0, actual_components = 0;
auto image = std::unique_ptr<u8, decltype(&::free)>
(
stbi_load_from_memory(gif.get(), ::narrow<int>(fileSize), &width, &height, &actual_components, 4),
&::free
@@ -515,6 +515,7 @@ error_code cellGifDecDecodeData(vm::ptr<GifDecoder> mainHandle, vm::cptr<GifStre
const int bytesPerLine = static_cast<int>(dataCtrlParam->outputBytesPerLine);
constexpr char nComponents = 4;
const u32 image_size = width * height * nComponents;
u8* src = image.get();
switch(current_outParam.outputColorSpace)
{
@@ -527,12 +528,12 @@ error_code cellGifDecDecodeData(vm::ptr<GifDecoder> mainHandle, vm::cptr<GifStre
{
const int dstOffset = i * bytesPerLine;
const int srcOffset = width * nComponents * i;
memcpy(&data[dstOffset], &image.get()[srcOffset], linesize);
std::memcpy(&data[dstOffset], &src[srcOffset], linesize);
}
}
else
{
memcpy(data.get_ptr(), image.get(), image_size);
std::memcpy(data.get_ptr(), src, image_size);
}
break;
}
@@ -549,10 +550,10 @@ error_code cellGifDecDecodeData(vm::ptr<GifDecoder> mainHandle, vm::cptr<GifStre
const int srcOffset = width * nComponents * i;
for (int j = 0; j < linesize; j += nComponents)
{
output[j + 0] = image.get()[srcOffset + j + 3];
output[j + 1] = image.get()[srcOffset + j + 0];
output[j + 2] = image.get()[srcOffset + j + 1];
output[j + 3] = image.get()[srcOffset + j + 2];
output[j + 0] = src[srcOffset + j + 3];
output[j + 1] = src[srcOffset + j + 0];
output[j + 2] = src[srcOffset + j + 1];
output[j + 3] = src[srcOffset + j + 2];
}
std::memcpy(&data[dstOffset], output.get(), linesize);
}
@@ -560,7 +561,7 @@ error_code cellGifDecDecodeData(vm::ptr<GifDecoder> mainHandle, vm::cptr<GifStre
else
{
const auto img = std::make_unique<uint[]>(image_size);
uint* source_current = reinterpret_cast<uint*>(image.get());
uint* source_current = reinterpret_cast<uint*>(src);
uint* dest_current = img.get();
for (uint i = 0; i < image_size / nComponents; i++)
{
+5
View File
@@ -6800,6 +6800,11 @@ error_code sceNpSignalingActivateConnection(u32 ctx_id, vm::ptr<SceNpId> npId, v
return SCE_NP_SIGNALING_ERROR_NOT_INITIALIZED;
}
if (!get_signaling_context(ctx_id))
{
return SCE_NP_SIGNALING_ERROR_CTX_NOT_FOUND;
}
if (!npId || !conn_id)
{
return SCE_NP_SIGNALING_ERROR_INVALID_ARGUMENT;

Some files were not shown because too many files have changed in this diff Show More