Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
137 commits
Select commit Hold shift + click to select a range
7afd889
fix(libkernel): accept MSG_DONTWAIT in the socket send and receive calls
milescoviello Oct 12, 2026
2e46550
fix(shader): honor disabled optimization during specialization
QRMOE Oct 12, 2026
cac1355
test(shader): preserve specialized words when optimization is disabled
QRMOE Oct 12, 2026
1258d35
docs(input): describe the forwarded touchpad fingers and the View button
dantdmdarealguy Oct 9, 2026
7822535
fix(progress): extract history archives on Python without tarfile fil…
Zurisen Oct 13, 2026
99ae2e8
fix(libc): preserve path services through process exit
krishalivaibhav Oct 13, 2026
72fae20
fix(libSceAudioOut): report the port's channel count from sceAudioOut…
xXPBSXx Oct 12, 2026
149aea5
fix(stubgen): clean read-only staged files after failure
ideabsassistenza Oct 12, 2026
8a51ff3
fix(tests): ignore bracket comments in registration audit
ideabsassistenza Oct 13, 2026
59fd2f7
fix(libSceSystemService): include rejected LoadExec path
MarcZX10 Oct 13, 2026
92618d2
fix(relinker): replace output files instead of rewriting them in place
SandstromPL Oct 12, 2026
08bd00c
docs(build): link the supported WinLibs release
kq62 Oct 13, 2026
4310220
docs(user): stage the original eboot.bin in app0
screamm Oct 13, 2026
59235d9
test(agc): compile each v_cmp denormals program once for its eight in…
LeandroLP23 Oct 13, 2026
3065b89
fix(libSceNetCtl): answer sceNetCtlGetInfo from the host IPv4 interface
0xRickx Oct 13, 2026
95e5198
fix(libSceJpegDec): use the JpegDec parameter and image info layouts
0xRickx Oct 13, 2026
3124895
fix(shader): put the compute wave index in TG_SIZE[11:6]
houcineBen Oct 13, 2026
27b7531
fix(libSceFiber): end the frame chain of a fiber with a null frame
ee6aba54 Oct 13, 2026
6ad9372
fix(agc): store a storage image whose last block row runs past its al…
johnmaia Oct 13, 2026
26c62cc
fix(relinker): give the output's temporary file a unique name
SandstromPL Oct 14, 2026
11ef8e6
fix(agc): settle registration preparations before a preparation scope…
fdfawef324 Oct 13, 2026
2251649
build(libs): keep import libraries stable so a source edit relinks on…
fdfawef324 Oct 12, 2026
dc39e05
fix(agc): advance stored layers when a write-back keeps CPU-written b…
fdfawef324 Oct 12, 2026
7bfeeb9
test(agc): skip the kept-unit settle direct case when its import is c…
fdfawef324 Oct 13, 2026
7b6faf7
fix(build): preserve UTF-8 shader cache source paths
Dripl1x Oct 13, 2026
d50eed2
fix(memory): preserve process-owned services during exit
krishalivaibhav Oct 13, 2026
39317d5
fix(tools): decode Ninja targets using its build-file encoding
Roojool Oct 12, 2026
6937530
fix(relinker): reject collisions between generated outputs
ArjenS-LA Oct 14, 2026
9d412df
fix(agc): fall back out-of-range sceAgcInit versions to table 13
mazen320 Oct 13, 2026
4832bd8
fix(agc): clamp sceAgcInit versions above 13 inline
mazen320 Oct 13, 2026
eb1b9ec
fix(agc): return 0 for out-of-range sceAgcInit without table lookup
mazen320 Oct 14, 2026
ca73d0f
test(agc): keep watched settle coverage when direct imports are unava…
fdfawef324 Oct 14, 2026
e052811
fix(conventions): ignore code blocks when checking doc links
GalaxyGamingFR Oct 14, 2026
fdf9215
refactor(libSceShare.native): drop duplicated exports
ducloc080202 Oct 13, 2026
2e461aa
build(recompiler): generate the shader cache version as a source file
fdfawef324 Oct 12, 2026
8ed0bc3
perf(shader): avoid redundancy traversal map copies
JJenkx Oct 13, 2026
fd192b2
docs(shader): place traversal debt with the component
JJenkx Oct 13, 2026
b009318
docs(shader): place traversal debt in existing Build section
JJenkx Oct 13, 2026
5281378
fix(libkernel): defer raises while a thread holds the address-wait lo…
oneandonlydean Oct 14, 2026
4b71846
feat(agc): sample a multisampled color target through its 2D MSAA tex…
nicolasabosch Oct 12, 2026
6e6334e
fix(agc): apply a pending color memory fill before sampling a multisa…
nicolasabosch Oct 13, 2026
84f6364
fix(agc): skip retired multisampled targets when sampling
nicolasabosch Oct 13, 2026
1ef97e5
fix(shader): group compute derivatives by four consecutive lanes
oneandonlydean Oct 14, 2026
0b5a4aa
fix(agc): store small pending storage results at each flip
gjonn Oct 12, 2026
62eff52
feat(agc): sample depth plane arrays from a later base slice
MichonGoddijn231849 Oct 13, 2026
a5904f4
test(agc): depth plane arrays sampled from a later base slice
MichonGoddijn231849 Oct 13, 2026
f8aa904
test(agc): pin the depth plane sampling views that must keep throwing
mrfelek Oct 13, 2026
a08310b
feat(libSceAudioOut): open HDMI bitstream ports with sceAudioOutExOpen
p3nicillin Oct 14, 2026
4a71c6b
docs(usage): note the NVIDIA 610.47 shader compiler crash on Windows
parl0v Oct 13, 2026
bb4ec48
fix(audio): preserve completed AudioOut2 grains across threads
eljackjoestar-cmd Oct 13, 2026
8847086
refactor(recompiler): emit the v_fma_mixlo/hi and v_interp_*_f16 emul…
fdfawef324 Oct 13, 2026
8029428
fix(libkernel): keep host standard streams open on guest close
SynnZer0 Oct 11, 2026
f6e9cd6
fix(videoout): keep mouse helpers out of NID exports
Oct 14, 2026
c794273
feat(agc): implement image tables whose records hold a pointer to the T#
Pipodi Oct 13, 2026
55eefe9
feat(agc): plan table columns whose descriptor spans two loads of a r…
Pipodi Oct 14, 2026
b8ed789
fix(input): read the input file from paths with non-ASCII characters
AlxcBTW Oct 12, 2026
a533324
feat(agc): report which trace threads dropped events and where their …
eliyarson Oct 14, 2026
52a3b15
feat(libkernel): report relative symbolic links in lstat on Windows
GitamarT045T3R Oct 14, 2026
cd0c6ed
test(libkernel): do not stat the dangling link on Windows
adriadam10 Oct 14, 2026
19e020a
Merge pull request #1186 from MichonGoddijn231849/feat/depth-plane-ar…
oneandonlydean Oct 14, 2026
0ccf53d
Merge pull request #4703 from AlxcBTW/fix/input-config-non-ascii-path
adriadam10 Oct 14, 2026
30e85a3
fix(shader): number an instanced draw's hull patches across its insta…
Pipodi Oct 12, 2026
3c17b3d
docs(debt): update the relative patch index line for instanced draws
adriadam10 Oct 14, 2026
c14fd87
Merge pull request #4721 from fdfawef324/build/stable-import-libraries
adriadam10 Oct 14, 2026
5ef619a
Merge pull request #5813 from eliyarson/trace-drop-detail
adriadam10 Oct 14, 2026
3864da5
Merge pull request #3909 from GalaxyGamingFR/fix/conventions-doc-link…
adriadam10 Oct 14, 2026
b60e0bc
Merge pull request #4676 from milescoviello/fix/socket-msg-dontwait
adriadam10 Oct 14, 2026
f3b5daa
Merge pull request #4836 from dantdmdarealguy/docs/input-touchpad-fin…
adriadam10 Oct 14, 2026
e154f56
Merge pull request #5844 from p3n1cillin/claude/audioout-ex-open
adriadam10 Oct 14, 2026
c280018
fix(agc): treat type-0 texture descriptors as null
MarcZX10 Oct 12, 2026
58b2245
docs(debt): record type-0 texture descriptors bound as null images
adriadam10 Oct 14, 2026
204c2ac
refactor(libSceSaveData.native): name sceSaveDataPrepareForTransferring
nicolasfalesy Oct 13, 2026
31e53e5
fix(libSceSaveData.native): drop the duplicate APS5_EXPORT of the rea…
adriadam10 Oct 14, 2026
5dcf28d
fix(libkernel): answer fcntl status flags on libSceNet sockets
nicolasfalesy Oct 13, 2026
5bf18f0
perf(libc): remember clean pages once per run in Windows write collects
CnRJay Oct 14, 2026
6b480cc
fix(agc): copy a depth surface's plane through the texture's padded l…
GustavoGamarra95 Oct 13, 2026
ad50734
test(agc): sample a small D16 cube whose linear slices are padded
GustavoGamarra95 Oct 13, 2026
86c6691
test(agc): sample a 128x128 D16 cube whose detiled rows are padded
alfalfa-star Oct 13, 2026
18522ae
fix(agc): wait for queued registration preparations before accepting …
gravelas Oct 13, 2026
db06cb4
Merge pull request #4732 from fdfawef324/build/shader-cache-version-s…
adriadam10 Oct 14, 2026
110cc13
Merge pull request #4770 from ee6aba54/fix/fiber-frame-chain
adriadam10 Oct 14, 2026
ec92b94
Merge pull request #4771 from Roojool/contrib/g10-registration-utf8
adriadam10 Oct 14, 2026
fe1ccd7
Merge pull request #4778 from xXPBSXx/fix/audioout2-port-state-channe…
adriadam10 Oct 14, 2026
2f3adfb
Merge pull request #4802 from ArjenS-LA/fix/relinker-output-collisions
adriadam10 Oct 14, 2026
a7d38a3
Merge pull request #4827 from QRMOE/fix-spirv-noopt-specialization
adriadam10 Oct 14, 2026
d9bfa0f
Merge pull request #4841 from gjonn/fix/agc-store-pending-at-flip
adriadam10 Oct 14, 2026
1cbd74e
Merge pull request #4906 from nicolasfalesy/feat/savedata-name-prepar…
adriadam10 Oct 14, 2026
93d69ed
Merge pull request #4932 from fdfawef324/perf/recompiler-fma-mix-once
adriadam10 Oct 14, 2026
e7784a0
Merge pull request #4961 from Dripl1x/codex/shader-cache-utf8
adriadam10 Oct 14, 2026
5d0e8fc
Merge pull request #4970 from Zurisen/fix/progress-history-python310
adriadam10 Oct 14, 2026
c2b55c6
Merge pull request #4974 from ideabsassistenza/fix/stubgen-readonly-c…
adriadam10 Oct 14, 2026
4ae78dc
Merge pull request #5012 from ideabsassistenza/fix/registration-brack…
adriadam10 Oct 14, 2026
38c0bfa
Merge pull request #5131 from parl0v/docs/nvidia-610-compiler-crash
adriadam10 Oct 14, 2026
8b8bfe0
Merge pull request #4820 from nicolasabosch/feat/agc-sample-msaa-color
oneandonlydean Oct 14, 2026
8ba869d
Merge pull request #4450 from Pipodi/feat/tessellation-instanced-hull
adriadam10 Oct 14, 2026
8fec47a
fix(agc): give each slice of a depth array its own HTILE
XairRrR Oct 13, 2026
276608d
Merge pull request #4475 from Pipodi/feat/image-table-indirect-column…
adriadam10 Oct 14, 2026
e9817cd
Merge pull request #4663 from fdfawef324/fix/agc-settle-stored-units
adriadam10 Oct 14, 2026
26ce6e9
Merge pull request #4779 from MarcZX100/codex/null-tsharp-type-4139
adriadam10 Oct 14, 2026
a84afe9
fix(agc): store a written storage image over a depth plane into the s…
XairRrR Oct 13, 2026
b3e5acc
fix(agc): store a covering storage image into the newest pairing of i…
XairRrR Oct 13, 2026
9394a6f
fix(agc): handle FMASK decompress on MSAA targets
Swastik-51 Oct 12, 2026
8c76693
test(agc): tighten FMASK decompress tests
Swastik-51 Oct 12, 2026
02974ea
fix(agc): reject DCC on multisampled targets outside FMASK decompress
Swastik-51 Oct 13, 2026
a15f163
docs(debt): FMASK decompress over multisampled targets
adriadam10 Oct 14, 2026
4d5411d
Merge pull request #4873 from GustavoGamarra95/fix/agc-depth-copy-pad…
adriadam10 Oct 14, 2026
e442f4c
Merge pull request #4924 from nicolasfalesy/fix/libkernel-fcntl-scene…
adriadam10 Oct 14, 2026
f6835a6
Merge pull request #4925 from MarcZX100/codex/systemservice-loadexec-…
adriadam10 Oct 14, 2026
f7628de
Merge pull request #4994 from krishalivaibhav/codex/path-service-life…
adriadam10 Oct 14, 2026
5561db2
Merge pull request #5018 from SandstromPL/fix/relinker-replace-outputs
adriadam10 Oct 14, 2026
0b13048
Merge pull request #5023 from fdfawef324/fix/agc-shader-prep-wait
adriadam10 Oct 14, 2026
ee6addf
Merge pull request #5030 from johnmaia/fix/storage-writeback-overhang
adriadam10 Oct 14, 2026
61cec42
Merge pull request #5032 from kq62/docs-winlibs-link
adriadam10 Oct 14, 2026
278765a
Merge pull request #5040 from screamm/docs/app0-eboot
adriadam10 Oct 14, 2026
03b7cb5
fix(agc): gather a sampled depth cube at the descriptor's layer offsets
NFSS10 Oct 13, 2026
6229879
Merge pull request #5936 from hossiendehghan989/fix/mouse-internal-he…
oneandonlydean Oct 14, 2026
0c4e430
Merge pull request #5829 from oneandonlydean/fix/compute-derivatives-…
oneandonlydean Oct 14, 2026
ed835aa
Merge pull request #5756 from oneandonlydean/fix/raise-address-lock-1488
oneandonlydean Oct 14, 2026
ededc2e
test(agc): drop the refusal cases main's relaxed geometry check no lo…
adriadam10 Oct 14, 2026
0c9e980
Merge pull request #5111 from XairRrR/fix/agc-depth-array-slice-htile
adriadam10 Oct 14, 2026
32e810d
Merge pull request #5113 from XairRrR/fix/agc-depth-store-back-any-st…
adriadam10 Oct 14, 2026
f25386b
Merge pull request #5167 from LeandroLP23/perf/vcmp-test-recompile
adriadam10 Oct 14, 2026
706ad6c
Merge pull request #5198 from eljackjoestar-cmd/codex/audioout2-advan…
adriadam10 Oct 14, 2026
ea30c92
Merge pull request #5214 from houcineBen/fix/agc-tg-size-wave-id
adriadam10 Oct 14, 2026
dc89131
Merge pull request #3864 from CnRJay/perf/libc-collect-view-walk
adriadam10 Oct 14, 2026
c5f6269
Merge pull request #4767 from Swastik-51/fix/agc-fmask-decompress-msaa
adriadam10 Oct 14, 2026
cb893e0
Merge pull request #5007 from gravelas/fix/agc-await-registration-pre…
adriadam10 Oct 14, 2026
55320f4
Merge pull request #5054 from NFSS10/fix/agc-depth-plane-cube-gather
adriadam10 Oct 14, 2026
9f373a4
Merge pull request #5056 from 0xRickx/fix/libscenetctl-get-info
adriadam10 Oct 14, 2026
3433555
Merge pull request #5072 from 0xRickx/fix/libscejpegdec-reference-abi
adriadam10 Oct 14, 2026
587b63d
Merge pull request #5073 from krishalivaibhav/codex/memory-service-li…
adriadam10 Oct 14, 2026
456ce66
Merge pull request #5163 from mazen320/fix/agc-init-fallback-out-of-r…
adriadam10 Oct 14, 2026
73efd94
Merge pull request #5212 from ducloc080202/feat/share-native-capture-…
adriadam10 Oct 14, 2026
43ea768
Merge pull request #5511 from JJenkx/perf/spirv-bounded-redundancy
oneandonlydean Oct 14, 2026
bebff8b
Merge pull request #3295 from SynnZer0/fix/libkernel-close-host-streams
oneandonlydean Oct 14, 2026
e27ff7c
Merge pull request #5819 from GitamarT045T3R/fix/windows-lstat-symbol…
adriadam10 Oct 14, 2026
4654163
feat(libSceNpManager): retain the game presence callback and validate…
KernelPanicNT Oct 14, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,10 @@ if(BUILD_TESTING)
set_tests_properties(request_serializer PROPERTIES TIMEOUT 20)
find_package(Python3 QUIET COMPONENTS Interpreter)
if(Python3_Interpreter_FOUND)
add_test(NAME shader_cache_native_paths COMMAND ${Python3_EXECUTABLE}
${CMAKE_CURRENT_SOURCE_DIR}/core/shader/recompiler/tests/test_shader_cache_native_paths.py
${CMAKE_CURRENT_SOURCE_DIR}/core/shader/recompiler/ShaderCacheVersion.cmake ${CMAKE_COMMAND})
set_tests_properties(shader_cache_native_paths PROPERTIES TIMEOUT 20)
add_test(NAME pr_overlap_encoding COMMAND ${Python3_EXECUTABLE}
${CMAKE_CURRENT_SOURCE_DIR}/tools/tests/test_pr_overlap_encoding.py)
add_test(NAME pr_overlap_dependencies COMMAND ${Python3_EXECUTABLE}
Expand Down Expand Up @@ -115,6 +119,8 @@ if(BUILD_TESTING)
${CMAKE_CURRENT_SOURCE_DIR}/tools/tests/test_check_conventions_wrapped_declarations.py)
add_test(NAME conventions_ci_gate COMMAND ${Python3_EXECUTABLE}
${CMAKE_CURRENT_SOURCE_DIR}/tools/tests/test_check_conventions_ci_gate.py)
add_test(NAME conventions_doc_links COMMAND ${Python3_EXECUTABLE}
${CMAKE_CURRENT_SOURCE_DIR}/tools/tests/test_check_conventions_doc_links.py)
add_test(NAME test_registration COMMAND ${Python3_EXECUTABLE}
${CMAKE_CURRENT_SOURCE_DIR}/tools/tests/test_test_registration.py)
add_test(NAME check_skips COMMAND ${Python3_EXECUTABLE}
Expand Down
27 changes: 25 additions & 2 deletions core/libs/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,21 @@ if(MINGW)
foreach(runtimeLinkFlag IN ITEMS -static-libgcc -static-libstdc++ -static)
string(REPLACE "${runtimeLinkFlag}" "" CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS}")
endforeach()

if(NOT EXISTS "${CMAKE_RANLIB}")
message(FATAL_ERROR "Stable import libraries require ranlib")
endif()
list(LENGTH CMAKE_CXX_CREATE_SHARED_LIBRARY linkCommandCount)
string(FIND "${CMAKE_CXX_CREATE_SHARED_LIBRARY}" "-Wl,--out-implib,<TARGET_IMPLIB> " implibOption)
if(NOT linkCommandCount EQUAL 1 OR implibOption EQUAL -1)
message(FATAL_ERROR "Expected one shared library link command that writes -Wl,--out-implib,<TARGET_IMPLIB>: ${CMAKE_CXX_CREATE_SHARED_LIBRARY}")
endif()
string(REPLACE "-Wl,--out-implib,<TARGET_IMPLIB> " "-Wl,--out-implib,<TARGET_IMPLIB>.new " linkCommand "${CMAKE_CXX_CREATE_SHARED_LIBRARY}")
set(CMAKE_CXX_CREATE_SHARED_LIBRARY
"\"${CMAKE_COMMAND}\" -E env SOURCE_DATE_EPOCH=0 ${linkCommand}"
"\"${CMAKE_RANLIB}\" -D <TARGET_IMPLIB>.new"
"\"${CMAKE_COMMAND}\" -E copy_if_different <TARGET_IMPLIB>.new <TARGET_IMPLIB>"
)
endif()

set(LIBC_DIR ${CMAKE_CURRENT_SOURCE_DIR}/prx/libc)
Expand Down Expand Up @@ -87,6 +102,14 @@ set_target_properties(libc PROPERTIES

set(LIBC_UNPATCHED ${UNPATCHED_DIR}/libc.prx)
set(LIBC_PATCHED ${PATCHED_DIR}/libc.prx)
set(LIBC_EXPORT_LIST ${CMAKE_CURRENT_BINARY_DIR}/libc.exports)

add_custom_command(
OUTPUT ${LIBC_EXPORT_LIST}
COMMAND $<TARGET_FILE:nid_patcher> --write-export-list ${LIBC_UNPATCHED} ${LIBC_EXPORT_LIST}
DEPENDS nid_patcher libc ${LIBC_UNPATCHED}
COMMENT "Listing libc exports"
)

add_custom_command(
OUTPUT ${LIBC_PATCHED}
Expand Down Expand Up @@ -146,8 +169,8 @@ foreach(LIB_DIR ${LIBS_DIRS})
add_custom_command(
OUTPUT ${PATCHED_FILE}
COMMAND ${CMAKE_COMMAND} -E copy ${UNPATCHED_FILE} ${PATCHED_FILE}
COMMAND $<TARGET_FILE:nid_patcher> ${LIB_NAME} --preserve-exports "${LIBC_UNPATCHED}" "${PATCHED_FILE}"
DEPENDS nid_patcher ${LIB_NAME} ${UNPATCHED_FILE} ${LIBC_UNPATCHED}
COMMAND $<TARGET_FILE:nid_patcher> ${LIB_NAME} --preserve-export-list "${LIBC_EXPORT_LIST}" "${PATCHED_FILE}"
DEPENDS nid_patcher ${LIB_NAME} ${UNPATCHED_FILE} ${LIBC_EXPORT_LIST}
COMMENT "Patching NIDs for ${LIB_NAME}"
)

Expand Down
36 changes: 30 additions & 6 deletions core/libs/SceTypes.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -1314,7 +1314,20 @@ struct Http2AsyncOption {

struct NpTitleId { char data[13]; char pad[3]; };
struct NpTitleSecret { std::uint8_t data[128]; };
struct NpContentRestriction { std::uint8_t opaque[128]; };
struct NpAgeRestriction {
char countryCode[4];
std::int8_t age;
std::uint8_t padding[3];
};
struct NpContentRestriction {
std::uint64_t size;
std::int8_t defaultAgeRestriction;
std::uint8_t padding[3];
std::int32_t ageRestrictionCount;
const NpAgeRestriction* ageRestriction;
};
static_assert(sizeof(NpAgeRestriction) == 8);
static_assert(sizeof(NpContentRestriction) == 0x18);
struct NpOnlineId { char data[17]; char pad[3]; };

struct SharePlayConnectionInfoA {
Expand Down Expand Up @@ -1750,32 +1763,43 @@ struct JpegEncOutputInfo {
};

struct JpegDecCreateParam {
std::uint32_t size;
std::uint32_t this_size;
std::uint32_t attribute;
std::uint32_t max_image_width;
};

struct JpegDecParseParam {
const void* jpeg_mem_addr;
std::uint32_t jpeg_mem_size;
std::uint32_t reserved0;
std::uint16_t decode_mode;
std::uint16_t down_scale;
};

struct JpegDecDecodeParam {
const void* jpeg_mem_addr;
void* image_mem_addr;
void* coefficient_mem_addr;
std::uint32_t jpeg_mem_size;
std::uint32_t image_mem_size;
std::uint32_t coefficient_mem_size;
std::uint16_t decode_mode;
std::uint16_t down_scale;
std::uint16_t pixel_format;
std::uint16_t reserved0;
std::uint16_t alpha_value;
std::uint32_t image_pitch;
};

struct JpegDecImageInfo {
std::uint32_t image_width;
std::uint32_t image_height;
std::uint16_t color_space;
std::uint16_t bit_depth;
std::uint32_t image_flag;
std::uint16_t component_number;
std::uint8_t component_id[4];
std::uint8_t sampling_factor[4];
std::uint32_t coefficient_mem_size;
std::uint32_t suitable_csc_attribute;
std::uint32_t output_image_width;
std::uint32_t output_image_height;
};

struct PlayGoInitParams {
Expand Down
2 changes: 2 additions & 0 deletions core/libs/nid/include/nid/ExportExclusions.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ namespace Nid {

std::string NormalizeExportName(const std::string& name);
std::unordered_set<std::string> ReadExportExclusions(const std::string& path);
std::unordered_set<std::string> ReadExportList(const std::string& path);
bool WriteExportList(const std::string& referencePath, const std::string& path);

}

Expand Down
48 changes: 48 additions & 0 deletions core/libs/nid/src/ExportExclusions.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,13 @@
#include <nid/MachONidPatcher.hpp>
#include <nid/NidPatcherUtils.hpp>
#include <nid/NativePath.hpp>
#include <algorithm>
#include <bit>
#include <cstring>
#include <fstream>
#include <iterator>
#include <stdexcept>
#include <vector>

namespace Nid {

Expand Down Expand Up @@ -113,6 +116,24 @@ std::unordered_set<std::string> ReadElfExports(const std::vector<std::uint8_t>&
return result;
}

std::string ReadText(const std::string& path, std::ifstream& input) {
std::string text{std::istreambuf_iterator<char>(input), {}};
if (input.bad()) throw std::runtime_error("cannot read export list: " + path);
return text;
}

std::string FormatExportList(const std::unordered_set<std::string>& exports) {
std::vector<std::string> names(exports.begin(), exports.end());
std::ranges::sort(names);
std::string text;
for (const auto& name : names) {
if (name.find('\n') != std::string::npos) throw std::runtime_error("export name contains a line break: " + name);
text += name;
text += '\n';
}
return text;
}

}

std::string NormalizeExportName(const std::string& name) {
Expand Down Expand Up @@ -153,4 +174,31 @@ std::unordered_set<std::string> ReadExportExclusions(const std::string& path) {
return result;
}

std::unordered_set<std::string> ReadExportList(const std::string& path) {
std::ifstream input(path, std::ios::binary);
if (!input) throw std::runtime_error("cannot open export list: " + path);
const auto text = ReadText(path, input);
if (text.empty() || text.back() != '\n') throw std::runtime_error("malformed export list: " + path);
std::unordered_set<std::string> result;
for (std::size_t start = 0; start < text.size();) {
const auto end = text.find('\n', start);
if (end == start) throw std::runtime_error("empty name in export list: " + path);
auto name = text.substr(start, end - start);
if (!result.insert(name).second) throw std::runtime_error("duplicate name in export list: " + name);
start = end + 1;
}
return result;
}

bool WriteExportList(const std::string& referencePath, const std::string& path) {
const auto text = FormatExportList(ReadExportExclusions(referencePath));
if (std::ifstream existing(path, std::ios::binary); existing && ReadText(path, existing) == text) return false;
std::ofstream output(path, std::ios::binary | std::ios::trunc);
if (!output) throw std::runtime_error("cannot write export list: " + path);
output.write(text.data(), static_cast<std::streamsize>(text.size()));
output.close();
if (!output) throw std::runtime_error("cannot write export list: " + path);
return true;
}

}
23 changes: 19 additions & 4 deletions core/libs/nid/src/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -25,21 +25,36 @@ void _writeFile(const std::string& path, const std::vector<std::uint8_t>& data)

int Run(int argc, char* argv[]) {
if (argc < 3) {
std::cerr << "Usage: nid_patcher <library_name> [--preserve-exports <unpatched-library>] <file> [file2 ...]\n";
std::cerr << "Usage: nid_patcher <library_name> [--preserve-exports <unpatched-library> | --preserve-export-list <export-list>] <file> [file2 ...]\n"
" nid_patcher --write-export-list <unpatched-library> <export-list>\n";
return 1;
}

if (std::string(argv[1]) == "--write-export-list") {
if (argc != 4) {
std::cerr << "FAIL: --write-export-list requires a reference library and an export list\n";
return 2;
}
try {
std::cout << (Nid::WriteExportList(argv[2], argv[3]) ? "WROTE: " : "UNCHANGED: ") << argv[3] << "\n";
} catch (const std::exception& e) {
std::cerr << "FAIL: " << argv[3] << ": " << e.what() << "\n";
return 2;
}
return 0;
}

const std::string libraryName = argv[1];
std::unordered_set<std::string> excludedExports;
std::vector<std::string> paths;
try {
bool hasReference = false;
for (int i = 2; i < argc; ++i) {
const std::string argument = argv[i];
if (argument == "--preserve-exports") {
if (hasReference || i + 1 == argc) throw std::runtime_error("--preserve-exports requires exactly one reference library");
if (argument == "--preserve-exports" || argument == "--preserve-export-list") {
if (hasReference || i + 1 == argc) throw std::runtime_error(argument + " requires exactly one reference");
hasReference = true;
excludedExports = Nid::ReadExportExclusions(argv[++i]);
excludedExports = argument == "--preserve-exports" ? Nid::ReadExportExclusions(argv[++i]) : Nid::ReadExportList(argv[++i]);
} else {
if (argument.starts_with("--")) throw std::runtime_error("unknown option: " + argument);
paths.push_back(argument);
Expand Down
49 changes: 49 additions & 0 deletions core/libs/nid/tests/test_macho_nids.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
"""Check nid_patcher on small byte-built Mach-O dylibs: the export trie, the chained imports and what it refuses."""

import hashlib
import os
import struct
import subprocess
import sys
Expand Down Expand Up @@ -211,6 +212,53 @@ def check_preserved(patcher, directory):
assert exports_of(path.read_bytes()) == {"_puts_nid_postfix": (0, 0x100), "_" + nid("exit"): (0, 0x108)}, exports_of(path.read_bytes())


def write_export_list(patcher, reference, listing):
return subprocess.run([str(patcher), "--write-export-list", str(reference), str(listing)], capture_output=True, text=True, timeout=30)


def check_export_list(patcher, directory):
reference = Path(directory) / "listed.dylib"
listing = Path(directory) / "listed.exports"
reference.write_bytes(build_dylib([("_puts_nid_postfix", 0, 0x100), ("_exit", 0, 0x108)], []))
result = write_export_list(patcher, reference, listing)
assert result.returncode == 0, (result.stdout, result.stderr)
assert listing.read_bytes() == b"exit\nputs\n", listing.read_bytes()

os.utime(listing, ns=(1_000_000_000_000_000_000, 1_000_000_000_000_000_000))
reference.write_bytes(build_dylib([("_exit", 0, 0x110), ("_puts_nid_postfix", 0, 0x118)], []))
result = write_export_list(patcher, reference, listing)
assert result.returncode == 0, (result.stdout, result.stderr)
assert listing.stat().st_mtime_ns == 1_000_000_000_000_000_000, "an unchanged export list was rewritten"

reference.write_bytes(build_dylib([("_puts", 0, 0x100)], []))
result = write_export_list(patcher, reference, listing)
assert result.returncode == 0, (result.stdout, result.stderr)
assert listing.read_bytes() == b"puts\n", listing.read_bytes()
assert listing.stat().st_mtime_ns != 1_000_000_000_000_000_000, "a changed export list kept its time"

path = Path(directory) / "listed-preserve.dylib"
path.write_bytes(build_dylib([("_puts_nid_postfix", 0, 0x100), ("_exit_nid_postfix", 0, 0x108)], []))
result = subprocess.run([str(patcher), "libtest", "--preserve-export-list", str(listing), str(path)], capture_output=True, text=True, timeout=30)
assert result.returncode == 0, (result.stdout, result.stderr)
assert exports_of(path.read_bytes()) == {"_puts_nid_postfix": (0, 0x100), "_" + nid("exit"): (0, 0x108)}, exports_of(path.read_bytes())

malformed_lists = [
("unterminated", b"puts", "malformed export list"),
("blank", b"puts\n\nexit\n", "empty name in export list"),
("twice", b"puts\nputs\n", "duplicate name in export list"),
("empty", b"", "malformed export list"),
]
for name, content, message in malformed_lists:
malformed = Path(directory) / (name + ".exports")
malformed.write_bytes(content)
target = Path(directory) / (name + ".dylib")
target.write_bytes(build_dylib([("_puts_nid_postfix", 0, 0x100)], []))
result = subprocess.run([str(patcher), "libtest", "--preserve-export-list", str(malformed), str(target)], capture_output=True, text=True, timeout=30)
assert result.returncode != 0 and message in result.stdout + result.stderr, (name, result.stdout, result.stderr)
result = subprocess.run([str(patcher), "libtest", "--preserve-exports", str(reference), "--preserve-export-list", str(listing), str(path)], capture_output=True, text=True, timeout=30)
assert result.returncode != 0 and "exactly one reference" in result.stdout + result.stderr, (result.stdout, result.stderr)


def check_refusals(patcher, directory):
growing = [("_ab", 0, 0x100), ("_cd", 0, 0x108)]
result, _ = patch(patcher, directory, "signed.dylib", build_dylib(growing, [], signed=True))
Expand All @@ -227,6 +275,7 @@ def main():
check_shrinking(patcher, directory)
check_growing(patcher, directory)
check_preserved(patcher, directory)
check_export_list(patcher, directory)
check_refusals(patcher, directory)
print("NID patcher Mach-O tests passed")

Expand Down
15 changes: 6 additions & 9 deletions core/libs/prx/libSceAgc/DcbState/src/Init.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,21 +7,18 @@
#include "SceTypes.hpp"
#include "prx/libc/include/General.hpp"

static constexpr int SCE_AGC_ERROR_INVALID_ARGUMENT = static_cast<int>(0x80890001);

extern "C" {

int APS5_VABI sceAgcInit_0090(std::uint32_t* state, std::uint32_t version) {
Agc::Command::CheckAddress(reinterpret_cast<std::uintptr_t>(state), alignof(std::uint32_t), __func__);
Agc::Command::Require(version < 14, __func__, "unsupported AGC initialization version");
return 0;
}

int APS5_VABI sceAgcInit(std::uint32_t version) {
if (version >= 14) return SCE_AGC_ERROR_INVALID_ARGUMENT;
if (version >= 14) return 0;
Agc::Command::GetRegisterDefaults(version, false, __func__);
Agc::Command::GetRegisterDefaults(version, true, __func__);
return 0;
}

int APS5_VABI sceAgcInit_0090(std::uint32_t* state, std::uint32_t version) {
Agc::Command::CheckAddress(reinterpret_cast<std::uintptr_t>(state), alignof(std::uint32_t), __func__);
return sceAgcInit(version);
}

}
2 changes: 1 addition & 1 deletion core/libs/prx/libSceAgc/Shader/src/InterpolantMapping.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ int CreateInterpolantMapping(const char* fn, ShaderRegister* regs, const Shader*
throw std::runtime_error(std::string(fn) + ": input semantic count exceeds 32");
}

AgcDriver::ShaderPreparationScope transaction;
AgcDriver::ShaderPreparationScope transaction({ps != nullptr ? gs : nullptr, ps});
std::array<ShaderRegister, 32> values{};
auto* output = regs;
regs = values.data();
Expand Down
2 changes: 1 addition & 1 deletion core/libs/prx/libSceAgc/Shader/src/LinkShaders.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ extern "C" int APS5_VABI sceAgcLinkShaders(ShaderRegister* context, ShaderRegist

// The simple vertex/pixel pipeline combines two primitive context registers
// and 32 interpolant registers. Publish only after both helpers succeed.
AgcDriver::ShaderPreparationScope transaction;
AgcDriver::ShaderPreparationScope transaction({vertex, pixel});
std::array<ShaderRegister, 34> contextValues{};
std::array<ShaderRegister, 3> primitiveValues{};
sceAgcCreatePrimState(contextValues.data(), primitiveValues.data(), nullptr, vertex, primitiveType);
Expand Down
3 changes: 3 additions & 0 deletions core/libs/prx/libSceAgc/Shader/src/PrimState.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@

#include "SceShaders.hpp"
#include "prx/libSceAgcDriver/Execution/include/Driver.hpp"
#include "prx/libSceAgcDriver/Execution/include/ShaderPreparationScope.hpp"
#include "prx/libSceAgc/Shader/include/ShaderUtils.hpp"
#include "prx/libSceAgc/Shader/include/ShaderConstants.hpp"

Expand Down Expand Up @@ -56,7 +57,9 @@ int APS5_VABI sceAgcCreatePrimState(ShaderRegister* cx_regs, ShaderRegister* uc_
const std::array<const Shader*, 2> stages{hs, gs};
const bool patch = prim_type == static_cast<std::uint32_t>(ShaderRegs::PrimitiveType::Patch);
if (patch == ((contextValues[0].value & ShaderRegs::VGT_SHADER_STAGES_HS_BIT) != 0)) {
AgcDriver::ShaderPreparationScope transaction({hs, gs});
AgcDriverResolveGraphicsStagesAbi_nid_postfix(std::span(stages).subspan(hs == nullptr ? 1u : 0u), contextValues, primitiveValues);
transaction.Commit();
}
if (cx_regs != nullptr) std::copy(contextValues.begin(), contextValues.end(), cx_regs);
if (uc_regs != nullptr) std::copy(primitiveValues.begin(), primitiveValues.end(), uc_regs);
Expand Down
Loading
Loading