mirror of
https://github.com/boykopovar/AnyPS5.git
synced 2026-10-27 00:28:14 +00:00
Merge main into codex/opus-native-decoder-20261021
This commit is contained in:
commit
c54134ed4b
247 files changed
+10601
-1131
No files matched your search
@@ -55,3 +55,9 @@
|
||||
[submodule "3rdparty/vgmstream"]
|
||||
path = 3rdparty/vgmstream
|
||||
url = https://github.com/vgmstream/vgmstream.git
|
||||
[submodule "3rdparty/ogg"]
|
||||
path = 3rdparty/ogg
|
||||
url = https://github.com/xiph/ogg.git
|
||||
[submodule "3rdparty/vorbis"]
|
||||
path = 3rdparty/vorbis
|
||||
url = https://github.com/xiph/vorbis.git
|
||||
+1
Submodule 3rdparty/ogg added at be05b13e98.
+1
Submodule 3rdparty/vorbis added at 0657aee69d.
@@ -248,6 +248,15 @@ if(BUILD_TESTING)
|
||||
set_tests_properties(guest_posix_scalar_io PROPERTIES ENVIRONMENT_MODIFICATION
|
||||
"PATH=path_list_prepend:$<TARGET_FILE_DIR:libkernel>")
|
||||
endif()
|
||||
add_test_executable(guest_kernel_sys_sdk_version_tests tests/GuestKernelSysSdkVersion.cpp)
|
||||
target_include_directories(guest_kernel_sys_sdk_version_tests PRIVATE ${CMAKE_CURRENT_SOURCE_DIR})
|
||||
target_link_libraries(guest_kernel_sys_sdk_version_tests PRIVATE libkernel_sys libkernel libc)
|
||||
configure_windows_unwind(guest_kernel_sys_sdk_version_tests)
|
||||
add_test(NAME guest_kernel_sys_sdk_version COMMAND guest_kernel_sys_sdk_version_tests)
|
||||
if(WIN32)
|
||||
set_tests_properties(guest_kernel_sys_sdk_version PROPERTIES ENVIRONMENT_MODIFICATION
|
||||
"PATH=path_list_prepend:$<TARGET_FILE_DIR:libkernel_sys>")
|
||||
endif()
|
||||
add_test_executable(nid_buffer_validation_tests nid/tests/BufferValidation.cpp)
|
||||
target_include_directories(nid_buffer_validation_tests PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/nid/include)
|
||||
target_compile_features(nid_buffer_validation_tests PRIVATE cxx_std_20)
|
||||
@@ -422,6 +431,17 @@ if(BUILD_TESTING)
|
||||
"PATH=path_list_prepend:$<TARGET_FILE_DIR:libSceHttp>")
|
||||
endif()
|
||||
|
||||
add_test_executable(guest_entitlements_tests tests/GuestEntitlements.cpp)
|
||||
target_include_directories(guest_entitlements_tests PRIVATE ${CMAKE_CURRENT_SOURCE_DIR})
|
||||
target_link_libraries(guest_entitlements_tests PRIVATE libSceNpEntitlementAccess libc)
|
||||
configure_windows_unwind(guest_entitlements_tests)
|
||||
add_test(NAME guest_entitlements COMMAND guest_entitlements_tests)
|
||||
add_test(NAME guest_entitlements_missing COMMAND guest_entitlements_tests missing)
|
||||
if(WIN32)
|
||||
set_tests_properties(guest_entitlements guest_entitlements_missing PROPERTIES ENVIRONMENT_MODIFICATION
|
||||
"PATH=path_list_prepend:$<TARGET_FILE_DIR:libSceNpEntitlementAccess>")
|
||||
endif()
|
||||
|
||||
add_test_executable(guest_signin_dialog_tests tests/GuestSigninDialog.cpp)
|
||||
target_include_directories(guest_signin_dialog_tests PRIVATE ${CMAKE_CURRENT_SOURCE_DIR})
|
||||
target_link_libraries(guest_signin_dialog_tests PRIVATE libSceSigninDialog libc)
|
||||
@@ -621,6 +641,16 @@ if(BUILD_TESTING)
|
||||
"PATH=path_list_prepend:$<TARGET_FILE_DIR:libSceNpCppWebApi>")
|
||||
endif()
|
||||
|
||||
add_test_executable(guest_np_cpp_web_api_signed_out_tests tests/GuestNpCppWebApiSignedOut.cpp)
|
||||
target_include_directories(guest_np_cpp_web_api_signed_out_tests PRIVATE ${CMAKE_CURRENT_SOURCE_DIR})
|
||||
target_link_libraries(guest_np_cpp_web_api_signed_out_tests PRIVATE libSceNpCppWebApi libc)
|
||||
configure_windows_unwind(guest_np_cpp_web_api_signed_out_tests)
|
||||
add_test(NAME guest_np_cpp_web_api_signed_out COMMAND guest_np_cpp_web_api_signed_out_tests)
|
||||
if(WIN32)
|
||||
set_tests_properties(guest_np_cpp_web_api_signed_out PROPERTIES ENVIRONMENT_MODIFICATION
|
||||
"PATH=path_list_prepend:$<TARGET_FILE_DIR:libSceNpCppWebApi>")
|
||||
endif()
|
||||
|
||||
add_test_executable(savedata_core_write_replacement_tests tests/SaveDataWriteReplacement.cpp)
|
||||
target_include_directories(savedata_core_write_replacement_tests PRIVATE ${CMAKE_CURRENT_SOURCE_DIR})
|
||||
target_link_libraries(savedata_core_write_replacement_tests PRIVATE libSceSaveData)
|
||||
@@ -713,9 +743,11 @@ if(BUILD_TESTING)
|
||||
|
||||
add_test_executable(guest_vorbis_dec_tests tests/GuestVorbisDec.cpp)
|
||||
target_include_directories(guest_vorbis_dec_tests PRIVATE ${CMAKE_CURRENT_SOURCE_DIR})
|
||||
target_link_libraries(guest_vorbis_dec_tests PRIVATE libSceVorbisDec libc)
|
||||
target_compile_definitions(guest_vorbis_dec_tests PRIVATE OV_EXCLUDE_STATIC_CALLBACKS)
|
||||
target_link_libraries(guest_vorbis_dec_tests PRIVATE libSceVorbisDec vorbisenc vorbisfile vorbis ogg libc)
|
||||
configure_windows_unwind(guest_vorbis_dec_tests)
|
||||
add_test(NAME guest_vorbis_dec COMMAND guest_vorbis_dec_tests)
|
||||
set_tests_properties(guest_vorbis_dec PROPERTIES TIMEOUT 30)
|
||||
if(WIN32)
|
||||
set_tests_properties(guest_vorbis_dec PROPERTIES ENVIRONMENT_MODIFICATION
|
||||
"PATH=path_list_prepend:$<TARGET_FILE_DIR:libSceVorbisDec>")
|
||||
|
||||
@@ -267,6 +267,19 @@ if(BUILD_TESTING)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
add_test_executable(agc_instrumentation_query_size_tests EXCLUDE_FROM_ALL tests/InstrumentationQuerySize.cpp)
|
||||
target_include_directories(agc_instrumentation_query_size_tests PRIVATE ${LIBS_INCLUDE_DIR})
|
||||
target_link_libraries(agc_instrumentation_query_size_tests PRIVATE libSceAgc libc)
|
||||
configure_windows_unwind(agc_instrumentation_query_size_tests)
|
||||
if(BUILD_TESTING)
|
||||
set_target_properties(agc_instrumentation_query_size_tests PROPERTIES EXCLUDE_FROM_ALL FALSE)
|
||||
add_test(NAME agc_instrumentation_query_size_tests COMMAND agc_instrumentation_query_size_tests)
|
||||
if(WIN32)
|
||||
set_tests_properties(agc_instrumentation_query_size_tests PROPERTIES ENVIRONMENT_MODIFICATION
|
||||
"PATH=path_list_prepend:$<TARGET_FILE_DIR:libc>")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
add_test_executable(agc_context_state_size_tests EXCLUDE_FROM_ALL tests/ContextStateSize.cpp)
|
||||
target_include_directories(agc_context_state_size_tests PRIVATE ${LIBS_INCLUDE_DIR})
|
||||
target_link_libraries(agc_context_state_size_tests PRIVATE libSceAgc libc)
|
||||
|
||||
@@ -22,13 +22,12 @@ std::uint32_t* APS5_VABI sceAgcDcbGetLodStats(CommandBuffer* buf, std::uint8_t c
|
||||
}
|
||||
|
||||
std::uint32_t APS5_VABI sceAgcDcbBeginOcclusionQueryGetSize(std::int32_t queryType) {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
return 0;
|
||||
if (queryType == 1) return 0x120u;
|
||||
return queryType == 0 ? 0x10u : 0u;
|
||||
}
|
||||
|
||||
std::uint32_t APS5_VABI sceAgcDcbEndOcclusionQueryGetSize() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
return 0;
|
||||
return 0x10u;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,9 +1,16 @@
|
||||
#include "prx/libSceAgc/Misc/include/Debug.hpp"
|
||||
|
||||
#include <atomic>
|
||||
#include <cstdint>
|
||||
#include "SceTypes.hpp"
|
||||
#include "prx/libc/include/General.hpp"
|
||||
|
||||
namespace {
|
||||
|
||||
std::atomic<std::uint32_t> shaderInstrumentation{0};
|
||||
|
||||
}
|
||||
|
||||
extern "C" {
|
||||
|
||||
int APS5_VABI sceAgcDebugRaiseException(std::uint32_t exceptionId) {
|
||||
@@ -11,4 +18,13 @@ int APS5_VABI sceAgcDebugRaiseException(std::uint32_t exceptionId) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int APS5_VABI sceAgcSetShaderInstrumentation(std::uint32_t flags) {
|
||||
shaderInstrumentation.store(flags, std::memory_order_relaxed);
|
||||
return 0;
|
||||
}
|
||||
|
||||
std::uint32_t APS5_VABI sceAgcGetShaderInstrumentation() {
|
||||
return shaderInstrumentation.load(std::memory_order_relaxed);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -53,12 +53,9 @@ std::uint32_t CreateInterpolantValueSplitF16(std::uint32_t psWord, const ShaderS
|
||||
: CreateInterpolantValue(psWord, gsSemantic);
|
||||
}
|
||||
|
||||
std::uint32_t UpdateInterpolantValue(std::uint32_t psWord, const ShaderSemantic* gsSemantic) {
|
||||
const std::uint32_t f16 = (psWord >> 20u) & 0x3u;
|
||||
if (f16 != 0 && f16 != InterpolantF16HiOnly && ((psWord >> 28u) & 0x3u) != ((psWord >> 30u) & 0x3u)) {
|
||||
throw std::runtime_error(std::string(__func__) + ": DEFAULT_VAL of an f16 input with different low and high defaults is unknown");
|
||||
}
|
||||
return CreateInterpolantValueSplitF16(psWord, gsSemantic);
|
||||
std::uint32_t CreateInterpolantValueFlatDefault(std::uint32_t psWord, const ShaderSemantic* gsSemantic) {
|
||||
const std::uint32_t value = CreateInterpolantValue(psWord, gsSemantic);
|
||||
return ((psWord & 0x00700000u) == 0x00400000u) ? (value | 0x00000020u) : value;
|
||||
}
|
||||
|
||||
int CreateInterpolantMapping(const char* fn, ShaderRegister* regs, const Shader* gs, const Shader* ps, CreateInterpolantValueFn createValue, bool fillIdentityTail) {
|
||||
@@ -132,7 +129,15 @@ int APS5_VABI sceAgcCreateInterpolantMapping_10000(ShaderRegister* regs, const S
|
||||
}
|
||||
|
||||
int APS5_VABI sceAgcUpdateInterpolantMapping_10000(ShaderRegister* regs, const Shader* gs, const Shader* ps) {
|
||||
return CreateInterpolantMapping(__func__, regs, gs, ps, UpdateInterpolantValue, false);
|
||||
return CreateInterpolantMapping(__func__, regs, gs, ps, CreateInterpolantValueSplitF16, false);
|
||||
}
|
||||
|
||||
int APS5_VABI sceAgcCreateInterpolantMapping_nid_postfix(ShaderRegister* regs, const Shader* gs, const Shader* ps) {
|
||||
return CreateInterpolantMapping(__func__, regs, gs, ps, CreateInterpolantValueFlatDefault, true);
|
||||
}
|
||||
|
||||
int APS5_VABI sceAgcUpdateInterpolantMapping_nid_postfix(ShaderRegister* regs, const Shader* gs, const Shader* ps) {
|
||||
return CreateInterpolantMapping(__func__, regs, gs, ps, CreateInterpolantValueFlatDefault, false);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -40,14 +40,4 @@ std::uint32_t* APS5_VABI sceAgcCbMemsetExclusive(CommandBuffer* buffer, void* de
|
||||
return 0;
|
||||
}
|
||||
|
||||
int APS5_VABI sceAgcSetShaderInstrumentation(std::uint32_t flags) {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int APS5_VABI sceAgcGetShaderInstrumentation() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
return 0;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
#include "prx/libc/include/general/VabiMacros.hpp"
|
||||
#include "prx/libc/include/Shutdown.hpp"
|
||||
|
||||
#include <cstdint>
|
||||
#include <cstdio>
|
||||
#include <stdexcept>
|
||||
|
||||
extern "C" {
|
||||
int APS5_VABI sceAgcSetShaderInstrumentation(std::uint32_t);
|
||||
std::uint32_t APS5_VABI sceAgcGetShaderInstrumentation();
|
||||
std::uint32_t APS5_VABI sceAgcDcbBeginOcclusionQueryGetSize(std::int32_t);
|
||||
std::uint32_t APS5_VABI sceAgcDcbEndOcclusionQueryGetSize();
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
void check(bool condition, const char* message) {
|
||||
if (!condition) throw std::runtime_error(message);
|
||||
}
|
||||
|
||||
void testShaderInstrumentation() {
|
||||
check(sceAgcGetShaderInstrumentation() == 0, "shader instrumentation starts cleared");
|
||||
check(sceAgcSetShaderInstrumentation(0x80000005u) == 0, "setting shader instrumentation failed");
|
||||
check(sceAgcGetShaderInstrumentation() == 0x80000005u, "shader instrumentation flags were not kept");
|
||||
check(sceAgcSetShaderInstrumentation(0) == 0 && sceAgcGetShaderInstrumentation() == 0, "shader instrumentation was not cleared");
|
||||
}
|
||||
|
||||
void testOcclusionQuerySizes() {
|
||||
check(sceAgcDcbBeginOcclusionQueryGetSize(0) == 0x10u, "begin occlusion query size for type 0");
|
||||
check(sceAgcDcbBeginOcclusionQueryGetSize(1) == 0x120u, "begin occlusion query size for type 1");
|
||||
check(sceAgcDcbBeginOcclusionQueryGetSize(2) == 0, "begin occlusion query size for an unknown type");
|
||||
check(sceAgcDcbEndOcclusionQueryGetSize() == 0x10u, "end occlusion query size");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
int main() {
|
||||
try {
|
||||
testShaderInstrumentation();
|
||||
testOcclusionQuerySizes();
|
||||
LibcRunShutdown_nid_postfix();
|
||||
std::puts("AGC shader instrumentation and occlusion query size tests passed");
|
||||
return 0;
|
||||
} catch (const std::exception& error) {
|
||||
std::fprintf(stderr, "%s\n", error.what());
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
@@ -14,6 +14,8 @@
|
||||
extern "C" int APS5_VABI sceAgcCreateInterpolantMapping_0100(ShaderRegister* regs, const Shader* gs, const Shader* ps);
|
||||
extern "C" int APS5_VABI sceAgcCreateInterpolantMapping_10000(ShaderRegister* regs, const Shader* gs, const Shader* ps);
|
||||
extern "C" int APS5_VABI sceAgcUpdateInterpolantMapping_10000(ShaderRegister* regs, const Shader* gs, const Shader* ps);
|
||||
extern "C" int APS5_VABI sceAgcCreateInterpolantMapping_nid_postfix(ShaderRegister* regs, const Shader* gs, const Shader* ps);
|
||||
extern "C" int APS5_VABI sceAgcUpdateInterpolantMapping_nid_postfix(ShaderRegister* regs, const Shader* gs, const Shader* ps);
|
||||
|
||||
namespace {
|
||||
|
||||
@@ -158,13 +160,46 @@ void testUpdateMapping() {
|
||||
check(std::memcmp(create.data(), update.data(), written) == 0, "update differs from the split f16 mapping");
|
||||
checkIdentity(create, static_cast<std::uint32_t>(inputs.size()), "unused interpolants are not the identity");
|
||||
|
||||
for (const std::uint32_t index : {1u, 3u}) {
|
||||
inputs[index].default_value = 0;
|
||||
update = filled();
|
||||
expectFailure([&] { sceAgcUpdateInterpolantMapping_10000(update.data(), &gs, &ps); });
|
||||
check(std::memcmp(update.data(), untouched.data(), sizeof(update)) == 0, "rejected update wrote registers");
|
||||
inputs[index].default_value = inputs[index].default_value_hi;
|
||||
inputs[1].default_value = 0;
|
||||
inputs[3].default_value = 0;
|
||||
update = filled();
|
||||
check(sceAgcUpdateInterpolantMapping_10000(update.data(), &gs, &ps) == 0, "update with split f16 defaults failed");
|
||||
check(update[1].value == 0x01380007u && update[3].value == 0x03680409u, "f16 DEFAULT_VAL does not come from the low default");
|
||||
}
|
||||
|
||||
void testUnversionedMapping() {
|
||||
std::array<ShaderSemantic, 5> inputs{
|
||||
semantic(1, 0, 2), semantic(2, 0, 2), semantic(5, 0, 2), semantic(3, 0, 0), semantic(4, 0, 3)};
|
||||
inputs[0].is_flat_shaded = 1;
|
||||
inputs[0].default_value = 1;
|
||||
inputs[0].default_value_hi = 3;
|
||||
inputs[1].default_value_hi = 1;
|
||||
inputs[2].is_flat_shaded = 1;
|
||||
inputs[2].default_value_hi = 2;
|
||||
inputs[3].is_flat_shaded = 1;
|
||||
inputs[3].default_value = 2;
|
||||
std::array<ShaderSemantic, 4> outputs{semantic(1, 7, 3), semantic(2, 4, 1), semantic(3, 9, 0), semantic(4, 2, 1)};
|
||||
Shader gs{};
|
||||
gs.output_semantics = outputs.data();
|
||||
gs.num_output_semantics = static_cast<std::uint16_t>(outputs.size());
|
||||
Shader ps{};
|
||||
ps.input_semantics = inputs.data();
|
||||
ps.num_input_semantics = static_cast<std::uint32_t>(inputs.size());
|
||||
const std::array<std::uint32_t, 5> flatDefault{0x02680527u, 0x02380024u, 0x02580020u, 0x00000629u, 0x03180002u};
|
||||
const std::size_t written = inputs.size() * sizeof(ShaderRegister);
|
||||
const auto untouched = filled();
|
||||
|
||||
auto create = filled();
|
||||
check(sceAgcCreateInterpolantMapping_nid_postfix(create.data(), &gs, &ps) == 0, "unversioned mapping failed");
|
||||
for (std::uint32_t i = 0; i < inputs.size(); ++i) {
|
||||
check(create[i].offset == ShaderRegs::SPI_PS_INPUT_CNTL_0 + i && create[i].value == flatDefault[i], "unversioned mapping changed");
|
||||
}
|
||||
checkIdentity(create, static_cast<std::uint32_t>(inputs.size()), "unused interpolants are not the identity");
|
||||
|
||||
auto update = filled();
|
||||
check(sceAgcUpdateInterpolantMapping_nid_postfix(update.data(), &gs, &ps) == 0, "unversioned update failed");
|
||||
check(std::memcmp(update.data(), create.data(), written) == 0, "unversioned update differs from its mapping");
|
||||
check(std::memcmp(update.data() + inputs.size(), untouched.data(), sizeof(update) - written) == 0, "unversioned update wrote past its inputs");
|
||||
}
|
||||
|
||||
void testRejections() {
|
||||
@@ -208,8 +243,9 @@ int main() {
|
||||
testIdentity();
|
||||
testMapping();
|
||||
testUpdateMapping();
|
||||
testUnversionedMapping();
|
||||
testRejections();
|
||||
check(mappings == 7u && links == 5u, "mapping preparation call count changed");
|
||||
check(mappings == 10u && links == 8u, "mapping preparation call count changed");
|
||||
LibcRunShutdown_nid_postfix();
|
||||
std::puts("AGC interpolant mapping tests passed");
|
||||
return 0;
|
||||
|
||||
@@ -433,6 +433,16 @@ if(MINGW OR CMAKE_SYSTEM_NAME STREQUAL "Linux")
|
||||
endif()
|
||||
|
||||
if(BUILD_TESTING)
|
||||
add_test_executable(agc_driver_unsupported_diagnostics_tests tests/UnsupportedDiagnostics.cpp)
|
||||
target_include_directories(agc_driver_unsupported_diagnostics_tests PRIVATE ${LIBS_INCLUDE_DIR})
|
||||
target_link_libraries(agc_driver_unsupported_diagnostics_tests PRIVATE libSceAgcDriver)
|
||||
configure_windows_unwind(agc_driver_unsupported_diagnostics_tests)
|
||||
add_test(NAME agc_driver_unsupported_diagnostics COMMAND agc_driver_unsupported_diagnostics_tests)
|
||||
if(WIN32)
|
||||
set_tests_properties(agc_driver_unsupported_diagnostics PROPERTIES ENVIRONMENT_MODIFICATION
|
||||
"PATH=path_list_prepend:$<TARGET_FILE_DIR:libSceAgcDriver>")
|
||||
endif()
|
||||
|
||||
add_test_executable(agc_driver_draw_program_trace_tests
|
||||
tests/DrawProgramTrace.cpp
|
||||
Execution/src/Driver/Draw/DrawProgramTrace.cpp
|
||||
@@ -459,6 +469,16 @@ if(WIN32)
|
||||
endif()
|
||||
|
||||
if(BUILD_TESTING)
|
||||
add_test_executable(agc_driver_nop_data_packet_tests tests/NopDataWritePacket.cpp)
|
||||
target_include_directories(agc_driver_nop_data_packet_tests PRIVATE ${LIBS_INCLUDE_DIR})
|
||||
target_link_libraries(agc_driver_nop_data_packet_tests PRIVATE libSceAgcDriver)
|
||||
configure_windows_unwind(agc_driver_nop_data_packet_tests)
|
||||
add_test(NAME agc_driver_nop_data_packet COMMAND agc_driver_nop_data_packet_tests)
|
||||
if(WIN32)
|
||||
set_tests_properties(agc_driver_nop_data_packet PROPERTIES ENVIRONMENT_MODIFICATION
|
||||
"PATH=path_list_prepend:$<TARGET_FILE_DIR:libc>")
|
||||
endif()
|
||||
|
||||
add_test_executable(agc_frame_dump_io_tests tests/FrameDumpIo.cpp)
|
||||
target_include_directories(agc_frame_dump_io_tests PRIVATE ${LIBS_INCLUDE_DIR})
|
||||
target_link_libraries(agc_frame_dump_io_tests PRIVATE libc)
|
||||
|
||||
@@ -250,9 +250,10 @@ DrawVerdict Driver::draw(QueueState& queue, std::span<const std::uint32_t> packe
|
||||
if (program.binary.stage == Stage::Fragment || roles[i] == Role::GeometryBack) return;
|
||||
decodeReads[i].clear();
|
||||
vertexInfos[i] = Graphics::DecodeVertexStageInfo(program.binary.header, program.binary.headerAddress, program.userData, &decodeReads[i], false, 8u - program.firstUserSgpr);
|
||||
if (vertexInfos[i]) vertexInfos[i]->paClVsOutCntl = PositionExportLayout(program.snapshot.get(), program.codeOffset, program.binary.code, readRegister(queue.context, 0x207), program.tailContinuation.get()) | graphics.layerExports;
|
||||
if (vertexInfos[i]) {
|
||||
vertexInfos[i]->paClVsOutCntl = PositionExportLayout(program.snapshot.get(), program.codeOffset, program.binary.code, readRegister(queue.context, 0x207), program.tailContinuation.get()) | graphics.layerExports;
|
||||
vertexInfos[i]->depthRemapMode = graphics.depthRemap.mode;
|
||||
Graphics::ApplyPointSize(graphics, *vertexInfos[i]);
|
||||
}
|
||||
};
|
||||
if (!registerKey) {
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
#include "prx/libSceAgcDriver/Execution/include/Driver/Diagnostics.hpp"
|
||||
#include "prx/libSceAgcDriver/Execution/include/GuestMemory.hpp"
|
||||
#include <algorithm>
|
||||
#include <bit>
|
||||
|
||||
namespace AgcDriver::DriverDetail {
|
||||
|
||||
@@ -51,6 +52,10 @@ void Driver::lookupDraw(const Submission& submission, const std::shared_ptr<Vulk
|
||||
mix(vertex.fetchBufferReg);
|
||||
mix(vertex.fetchEmbedded);
|
||||
mix(vertex.paClVsOutCntl);
|
||||
mix(vertex.pointList);
|
||||
mix(std::bit_cast<std::uint32_t>(vertex.pointSize));
|
||||
mix(std::bit_cast<std::uint32_t>(vertex.pointSizeMin));
|
||||
mix(std::bit_cast<std::uint32_t>(vertex.pointSizeMax));
|
||||
for (std::uint32_t r = 0; r < vertex.resourcesNum; ++r) {
|
||||
for (const auto field : vertex.resources[r].fields) mix(field);
|
||||
const auto& destination = vertex.resourcesDst[r];
|
||||
|
||||
@@ -213,7 +213,7 @@ void Driver::traceDrawKeyLookup(const std::array<std::uint64_t, 5>& components,
|
||||
}
|
||||
|
||||
bool Driver::sameVertexInfo(const ShaderRecompiler::ShaderVertexStageInfo& a, const ShaderRecompiler::ShaderVertexStageInfo& b) {
|
||||
if (a.resourcesNum != b.resourcesNum || a.fetchAttribReg != b.fetchAttribReg || a.fetchBufferReg != b.fetchBufferReg || a.fetchEmbedded != b.fetchEmbedded || a.paClVsOutCntl != b.paClVsOutCntl) return false;
|
||||
if (a.resourcesNum != b.resourcesNum || a.fetchAttribReg != b.fetchAttribReg || a.fetchBufferReg != b.fetchBufferReg || a.fetchEmbedded != b.fetchEmbedded || a.paClVsOutCntl != b.paClVsOutCntl || a.pointList != b.pointList || a.pointSize != b.pointSize || a.pointSizeMin != b.pointSizeMin || a.pointSizeMax != b.pointSizeMax) return false;
|
||||
if (a.depthRemapMode != b.depthRemapMode) return false;
|
||||
for (std::uint32_t i = 0; i < a.resourcesNum && i < a.resources.size(); ++i) {
|
||||
if (a.resources[i].fields != b.resources[i].fields) return false;
|
||||
|
||||
@@ -1440,7 +1440,10 @@ std::vector<PreparedGraphicsStage> PrepareGraphicsStages(const DrawDecode& decod
|
||||
prepared.push_back({program.snapshot, {program.codeOffset, nullptr}, program.binary.stage, offset, nullptr});
|
||||
continue;
|
||||
}
|
||||
if (vertex) vertex->paClVsOutCntl = PositionExportLayout(program.snapshot.get(), program.codeOffset, program.binary.code, decoded.state.paClVsOutCntl, program.tailContinuation.get()) | decoded.state.layerExports;
|
||||
if (vertex) {
|
||||
vertex->paClVsOutCntl = PositionExportLayout(program.snapshot.get(), program.codeOffset, program.binary.code, decoded.state.paClVsOutCntl, program.tailContinuation.get()) | decoded.state.layerExports;
|
||||
Graphics::ApplyPointSize(decoded.state, *vertex);
|
||||
}
|
||||
ShaderRecompiler::RecompileRequest request{program.binary, {wave, program.firstUserSgpr, program.userData, {}, fragment ? std::optional(decoded.pixel) : std::nullopt, vertex, memory, RegisteredFloatMode(*program.snapshot)}, target, {0, 0, offset, room}, ShaderRecompiler::GraphicsCompileContext{program.firstUserSgpr, linked, decoded.state.stages.mesh, decoded.state.stages.tessellation, {}}};
|
||||
std::vector<std::uint64_t> key;
|
||||
ShaderRecompiler::BuildPreparedShaderKey(request, key);
|
||||
|
||||
@@ -16,8 +16,12 @@ namespace {
|
||||
std::atomic<bool> requested{false};
|
||||
|
||||
std::filesystem::path directory() {
|
||||
#ifdef _WIN32
|
||||
const wchar_t* configured = _wgetenv(L"ANYPS5_SCREENSHOTS");
|
||||
#else
|
||||
const char* configured = std::getenv("ANYPS5_SCREENSHOTS");
|
||||
if (configured != nullptr && configured[0] != '\0') return configured;
|
||||
#endif
|
||||
if (configured != nullptr && configured[0] != 0) return configured;
|
||||
const std::unique_ptr<char, decltype(&SDL_free)> basePath(SDL_GetBasePath(), SDL_free);
|
||||
if (!basePath) throw std::runtime_error(std::string("Screenshot: cannot locate the executable: ") + SDL_GetError());
|
||||
return std::filesystem::path(reinterpret_cast<const char8_t*>(basePath.get())) / "anyps5-screenshots";
|
||||
|
||||
@@ -316,6 +316,7 @@ struct VulkanDevice::State {
|
||||
bool fragmentShaderBarycentric = false;
|
||||
bool shaderTerminateInvocation = false;
|
||||
bool geometryShader = false;
|
||||
bool largePoints = false;
|
||||
bool sampleRateShading = false;
|
||||
bool storageImageMultisample = false;
|
||||
bool storageImageWriteWithoutFormat = false;
|
||||
@@ -1718,6 +1719,8 @@ VulkanDevice::VulkanDevice(const PresentationWindow* window, bool compileOnly) :
|
||||
enabled.sampleRateShading = available.sampleRateShading;
|
||||
enabled.geometryShader = available.geometryShader;
|
||||
state->geometryShader = enabled.geometryShader == VK_TRUE;
|
||||
enabled.largePoints = available.largePoints;
|
||||
state->largePoints = enabled.largePoints == VK_TRUE;
|
||||
state->sampleRateShading = enabled.sampleRateShading == VK_TRUE;
|
||||
if (enabled.sampleRateShading) state->capabilities.push_back(spv::CapabilityInterpolationFunction);
|
||||
if (enabled.geometryShader) state->capabilities.push_back(spv::CapabilityGeometry);
|
||||
@@ -3847,6 +3850,7 @@ Graphics::Context VulkanDevice::buildContext() const {
|
||||
context.imageTableUpdateAfterBind = ImageTableUpdateAfterBind(context);
|
||||
context.samplerTableUpdateAfterBind = SamplerTableUpdateAfterBind(context);
|
||||
context.geometryShader = state->geometryShader;
|
||||
context.largePoints = state->largePoints;
|
||||
context.sampleRateShading = state->sampleRateShading;
|
||||
context.fillModeNonSolid = state->fillModeNonSolid;
|
||||
context.maintenance5 = state->maintenance5;
|
||||
|
||||
@@ -239,6 +239,7 @@ struct Context {
|
||||
bool imageTableUpdateAfterBind = false;
|
||||
bool samplerTableUpdateAfterBind = false;
|
||||
bool geometryShader = false;
|
||||
bool largePoints = false;
|
||||
bool sampleRateShading = false;
|
||||
bool fillModeNonSolid = false;
|
||||
bool maintenance5 = false;
|
||||
|
||||
@@ -156,6 +156,10 @@ struct State {
|
||||
bool customSampleLocations = false;
|
||||
bool sampleLocationGrid = false;
|
||||
std::uint32_t paClVsOutCntl = 0;
|
||||
bool vertexPoints = false;
|
||||
float pointSize = 1.0f;
|
||||
float pointSizeMin = 0.0f;
|
||||
float pointSizeMax = 0.0f;
|
||||
std::array<std::uint16_t, 4> quadSampleMask{0xffffu, 0xffffu, 0xffffu, 0xffffu};
|
||||
bool pixelEarlyZ = false;
|
||||
};
|
||||
@@ -165,6 +169,7 @@ struct State {
|
||||
inline constexpr std::uint32_t PositionExportLayoutBits = 0xffffu | (1u << 21u) | (1u << 22u) | (1u << 23u);
|
||||
|
||||
ShaderStages DecodeShaderStages(const QueueState& queue, bool vertexWorkgroup = false);
|
||||
void ApplyPointSize(const State& state, ShaderRecompiler::ShaderVertexStageInfo& vertex);
|
||||
State DecodeState(const QueueState& queue, bool vertexWorkgroup = false);
|
||||
void ApplyDepthRemap(const Context& context, State& state);
|
||||
void NormalizeUnusedViewportDepth(State& state, const ShaderRecompiler::ShaderPixelStageInfo& pixel);
|
||||
|
||||
@@ -671,6 +671,7 @@ bool ValidationKey(const Context& context, std::span<const CompiledShader> shade
|
||||
add(context.viewportIndexLayer);
|
||||
add(context.shaderTerminateInvocation);
|
||||
add(state.paClVsOutCntl);
|
||||
add(state.vertexPoints);
|
||||
add(state.stages.mesh.has_value());
|
||||
if (state.stages.mesh) {
|
||||
const auto& mesh = *state.stages.mesh;
|
||||
|
||||
@@ -5,6 +5,8 @@
|
||||
#include "prx/libSceAgcDriver/Graphics/include/TextureFormat.hpp"
|
||||
#include "RdnaDecoder/RdnaDescriptorFormat.hpp"
|
||||
#include <algorithm>
|
||||
#include <array>
|
||||
#include <optional>
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
|
||||
@@ -50,6 +52,45 @@ TextureDimension resolveDimension(std::uint32_t raw) {
|
||||
}
|
||||
}
|
||||
|
||||
bool ZeroTail(std::span<const std::uint32_t> words) {
|
||||
return words[4] == 0u && words[5] == 0u && words[6] == 0u && words[7] == 0u;
|
||||
}
|
||||
|
||||
bool SameLevels(const TileMipLayout& a, const TileMipLayout& b) {
|
||||
return a.tiledOffset == b.tiledOffset && a.tiledSize == b.tiledSize && a.width == b.width && a.height == b.height && a.blocksPerRow == b.blocksPerRow && a.pitchBytes == b.pitchBytes && a.tail == b.tail && a.tailX == b.tailX && a.tailY == b.tailY;
|
||||
}
|
||||
|
||||
std::optional<std::array<std::uint32_t, 8>> R128ResidentLevelWords(std::span<const std::uint32_t> words) {
|
||||
const auto baseLevel = (words[3] >> 12u) & 0xfu;
|
||||
const auto lastLevel = (words[3] >> 16u) & 0xfu;
|
||||
const auto typeRaw = (words[3] >> 28u) & 0xfu;
|
||||
if (baseLevel == 0u || baseLevel > lastLevel || (typeRaw != 8u && typeRaw != 9u)) return std::nullopt;
|
||||
const std::array<std::uint32_t, 8> chainWords{words[0], words[1], words[2], words[3], 0u, lastLevel << 4u, 0u, 0u};
|
||||
const auto width = (((words[1] >> 30u) & 0x3u) | ((words[2] & 0xfffu) << 2u)) + 1u;
|
||||
const auto height = ((words[2] >> 14u) & 0x3fffu) + 1u;
|
||||
const auto minLod = (words[1] >> 8u) & 0xfffu;
|
||||
const auto widthMinus1 = std::max(width >> baseLevel, 1u) - 1u;
|
||||
const auto heightMinus1 = std::max(height >> baseLevel, 1u) - 1u;
|
||||
const auto rebasedMinLod = minLod > baseLevel * 256u ? minLod - baseLevel * 256u : 0u;
|
||||
const auto levels = lastLevel - baseLevel;
|
||||
auto rebased = chainWords;
|
||||
rebased[1] = (words[1] & ~((0xfffu << 8u) | (0x3u << 30u))) | (rebasedMinLod << 8u) | ((widthMinus1 & 0x3u) << 30u);
|
||||
rebased[2] = (words[2] & ~(0xfffu | (0x3fffu << 14u))) | ((widthMinus1 >> 2u) & 0xfffu) | ((heightMinus1 & 0x3fffu) << 14u);
|
||||
rebased[3] = (words[3] & ~(0xffu << 12u)) | (levels << 16u);
|
||||
rebased[5] = levels << 4u;
|
||||
try {
|
||||
const auto chain = DescribeSurface(DecodeTextureResource(chainWords));
|
||||
const auto view = DescribeSurface(DecodeTextureResource(rebased));
|
||||
if (chain.mips.size() != lastLevel + 1u || view.mips.size() != levels + 1u || chain.layers != view.layers) return std::nullopt;
|
||||
for (std::uint32_t level = baseLevel; level <= lastLevel; ++level) {
|
||||
if (!SameLevels(chain.mips[level], view.mips[level - baseLevel])) return std::nullopt;
|
||||
}
|
||||
} catch (const std::exception&) {
|
||||
return std::nullopt;
|
||||
}
|
||||
return rebased;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
bool IsNullTextureResource(std::span<const std::uint32_t> words) {
|
||||
@@ -238,7 +279,11 @@ GuestTextureResource DecodeTextureResource(std::span<const std::uint32_t> words)
|
||||
result.minLod = minLod;
|
||||
result.samples = samples;
|
||||
if (baseLevel > maxMip) {
|
||||
Require(LevelsFitAllocation(result, lastLevel + 1u), "guest texture descriptor starts past the surface's last mip level at levels that would move the surface's own" + describe());
|
||||
const bool fits = LevelsFitAllocation(result, lastLevel + 1u);
|
||||
if (!fits && ZeroTail(words)) {
|
||||
if (const auto resident = R128ResidentLevelWords(words)) return DecodeTextureResource(*resident);
|
||||
}
|
||||
Require(fits, "guest texture descriptor starts past the surface's last mip level at levels that would move the surface's own" + describe());
|
||||
result.mipCount = lastLevel + 1u;
|
||||
}
|
||||
return result;
|
||||
|
||||
@@ -347,6 +347,7 @@ Pipeline::Pipeline(const Context& context, const State& state, const VertexInput
|
||||
Require(!state.negativeOneToOne || context.depthClipControl, "negative-one-to-one depth clipping requires VK_EXT_depth_clip_control with depthClipControl enabled");
|
||||
Require(!state.perSampleShading || context.sampleRateShading, "per-sample pixel shading requires the sampleRateShading device feature");
|
||||
Require(!state.mergedCoverage || (context.mergedCoverageSampleCounts & state.samples) != 0, "an overrasterized draw (a multisampled rasterizer into one-sample color targets) requires VK_NV_framebuffer_mixed_samples with merged coverage reduction");
|
||||
Require(!(state.vertexPoints || (state.stages.mesh.has_value() && state.stages.mesh->outputPrimitiveSize == 1u)) || context.largePoints || (state.pointSize == 1.0f && ((state.paClVsOutCntl & (1u << 16u)) == 0 || (state.pointSizeMin == 1.0f && state.pointSizeMax == 1.0f))), "points of a size other than one pixel require the largePoints device feature");
|
||||
Require(!state.truncatedCoverage || (context.truncatedCoverageSampleCounts & state.samples) != 0, "one-sample color targets beside a multisampled depth target require VK_AMD_mixed_attachment_samples or VK_NV_framebuffer_mixed_samples with truncated coverage reduction");
|
||||
Require(state.conservativeRasterization == VK_CONSERVATIVE_RASTERIZATION_MODE_DISABLED_EXT || context.conservativeRasterization, "conservative rasterization requires VK_EXT_conservative_rasterization with at most 1/256 pixel of overestimation and degenerate triangles rasterized");
|
||||
ValidateProvokingVertex(context, state, shaders);
|
||||
|
||||
@@ -35,7 +35,7 @@ static_assert(sizeof(VkStencilOpState) == 28, "VkStencilOpState changed: update
|
||||
static_assert(sizeof(VkVertexInputBindingDescription) == 12, "VkVertexInputBindingDescription changed: update the recipe codec");
|
||||
static_assert(sizeof(VkVertexInputAttributeDescription) == 16, "VkVertexInputAttributeDescription changed: update the recipe codec");
|
||||
#if defined(__linux__) && defined(__x86_64__) && defined(__GLIBCXX__)
|
||||
static_assert(sizeof(State) == 808, "State changed: update CanonicalPipelineState and the recipe codec");
|
||||
static_assert(sizeof(State) == 824, "State changed: update CanonicalPipelineState and the recipe codec");
|
||||
static_assert(sizeof(ShaderStages) == 112, "ShaderStages changed: update the recipe codec");
|
||||
static_assert(sizeof(ShaderRecompiler::MeshConfiguration) == 40, "MeshConfiguration changed: update the recipe codec");
|
||||
static_assert(sizeof(ShaderRecompiler::TessellationConfiguration) == 40, "TessellationConfiguration changed: update the recipe codec");
|
||||
@@ -44,7 +44,7 @@ static_assert(sizeof(ShaderRecompiler::TessellationConfiguration) == 40, "Tessel
|
||||
constexpr std::uint32_t FileMagic = 0x4c4a5041u;
|
||||
// Bumped when the recipe codec, CanonicalPipelineState or the store key change in a way the
|
||||
// layout guards above do not catch (a field renumbered or reinterpreted at the same size).
|
||||
constexpr std::uint32_t FileFormat = 7u;
|
||||
constexpr std::uint32_t FileFormat = 8u;
|
||||
constexpr std::uint32_t ModuleRecord = 1u;
|
||||
constexpr std::uint32_t GraphicsRecord = 2u;
|
||||
constexpr std::uint32_t ComputeRecord = 3u;
|
||||
@@ -220,6 +220,10 @@ void encodeState(Writer& writer, const State& state) {
|
||||
writer.Bool(state.truncatedCoverage);
|
||||
for (const auto mask : state.quadSampleMask) writer.Raw(mask);
|
||||
writer.U32(state.depthRemap.mode);
|
||||
writer.Bool(state.vertexPoints);
|
||||
writer.Raw(state.pointSize);
|
||||
writer.Raw(state.pointSizeMin);
|
||||
writer.Raw(state.pointSizeMax);
|
||||
}
|
||||
|
||||
void decodeState(Reader& reader, State& state) {
|
||||
@@ -282,6 +286,10 @@ void decodeState(Reader& reader, State& state) {
|
||||
state.truncatedCoverage = reader.Bool();
|
||||
for (auto& mask : state.quadSampleMask) mask = reader.Raw<std::uint16_t>();
|
||||
state.depthRemap.mode = reader.U32();
|
||||
state.vertexPoints = reader.Bool();
|
||||
state.pointSize = reader.Raw<float>();
|
||||
state.pointSizeMin = reader.Raw<float>();
|
||||
state.pointSizeMax = reader.Raw<float>();
|
||||
}
|
||||
|
||||
void encodeRecipe(Writer& writer, const GraphicsPipelineRecipe& recipe) {
|
||||
@@ -1056,6 +1064,10 @@ State CanonicalPipelineState(const State& state) {
|
||||
canonical.truncatedCoverage = state.truncatedCoverage;
|
||||
canonical.quadSampleMask = state.quadSampleMask;
|
||||
canonical.depthRemap.mode = state.depthRemap.mode;
|
||||
canonical.vertexPoints = state.vertexPoints;
|
||||
canonical.pointSize = state.pointSize;
|
||||
canonical.pointSizeMin = state.pointSizeMin;
|
||||
canonical.pointSizeMax = state.pointSizeMax;
|
||||
return canonical;
|
||||
}
|
||||
|
||||
|
||||
@@ -53,6 +53,8 @@ struct Module {
|
||||
bool layerOutput = false;
|
||||
bool meshCapability = false;
|
||||
std::uint32_t primitiveInputs = 0;
|
||||
bool pointSizeOutput = false;
|
||||
bool pointSize = false;
|
||||
std::map<std::uint32_t, std::vector<std::uint32_t>> modes;
|
||||
|
||||
const std::vector<std::uint32_t>& Type(std::uint32_t id) const {
|
||||
@@ -138,6 +140,10 @@ struct Module {
|
||||
Require(input && (clipInput || (value == spv::BuiltInPosition && signature == "f32x4") || (value == spv::BuiltInTessCoord && stage == Stage::TessellationEvaluation && signature == "f32x3") || ((value == spv::BuiltInInvocationId || value == spv::BuiltInPrimitiveId || value == spv::BuiltInPatchVertices) && (signature == "i32" || signature == "u32"))), "unsupported tessellation built-in");
|
||||
return;
|
||||
}
|
||||
if (!input && value == spv::BuiltInPointSize && pointSizeOutput && signature == "f32" && !pointSize) {
|
||||
pointSize = true;
|
||||
return;
|
||||
}
|
||||
if (!input && value == spv::BuiltInPrimitivePointIndicesEXT) primitiveIndices = 1u;
|
||||
if (!input && value == spv::BuiltInPrimitiveLineIndicesEXT) primitiveIndices = 2u;
|
||||
if (!input && value == spv::BuiltInPrimitiveTriangleIndicesEXT) primitiveIndices = 3u;
|
||||
@@ -149,6 +155,10 @@ struct Module {
|
||||
Require((value == spv::BuiltInVertexIndex || value == spv::BuiltInInstanceIndex || value == spv::BuiltInBaseInstance) && signature == "i32", "unsupported vertex built-in input");
|
||||
} else if (vertex && storage == spv::StorageClassOutput) {
|
||||
if (value == spv::BuiltInLayer && layerOutput && (signature == "u32" || signature == "i32")) return;
|
||||
if (value == spv::BuiltInPointSize && pointSizeOutput && signature == "f32" && !pointSize) {
|
||||
pointSize = true;
|
||||
return;
|
||||
}
|
||||
Require(value == spv::BuiltInPosition && signature == "f32x4" && !position, "unsupported or duplicate vertex built-in output");
|
||||
position = true;
|
||||
} else {
|
||||
@@ -186,6 +196,7 @@ Module Inspect(const CompiledShader& compiled, const State& state, const VkPhysi
|
||||
Require(words[4] == 0, "unsupported SPIR-V schema: " + std::to_string(words[4]));
|
||||
|
||||
Module module;
|
||||
module.pointSizeOutput = (state.vertexPoints && stage == Stage::Vertex) || (mesh && state.stages.mesh.has_value() && state.stages.mesh->outputPrimitiveSize == 1u);
|
||||
std::uint32_t entries = 0;
|
||||
std::uint32_t memoryModels = 0;
|
||||
std::uint32_t entryPoint = 0;
|
||||
|
||||
@@ -190,6 +190,37 @@ std::uint32_t inactiveVertexPointSize(const QueueState& queue) {
|
||||
}
|
||||
}
|
||||
|
||||
bool pointOutput(const QueueState& queue) {
|
||||
const auto stages = find(queue.context, 0x2d5);
|
||||
const auto primitive = find(queue.userConfig, 0x242, RegisterBank::UserConfig);
|
||||
if (stages == queue.context.end()) return false;
|
||||
if ((stages->second & 0x24u) == 0) return primitive != queue.userConfig.end() && primitive->second == 1u;
|
||||
const auto output = find(queue.context, 0x29b);
|
||||
return (stages->second & 0x24u) == 0x20u && output != queue.context.end() && output->second == 0u;
|
||||
}
|
||||
|
||||
void decodePointSize(const QueueState& queue, State& result) {
|
||||
const auto& cx = queue.context;
|
||||
const auto size = read(cx, 0x280);
|
||||
const auto limits = read(cx, 0x281);
|
||||
const bool fromVertex = (result.paClVsOutCntl & (1u << 16u)) != 0;
|
||||
Require(!fromVertex || (result.paClVsOutCntl & (1u << 21u)) != 0, "USE_VTX_POINT_SIZE without VS_OUT_MISC_VEC_ENA is unsupported");
|
||||
Require(fromVertex || (size & 0xffffu) == size >> 16u, "points whose PA_SU_POINT_SIZE width and height differ are unsupported");
|
||||
Require(fromVertex || (size & 0xffffu) != 0, "points of size 0 (PA_SU_POINT_SIZE 0) are unsupported");
|
||||
Require((limits & 0xffffu) <= limits >> 16u, "PA_SU_POINT_MINMAX with a minimum above its maximum is unsupported");
|
||||
Require(!fromVertex || (limits >> 16u) != 0, "a vertex point size clamped to 0 (PA_SU_POINT_MINMAX maximum 0) is unsupported");
|
||||
result.pointSize = static_cast<float>(size & 0xffffu) / 8.0f;
|
||||
result.pointSizeMin = static_cast<float>(limits & 0xffffu) / 8.0f;
|
||||
result.pointSizeMax = static_cast<float>(limits >> 16u) / 8.0f;
|
||||
const auto interpolation = find(cx, 0x1b5);
|
||||
const auto inputs = find(cx, 0x1b6);
|
||||
if (interpolation == cx.end() || (interpolation->second & 2u) == 0 || inputs == cx.end()) return;
|
||||
for (std::uint32_t input = 0; input < (inputs->second & 0x3fu); ++input) {
|
||||
const auto control = find(cx, 0x191 + input);
|
||||
Require(control == cx.end() || (control->second & 0x820000u) == 0, "point sprite texture coordinates (SPI_PS_INPUT_CNTL PT_SPRITE_TEX) are not implemented");
|
||||
}
|
||||
}
|
||||
|
||||
constexpr std::uint32_t DepthControlMask = ~0x007007f0u;
|
||||
// EXEC_ON_HIER_FAIL / EXEC_ON_NOOP / EXEC_IF_OVERLAPPED (bits 9, 10, 17) only force the pixel shader
|
||||
// to run, which it always does here.
|
||||
@@ -1082,6 +1113,15 @@ std::array<std::uint8_t, 32> PixelSampleLocations(const State& state, const Shad
|
||||
return locations;
|
||||
}
|
||||
|
||||
void ApplyPointSize(const State& state, ShaderRecompiler::ShaderVertexStageInfo& vertex) {
|
||||
if (!state.vertexPoints && !(state.stages.mesh.has_value() && state.stages.mesh->outputPrimitiveSize == 1u)) return;
|
||||
vertex.paClVsOutCntl |= state.paClVsOutCntl & (1u << 16u);
|
||||
vertex.pointList = true;
|
||||
vertex.pointSize = state.pointSize;
|
||||
vertex.pointSizeMin = state.pointSizeMin;
|
||||
vertex.pointSizeMax = state.pointSizeMax;
|
||||
}
|
||||
|
||||
ShaderStages DecodeShaderStages(const QueueState& queue, bool vertexWorkgroup) {
|
||||
const auto value = read(queue.context, 0x2d5);
|
||||
const auto validate = [&](bool condition, const char* reason) {
|
||||
@@ -1256,7 +1296,11 @@ State DecodeState(const QueueState& queue, bool vertexWorkgroup) {
|
||||
const auto primitive = read(queue.userConfig, 0x242, RegisterBank::UserConfig);
|
||||
APS5_LOG_OUT_DEBUG("DecodeState primitive=%u path=%u vertexWave=%u", primitive, static_cast<unsigned>(result.stages.path), result.stages.vertexWaveSize);
|
||||
switch (primitive) {
|
||||
case 1: Require(result.stages.mesh.has_value(), "point-list vertex rendering requires point-size output support"); result.topology = VK_PRIMITIVE_TOPOLOGY_POINT_LIST; break;
|
||||
case 1:
|
||||
Require(result.stages.mesh.has_value() || result.stages.path == ShaderPath::Vertex, "point lists are only drawn through the vertex and geometry paths");
|
||||
result.topology = VK_PRIMITIVE_TOPOLOGY_POINT_LIST;
|
||||
result.vertexPoints = result.stages.path == ShaderPath::Vertex;
|
||||
break;
|
||||
case 2: result.topology = VK_PRIMITIVE_TOPOLOGY_LINE_LIST; break;
|
||||
case 3: result.topology = VK_PRIMITIVE_TOPOLOGY_LINE_STRIP; break;
|
||||
case 7:
|
||||
@@ -1281,9 +1325,10 @@ State DecodeState(const QueueState& queue, bool vertexWorkgroup) {
|
||||
}
|
||||
APS5_LOG_OUT_DEBUG("Topology=%u", static_cast<unsigned>(result.topology));
|
||||
result.primitiveRestart = read(queue.userConfig, 0x24b, RegisterBank::UserConfig) != 0 && !result.rectList && !result.quadList && result.topology != VK_PRIMITIVE_TOPOLOGY_PATCH_LIST;
|
||||
zero(cx, 0x207, ~(LayerExports | ClipCullExports | inactiveVertexPointSize(queue)), "layer, viewport or auxiliary vertex exports");
|
||||
zero(cx, 0x207, ~(LayerExports | ClipCullExports | ((result.vertexPoints || (result.stages.mesh.has_value() && result.stages.mesh->outputPrimitiveSize == 1u)) ? 1u << 16u : inactiveVertexPointSize(queue))), "layer, viewport or auxiliary vertex exports");
|
||||
Require(std::popcount(read(cx, 0x207) & 0xffffu) <= 8, "more than eight clip and cull distances are unsupported");
|
||||
result.paClVsOutCntl = read(cx, 0x207);
|
||||
if (result.vertexPoints || (result.stages.mesh.has_value() && result.stages.mesh->outputPrimitiveSize == 1u)) decodePointSize(queue, result);
|
||||
result.samples = decodeSamples(cx);
|
||||
Require(coveredCentroidSupported(queue), "COVERED_CENTROID_IS_CENTER with active or unspecified centroid inputs is not implemented");
|
||||
decodeSampleLocations(cx, result);
|
||||
@@ -2053,7 +2098,7 @@ std::string DrawRejection(const QueueState& queue, bool indexed) {
|
||||
if (value(queue.userConfig, 0x242, primitive) && (primitive & 0x3fu) != 1 && (primitive & 0x3fu) != 2 && (primitive & 0x3fu) != 3 && (primitive & 0x3fu) != 4 && (primitive & 0x3fu) != 5 && (primitive & 0x3fu) != 6 && (primitive & 0x3fu) != 21) return "AGC graphics: primitive restart is only supported for point, line and triangle topologies";
|
||||
if (value(cx, 0x103, resetIndex) && (resetIndex & 0xffffu) != 0xffffu) return "AGC graphics: primitive restart index other than all ones is unsupported";
|
||||
}
|
||||
if (auto reason = nonzero(cx, 0x207, ~(LayerExports | ClipCullExports | inactiveVertexPointSize(queue)), "layer, viewport or auxiliary vertex exports"); !reason.empty()) return reason;
|
||||
if (auto reason = nonzero(cx, 0x207, ~(LayerExports | ClipCullExports | (pointOutput(queue) ? 1u << 16u : inactiveVertexPointSize(queue))), "layer, viewport or auxiliary vertex exports"); !reason.empty()) return reason;
|
||||
if (value(cx, 0x207, word) && std::popcount(word & 0xffffu) > 8) return require(false, "more than eight clip and cull distances are unsupported");
|
||||
if (value(cx, 0x200, word)) {
|
||||
const auto renderControl = find(cx, 0x000);
|
||||
|
||||
@@ -5,6 +5,12 @@
|
||||
#include "SceTypes.hpp"
|
||||
#include "prx/libc/include/General.hpp"
|
||||
|
||||
namespace {
|
||||
|
||||
constexpr int CAPTURE_UNAVAILABLE = static_cast<int>(0x8A6C1000);
|
||||
|
||||
}
|
||||
|
||||
extern "C" {
|
||||
|
||||
bool APS5_VABI sceAgcDriverIsCaptureInProgress(void) {
|
||||
@@ -21,18 +27,15 @@ bool APS5_VABI sceAgcDriverIsSubmitValidationEnabled(void) {
|
||||
|
||||
int APS5_VABI sceAgcDriverRequestCaptureStart(const char* path) {
|
||||
(void)path;
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
return 0;
|
||||
return CAPTURE_UNAVAILABLE;
|
||||
}
|
||||
|
||||
int APS5_VABI sceAgcDriverRequestCaptureStop() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
return 0;
|
||||
return CAPTURE_UNAVAILABLE;
|
||||
}
|
||||
|
||||
int APS5_VABI sceAgcDriverTriggerCapture() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
return 0;
|
||||
return CAPTURE_UNAVAILABLE;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -57,6 +57,17 @@ int APS5_VABI sceAgcDriverGetHsOffchipParam(uint16_t* first, uint16_t* second) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int APS5_VABI sceAgcDriverNopDataWritePacket(void* destination, uint32_t address, const void* data, uint32_t bytes) {
|
||||
const auto alignedBytes = (static_cast<std::uint64_t>(bytes) + 3) & ~std::uint64_t{3};
|
||||
const auto totalBytes = alignedBytes + 8;
|
||||
std::memset(destination, 0, static_cast<std::size_t>(totalBytes));
|
||||
const auto header = (static_cast<std::uint32_t>(totalBytes) << 14) + 0x3ffe0000U | 0xc0001000U;
|
||||
std::memcpy(destination, &header, sizeof(header));
|
||||
std::memcpy(static_cast<std::byte*>(destination) + 4, &address, sizeof(address));
|
||||
if (data != nullptr && bytes != 0) std::memcpy(static_cast<std::byte*>(destination) + 8, data, bytes);
|
||||
return data == nullptr || bytes == 0 ? 2 : static_cast<int>(totalBytes / 4);
|
||||
}
|
||||
|
||||
|
||||
int APS5_VABI sceAgcDriverSetValidationDisabled() {
|
||||
return DEBUG_UNAVAILABLE;
|
||||
@@ -154,9 +165,8 @@ int APS5_VABI sceAgcDriverAcquireHDRScopesACQ() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int APS5_VABI sceAgcDriverGetCoredumpAddress() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
return 0;
|
||||
void* APS5_VABI sceAgcDriverGetCoredumpAddress() {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
int APS5_VABI sceAgcDriverHp3dLockEnd() {
|
||||
@@ -174,19 +184,13 @@ int APS5_VABI sceAgcDriverIsEsvmProcess() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int APS5_VABI sceAgcDriverNopDataWritePacket() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int APS5_VABI sceAgcDriverReleaseHDRScopesACQ() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int APS5_VABI sceAgcDriverSetTargetRingForDiag() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
return 0;
|
||||
return DRIVER_FEATURE_UNAVAILABLE;
|
||||
}
|
||||
|
||||
int APS5_VABI sceAgcDriverSetValueToSharedGds() {
|
||||
|
||||
@@ -163,9 +163,15 @@ void inactiveVertexPointSizeTests() {
|
||||
}
|
||||
throw std::runtime_error("potentially active point size passed the state decoder");
|
||||
};
|
||||
for (const auto primitive : {1u, 9u}) {
|
||||
{
|
||||
auto queue = pointSizeState();
|
||||
queue.userConfig[0x242] = primitive;
|
||||
queue.userConfig[0x242] = 9;
|
||||
rejected(queue);
|
||||
}
|
||||
{
|
||||
auto queue = pointSizeState();
|
||||
queue.userConfig[0x242] = 1;
|
||||
queue.context[0x2d5] = 0x2020;
|
||||
rejected(queue);
|
||||
}
|
||||
for (const auto stages : {0x2004u, 0x2020u}) {
|
||||
@@ -222,6 +228,73 @@ void PolygonPrimitiveTests() {
|
||||
Require(indexedState.topology == VK_PRIMITIVE_TOPOLOGY_TRIANGLE_FAN && indexedState.primitiveRestart, "indexed polygon decoding did not keep primitive restart");
|
||||
}
|
||||
|
||||
void vertexPointListTests() {
|
||||
const auto pointState = [](std::uint32_t control, std::uint32_t size, std::uint32_t limits) {
|
||||
auto queue = makeState();
|
||||
queue.userConfig[0x242] = 1;
|
||||
queue.context[0x1b3] = queue.context[0x1b4] = 2;
|
||||
queue.context[0x207] = control;
|
||||
queue.context[0x280] = size;
|
||||
queue.context[0x281] = limits;
|
||||
return queue;
|
||||
};
|
||||
{
|
||||
const auto queue = pointState(0x01210000u, 0x00080008u, 0x00080008u);
|
||||
const auto rejection = AgcDriver::Graphics::DrawRejection(queue, false);
|
||||
Require(rejection.empty(), "a vertex-path point list with a vertex point size failed the draw precheck: " + rejection);
|
||||
const auto state = AgcDriver::Graphics::DecodeState(queue);
|
||||
Require(state.topology == VK_PRIMITIVE_TOPOLOGY_POINT_LIST && state.paClVsOutCntl == 0x01210000u, "a vertex-path point list with a vertex point size did not decode as a point list");
|
||||
Require(AgcDriver::Graphics::RasterPrimitiveOf(state) == ShaderRecompiler::RasterPrimitive::Point, "a vertex-path point list is not rasterized as points");
|
||||
Require(state.vertexPoints && state.pointSize == 1.0f && state.pointSizeMin == 1.0f && state.pointSizeMax == 1.0f, "PA_SU_POINT_SIZE and PA_SU_POINT_MINMAX of 8 did not decode as one-pixel points");
|
||||
ShaderRecompiler::ShaderVertexStageInfo vertex{};
|
||||
vertex.paClVsOutCntl = 1u << 21u;
|
||||
AgcDriver::Graphics::ApplyPointSize(state, vertex);
|
||||
Require(vertex.pointList && vertex.paClVsOutCntl == ((1u << 16u) | (1u << 21u)) && vertex.pointSize == 1.0f && vertex.pointSizeMin == 1.0f && vertex.pointSizeMax == 1.0f, "the vertex stage did not receive the vertex point size");
|
||||
}
|
||||
{
|
||||
const auto state = AgcDriver::Graphics::DecodeState(pointState(0, 0x00200020u, 0x00100004u));
|
||||
Require(state.vertexPoints && state.pointSize == 4.0f && state.pointSizeMin == 0.5f && state.pointSizeMax == 2.0f, "a register point size did not decode as diameters");
|
||||
ShaderRecompiler::ShaderVertexStageInfo vertex{};
|
||||
vertex.paClVsOutCntl = 1u << 21u;
|
||||
AgcDriver::Graphics::ApplyPointSize(state, vertex);
|
||||
Require(vertex.pointList && vertex.paClVsOutCntl == (1u << 21u) && vertex.pointSize == 4.0f, "a register point size turned on the vertex point size");
|
||||
}
|
||||
{
|
||||
const auto state = AgcDriver::Graphics::DecodeState(pointState(0x01210000u, 0x00200010u, 0x00400000u));
|
||||
Require(state.pointSizeMin == 0.0f && state.pointSizeMax == 8.0f, "a vertex point size refused a register size whose width and height differ");
|
||||
}
|
||||
{
|
||||
auto queue = makeState();
|
||||
queue.context[0x1b3] = queue.context[0x1b4] = 2;
|
||||
queue.context[0x207] = 0x01210000u;
|
||||
const auto state = AgcDriver::Graphics::DecodeState(queue);
|
||||
Require(!state.vertexPoints, "a triangle draw decoded as vertex points");
|
||||
ShaderRecompiler::ShaderVertexStageInfo vertex{};
|
||||
AgcDriver::Graphics::ApplyPointSize(state, vertex);
|
||||
Require(!vertex.pointList && vertex.paClVsOutCntl == 0, "a triangle draw received a point size");
|
||||
}
|
||||
expectFailure([&] { AgcDriver::Graphics::DecodeState(pointState(0, 0x00200010u, 0x00080008u)); }, "points whose PA_SU_POINT_SIZE width and height differ are unsupported");
|
||||
expectFailure([&] { AgcDriver::Graphics::DecodeState(pointState(0, 0x00080008u, 0x00080010u)); }, "PA_SU_POINT_MINMAX with a minimum above its maximum is unsupported");
|
||||
expectFailure([&] { AgcDriver::Graphics::DecodeState(pointState(1u << 16u, 0x00080008u, 0x00080008u)); }, "USE_VTX_POINT_SIZE without VS_OUT_MISC_VEC_ENA is unsupported");
|
||||
expectFailure([&] { AgcDriver::Graphics::DecodeState(pointState(0, 0, 0x00080008u)); }, "points of size 0 (PA_SU_POINT_SIZE 0) are unsupported");
|
||||
expectFailure([&] { AgcDriver::Graphics::DecodeState(pointState(0x01210000u, 0x00080008u, 0)); }, "a vertex point size clamped to 0 (PA_SU_POINT_MINMAX maximum 0) is unsupported");
|
||||
{
|
||||
const auto state = AgcDriver::Graphics::DecodeState(pointState(0x01210000u, 0, 0x00200000u));
|
||||
Require(state.pointSize == 0.0f && state.pointSizeMin == 0.0f && state.pointSizeMax == 4.0f, "a vertex point size refused a zero register size or a zero clamp minimum");
|
||||
static_cast<void>(AgcDriver::Graphics::DecodeState(pointState(0, 0x00080008u, 0)));
|
||||
}
|
||||
for (const auto sprite : {1u << 17u, 1u << 23u}) {
|
||||
auto queue = pointState(0x01210000u, 0x00080008u, 0x00080008u);
|
||||
queue.context[0x1b5] = 0x486bu;
|
||||
queue.context[0x1b6] = 2;
|
||||
queue.context[0x191] = 0;
|
||||
queue.context[0x192] = sprite;
|
||||
expectFailure([&] { AgcDriver::Graphics::DecodeState(queue); }, "point sprite texture coordinates (SPI_PS_INPUT_CNTL PT_SPRITE_TEX) are not implemented");
|
||||
queue.context[0x1b5] = 0x4869u;
|
||||
Require(AgcDriver::Graphics::DecodeState(queue).vertexPoints, "PT_SPRITE_TEX was refused with point sprites off");
|
||||
}
|
||||
}
|
||||
|
||||
void retainedPixelStageTests() {
|
||||
using namespace AgcDriver::Graphics;
|
||||
auto queue = makeState();
|
||||
@@ -1080,11 +1153,30 @@ void ShaderStageTests() {
|
||||
lines.context[0x29b] = 1;
|
||||
Require(AgcDriver::Graphics::DecodeState(lines).stages.mesh->provokingVertex == 1, "a last-vertex geometry draw does not take its flat inputs and layer from the second vertex of each output line");
|
||||
lines.context[0x29b] = 0;
|
||||
expectFailure([&] { AgcDriver::Graphics::DecodeState(lines); }, "missing register in context bank at DWORD 0x280");
|
||||
lines.context[0x280] = 0x00080008u;
|
||||
expectFailure([&] { AgcDriver::Graphics::DecodeState(lines); }, "missing register in context bank at DWORD 0x281");
|
||||
lines.context[0x281] = 0xffff0000u;
|
||||
state = AgcDriver::Graphics::DecodeState(lines);
|
||||
mesh = *state.stages.mesh;
|
||||
Require(mesh.outputPrimitiveSize == 1 && mesh.maxPrimitives == 255 && AgcDriver::Graphics::RasterPrimitiveOf(state) == ShaderRecompiler::RasterPrimitive::Point, "a point-list subgroup did not decode as points");
|
||||
Require(mesh.provokingVertex == 0, "a point draw has provoking vertex 0");
|
||||
Require(state.pointSize == 1.0f && state.pointSizeMin == 0.0f && state.pointSizeMax == 8191.875f, "geometry points did not decode the queue's default point size and limits");
|
||||
lines.context[0x205] = raster;
|
||||
auto points = lines;
|
||||
points.userConfig[0x242] = 6;
|
||||
points.userConfig[0x25b] = 0x5c2e;
|
||||
points.context[0x1ff] = 0x8a;
|
||||
points.context[0x2ce] = 3;
|
||||
points.context[0x29b] = 0;
|
||||
points.context[0x280] = 0x00180018u;
|
||||
points.context[0x281] = 0x00400008u;
|
||||
const auto pointState = AgcDriver::Graphics::DecodeState(points);
|
||||
const auto& pointMesh = *pointState.stages.mesh;
|
||||
ShaderRecompiler::ShaderVertexStageInfo pointInfo{};
|
||||
AgcDriver::Graphics::ApplyPointSize(pointState, pointInfo);
|
||||
Require(pointInfo.pointList && pointInfo.pointSize == 3.0f && pointInfo.pointSizeMin == 1.0f && pointInfo.pointSizeMax == 8.0f, "geometry points lost their register sizes");
|
||||
Require(pointMesh.outputPrimitiveSize == 1u && pointMesh.primitivesPerGroup == 44u && pointMesh.verticesPerGroup == 46u && pointMesh.maxVertices == 138u && pointMesh.maxPrimitives == 138u && pointMesh.threadsPerGroup == 192u && AgcDriver::Graphics::RasterPrimitiveOf(pointState) == ShaderRecompiler::RasterPrimitive::Point, "triangle-strip input with point output did not decode the reported subgroup");
|
||||
lines.context[0x29b] = 1;
|
||||
lines.context[0x2ce] = 1;
|
||||
expectFailure([&] { AgcDriver::Graphics::DecodeState(lines); }, "unsupported geometry input or output assembly");
|
||||
@@ -3386,6 +3478,8 @@ void msaaEnableClearDepthTests() {
|
||||
queue.context[0x2ce] = 5;
|
||||
queue.context[0x29b] = 0;
|
||||
queue.context[0x2ab] = 4;
|
||||
queue.context[0x280] = 0x00080008u; // point-output geometry programs decode PA_SU_POINT_SIZE / PA_SU_POINT_MINMAX before this rejection
|
||||
queue.context[0x281] = 0x00080008u;
|
||||
queue.shader[0x8a] = 3u << 29u;
|
||||
queue.shader[0x8b] = 3u << 16u;
|
||||
expectFailure([&] { DecodeState(queue); }, "multisampled targets rasterized without MSAA_ENABLE are unsupported for points or alpha-to-coverage");
|
||||
@@ -9387,6 +9481,8 @@ void ConservativeRasterizationTests() {
|
||||
geometry.context[0x2ce] = 3;
|
||||
geometry.context[0x29b] = 2;
|
||||
geometry.context[0x2ab] = 4;
|
||||
geometry.context[0x280] = 0x00080008u; // PA_SU_POINT_SIZE and PA_SU_POINT_MINMAX: a point-output geometry program decodes them
|
||||
geometry.context[0x281] = 0x00080008u;
|
||||
geometry.shader[0x8a] = 3u << 29u;
|
||||
geometry.shader[0x8b] = 3u << 16u;
|
||||
for (const auto input : {1u, 2u, 4u}) {
|
||||
@@ -10849,6 +10945,22 @@ void pipelineJournalTests(bool longPath = false, bool extended = false) {
|
||||
GraphicsPipelineRecipe lineDecoded;
|
||||
Require(DecodeGraphicsPipelineRecipe(EncodeGraphicsPipelineRecipe(MakeGraphicsPipelineRecipe(lineState, input, layouts.View(), shaders, VK_IMAGE_LAYOUT_GENERAL)), lineDecoded), "the line strip mesh recipe does not decode");
|
||||
Require(lineDecoded.state.stages.mesh && lineDecoded.state.stages.mesh->outputPrimitiveSize == 2u && lineDecoded.state.stages.mesh->esgsItemSize == 4u, "the recipe dropped the mesh output primitive size");
|
||||
auto pointState = state;
|
||||
pointState.vertexPoints = true;
|
||||
pointState.pointSize = 4.0f;
|
||||
pointState.pointSizeMin = 0.5f;
|
||||
pointState.pointSizeMax = 8.0f;
|
||||
GraphicsPipelineRecipe pointDecoded;
|
||||
Require(DecodeGraphicsPipelineRecipe(EncodeGraphicsPipelineRecipe(MakeGraphicsPipelineRecipe(pointState, input, layouts.View(), shaders, VK_IMAGE_LAYOUT_GENERAL)), pointDecoded), "the point list recipe does not decode");
|
||||
Require(pointDecoded.state.vertexPoints && pointDecoded.state.pointSize == 4.0f && pointDecoded.state.pointSizeMin == 0.5f && pointDecoded.state.pointSizeMax == 8.0f, "the recipe dropped the vertex point list or its point sizes");
|
||||
auto meshPointState = pointState;
|
||||
meshPointState.vertexPoints = false;
|
||||
meshPointState.stages.mesh = *lineState.stages.mesh;
|
||||
meshPointState.stages.mesh->outputPrimitiveSize = 1u;
|
||||
meshPointState.stages.mesh->provokingVertex = 0u;
|
||||
GraphicsPipelineRecipe meshPointDecoded;
|
||||
Require(DecodeGraphicsPipelineRecipe(EncodeGraphicsPipelineRecipe(MakeGraphicsPipelineRecipe(meshPointState, input, layouts.View(), shaders, VK_IMAGE_LAYOUT_GENERAL)), meshPointDecoded), "the mesh point recipe does not decode");
|
||||
Require(!meshPointDecoded.state.vertexPoints && meshPointDecoded.state.stages.mesh && meshPointDecoded.state.stages.mesh->outputPrimitiveSize == 1u && meshPointDecoded.state.pointSize == 4.0f && meshPointDecoded.state.pointSizeMin == 0.5f && meshPointDecoded.state.pointSizeMax == 8.0f, "the recipe dropped mesh points or their sizes without the vertex point flag");
|
||||
auto fourSampleState = state;
|
||||
fourSampleState.samples = 4;
|
||||
auto maskState = fourSampleState;
|
||||
@@ -11330,6 +11442,7 @@ int main(int argc, char** argv) {
|
||||
NggVertexWorkgroupTests();
|
||||
inactiveVertexPointSizeTests();
|
||||
PolygonPrimitiveTests();
|
||||
vertexPointListTests();
|
||||
TuningFieldTests();
|
||||
PixelInputLayoutTests();
|
||||
UnexportedPixelInputTests();
|
||||
|
||||
@@ -95,6 +95,52 @@ void rejectFields(const Fields& f, std::string_view reason) {
|
||||
|
||||
}
|
||||
|
||||
static void RunR128TextureTests() {
|
||||
constexpr std::array<std::uint32_t, 8> streamed{0xa0c18800u, 0xcad00000u, 0x01ffc1ffu, 0x905b2facu, 0u, 0u, 0u, 0u};
|
||||
const auto view = DecodeTextureResource(streamed);
|
||||
Require(view.baseAddress == 0xa0c1880000ull && view.format == 173u && view.tileMode == TextureTileMode::kStandard4KB && view.width == 512u && view.height == 512u && view.baseLevel == 0u && view.lastLevel == 9u && view.mipCount == 10u && view.allocatedMipCount == 10u && view.minLod == 0u,
|
||||
"a 128-bit BC3 T# (2048x2048, levels 2..11, words 4-7 zero) must read as the 512x512 chain of its 10 resident levels, got " + std::to_string(view.width) + "x" + std::to_string(view.height) + " levels " + std::to_string(view.baseLevel) + ".." + std::to_string(view.lastLevel) + " of " + std::to_string(view.mipCount));
|
||||
auto chainWords = streamed;
|
||||
chainWords[3] &= ~(0xfu << 12u);
|
||||
chainWords[5] = 11u << 4u;
|
||||
const auto full = DecodeTextureResource(chainWords);
|
||||
Require(full.width == 2048u && full.mipCount == 12u, "the same surface with MAX_MIP 11 must be the 12-level 2048x2048 chain");
|
||||
const auto chain = DescribeSurface(full);
|
||||
const auto resident = DescribeSurface(view);
|
||||
Require(chain.mips.size() == 12u && resident.mips.size() == 10u, "the chain and the resident levels must have 12 and 10 levels");
|
||||
for (std::uint32_t level = 0; level < 10u; ++level) {
|
||||
const auto& a = chain.mips[level + 2u];
|
||||
const auto& b = resident.mips[level];
|
||||
Require(a.tiledOffset == b.tiledOffset && a.tiledSize == b.tiledSize && a.width == b.width && a.height == b.height && a.blocksPerRow == b.blocksPerRow && a.tail == b.tail && a.tailX == b.tailX && a.tailY == b.tailY, "resident level " + std::to_string(level) + " must be level " + std::to_string(level + 2u) + " of the 12-level chain");
|
||||
}
|
||||
Require(resident.guestBytes <= chain.mips[1].tiledOffset && chain.mips[0].tiledOffset > chain.mips[1].tiledOffset, "the resident levels must end before the chain's levels 1 and 0, which come last in a GFX10 swizzled chain");
|
||||
auto levelZero = streamed;
|
||||
levelZero[3] &= ~(0xfu << 12u);
|
||||
const auto single = DecodeTextureResource(levelZero);
|
||||
Require(single.mipCount == 1u && single.lastLevel == 0u, "a T# with words 4-7 zero that starts at level 0 must stay one level");
|
||||
auto tailed = streamed;
|
||||
tailed[5] = 4u << 20u;
|
||||
reject([&] { DecodeTextureResource(tailed); }, "would move the surface's own");
|
||||
|
||||
constexpr std::array<std::uint32_t, 8> tall{0xa0c1de00u, 0xcad00000u, 0x01ffc0ffu, 0x905b4facu, 0u, 0u, 0u, 0u};
|
||||
const auto tallView = DecodeTextureResource(tall);
|
||||
Require(tallView.width == 64u && tallView.height == 128u && tallView.lastLevel == 7u && tallView.mipCount == 8u, "a 128-bit 1024x2048 T# of levels 4..11 must read as its 64x128 chain of 8 levels");
|
||||
|
||||
Fields clamped;
|
||||
clamped.base40 = 0x55ea000ull;
|
||||
clamped.format = 20;
|
||||
clamped.width = 1024;
|
||||
clamped.height = 1024;
|
||||
clamped.tileModeRaw = 0x1b;
|
||||
clamped.baseLevel = 2;
|
||||
clamped.lastLevel = 10;
|
||||
clamped.minLod = 2u * 256u + 64u;
|
||||
const auto clampedView = DecodeTextureResource(pack(clamped));
|
||||
Require(clampedView.width == 256u && clampedView.mipCount == 9u && clampedView.minLod == 64u, "reading a 128-bit T# from its resident levels must move its MIN_LOD clamp with the base level");
|
||||
clamped.minLod = 256u;
|
||||
Require(DecodeTextureResource(pack(clamped)).minLod == 0u, "a MIN_LOD clamp below the base level must vanish when read from the resident levels");
|
||||
}
|
||||
|
||||
void RunGuestTextureResourceTests() {
|
||||
Fields base;
|
||||
const auto baseWords = pack(base);
|
||||
@@ -629,6 +675,7 @@ void RunGuestTextureResourceTests() {
|
||||
pastUntailed.maxMip = 0;
|
||||
pastUntailed.baseLevel = 1;
|
||||
pastUntailed.lastLevel = 1;
|
||||
pastUntailed.perfMod = 4;
|
||||
rejectFields(pastUntailed, "would move the surface's own");
|
||||
auto untailedChain = tailView;
|
||||
untailedChain.mipCount = 1;
|
||||
@@ -636,6 +683,8 @@ void RunGuestTextureResourceTests() {
|
||||
untailedChain.mipCount = 2;
|
||||
Require(untailedAllocated == 0xff0000u && DescribeSurface(untailedChain).guestBytes == 0x1470000u, "a second level must grow a 1920x1080 64 bpp SW_64KB_R_X surface from addrlib's 0xff0000 to 0x1470000 bytes");
|
||||
|
||||
RunR128TextureTests();
|
||||
|
||||
std::array<std::uint32_t, 4> shortWords{};
|
||||
reject([&] { DecodeTextureResource(shortWords); }, "8 dwords");
|
||||
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
#include "prx/libc/include/GuestAllocations.hpp"
|
||||
#include <algorithm>
|
||||
#include <array>
|
||||
#include <bit>
|
||||
#include <cmath>
|
||||
#include <cstdio>
|
||||
#include <cstdlib>
|
||||
@@ -144,6 +145,7 @@ struct MeshDraw {
|
||||
VkCullModeFlags cull = VK_CULL_MODE_NONE;
|
||||
std::span<const std::uint32_t> code = {};
|
||||
std::uint32_t stagesRegister = 0x20u;
|
||||
ShaderRecompiler::ShaderVertexStageInfo vertex{};
|
||||
};
|
||||
|
||||
bool ReadsNumWorkgroups(std::span<const std::uint32_t> words) {
|
||||
@@ -176,7 +178,7 @@ void DrawMesh(AgcDriver::VulkanDevice& device, const MeshDraw& setup) {
|
||||
const std::array<ShaderRecompiler::MemoryRegion, 1> geometryMemory{{{reinterpret_cast<std::uintptr_t>(code.data()), std::as_bytes(std::span(code))}}};
|
||||
ShaderRecompiler::RecompileRequest geometry{
|
||||
{ShaderStage::Mesh, reinterpret_cast<std::uintptr_t>(code.data()), code, 0, {}},
|
||||
{setup.waveSize, 0, userData, std::nullopt, std::nullopt, ShaderRecompiler::ShaderVertexStageInfo{}, geometryMemory},
|
||||
{setup.waveSize, 0, userData, std::nullopt, std::nullopt, setup.vertex, geometryMemory},
|
||||
target,
|
||||
{0, 0, 0, setup.geometryPushBytes},
|
||||
ShaderRecompiler::GraphicsCompileContext{0, {}, setup.mesh, std::nullopt, {setup.draw.indexAddress, setup.draw.indexCount, setup.draw.indexSize, setup.draw.instanceCount}}
|
||||
@@ -207,6 +209,10 @@ void DrawMesh(AgcDriver::VulkanDevice& device, const MeshDraw& setup) {
|
||||
|
||||
AgcDriver::Graphics::State state{};
|
||||
state.stages = {AgcDriver::Graphics::ShaderPath::Geometry, setup.stagesRegister, setup.waveSize, 64, setup.mesh, std::nullopt};
|
||||
state.pointSize = setup.vertex.pointSize;
|
||||
state.pointSizeMin = setup.vertex.pointSizeMin;
|
||||
state.pointSizeMax = setup.vertex.pointSizeMax;
|
||||
state.paClVsOutCntl = setup.vertex.paClVsOutCntl;
|
||||
state.color = {reinterpret_cast<std::uintptr_t>(Pixels.data()), {Width, Height}, VK_FORMAT_R8G8B8A8_UNORM, Pixels.size(), 0xe4u};
|
||||
state.colors = {state.color};
|
||||
state.hasColorTarget = true;
|
||||
@@ -394,6 +400,63 @@ int main() {
|
||||
}
|
||||
}
|
||||
|
||||
ClearPixels();
|
||||
auto pointSubgroup = SmallSubgroup;
|
||||
pointSubgroup.outputPrimitiveSize = 1u;
|
||||
for (const auto pointWave : {32u, 64u}) {
|
||||
ClearPixels();
|
||||
DrawMesh(device, {pointSubgroup, {0, static_cast<std::uint32_t>(Ordered.size()), 0, 1, 0, false}, VertexBufferDescriptor(Ordered.data(), static_cast<std::uint32_t>(Ordered.size())), ShaderRecompiler::MeshDrawPushOffsetBytes, false, pointWave});
|
||||
for (std::uint32_t triangle = 0; triangle < Triangles; ++triangle) {
|
||||
const auto& position = Ordered[3u * triangle].position;
|
||||
const auto x = static_cast<std::uint32_t>((position[0] + 1.0f) * 0.5f * Width);
|
||||
const auto y = static_cast<std::uint32_t>((1.0f - position[1]) * 0.5f * Height);
|
||||
const auto offset = (static_cast<std::size_t>(y) * Width + x) * 4u;
|
||||
Require(PixelIs(offset, TriangleColor(triangle)), "mesh point missing at first exported index for primitive " + std::to_string(triangle));
|
||||
Require(PixelIs(CellPixel(triangle), Background), "mesh point output filled the interior of its packed triangle");
|
||||
}
|
||||
}
|
||||
|
||||
for (const auto pointWave : {32u, 64u}) {
|
||||
for (const auto size : {3.0f, 4.0f}) {
|
||||
ClearPixels();
|
||||
MeshDraw points{pointSubgroup, {0, static_cast<std::uint32_t>(Ordered.size()), 0, 1, 0, false}, VertexBufferDescriptor(Ordered.data(), static_cast<std::uint32_t>(Ordered.size()))};
|
||||
points.waveSize = pointWave;
|
||||
points.vertex.pointSize = size;
|
||||
DrawMesh(device, points);
|
||||
for (std::uint32_t primitive = 0; primitive < Triangles; ++primitive) {
|
||||
std::uint32_t covered = 0;
|
||||
for (std::size_t pixel = 0; pixel < Pixels.size(); pixel += 4u) covered += PixelIs(pixel, TriangleColor(primitive));
|
||||
Require(covered == static_cast<std::uint32_t>(size * size), "mesh point did not cover its register-sized square");
|
||||
}
|
||||
}
|
||||
for (const auto exportedSize : {6.0f, -3.0f}) {
|
||||
ClearPixels();
|
||||
const auto& baseCode = pointWave == 32u ? Wave32GeometryCode : GeometryCode;
|
||||
std::array<std::uint32_t, GeometryCode.size() + 4u> sizedCode{};
|
||||
std::copy_n(baseCode.begin(), 101u, sizedCode.begin());
|
||||
sizedCode[92] = 0xbf88000eu;
|
||||
sizedCode[99] = 0xf80000cfu;
|
||||
sizedCode[101] = 0x7e6802ffu;
|
||||
sizedCode[102] = std::bit_cast<std::uint32_t>(exportedSize);
|
||||
sizedCode[103] = 0xf80008d1u;
|
||||
sizedCode[104] = 0x00000034u;
|
||||
std::copy(baseCode.begin() + 101u, baseCode.end(), sizedCode.begin() + 105u);
|
||||
MeshDraw exported{pointSubgroup, {0, static_cast<std::uint32_t>(Ordered.size()), 0, 1, 0, false}, VertexBufferDescriptor(Ordered.data(), static_cast<std::uint32_t>(Ordered.size()))};
|
||||
exported.waveSize = pointWave;
|
||||
exported.code = sizedCode;
|
||||
exported.vertex.paClVsOutCntl = (1u << 16u) | (1u << 21u);
|
||||
exported.vertex.pointSizeMin = 3.0f;
|
||||
exported.vertex.pointSizeMax = 4.0f;
|
||||
DrawMesh(device, exported);
|
||||
for (std::uint32_t primitive = 0; primitive < Triangles; ++primitive) {
|
||||
std::uint32_t covered = 0;
|
||||
for (std::size_t pixel = 0; pixel < Pixels.size(); pixel += 4u) covered += PixelIs(pixel, TriangleColor(primitive));
|
||||
const auto side = exportedSize < 3.0f ? 3u : 4u;
|
||||
Require(covered == side * side, "mesh point ignored its exported size or clamp");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ClearPixels();
|
||||
auto lineSubgroup = FastLaunchSubgroup;
|
||||
lineSubgroup.maxPrimitives = 2u;
|
||||
|
||||
@@ -0,0 +1,38 @@
|
||||
#include "SceTypes.hpp"
|
||||
#include <algorithm>
|
||||
#include <array>
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <cstring>
|
||||
|
||||
extern "C" int APS5_VABI sceAgcDriverNopDataWritePacket(void* destination, uint32_t address, const void* data, uint32_t bytes);
|
||||
|
||||
int main() {
|
||||
std::array<std::byte, 24> storage;
|
||||
storage.fill(std::byte{0xaa});
|
||||
const std::array<std::byte, 5> data{std::byte{0x11}, std::byte{0x22}, std::byte{0x33}, std::byte{0x44}, std::byte{0x55}};
|
||||
const auto words = sceAgcDriverNopDataWritePacket(storage.data() + 4, 0x12345678, data.data(), static_cast<std::uint32_t>(data.size()));
|
||||
std::uint32_t header = 0;
|
||||
std::uint32_t address = 0;
|
||||
std::memcpy(&header, storage.data() + 4, sizeof(header));
|
||||
std::memcpy(&address, storage.data() + 8, sizeof(address));
|
||||
if (words != 4 || header != 0xc0021000U || address != 0x12345678U) return 1;
|
||||
if (!std::equal(data.begin(), data.end(), storage.begin() + 12)) return 2;
|
||||
if (storage[17] != std::byte{0} || storage[18] != std::byte{0} || storage[19] != std::byte{0}) return 3;
|
||||
if (storage[3] != std::byte{0xaa} || storage[20] != std::byte{0xaa}) return 4;
|
||||
|
||||
storage.fill(std::byte{0xaa});
|
||||
const auto emptyWords = sceAgcDriverNopDataWritePacket(storage.data() + 4, 0x87654321, nullptr, 5);
|
||||
std::memcpy(&header, storage.data() + 4, sizeof(header));
|
||||
std::memcpy(&address, storage.data() + 8, sizeof(address));
|
||||
if (emptyWords != 2 || header != 0xc0021000U || address != 0x87654321U) return 5;
|
||||
if (storage[12] != std::byte{0} || storage[19] != std::byte{0} || storage[20] != std::byte{0xaa}) return 6;
|
||||
|
||||
storage.fill(std::byte{0xaa});
|
||||
const auto zeroBytesWords = sceAgcDriverNopDataWritePacket(storage.data() + 4, 0x01020304, data.data(), 0);
|
||||
std::memcpy(&header, storage.data() + 4, sizeof(header));
|
||||
std::memcpy(&address, storage.data() + 8, sizeof(address));
|
||||
if (zeroBytesWords != 2 || header != 0xc0001000U || address != 0x01020304U) return 7;
|
||||
if (storage[12] != std::byte{0xaa}) return 8;
|
||||
return 0;
|
||||
}
|
||||
@@ -21,9 +21,9 @@ void require(bool condition, const char* message) {
|
||||
|
||||
void setScreenshotDirectory(const std::filesystem::path& directory) {
|
||||
#ifdef _WIN32
|
||||
require(_putenv_s("ANYPS5_SCREENSHOTS", directory.string().c_str()) == 0, "set ANYPS5_SCREENSHOTS");
|
||||
require(_wputenv_s(L"ANYPS5_SCREENSHOTS", directory.wstring().c_str()) == 0, "set ANYPS5_SCREENSHOTS");
|
||||
#else
|
||||
require(::setenv("ANYPS5_SCREENSHOTS", directory.string().c_str(), 1) == 0, "set ANYPS5_SCREENSHOTS");
|
||||
require(::setenv("ANYPS5_SCREENSHOTS", directory.c_str(), 1) == 0, "set ANYPS5_SCREENSHOTS");
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -73,7 +73,7 @@ void rejectsInvalidFrames() {
|
||||
|
||||
int main() try {
|
||||
const auto root = std::filesystem::temp_directory_path() / ("anyps5_screenshot-" + std::to_string(std::random_device{}()));
|
||||
const auto directory = root / "nested";
|
||||
const auto directory = root / std::filesystem::path(u8"nested-a\u00e7\u00e3o-\u65e5\u672c");
|
||||
std::filesystem::remove_all(root);
|
||||
setScreenshotDirectory(directory);
|
||||
requestsMerge();
|
||||
|
||||
@@ -4513,13 +4513,15 @@ void verifyMeshConfiguration() {
|
||||
RecompileCacheKey::Build(other, key);
|
||||
require(key != first && RecompileCacheKey::ContextHash(request) != RecompileCacheKey::ContextHash(other), "the cache keys ignore the mesh configuration");
|
||||
require(mesh.outputPrimitiveSize == 3u && replay.request.graphics->mesh->outputPrimitiveSize == 3u, "a mesh configuration does not output triangles by default");
|
||||
otherMesh = mesh;
|
||||
otherMesh.outputPrimitiveSize = 2u;
|
||||
other.graphics = GraphicsCompileContext{0u, {}, otherMesh, std::nullopt, {}};
|
||||
const auto lineReplay = RequestSerializer{}.Deserialize(RequestSerializer{}.Serialize(other));
|
||||
require(lineReplay.request.graphics.has_value() && lineReplay.request.graphics->mesh.has_value() && lineReplay.request.graphics->mesh->outputPrimitiveSize == 2u, "the mesh output primitive size was lost in serialization");
|
||||
RecompileCacheKey::Build(other, key);
|
||||
require(key != first && RecompileCacheKey::ContextHash(request) != RecompileCacheKey::ContextHash(other), "the cache keys ignore the mesh output primitive size");
|
||||
for (const auto primitiveSize : {1u, 2u}) {
|
||||
otherMesh = mesh;
|
||||
otherMesh.outputPrimitiveSize = primitiveSize;
|
||||
other.graphics = GraphicsCompileContext{0u, {}, otherMesh, std::nullopt, {}};
|
||||
const auto primitiveReplay = RequestSerializer{}.Deserialize(RequestSerializer{}.Serialize(other));
|
||||
require(primitiveReplay.request.graphics.has_value() && primitiveReplay.request.graphics->mesh.has_value() && primitiveReplay.request.graphics->mesh->outputPrimitiveSize == primitiveSize, "the mesh output primitive size was lost in serialization");
|
||||
RecompileCacheKey::Build(other, key);
|
||||
require(key != first && RecompileCacheKey::ContextHash(request) != RecompileCacheKey::ContextHash(other), "the cache keys ignore the mesh output primitive size");
|
||||
}
|
||||
RecompileRequest hull{};
|
||||
hull.shader = {ShaderStage::TessellationControl, 0x10000u, code, 0, {}};
|
||||
hull.context.waveSize = 64;
|
||||
@@ -4896,7 +4898,7 @@ void verifyPixelRequestSerialization() {
|
||||
minimal.context.pixel->layerExported = true;
|
||||
minimal.context.pixel->ditheredAlphaToCoverage = true;
|
||||
const auto encoded = serializer.Serialize(minimal);
|
||||
require(requestPrefix(encoded, 8u) == "NVNQQSoAAAA=", "new requests did not use serialization version 42");
|
||||
require(requestPrefix(encoded, 8u) == "NVNQQSsAAAA=", "new requests did not use serialization version 43");
|
||||
const std::array<std::uint32_t, 2> fallbacks{0x40u, 0x1ac4u};
|
||||
auto withFallbacks = minimal;
|
||||
withFallbacks.context.linkedCallFallbacks = fallbacks;
|
||||
@@ -5014,7 +5016,7 @@ void verifyPixelRequestSerialization() {
|
||||
for (std::size_t bytes = 0; bytes < 45u; ++bytes) {
|
||||
expectFailure([&] { static_cast<void>(serializer.Deserialize(requestPrefix(encoded, mappingOffset + bytes))); }, "truncated data", "a truncated pixel mapping, packing, dual-source, alpha-to-coverage, stencil reference export flag, primitive class, layer export, dither or front-face flag, quad pixel mask or quad sample mask was accepted");
|
||||
}
|
||||
for (const auto unsupported : {"NVNQQQAAAAA=", "NVNQQSsAAAA="}) {
|
||||
for (const auto unsupported : {"NVNQQQAAAAA=", "NVNQQSwAAAA="}) {
|
||||
expectFailure([&] { static_cast<void>(serializer.Deserialize(unsupported)); }, "serialization version", "an unsupported request version was accepted");
|
||||
}
|
||||
static constexpr std::string_view version18Request{
|
||||
@@ -5303,15 +5305,16 @@ void verifyDepthRemapRequests() {
|
||||
const auto replay = serializer.Deserialize(remapped);
|
||||
require(replay.request.target.depthRangeRemap && replay.request.context.vertex.has_value() && replay.request.context.vertex->paClVsOutCntl == 0x89abcdefu, "the depth remap target flag or the vertex info did not round-trip");
|
||||
require(replay.request.context.vertex->depthRemapMode == 2u, "the depth remap mode did not round-trip");
|
||||
require(serializer.Serialize(replay.request) == remapped, "a version 35 depth remap request changed on re-serialization");
|
||||
require(serializer.Serialize(replay.request) == remapped, "the depth remap request changed on re-serialization");
|
||||
const auto plainBytes = decodeBase64(plain);
|
||||
const auto remappedBytes = decodeBase64(remapped);
|
||||
require(plainBytes.size() == remappedBytes.size() && plainBytes.size() > 5u && std::equal(plainBytes.begin(), plainBytes.end() - 7, remappedBytes.begin()), "the depth remap flag and mode are not the 6 bytes before the f32 flush and denormal preserve flags of a vertex request");
|
||||
constexpr std::size_t pointTailBytes = 13u;
|
||||
require(plainBytes.size() == remappedBytes.size() && plainBytes.size() > 7u + pointTailBytes && std::equal(plainBytes.begin(), plainBytes.end() - 7 - pointTailBytes, remappedBytes.begin()) && std::equal(plainBytes.end() - pointTailBytes, plainBytes.end(), remappedBytes.end() - pointTailBytes), "the depth remap flag and mode are not the 6 bytes before the f32 flush and denormal preserve flags and the point tail of a vertex request");
|
||||
for (const std::uint8_t legacyVersion : {32u, 34u}) {
|
||||
auto legacyBytes = remappedBytes;
|
||||
legacyBytes.pop_back();
|
||||
legacyBytes[4] = legacyVersion;
|
||||
legacyBytes.resize(legacyBytes.size() - 6u);
|
||||
legacyBytes.resize(legacyBytes.size() - 6u - pointTailBytes);
|
||||
const auto legacy = serializer.Deserialize(encodeBase64(legacyBytes));
|
||||
require(!legacy.request.target.depthRangeRemap && legacy.request.context.vertex.has_value() && legacy.request.context.vertex->depthRemapMode == 0u, ("a version " + std::to_string(legacyVersion) + " vertex request read depth remap fields").c_str());
|
||||
require(serializer.Serialize(legacy.request) == plain, ("a version " + std::to_string(legacyVersion) + " vertex request misread the fields before the depth remap").c_str());
|
||||
@@ -5319,10 +5322,10 @@ void verifyDepthRemapRequests() {
|
||||
auto version35 = remappedBytes;
|
||||
version35.pop_back();
|
||||
version35[4] = 35u;
|
||||
version35.pop_back();
|
||||
version35.resize(version35.size() - 1u - pointTailBytes);
|
||||
const auto replay35 = serializer.Deserialize(encodeBase64(version35));
|
||||
require(replay35.request.target.depthRangeRemap && replay35.request.context.vertex->depthRemapMode == 2u && !replay35.request.target.float32FlushToZero && serializer.Serialize(replay35.request) == remapped, "a version 35 request misread the depth remap fields or read an f32 flush flag");
|
||||
auto truncated = remappedBytes;
|
||||
auto truncated = version35;
|
||||
truncated.resize(truncated.size() - 2u);
|
||||
expectFailure([&] { static_cast<void>(serializer.Deserialize(encodeBase64(truncated))); }, "truncated data", "a truncated depth remap mode was accepted");
|
||||
auto trailing = remappedBytes;
|
||||
@@ -5363,9 +5366,12 @@ void verifyMergedHullConfiguration() {
|
||||
const auto replay = serializer.Deserialize(merged);
|
||||
require(replay.request.graphics.has_value() && replay.request.graphics->tessellation.has_value() && replay.request.graphics->tessellation->mergedHull, "a merged hull configuration was lost in serialization");
|
||||
require(!serializer.Deserialize(separate).request.graphics->tessellation->mergedHull, "a separate hull configuration was read as merged");
|
||||
constexpr std::size_t pointTailBytes = 13u;
|
||||
auto legacy = decodeBase64(merged);
|
||||
require(legacy.size() > 53u + pointTailBytes && legacy[4] == 43u, "a merged hull request did not use serialization version 43");
|
||||
legacy.resize(legacy.size() - pointTailBytes);
|
||||
legacy.pop_back();
|
||||
require(legacy.size() > 52u && legacy[legacy.size() - 52u] == 1u, "the merged hull flag is not the last byte of the tessellation configuration");
|
||||
require(legacy[legacy.size() - 52u] == 1u, "the merged hull flag is not the last byte of the tessellation configuration");
|
||||
legacy.erase(legacy.end() - 52);
|
||||
for (const auto version : {30u, 31u, 32u, 34u, 35u, 36u, 37u, 38u}) {
|
||||
auto older = legacy;
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
#include "SceTypes.hpp"
|
||||
|
||||
extern "C" void* APS5_VABI sceAgcDriverGetCoredumpAddress();
|
||||
extern "C" int APS5_VABI sceAgcDriverSetTargetRingForDiag();
|
||||
|
||||
int main() {
|
||||
if (sceAgcDriverGetCoredumpAddress() != nullptr) return 1;
|
||||
if (sceAgcDriverSetTargetRingForDiag() != static_cast<int>(0x8A6D0001)) return 2;
|
||||
return 0;
|
||||
}
|
||||
@@ -120,7 +120,7 @@ void Run(AgcDriver::VulkanDevice& device, std::uint32_t baseArray = BaseArray) {
|
||||
device.WaitIdle();
|
||||
for (std::uint32_t tid = 0; tid < Threads; ++tid) {
|
||||
const float u = std::bit_cast<float>(Input[tid * 4u + 0u]);
|
||||
const float layer = std::clamp(std::nearbyint(std::bit_cast<float>(Input[tid * 4u + 1u])), 0.0f, static_cast<float>(Layers - 1u));
|
||||
const float layer = std::clamp(std::nearbyint(std::bit_cast<float>(Input[tid * 4u + 1u])), 0.0f, static_cast<float>(LastArray - baseArray));
|
||||
const auto x = static_cast<std::uint32_t>(std::clamp(static_cast<int>(std::floor(u * static_cast<float>(Width))), 0, static_cast<int>(Width) - 1));
|
||||
Expect(tid, "image_sample_lz on a window of a 1D array past maxImageArrayLayers", &Output[tid * 8u], Texel(x, baseArray + static_cast<std::uint32_t>(layer)));
|
||||
Expect(tid, "image_load on a window of a 1D array past maxImageArrayLayers", &Output[tid * 8u + 4u], Texel(Input[tid * 4u + 2u], baseArray + Input[tid * 4u + 3u]));
|
||||
|
||||
@@ -0,0 +1,165 @@
|
||||
#include "prx/libSceAgcDriver/Execution/include/VulkanDevice.hpp"
|
||||
#include "prx/libSceAgcDriver/Graphics/include/Draw.hpp"
|
||||
#include "Recompiler.hpp"
|
||||
#include "VulkanTestDevice.hpp"
|
||||
#include <algorithm>
|
||||
#include <array>
|
||||
#include <bit>
|
||||
#include <cstdint>
|
||||
#include <cstring>
|
||||
#include <exception>
|
||||
#include <iostream>
|
||||
#include <optional>
|
||||
#include <span>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace {
|
||||
|
||||
using AgcDriver::Graphics::Require;
|
||||
using ShaderRecompiler::ShaderStage;
|
||||
|
||||
constexpr std::uint32_t Extent = 64u;
|
||||
constexpr std::uint32_t MiscVector = 1u << 21u;
|
||||
constexpr std::uint32_t VertexPointSize = 1u << 16u;
|
||||
alignas(256) std::array<std::byte, Extent * Extent * 4u> pixels{};
|
||||
alignas(256) std::array<std::byte, 512> vertices{};
|
||||
constexpr std::array<std::uint32_t, 11> positionCode{0xf4080100u, 0xfa000000u, 0x4a0a0a02u, 0x4a0a0b08u, 0x4a0a0a03u, 0xe00c2000u, 0x80010005u, 0xbf8c3f70u, 0xf80008cfu, 0x03020100u, 0xbf810000u};
|
||||
constexpr std::array<std::uint32_t, 5> pixelCode{0x7e0002f2u, 0x7e020280u, 0xf800180fu, 0x00010100u, 0xbf810000u};
|
||||
|
||||
std::vector<std::uint32_t> SizeExportCode(float size) {
|
||||
std::vector<std::uint32_t> code(positionCode.begin(), positionCode.begin() + 8);
|
||||
code.insert(code.end(), {0x7e0802ffu, std::bit_cast<std::uint32_t>(size), 0xf80000cfu, 0x03020100u, 0xf80008d1u, 0x00000004u, 0xbf810000u});
|
||||
return code;
|
||||
}
|
||||
|
||||
struct PointSize {
|
||||
float size = 1.0f;
|
||||
float minimum = 0.0f;
|
||||
float maximum = 0.0f;
|
||||
bool fromVertex = false;
|
||||
};
|
||||
|
||||
struct Square {
|
||||
unsigned pixels = 0;
|
||||
std::uint32_t left = Extent, top = Extent, right = 0, bottom = 0;
|
||||
};
|
||||
|
||||
std::vector<Square> RunCase(AgcDriver::VulkanDevice& device, const char* name, std::span<const std::uint32_t> vertexCode, const PointSize& points, float offset) {
|
||||
const std::array<std::array<float, 2>, 4> centres{{{16.0f, 16.0f}, {48.0f, 16.0f}, {16.0f, 48.0f}, {48.0f, 48.0f}}};
|
||||
vertices.fill(std::byte{0});
|
||||
constexpr std::uint32_t stride = 16u;
|
||||
for (std::size_t index = 0; index < centres.size(); ++index) {
|
||||
const std::array<float, 4> position{(centres[index][0] + offset) / Extent * 2.0f - 1.0f, (centres[index][1] + offset) / Extent * 2.0f - 1.0f, 0.0f, 1.0f};
|
||||
std::memcpy(vertices.data() + index * stride, position.data(), sizeof(position));
|
||||
}
|
||||
std::array<std::uint32_t, 4> descriptor{};
|
||||
const auto tableAddress = reinterpret_cast<std::uintptr_t>(descriptor.data());
|
||||
std::array<std::uint32_t, 4> userData{static_cast<std::uint32_t>(tableAddress), static_cast<std::uint32_t>(tableAddress >> 32u), 0u, 0u};
|
||||
const std::array<ShaderRecompiler::MemoryRegion, 1> memory{{{tableAddress, std::as_bytes(std::span(descriptor))}}};
|
||||
ShaderRecompiler::ShaderVertexStageInfo vertexInfo{};
|
||||
vertexInfo.fetchEmbedded = true;
|
||||
vertexInfo.resourcesNum = 1u;
|
||||
vertexInfo.resourcesDst[0] = {0, 4, 0, 0};
|
||||
vertexInfo.paClVsOutCntl = points.fromVertex ? MiscVector | VertexPointSize : 0u;
|
||||
vertexInfo.pointList = true;
|
||||
vertexInfo.pointSize = points.size;
|
||||
vertexInfo.pointSizeMin = points.minimum;
|
||||
vertexInfo.pointSizeMax = points.maximum;
|
||||
ShaderRecompiler::RecompileRequest request{{ShaderStage::Vertex, reinterpret_cast<std::uintptr_t>(vertexCode.data()), vertexCode, 0, {}}, {32u, 0u, userData, std::nullopt, std::nullopt, vertexInfo, memory}, device.Target(), {0u, 0u, 0u, 96u}};
|
||||
const auto address = reinterpret_cast<std::uintptr_t>(vertices.data());
|
||||
descriptor = {static_cast<std::uint32_t>(address), static_cast<std::uint32_t>(address >> 32u) | (stride << 16u), static_cast<std::uint32_t>(centres.size()), 0x01000facu | (77u << 12u)};
|
||||
request.context.vertex->resources[0].fields = descriptor;
|
||||
const auto vertex = ShaderRecompiler::Recompile(request);
|
||||
const auto pushBytes = static_cast<std::uint32_t>(vertex.pushConstants.size());
|
||||
ShaderRecompiler::ShaderPixelStageInfo pixelInfo{};
|
||||
pixelInfo.wave32 = true;
|
||||
pixelInfo.targetOutputMode[0] = 9u;
|
||||
pixelInfo.targetExportMapping.fill(0xe4u);
|
||||
pixelInfo.rasterPrimitive = ShaderRecompiler::RasterPrimitive::Point;
|
||||
ShaderRecompiler::RecompileRequest pixelRequest{{ShaderStage::Fragment, reinterpret_cast<std::uintptr_t>(pixelCode.data()), pixelCode, 0, {}}, {32u, 0u, {}, std::nullopt, pixelInfo, std::nullopt, {}}, device.Target(), PixelPushLayout(pushBytes, device.Target())};
|
||||
const auto pixel = ShaderRecompiler::Recompile(pixelRequest);
|
||||
const std::array<AgcDriver::Graphics::CompiledShader, 2> shaders{{{ShaderStage::Vertex, &vertex, 0u}, {ShaderStage::Fragment, &pixel, PixelPushOffset(pushBytes, device.Target())}}};
|
||||
AgcDriver::Graphics::State state{};
|
||||
state.stages = {AgcDriver::Graphics::ShaderPath::Vertex, 0u, 32u, 32u, std::nullopt, std::nullopt};
|
||||
state.color = {reinterpret_cast<std::uintptr_t>(pixels.data()), {Extent, Extent}, VK_FORMAT_R8G8B8A8_UNORM, pixels.size(), 0xe4u};
|
||||
state.colors = {state.color};
|
||||
state.hasColorTarget = true;
|
||||
state.renderExtent = {Extent, Extent};
|
||||
state.topology = VK_PRIMITIVE_TOPOLOGY_POINT_LIST;
|
||||
state.paClVsOutCntl = vertexInfo.paClVsOutCntl;
|
||||
state.vertexPoints = true;
|
||||
state.pointSize = points.size;
|
||||
state.pointSizeMin = points.minimum;
|
||||
state.pointSizeMax = points.maximum;
|
||||
state.viewport = {0.0f, static_cast<float>(Extent), static_cast<float>(Extent), -static_cast<float>(Extent), 0.0f, 1.0f};
|
||||
state.scissor = {{0, 0}, {Extent, Extent}};
|
||||
state.cullMode = VK_CULL_MODE_NONE;
|
||||
state.frontFace = VK_FRONT_FACE_COUNTER_CLOCKWISE;
|
||||
state.blend.colorWriteMask = 15u;
|
||||
state.blends = {state.blend};
|
||||
AgcDriver::Pm4::DrawParameters draw{0u, static_cast<std::uint32_t>(centres.size()), 0u, 1u, 0u, false};
|
||||
draw.firstInstance = 0u;
|
||||
pixels.fill(std::byte{0});
|
||||
device.Draw(state, draw, shaders);
|
||||
device.WaitIdle();
|
||||
std::vector<Square> squares(centres.size());
|
||||
for (std::uint32_t y = 0; y < Extent; ++y) {
|
||||
for (std::uint32_t x = 0; x < Extent; ++x) {
|
||||
const auto index = (y * Extent + x) * 4u;
|
||||
if (pixels[index] == std::byte{0} && pixels[index + 3u] == std::byte{0}) continue;
|
||||
auto& square = squares[(y >= Extent / 2u ? 2u : 0u) + (x >= Extent / 2u ? 1u : 0u)];
|
||||
++square.pixels;
|
||||
square.left = std::min(square.left, x);
|
||||
square.top = std::min(square.top, y);
|
||||
square.right = std::max(square.right, x + 1u);
|
||||
square.bottom = std::max(square.bottom, y + 1u);
|
||||
}
|
||||
}
|
||||
std::cout << "case " << name << ":";
|
||||
for (const auto& square : squares) std::cout << " " << square.pixels << " [" << square.left << "," << square.top << ")-(" << square.right << "," << square.bottom << ")";
|
||||
std::cout << "\n";
|
||||
return squares;
|
||||
}
|
||||
|
||||
void RequireSquares(const std::vector<Square>& squares, std::uint32_t side, const char* name) {
|
||||
for (const auto& square : squares) {
|
||||
Require(square.pixels == side * side && square.right - square.left == side && square.bottom - square.top == side, std::string(name) + ": a point is not a " + std::to_string(side) + "x" + std::to_string(side) + " square");
|
||||
}
|
||||
}
|
||||
|
||||
void RequireAtMostOnePixel(const std::vector<Square>& squares, const char* name) {
|
||||
for (const auto& square : squares) Require(square.pixels <= 1u, std::string(name) + ": a point with no positive size covers more than one pixel");
|
||||
}
|
||||
|
||||
void Run(AgcDriver::VulkanDevice& device) {
|
||||
std::cout << "device: " << device.DeviceName() << "\n";
|
||||
RequireSquares(RunCase(device, "register size 1", positionCode, {1.0f, 1.0f, 1.0f, false}, 0.5f), 1u, "register size 1");
|
||||
RequireSquares(RunCase(device, "register size 4", positionCode, {4.0f, 1.0f, 1.0f, false}, 0.0f), 4u, "register size 4");
|
||||
RequireSquares(RunCase(device, "register size 3 ignores the clamp", positionCode, {3.0f, 6.0f, 8.0f, false}, 0.5f), 3u, "register size 3 ignores the clamp");
|
||||
const auto two = SizeExportCode(2.0f);
|
||||
RequireSquares(RunCase(device, "vertex size 2 within [1, 8]", two, {1.0f, 1.0f, 8.0f, true}, 0.0f), 2u, "vertex size 2 within [1, 8]");
|
||||
const auto six = SizeExportCode(6.0f);
|
||||
RequireSquares(RunCase(device, "vertex size 6 clamped to 4", six, {1.0f, 0.5f, 4.0f, true}, 0.0f), 4u, "vertex size 6 clamped to 4");
|
||||
const auto one = SizeExportCode(1.0f);
|
||||
RequireSquares(RunCase(device, "vertex size 1 clamped to 5", one, {1.0f, 5.0f, 8.0f, true}, 0.5f), 5u, "vertex size 1 clamped to 5");
|
||||
RequireSquares(RunCase(device, "vertex size over a register size", six, {1.0f, 1.0f, 8.0f, true}, 0.0f), 6u, "vertex size over a register size");
|
||||
const auto zero = SizeExportCode(0.0f);
|
||||
RequireAtMostOnePixel(RunCase(device, "vertex size 0 within [0, 4]", zero, {0.0f, 0.0f, 4.0f, true}, 0.5f), "vertex size 0 within [0, 4]");
|
||||
const auto negative = SizeExportCode(-3.0f);
|
||||
RequireAtMostOnePixel(RunCase(device, "vertex size -3 within [0, 4]", negative, {1.0f, 0.0f, 4.0f, true}, 0.5f), "vertex size -3 within [0, 4]");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
int main() {
|
||||
try {
|
||||
const auto device = OpenVulkanTestDevice();
|
||||
if (!device) return VulkanTestSkipped;
|
||||
Run(*device);
|
||||
return 0;
|
||||
} catch (const std::exception& error) {
|
||||
std::cerr << error.what() << '\n';
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
@@ -62,6 +62,11 @@ if(BUILD_TESTING)
|
||||
target_link_libraries(guest_ajm_vibration_tests PRIVATE libSceAjm.native libc)
|
||||
configure_windows_unwind(guest_ajm_vibration_tests)
|
||||
add_test(NAME guest_ajm_vibration COMMAND guest_ajm_vibration_tests)
|
||||
add_test_executable(guest_ajm_wvorbis_tests ${LIBS_INCLUDE_DIR}/tests/GuestAjmWVorbis.cpp)
|
||||
target_include_directories(guest_ajm_wvorbis_tests PRIVATE ${LIBS_INCLUDE_DIR})
|
||||
target_link_libraries(guest_ajm_wvorbis_tests PRIVATE libSceAjm.native libc)
|
||||
configure_windows_unwind(guest_ajm_wvorbis_tests)
|
||||
add_test(NAME guest_ajm_wvorbis COMMAND guest_ajm_wvorbis_tests)
|
||||
if(UNIX)
|
||||
add_test_executable(guest_ajm_teardown_tests ${LIBS_INCLUDE_DIR}/tests/GuestAjmTeardown.cpp)
|
||||
target_include_directories(guest_ajm_teardown_tests PRIVATE ${LIBS_INCLUDE_DIR})
|
||||
@@ -70,7 +75,7 @@ if(BUILD_TESTING)
|
||||
add_test(NAME guest_ajm_teardown COMMAND guest_ajm_teardown_tests $<TARGET_FILE:libSceAjm.native>)
|
||||
endif()
|
||||
if(WIN32)
|
||||
set_tests_properties(guest_ajm guest_ajm_vibration PROPERTIES ENVIRONMENT_MODIFICATION
|
||||
set_tests_properties(guest_ajm guest_ajm_vibration guest_ajm_wvorbis PROPERTIES ENVIRONMENT_MODIFICATION
|
||||
"PATH=path_list_prepend:$<TARGET_FILE_DIR:libSceAjm.native>")
|
||||
endif()
|
||||
endif()
|
||||
@@ -4,6 +4,7 @@
|
||||
#include "prx/libc/include/General.hpp"
|
||||
#include <atomic>
|
||||
#include <cstdio>
|
||||
#include <cstring>
|
||||
|
||||
// Entry points this library does not implement: reported before the unimplemented-call exception so an
|
||||
// APS5_TRACE_AJM run shows which one a title reached.
|
||||
@@ -43,6 +44,38 @@ static_assert(offsetof(WVorbisHeaderPacketParameter, setupPacket) == 32);
|
||||
static_assert(sizeof(WVorbisSetupPacketParameter) == 56);
|
||||
static_assert(offsetof(WVorbisSetupPacketParameter, input) == 16);
|
||||
|
||||
namespace {
|
||||
|
||||
constexpr int AJM_WVORBIS_ERROR_INVALID_PARAMETER = static_cast<int>(0x8A6E0001);
|
||||
constexpr int AJM_WVORBIS_ERROR_INVALID_SIZE = static_cast<int>(0x8A6E0002);
|
||||
constexpr int AJM_WVORBIS_ERROR_OUTPUT_TOO_SMALL = static_cast<int>(0x8A6E0003);
|
||||
constexpr int AJM_WVORBIS_ERROR_INVALID_SETUP = static_cast<int>(0x8A6E0004);
|
||||
constexpr std::size_t WVORBIS_LENGTH_TABLE_SIZE = 10;
|
||||
constexpr std::size_t VORBIS_IDENTIFICATION_SIZE = 30;
|
||||
constexpr std::size_t VORBIS_COMMENT_SIZE = 16;
|
||||
constexpr std::size_t WVORBIS_SETUP_MIN_SIZE = 9;
|
||||
constexpr std::size_t WVORBIS_SETUP_PART1_LENGTH_OFFSET = 7;
|
||||
constexpr std::int32_t VORBIS_BLOCK_SIZE_MIN = 64;
|
||||
constexpr std::int32_t VORBIS_BLOCK_SIZE_MAX = 8192;
|
||||
constexpr std::uint8_t VORBIS_MAGIC[] {'v', 'o', 'r', 'b', 'i', 's'};
|
||||
|
||||
std::int32_t WVorbisBlockSize(std::int32_t log2) {
|
||||
return static_cast<std::int32_t>(1u << (static_cast<std::uint32_t>(log2) & 31u));
|
||||
}
|
||||
|
||||
std::uint8_t* PutLittle(std::uint8_t* out, std::uint32_t value, std::size_t bytes) {
|
||||
for (std::size_t i = 0; i < bytes; ++i) out[i] = static_cast<std::uint8_t>(value >> (8 * i));
|
||||
return out + bytes;
|
||||
}
|
||||
|
||||
std::uint8_t* PutVorbisHeaderStart(std::uint8_t* out, std::uint8_t type) {
|
||||
*out++ = type;
|
||||
std::memcpy(out, VORBIS_MAGIC, sizeof(VORBIS_MAGIC));
|
||||
return out + sizeof(VORBIS_MAGIC);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
extern "C" {
|
||||
|
||||
int APS5_VABI sceAjmBatchJobEncode(AjmBatchInfo* info, uint32_t instance, const void* pcm_input, size_t pcm_input_size, void* bitstream_output, size_t bitstream_output_size, void* result) {
|
||||
@@ -63,8 +96,45 @@ const char* APS5_VABI sceAjmStrError(int error) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
int APS5_VABI sceAjmDecWVorbisCreateHeaderPacket(WVorbisHeaderPacketParameter* parameter) {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
int APS5_VABI sceAjmDecWVorbisCreateHeaderPacket(WVorbisHeaderPacketParameter* param) {
|
||||
if (param == nullptr) return AJM_WVORBIS_ERROR_INVALID_PARAMETER;
|
||||
if (param->size != sizeof(WVorbisHeaderPacketParameter)) return AJM_WVORBIS_ERROR_INVALID_SIZE;
|
||||
if (param->bytesPerSecond < 0) return AJM_WVORBIS_ERROR_INVALID_PARAMETER;
|
||||
if (WVorbisBlockSize(param->shortBlockExponent) < VORBIS_BLOCK_SIZE_MIN) return AJM_WVORBIS_ERROR_INVALID_PARAMETER;
|
||||
if (param->longBlockExponent < param->shortBlockExponent || WVorbisBlockSize(param->longBlockExponent) > VORBIS_BLOCK_SIZE_MAX)
|
||||
return AJM_WVORBIS_ERROR_INVALID_PARAMETER;
|
||||
if (param->setupPacket == nullptr) return AJM_WVORBIS_ERROR_INVALID_PARAMETER;
|
||||
if (param->setupPacketSize < WVORBIS_SETUP_MIN_SIZE) return AJM_WVORBIS_ERROR_INVALID_SETUP;
|
||||
if (param->output == nullptr) return AJM_WVORBIS_ERROR_INVALID_PARAMETER;
|
||||
constexpr std::size_t headers = WVORBIS_LENGTH_TABLE_SIZE + VORBIS_IDENTIFICATION_SIZE + VORBIS_COMMENT_SIZE;
|
||||
if (param->outputCapacity < headers || param->setupPacketSize > param->outputCapacity - headers) return AJM_WVORBIS_ERROR_OUTPUT_TOO_SMALL;
|
||||
|
||||
const auto* setup = static_cast<const std::uint8_t*>(param->setupPacket);
|
||||
const auto part1 = static_cast<std::uint16_t>(setup[WVORBIS_SETUP_PART1_LENGTH_OFFSET] | setup[WVORBIS_SETUP_PART1_LENGTH_OFFSET + 1] << 8);
|
||||
auto* out = static_cast<std::uint8_t*>(param->output);
|
||||
out = PutLittle(out, 0, 2);
|
||||
out = PutLittle(out, VORBIS_IDENTIFICATION_SIZE, 2);
|
||||
out = PutLittle(out, VORBIS_COMMENT_SIZE, 2);
|
||||
out = PutLittle(out, part1, 2);
|
||||
out = PutLittle(out, static_cast<std::uint16_t>(param->setupPacketSize) - part1, 2);
|
||||
|
||||
out = PutVorbisHeaderStart(out, 1);
|
||||
out = PutLittle(out, 0, 4);
|
||||
out = PutLittle(out, static_cast<std::uint32_t>(param->channels), 1);
|
||||
out = PutLittle(out, param->sampleRate, 4);
|
||||
out = PutLittle(out, 0, 4);
|
||||
out = PutLittle(out, static_cast<std::uint32_t>(param->bytesPerSecond) * 8u, 4);
|
||||
out = PutLittle(out, 0, 4);
|
||||
*out++ = static_cast<std::uint8_t>((param->shortBlockExponent & 0xF) | (param->longBlockExponent & 0xF) << 4);
|
||||
*out++ = 1;
|
||||
|
||||
out = PutVorbisHeaderStart(out, 3);
|
||||
out = PutLittle(out, 0, 4);
|
||||
out = PutLittle(out, 0, 4);
|
||||
*out++ = 1;
|
||||
|
||||
std::memcpy(out, setup, param->setupPacketSize);
|
||||
param->outputSize = headers + param->setupPacketSize;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -22,6 +22,15 @@ if(BUILD_TESTING)
|
||||
set_tests_properties(guest_audio3d_port PROPERTIES ENVIRONMENT_MODIFICATION
|
||||
"PATH=path_list_prepend:$<TARGET_FILE_DIR:libSceAudio3d>")
|
||||
endif()
|
||||
add_test_executable(guest_audio3d_speaker_array_tests ${LIBS_INCLUDE_DIR}/tests/GuestAudio3dSpeakerArray.cpp)
|
||||
target_include_directories(guest_audio3d_speaker_array_tests PRIVATE ${LIBS_INCLUDE_DIR})
|
||||
target_link_libraries(guest_audio3d_speaker_array_tests PRIVATE libSceAudio3d libSceAudioOut libc)
|
||||
configure_windows_unwind(guest_audio3d_speaker_array_tests)
|
||||
add_test(NAME guest_audio3d_speaker_array COMMAND guest_audio3d_speaker_array_tests)
|
||||
if(WIN32)
|
||||
set_tests_properties(guest_audio3d_speaker_array PROPERTIES ENVIRONMENT_MODIFICATION
|
||||
"PATH=path_list_prepend:$<TARGET_FILE_DIR:libSceAudio3d>")
|
||||
endif()
|
||||
add_test_executable(guest_audio3d_mixer_tests ${LIBS_INCLUDE_DIR}/tests/GuestAudio3dMixer.cpp)
|
||||
target_include_directories(guest_audio3d_mixer_tests PRIVATE
|
||||
${LIBS_INCLUDE_DIR} ${CMAKE_CURRENT_SOURCE_DIR})
|
||||
|
||||
@@ -472,29 +472,42 @@ int APS5_VABI sceAudio3dReportUnregisterHandler(void) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int APS5_VABI sceAudio3dGetSpeakerArrayMemorySize(void) {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
return 0;
|
||||
size_t APS5_VABI sceAudioOut2GetSpeakerArrayMemorySize(uint32_t num_speakers, uint8_t is_3d, uint8_t is_ambisonics);
|
||||
int APS5_VABI sceAudioOut2SpeakerArrayCreate(AudioOut2SpeakerArrayHandle* handle, const void* vbap_params, const void* ambi_params);
|
||||
int APS5_VABI sceAudioOut2SpeakerArrayDestroy(AudioOut2SpeakerArrayHandle handle);
|
||||
int APS5_VABI sceAudioOut2GetSpeakerArrayCoefficients(AudioOut2SpeakerArrayHandle handle, AudioOut2Position pos, float spread, float* coefficients, uint32_t num_coefficients, uint8_t height_aware, float downmix_spread_radius);
|
||||
|
||||
struct Audio3dSpeakerArrayParameters {
|
||||
const AudioOut2Position* positions;
|
||||
std::uint32_t numSpeakers;
|
||||
std::uint8_t is3d;
|
||||
void* memory;
|
||||
std::size_t memorySize;
|
||||
};
|
||||
|
||||
static_assert(sizeof(Audio3dSpeakerArrayParameters) == 0x20);
|
||||
|
||||
size_t APS5_VABI sceAudio3dGetSpeakerArrayMemorySize(uint32_t num_speakers, uint8_t is_3d) {
|
||||
return sceAudioOut2GetSpeakerArrayMemorySize(num_speakers, is_3d, 0);
|
||||
}
|
||||
|
||||
int APS5_VABI sceAudio3dCreateSpeakerArray(void) {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
return 0;
|
||||
int APS5_VABI sceAudio3dCreateSpeakerArray(AudioOut2SpeakerArrayHandle* handle, const Audio3dSpeakerArrayParameters* parameters) {
|
||||
if (!handle || !parameters) return AUDIO3D_ERROR_INVALID_PARAMETER;
|
||||
unsigned char extended[0x28] = {};
|
||||
std::memcpy(extended, parameters, sizeof(*parameters));
|
||||
return sceAudioOut2SpeakerArrayCreate(handle, extended, nullptr);
|
||||
}
|
||||
|
||||
int APS5_VABI sceAudio3dDeleteSpeakerArray(void) {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
return 0;
|
||||
int APS5_VABI sceAudio3dDeleteSpeakerArray(AudioOut2SpeakerArrayHandle handle) {
|
||||
return sceAudioOut2SpeakerArrayDestroy(handle);
|
||||
}
|
||||
|
||||
int APS5_VABI sceAudio3dGetSpeakerArrayMixCoefficients(void) {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
return 0;
|
||||
int APS5_VABI sceAudio3dGetSpeakerArrayMixCoefficients(AudioOut2SpeakerArrayHandle handle, AudioOut2Position pos, float spread, float* coefficients, uint32_t num_coefficients) {
|
||||
return sceAudioOut2GetSpeakerArrayCoefficients(handle, pos, spread, coefficients, num_coefficients, 0, 0.1f);
|
||||
}
|
||||
|
||||
int APS5_VABI sceAudio3dGetSpeakerArrayMixCoefficients2(void) {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
return 0;
|
||||
int APS5_VABI sceAudio3dGetSpeakerArrayMixCoefficients2(AudioOut2SpeakerArrayHandle handle, AudioOut2Position pos, float spread, float* coefficients, uint32_t num_coefficients, uint8_t height_aware, float downmix_spread_radius) {
|
||||
return sceAudioOut2GetSpeakerArrayCoefficients(handle, pos, spread, coefficients, num_coefficients, height_aware, downmix_spread_radius);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -191,9 +191,9 @@ int32_t APS5_VABI sceAudioInAsyncOpen(int32_t userId, uint32_t type, uint32_t in
|
||||
}
|
||||
|
||||
int32_t APS5_VABI sceAudioInIsPadEmbeddedMic(int32_t handle) {
|
||||
(void)handle;
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
return 0;
|
||||
std::lock_guard lock(g_mutex);
|
||||
if (!find(handle)) return AUDIO_IN_ERROR_INVALID_HANDLE;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int32_t APS5_VABI sceAudioInGetGain(int32_t handle, float* gain) {
|
||||
|
||||
@@ -47,6 +47,21 @@ if(BUILD_TESTING)
|
||||
endif()
|
||||
endforeach()
|
||||
|
||||
add_test_executable(audio_out_buffer_size_tests tests/AudioOutBufferSize.cpp src/AudioOut.cpp src/AudioOut2PadMix.cpp src/AudioOutShutdown.cpp)
|
||||
target_compile_definitions(audio_out_buffer_size_tests PRIVATE SDL_MAIN_HANDLED)
|
||||
target_include_directories(audio_out_buffer_size_tests PRIVATE ${LIBS_INCLUDE_DIR} ${ANYPS5_SDL2_INCLUDE_DIR})
|
||||
target_link_libraries(audio_out_buffer_size_tests PRIVATE libc libkernel libScePad)
|
||||
configure_windows_unwind(audio_out_buffer_size_tests)
|
||||
foreach(bufferSizeMode IN ITEMS pass_through wrap mix threshold)
|
||||
set(bufferSizeTest "audio_out_buffer_size_${bufferSizeMode}")
|
||||
add_test(NAME ${bufferSizeTest} COMMAND audio_out_buffer_size_tests ${bufferSizeMode})
|
||||
set_tests_properties(${bufferSizeTest} PROPERTIES TIMEOUT 5)
|
||||
if(WIN32)
|
||||
set_tests_properties(${bufferSizeTest} PROPERTIES ENVIRONMENT_MODIFICATION
|
||||
"PATH=path_list_prepend:$<TARGET_FILE_DIR:libc>")
|
||||
endif()
|
||||
endforeach()
|
||||
|
||||
add_test_executable(audio_out_vibration_tests tests/AudioOutVibration.cpp)
|
||||
target_include_directories(audio_out_vibration_tests PRIVATE ${LIBS_INCLUDE_DIR})
|
||||
target_link_libraries(audio_out_vibration_tests PRIVATE libSceAudioOut libScePad libc)
|
||||
|
||||
@@ -22,6 +22,11 @@ int APS5_VABI sceAudioOut2MasteringInit(uint32_t flags) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int APS5_VABI sceAudioOut2MasteringInitEx(uint32_t flags) {
|
||||
if ((flags & 0x7FFFFFFFu) != 0) NotImplemented_nid_no_patch(__func__);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int APS5_VABI sceAudioOut2MasteringTerm(void) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -68,7 +68,7 @@ extern "C" {
|
||||
|
||||
int APS5_VABI sceAudioOut2SpeakerArrayCreate(AudioOut2SpeakerArrayHandle* handle, const void* vbap_params, const void* ambi_params) {
|
||||
const auto* params = static_cast<const GuestVbapParams*>(vbap_params);
|
||||
if (handle == nullptr || params == nullptr || ambi_params == nullptr || params->positions == nullptr ||
|
||||
if (handle == nullptr || params == nullptr || params->positions == nullptr ||
|
||||
params->numSpeakers == 0 || params->numSpeakers > MaxSpeakers || params->memory == nullptr ||
|
||||
params->memorySize < sizeof(SpeakerArray) || reinterpret_cast<std::uintptr_t>(params->memory) % alignof(SpeakerArray) != 0) {
|
||||
APS5_INVALID_ARG_EX;
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
#include <atomic>
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include "SceTypes.hpp"
|
||||
#include "prx/libc/include/General.hpp"
|
||||
@@ -33,7 +34,15 @@ int APS5_VABI sceAudioOut2GetSystemState(AudioOut2SystemState* state) {
|
||||
}
|
||||
|
||||
int APS5_VABI sceAudioOut2SetSystemDebugState(const AudioOut2SystemDebugStateParam* param) {
|
||||
if (param == nullptr) return static_cast<int>(0x80260502);
|
||||
constexpr int ErrorInvalidPointer = static_cast<int>(0x8026800C);
|
||||
constexpr std::uint32_t DebugStateIdLoudness = 1;
|
||||
constexpr std::uint32_t DebugStateIdUnmodelled = 0x20;
|
||||
constexpr std::size_t LoudnessParamSize = 8;
|
||||
constexpr std::size_t UnmodelledParamSize = 4;
|
||||
if (param == nullptr) return ErrorInvalidPointer;
|
||||
if (param->debug_state_id == DebugStateIdUnmodelled && param->param_size == UnmodelledParamSize) NotImplemented_nid_no_patch(__func__);
|
||||
if (param->debug_state_id != DebugStateIdLoudness || param->param_size != LoudnessParamSize) return SCE_AUDIO_OUT2_ERROR_INVALID_PARAM;
|
||||
if (param->param == nullptr) NotImplemented_nid_no_patch(__func__);
|
||||
AUDIOOUT2_TRACE("t=%.3f SetSystemDebugState: debug state %u recorded; the host has no system mix to apply it to\n", AudioOut2TraceSeconds(), param->debug_state_id);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -365,11 +365,6 @@ int APS5_VABI sceAudioOut2GetSystemStateEx(void) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int APS5_VABI sceAudioOut2MasteringInitEx(void) {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int APS5_VABI sceAudioOut2SetDebugHeadphoneMode(void) {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
return 0;
|
||||
|
||||
@@ -14,6 +14,7 @@ int APS5_VABI sceAudioOut2LoInit();
|
||||
int APS5_VABI sceAudioOut2LoTerminate();
|
||||
int APS5_VABI sceAudioOut2Set3DLatency(int, std::uint32_t);
|
||||
int APS5_VABI sceAudioOut2MasteringInit(std::uint32_t);
|
||||
int APS5_VABI sceAudioOut2MasteringInitEx(std::uint32_t);
|
||||
int APS5_VABI sceAudioOut2MasteringTerm();
|
||||
int APS5_VABI sceAudioOut2MasteringSetParam(const void*, std::uint32_t, std::uint32_t);
|
||||
int APS5_VABI sceAudioOut2MasteringGetState(void*, std::uint32_t, std::uint64_t);
|
||||
@@ -49,7 +50,7 @@ static_assert(sizeof(AudioOut2MasteringStatesV2) == 400);
|
||||
constexpr int systemUser = 0xFF;
|
||||
constexpr int user = 0x10000000;
|
||||
constexpr int errorInvalidParam = static_cast<int>(0x80268001);
|
||||
constexpr int errorInvalidArgument = static_cast<int>(0x80260502);
|
||||
constexpr int errorInvalidPointer = static_cast<int>(0x8026800C);
|
||||
constexpr int errorMasteringInvalidApiParam = static_cast<int>(0x80268201);
|
||||
constexpr int errorMasteringInvalidStatesId = static_cast<int>(0x80268204);
|
||||
|
||||
@@ -69,6 +70,10 @@ void TestSet3DLatency() {
|
||||
void TestMasteringInit() {
|
||||
Require(sceAudioOut2MasteringInit(0) == 0, "flags 0 must be accepted");
|
||||
Require(ThrowsRuntimeError([] { sceAudioOut2MasteringInit(1); }), "flags 1 must throw");
|
||||
Require(sceAudioOut2MasteringInitEx(0) == 0, "InitEx flags 0 must be accepted");
|
||||
Require(sceAudioOut2MasteringInitEx(0x80000000u) == 0, "InitEx flag bit 31 must be accepted");
|
||||
Require(ThrowsRuntimeError([] { sceAudioOut2MasteringInitEx(1); }), "InitEx flag bit 0 must throw");
|
||||
Require(ThrowsRuntimeError([] { sceAudioOut2MasteringInitEx(0x40000000u); }), "InitEx flag bit 30 must throw");
|
||||
}
|
||||
|
||||
void TestMasteringTerm() {
|
||||
@@ -109,10 +114,25 @@ void TestMasteringGetState() {
|
||||
}
|
||||
|
||||
void TestSetSystemDebugState() {
|
||||
const std::uint64_t param[4] = {1, 0, 0, 0};
|
||||
Require(sceAudioOut2SetSystemDebugState(reinterpret_cast<const void*>(param)) == 0, "a debug state must be accepted");
|
||||
Require(sceAudioOut2SetSystemDebugState(reinterpret_cast<const void*>(param)) == 0, "a debug state must be accepted again");
|
||||
Require(sceAudioOut2SetSystemDebugState(nullptr) == errorInvalidArgument, "a null debug state is refused");
|
||||
std::uint32_t loudness[2] = {1, 0};
|
||||
const auto set = [&loudness](std::uint32_t id, void* data, std::size_t size) {
|
||||
const AudioOut2SystemDebugStateParam param{id, 0, data, size};
|
||||
return sceAudioOut2SetSystemDebugState(¶m);
|
||||
};
|
||||
Require(set(1, loudness, 8) == 0, "the loudness debug state must be accepted");
|
||||
Require(set(1, loudness, 8) == 0, "the loudness debug state must be accepted again");
|
||||
Require(set(1, loudness, 0) == errorInvalidParam, "a loudness debug state of size 0 is refused");
|
||||
Require(set(1, loudness, 4) == errorInvalidParam, "a loudness debug state of size 4 is refused");
|
||||
Require(set(1, loudness, 16) == errorInvalidParam, "a loudness debug state of size 16 is refused");
|
||||
Require(set(0, loudness, 8) == errorInvalidParam, "debug state id 0 is refused");
|
||||
Require(set(2, loudness, 8) == errorInvalidParam, "debug state id 2 is refused");
|
||||
Require(set(0x21, loudness, 8) == errorInvalidParam, "debug state id 0x21 is refused");
|
||||
Require(set(0xFFFFFFFFu, loudness, 8) == errorInvalidParam, "a large debug state id is refused");
|
||||
Require(set(0x20, loudness, 8) == errorInvalidParam, "debug state id 0x20 of size 8 is refused");
|
||||
Require(set(0x20, loudness, 0) == errorInvalidParam, "debug state id 0x20 of size 0 is refused");
|
||||
Require(ThrowsRuntimeError([&] { set(0x20, loudness, 4); }), "debug state id 0x20 of size 4 must throw");
|
||||
Require(ThrowsRuntimeError([&] { set(1, nullptr, 8); }), "a loudness debug state without a param must throw");
|
||||
Require(sceAudioOut2SetSystemDebugState(nullptr) == errorInvalidPointer, "a null debug state is refused");
|
||||
}
|
||||
|
||||
void TestEnableChat() {
|
||||
|
||||
@@ -0,0 +1,100 @@
|
||||
#include "SDL.h"
|
||||
#include "prx/libSceAudioOut/include/AudioOutSdl.hpp"
|
||||
#include "prx/libc/include/general/VabiMacros.hpp"
|
||||
#include <cstdint>
|
||||
#include <cstdio>
|
||||
#include <cstring>
|
||||
#include <stdexcept>
|
||||
#include <string_view>
|
||||
#include <vector>
|
||||
|
||||
extern "C" {
|
||||
int APS5_VABI sceAudioOutOpen(int, int, int, std::uint32_t, std::uint32_t, std::uint32_t);
|
||||
int APS5_VABI sceAudioOutClose(int);
|
||||
int APS5_VABI sceAudioOutOutput(int, const void*);
|
||||
}
|
||||
|
||||
namespace {
|
||||
constexpr SDL_AudioDeviceID device = 7;
|
||||
int opened = 0;
|
||||
int closed = 0;
|
||||
int queued = 0;
|
||||
std::uint32_t queuedBytes = 0;
|
||||
const void* supplied = nullptr;
|
||||
std::uint32_t suppliedBytes = 0;
|
||||
|
||||
void Require(bool value, const char* message) {
|
||||
if (!value) throw std::runtime_error(message);
|
||||
}
|
||||
|
||||
void RunPassThrough() {
|
||||
std::vector<float> samples(512u * 8u);
|
||||
for (std::size_t i = 0; i < samples.size(); ++i) samples[i] = static_cast<float>(i % 97u) / 97.0f;
|
||||
const int handle = sceAudioOutOpen(0, 0, 0, 512, 48000, 5);
|
||||
Require(handle > 0 && opened == 1, "a 512-frame F32 8-channel port did not open its device");
|
||||
supplied = samples.data();
|
||||
suppliedBytes = static_cast<std::uint32_t>(samples.size() * sizeof(float));
|
||||
Require(sceAudioOutOutput(handle, samples.data()) == 512, "a 512-frame output did not return 512");
|
||||
Require(queued == 1 && queuedBytes == 16384, "a 512-frame F32 8-channel output did not queue 16384 bytes");
|
||||
Require(sceAudioOutClose(handle) == 0 && closed == 1, "the port did not close its device");
|
||||
}
|
||||
|
||||
void RunOverflow(std::uint32_t frames, std::uint32_t format, std::uint32_t frameBytes) {
|
||||
std::vector<std::uint8_t> frame(frameBytes);
|
||||
const int handle = sceAudioOutOpen(0, 0, 0, frames, 48000, format);
|
||||
Require(handle > 0 && opened == 1, "a port with an oversized length did not open its device");
|
||||
supplied = frame.data();
|
||||
suppliedBytes = frameBytes;
|
||||
bool threw = false;
|
||||
try {
|
||||
static_cast<void>(sceAudioOutOutput(handle, frame.data()));
|
||||
} catch (const std::runtime_error&) {
|
||||
threw = true;
|
||||
}
|
||||
Require(threw, "an output whose buffer size overflows did not throw");
|
||||
Require(queued == 0, "an output whose buffer size overflows queued audio");
|
||||
Require(sceAudioOutClose(handle) == 0 && closed == 1, "the port did not close after the refused output");
|
||||
}
|
||||
}
|
||||
|
||||
int InitializeSdlAudio_nid_no_patch() { return 0; }
|
||||
extern "C" Uint32 SDLCALL SDL_WasInit(Uint32) { return SDL_INIT_AUDIO; }
|
||||
extern "C" int SDLCALL SDL_GetNumAudioDevices(int) { return 1; }
|
||||
extern "C" const char* SDLCALL SDL_GetAudioDeviceName(int, int) { return "Main speakers"; }
|
||||
extern "C" int SDLCALL SDL_GetAudioDeviceSpec(int, int, SDL_AudioSpec* spec) { *spec = {}; spec->channels = 2; return 0; }
|
||||
extern "C" const char* SDLCALL SDL_GetCurrentAudioDriver() { return "dummy"; }
|
||||
extern "C" const char* SDLCALL SDL_GetError() { return "test error"; }
|
||||
extern "C" SDL_AudioDeviceID SDLCALL SDL_OpenAudioDevice(const char* name, int capture, const SDL_AudioSpec* desired, SDL_AudioSpec* obtained, int) {
|
||||
Require(name == nullptr && capture == 0 && desired->callback == nullptr, "the main port did not open the default device");
|
||||
++opened;
|
||||
*obtained = *desired;
|
||||
return device;
|
||||
}
|
||||
extern "C" void SDLCALL SDL_PauseAudioDevice(SDL_AudioDeviceID id, int) { Require(id == device, "wrong device paused"); }
|
||||
extern "C" Uint32 SDLCALL SDL_GetQueuedAudioSize(SDL_AudioDeviceID id) { Require(id == device, "wrong queue queried"); return 0; }
|
||||
extern "C" int SDLCALL SDL_QueueAudio(SDL_AudioDeviceID id, const void* data, Uint32 bytes) {
|
||||
Require(id == device, "wrong queue fed");
|
||||
++queued;
|
||||
queuedBytes = bytes;
|
||||
if (bytes <= suppliedBytes) Require(std::memcmp(data, supplied, bytes) == 0, "the queued audio is not the supplied samples");
|
||||
return 0;
|
||||
}
|
||||
extern "C" void SDLCALL SDL_ClearQueuedAudio(SDL_AudioDeviceID id) { Require(id == device, "wrong queue cleared"); }
|
||||
extern "C" void SDLCALL SDL_CloseAudioDevice(SDL_AudioDeviceID id) { Require(id == device, "wrong device closed"); ++closed; }
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
try {
|
||||
Require(argc == 2, "invalid test arguments");
|
||||
const std::string_view mode = argv[1];
|
||||
if (mode == "pass_through") RunPassThrough();
|
||||
else if (mode == "wrap") RunOverflow(0x80000000u, 5, 8u * sizeof(float));
|
||||
else if (mode == "mix") RunOverflow(0x80000000u, 7, 8u * sizeof(float));
|
||||
else if (mode == "threshold") RunOverflow(0x40000000u, 0, sizeof(std::int16_t));
|
||||
else Require(false, "invalid buffer size mode");
|
||||
std::puts("audio out buffer size tests passed");
|
||||
return 0;
|
||||
} catch (const std::exception& error) {
|
||||
std::fprintf(stderr, "%s\n", error.what());
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
@@ -21,10 +21,10 @@ constexpr int CES_ERROR_UNASSIGNED_CODE = static_cast<int>(0x805C0020);
|
||||
constexpr int CES_ERROR_INVALID_DST_BUFFER = static_cast<int>(0x805C0030);
|
||||
constexpr int CES_ERROR_DST_BUFFER_END = static_cast<int>(0x805C0031);
|
||||
|
||||
constexpr uint8_t PROFILES[3] = {0, 1, 2};
|
||||
constexpr const uint8_t* CP1252_PROFILE = &PROFILES[0];
|
||||
constexpr const uint8_t* CP1251_PROFILE = &PROFILES[1];
|
||||
constexpr const uint8_t* CP1250_PROFILE = &PROFILES[2];
|
||||
constexpr uint8_t PROFILES[3][8] = {{0}, {1}, {2}};
|
||||
constexpr const uint8_t* CP1252_PROFILE = PROFILES[0];
|
||||
constexpr const uint8_t* CP1251_PROFILE = PROFILES[1];
|
||||
constexpr const uint8_t* CP1250_PROFILE = PROFILES[2];
|
||||
|
||||
constexpr uint16_t CP1252_HIGH[32] = {
|
||||
0x20AC, 0x0081, 0x201A, 0x0192, 0x201E, 0x2026, 0x2020, 0x2021, 0x02C6, 0x2030, 0x0160, 0x2039, 0x0152, 0x008D, 0x017D, 0x008F,
|
||||
|
||||
@@ -248,6 +248,7 @@ inline bool ValidateCommonDialogBaseParam(const CommonDialogBaseParam& param) {
|
||||
}
|
||||
|
||||
constexpr int COMMON_DIALOG_OK = 0;
|
||||
constexpr int COMMON_DIALOG_ERROR_ALREADY_SYSTEM_INITIALIZED = static_cast<int>(0x80B80002);
|
||||
constexpr int COMMON_DIALOG_ERROR_ALREADY_INITIALIZED = static_cast<int>(0x80B80004);
|
||||
|
||||
#endif
|
||||
@@ -12,7 +12,7 @@ extern "C" {
|
||||
int APS5_VABI sceCommonDialogInitialize(void) {
|
||||
bool expected = false;
|
||||
if (!g_initialized.compare_exchange_strong(expected, true)) {
|
||||
return COMMON_DIALOG_ERROR_ALREADY_INITIALIZED;
|
||||
return COMMON_DIALOG_ERROR_ALREADY_SYSTEM_INITIALIZED;
|
||||
}
|
||||
return COMMON_DIALOG_OK;
|
||||
}
|
||||
|
||||
@@ -78,8 +78,7 @@ int APS5_VABI sceFontFtSupportTrueType(FontLibrary library) {
|
||||
}
|
||||
|
||||
int APS5_VABI sceFontFtSupportTrueTypeGx(FontLibrary library) {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
return 0;
|
||||
return FontFt::SupportFormats(library, {"truetype"});
|
||||
}
|
||||
|
||||
int APS5_VABI sceFontFtSupportType1(FontLibrary library) {
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
add_library(libSceFreeType SHARED EXCLUDE_FROM_ALL
|
||||
Export.cpp
|
||||
src/GuestObjects.cpp
|
||||
src/Names.cpp
|
||||
)
|
||||
target_include_directories(libSceFreeType PRIVATE ${LIBS_INCLUDE_DIR})
|
||||
target_link_libraries(libSceFreeType PRIVATE freetype)
|
||||
@@ -20,7 +21,21 @@ if(BUILD_TESTING)
|
||||
target_link_libraries(guest_freetype_charmap_tests PRIVATE libSceFreeType freetype libc)
|
||||
configure_windows_unwind(guest_freetype_charmap_tests)
|
||||
add_test(NAME guest_freetype_charmap COMMAND guest_freetype_charmap_tests)
|
||||
add_test_executable(guest_freetype_names_tests ${LIBS_INCLUDE_DIR}/tests/GuestFreeTypeNames.cpp)
|
||||
target_include_directories(guest_freetype_names_tests PRIVATE ${LIBS_INCLUDE_DIR})
|
||||
target_link_libraries(guest_freetype_names_tests PRIVATE libSceFreeType freetype libc)
|
||||
configure_windows_unwind(guest_freetype_names_tests)
|
||||
add_test(NAME guest_freetype_names COMMAND guest_freetype_names_tests)
|
||||
add_test_executable(guest_freetype_sfnt_names_tests ${LIBS_INCLUDE_DIR}/tests/GuestFreeTypeSfntNames.cpp)
|
||||
target_include_directories(guest_freetype_sfnt_names_tests PRIVATE ${LIBS_INCLUDE_DIR})
|
||||
target_link_libraries(guest_freetype_sfnt_names_tests PRIVATE libSceFreeType freetype libc)
|
||||
configure_windows_unwind(guest_freetype_sfnt_names_tests)
|
||||
add_test(NAME guest_freetype_sfnt_names COMMAND guest_freetype_sfnt_names_tests)
|
||||
if(WIN32)
|
||||
set_tests_properties(guest_freetype_sfnt_names PROPERTIES ENVIRONMENT_MODIFICATION
|
||||
"PATH=path_list_prepend:$<TARGET_FILE_DIR:libSceFreeType>")
|
||||
set_tests_properties(guest_freetype_names PROPERTIES ENVIRONMENT_MODIFICATION
|
||||
"PATH=path_list_prepend:$<TARGET_FILE_DIR:libSceFreeType>")
|
||||
set_tests_properties(guest_freetype PROPERTIES ENVIRONMENT_MODIFICATION
|
||||
"PATH=path_list_prepend:$<TARGET_FILE_DIR:libSceFreeType>")
|
||||
set_tests_properties(guest_freetype_charmap PROPERTIES ENVIRONMENT_MODIFICATION
|
||||
|
||||
@@ -149,6 +149,28 @@ int APS5_VABI FT_Set_Pixel_Sizes_nid_postfix(GuestFaceRec* face, std::uint32_t p
|
||||
return error;
|
||||
}
|
||||
|
||||
int APS5_VABI FT_Set_Char_Size_nid_postfix(GuestFaceRec* face, std::int64_t charWidth, std::int64_t charHeight,
|
||||
std::uint32_t horizontalResolution, std::uint32_t verticalResolution) {
|
||||
GuestFace* owner = FaceOf(face);
|
||||
if (!owner) return FT_Err_Invalid_Face_Handle;
|
||||
if (!owner->host->size) return FT_Err_Invalid_Size_Handle;
|
||||
if (!charWidth) charWidth = charHeight;
|
||||
else if (!charHeight) charHeight = charWidth;
|
||||
if (charWidth < 64) charWidth = 64;
|
||||
if (charHeight < 64) charHeight = 64;
|
||||
if (!horizontalResolution) horizontalResolution = verticalResolution;
|
||||
else if (!verticalResolution) verticalResolution = horizontalResolution;
|
||||
if (!horizontalResolution) horizontalResolution = verticalResolution = 72;
|
||||
const auto maximum = std::numeric_limits<FT_Long>::max();
|
||||
if (charWidth > (maximum - 36) / horizontalResolution || charHeight > (maximum - 36) / verticalResolution) {
|
||||
throw std::runtime_error("FT_Set_Char_Size: a character size or resolution outside the host arithmetic range is not implemented");
|
||||
}
|
||||
const FT_Error error = FT_Set_Char_Size(owner->host, static_cast<FT_F26Dot6>(charWidth), static_cast<FT_F26Dot6>(charHeight),
|
||||
horizontalResolution, verticalResolution);
|
||||
SyncSize(*owner);
|
||||
return error;
|
||||
}
|
||||
|
||||
std::uint32_t APS5_VABI FT_Get_Char_Index_nid_postfix(GuestFaceRec* face, std::uint64_t charcode) {
|
||||
const GuestFace* owner = FaceOf(face);
|
||||
return FT_Get_Char_Index(owner ? owner->host : nullptr, static_cast<FT_ULong>(static_cast<std::uint32_t>(charcode)));
|
||||
@@ -205,4 +227,20 @@ std::uint64_t APS5_VABI FT_Get_Next_Char_nid_postfix(GuestFaceRec* face, std::ui
|
||||
return FT_Get_Next_Char(owner ? owner->host : nullptr, static_cast<FT_ULong>(static_cast<std::uint32_t>(charcode)), glyphIndex);
|
||||
}
|
||||
|
||||
void APS5_VABI FT_Set_Transform_nid_postfix(GuestFaceRec* face, const GuestMatrix* matrix, const GuestVector* delta) {
|
||||
GuestFace* owner = FaceOf(face);
|
||||
if (!owner) return;
|
||||
const auto component = [](std::int64_t value) {
|
||||
if (value < std::numeric_limits<FT_Long>::min() || value > std::numeric_limits<FT_Long>::max()) {
|
||||
throw std::runtime_error("FT_Set_Transform: a component outside the host FT_Long range is not implemented");
|
||||
}
|
||||
return static_cast<FT_Long>(value);
|
||||
};
|
||||
FT_Matrix nativeMatrix{};
|
||||
FT_Vector nativeDelta{};
|
||||
if (matrix) nativeMatrix = {component(matrix->xx), component(matrix->xy), component(matrix->yx), component(matrix->yy)};
|
||||
if (delta) nativeDelta = {component(delta->x), component(delta->y)};
|
||||
FT_Set_Transform(owner->host, matrix ? &nativeMatrix : nullptr, delta ? &nativeDelta : nullptr);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -18,6 +18,13 @@ struct GuestVector {
|
||||
std::int64_t y;
|
||||
};
|
||||
|
||||
struct GuestMatrix {
|
||||
std::int64_t xx;
|
||||
std::int64_t xy;
|
||||
std::int64_t yx;
|
||||
std::int64_t yy;
|
||||
};
|
||||
|
||||
struct GuestBBox {
|
||||
std::int64_t xMin;
|
||||
std::int64_t yMin;
|
||||
@@ -40,6 +47,15 @@ struct GuestCharMapRec {
|
||||
std::uint16_t encoding_id;
|
||||
};
|
||||
|
||||
struct GuestSfntName {
|
||||
std::uint16_t platform_id;
|
||||
std::uint16_t encoding_id;
|
||||
std::uint16_t language_id;
|
||||
std::uint16_t name_id;
|
||||
unsigned char* string;
|
||||
std::uint32_t string_len;
|
||||
};
|
||||
|
||||
struct GuestSizeMetrics {
|
||||
std::uint16_t x_ppem;
|
||||
std::uint16_t y_ppem;
|
||||
@@ -149,9 +165,11 @@ struct GuestFaceRec {
|
||||
void* internal;
|
||||
};
|
||||
|
||||
static_assert(sizeof(GuestMatrix) == 32 && offsetof(GuestMatrix, xy) == 8 && offsetof(GuestMatrix, yx) == 16 && offsetof(GuestMatrix, yy) == 24);
|
||||
static_assert(sizeof(GuestGeneric) == 16 && offsetof(GuestGeneric, finalizer) == 8);
|
||||
static_assert(sizeof(GuestBitmapSize) == 32 && offsetof(GuestBitmapSize, size) == 8);
|
||||
static_assert(sizeof(GuestCharMapRec) == 16 && offsetof(GuestCharMapRec, platform_id) == 12);
|
||||
static_assert(sizeof(GuestSfntName) == 24 && offsetof(GuestSfntName, string) == 8 && offsetof(GuestSfntName, string_len) == 16);
|
||||
static_assert(sizeof(GuestSizeMetrics) == 56 && offsetof(GuestSizeMetrics, x_scale) == 8);
|
||||
static_assert(sizeof(GuestSizeRec) == 88 && offsetof(GuestSizeRec, metrics) == 24);
|
||||
static_assert(sizeof(GuestBitmap) == 40 && offsetof(GuestBitmap, buffer) == 16 && offsetof(GuestBitmap, palette) == 32);
|
||||
|
||||
@@ -0,0 +1,55 @@
|
||||
#include "prx/libSceFreeType/include/GuestObjects.hpp"
|
||||
#include "prx/libc/include/GuestArena.hpp"
|
||||
#include "prx/libc/include/general/VabiMacros.hpp"
|
||||
|
||||
#include FT_SFNT_NAMES_H
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
using namespace FreeType;
|
||||
|
||||
extern "C" {
|
||||
|
||||
int APS5_VABI FT_Get_Glyph_Name_nid_postfix(GuestFaceRec* face, std::uint32_t glyphIndex, void* buffer, std::uint32_t bufferSize) {
|
||||
const GuestFace* owner = FaceOf(face);
|
||||
const FT_Face host = owner ? owner->host : nullptr;
|
||||
if (!host || !buffer || bufferSize == 0) return FT_Get_Glyph_Name(host, glyphIndex, buffer, bufferSize);
|
||||
GuestArena::HostWrite write(buffer, bufferSize);
|
||||
if (static_cast<std::int64_t>(glyphIndex) >= host->num_glyphs) {
|
||||
static_cast<char*>(buffer)[0] = '\0';
|
||||
return FT_Err_Invalid_Glyph_Index;
|
||||
}
|
||||
return FT_Get_Glyph_Name(host, glyphIndex, buffer, bufferSize);
|
||||
}
|
||||
|
||||
std::uint32_t APS5_VABI FT_Get_Name_Index_nid_postfix(GuestFaceRec* face, const char* glyphName) {
|
||||
const GuestFace* owner = FaceOf(face);
|
||||
return FT_Get_Name_Index(owner ? owner->host : nullptr, glyphName);
|
||||
}
|
||||
|
||||
const char* APS5_VABI FT_Get_Postscript_Name_nid_postfix(GuestFaceRec* face) {
|
||||
const GuestFace* owner = FaceOf(face);
|
||||
return FT_Get_Postscript_Name(owner ? owner->host : nullptr);
|
||||
}
|
||||
|
||||
std::uint32_t APS5_VABI FT_Get_Sfnt_Name_Count_nid_postfix(GuestFaceRec* face) {
|
||||
const GuestFace* owner = FaceOf(face);
|
||||
return FT_Get_Sfnt_Name_Count(owner ? owner->host : nullptr);
|
||||
}
|
||||
|
||||
int APS5_VABI FT_Get_Sfnt_Name_nid_postfix(GuestFaceRec* face, std::uint32_t index, GuestSfntName* name) {
|
||||
const GuestFace* owner = FaceOf(face);
|
||||
FT_SfntName native{};
|
||||
const FT_Error error = FT_Get_Sfnt_Name(owner ? owner->host : nullptr, index, name ? &native : nullptr);
|
||||
if (!error) {
|
||||
name->platform_id = native.platform_id;
|
||||
name->encoding_id = native.encoding_id;
|
||||
name->language_id = native.language_id;
|
||||
name->name_id = native.name_id;
|
||||
name->string = native.string;
|
||||
name->string_len = native.string_len;
|
||||
}
|
||||
return error;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -5,6 +5,8 @@
|
||||
#include "prx/libSceUserService/UserService.hpp"
|
||||
#include <cstring>
|
||||
#include <mutex>
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
|
||||
static std::mutex g_mutex;
|
||||
static bool g_initialized = false;
|
||||
@@ -271,8 +273,10 @@ int APS5_VABI sceGameLiveStreamingStopDebugBroadcast(void) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int APS5_VABI sceGameLiveStreamingEnableLiveStreaming(void) {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
int APS5_VABI sceGameLiveStreamingEnableLiveStreaming(bool isEnableLiveStreaming) {
|
||||
std::lock_guard lock(g_mutex);
|
||||
if (!g_initialized) throw std::logic_error(std::string(__func__) + ": not initialized");
|
||||
(void)isEnableLiveStreaming;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,11 +1,13 @@
|
||||
add_library(libSceHmd SHARED EXCLUDE_FROM_ALL Export.cpp)
|
||||
target_include_directories(libSceHmd PRIVATE ${LIBS_INCLUDE_DIR})
|
||||
target_link_libraries(libSceHmd PRIVATE libc)
|
||||
configure_windows_unwind(libSceHmd)
|
||||
|
||||
if(BUILD_TESTING)
|
||||
add_test_executable(guest_hmd_tests ${LIBS_INCLUDE_DIR}/tests/GuestHmd.cpp)
|
||||
target_include_directories(guest_hmd_tests PRIVATE ${LIBS_INCLUDE_DIR})
|
||||
target_link_libraries(guest_hmd_tests PRIVATE libSceHmd)
|
||||
configure_windows_unwind(guest_hmd_tests)
|
||||
add_test(NAME guest_hmd COMMAND guest_hmd_tests)
|
||||
if(WIN32)
|
||||
set_tests_properties(guest_hmd PROPERTIES ENVIRONMENT_MODIFICATION
|
||||
|
||||
@@ -1,7 +1,12 @@
|
||||
#include "Hmd.hpp"
|
||||
#include "prx/libc/include/ApplicationHeap.hpp"
|
||||
#include "prx/libc/include/General.hpp"
|
||||
|
||||
#include <atomic>
|
||||
#include <cstddef>
|
||||
#include <cstring>
|
||||
#include <initializer_list>
|
||||
#include <string>
|
||||
|
||||
struct HmdDistortionCommandParameter;
|
||||
struct HmdWideNearDistortionCommandParameter;
|
||||
@@ -64,6 +69,36 @@ std::int32_t Initialize(const Hmd::InitializeParam* param) {
|
||||
return initialized.exchange(true) ? Hmd::AlreadyInitialized : 0;
|
||||
}
|
||||
|
||||
std::uint32_t CompiledSdkVersion() {
|
||||
static const auto* processParameters = static_cast<const std::byte*>(ApplicationProcessParameters_nid_no_patch());
|
||||
std::uint32_t version;
|
||||
std::memcpy(&version, processParameters + 0x10, sizeof(version));
|
||||
return version;
|
||||
}
|
||||
|
||||
std::int32_t CommandQueryHandle(std::int32_t handle, const char* query) {
|
||||
if (handle != 0) return Hmd::InvalidHandle;
|
||||
if (initialized.load()) NotImplemented_nid_no_patch((std::string(query) + " with handle 0 after sceHmdInitialize").c_str());
|
||||
if (CompiledSdkVersion() >= Hmd::StartupStateSdkVersion) NotImplemented_nid_no_patch((std::string(query) + " with handle 0 before sceHmdInitialize from SDK 4.50").c_str());
|
||||
return Hmd::NotInitialized;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
T ParameterWord(const Hmd2dVrCommandParameter* parameter, std::size_t offset) {
|
||||
T value;
|
||||
std::memcpy(&value, reinterpret_cast<const unsigned char*>(parameter) + offset, sizeof(value));
|
||||
return value;
|
||||
}
|
||||
|
||||
std::int32_t Vr2dCommandArguments(const Hmd2dVrCommandParameter* parameter, const HmdCommandBuffer* commandBuffer) {
|
||||
if (!parameter || !commandBuffer) return Hmd::ParameterNull;
|
||||
for (const std::size_t offset : {0x00u, 0x08u, 0x20u}) {
|
||||
if (ParameterWord<std::uint64_t>(parameter, offset) == 0) return Hmd::ParameterNull;
|
||||
}
|
||||
if (ParameterWord<std::uint32_t>(parameter, 0x34) != 0 || ParameterWord<std::uint64_t>(parameter, 0x38) != 0) return Hmd::ParameterInvalid;
|
||||
return 0;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
struct HmdEyeDistances {
|
||||
@@ -428,8 +463,7 @@ int APS5_VABI sceHmdReprojectionStopCapture(HmdCaptureInfo* info) {
|
||||
}
|
||||
|
||||
bool APS5_VABI sceHmdInternalIsCommonDlgMiniAppVr2d(void) {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
return 0;
|
||||
return false;
|
||||
}
|
||||
|
||||
int APS5_VABI sceHmdInternalMmapGetSensorCalibrationData(void* buffer, std::uint32_t size) {
|
||||
@@ -438,8 +472,9 @@ int APS5_VABI sceHmdInternalMmapGetSensorCalibrationData(void* buffer, std::uint
|
||||
}
|
||||
|
||||
int APS5_VABI sceHmdDistortionGetCorrectionCommand(std::int32_t handle, const HmdDistortionCommandParameter* parameter, HmdCommandBuffer* commandBuffer) {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
return 0;
|
||||
(void)parameter;
|
||||
(void)commandBuffer;
|
||||
return CommandQueryHandle(handle, __func__);
|
||||
}
|
||||
|
||||
int APS5_VABI sceHmdReprojectionQueryOnionBuffAlign(void) {
|
||||
@@ -452,13 +487,11 @@ int APS5_VABI sceHmdInternalGetDebugMode(std::uint8_t* mode) {
|
||||
}
|
||||
|
||||
bool APS5_VABI sceHmdInternalIsMiniAppVr2d(void) {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
return 0;
|
||||
return false;
|
||||
}
|
||||
|
||||
bool APS5_VABI sceHmdInternalIsCommonDlgVr2d(void) {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
return 0;
|
||||
return false;
|
||||
}
|
||||
|
||||
int APS5_VABI sceHmdReprojectionSetOutputMinColor(float red, float green, float blue) {
|
||||
@@ -572,8 +605,9 @@ int APS5_VABI sceHmdInternalGetHmuSerialNumber(std::uint8_t* serialNumber) {
|
||||
}
|
||||
|
||||
int APS5_VABI sceHmdDistortionGetWideNearCorrectionCommand(std::int32_t handle, const HmdWideNearDistortionCommandParameter* parameter, HmdCommandBuffer* commandBuffer) {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
return 0;
|
||||
(void)parameter;
|
||||
(void)commandBuffer;
|
||||
return CommandQueryHandle(handle, __func__);
|
||||
}
|
||||
|
||||
int APS5_VABI sceHmdInternalCheckS3dPassModeAvailable(bool* available) {
|
||||
@@ -597,8 +631,7 @@ int APS5_VABI sceHmdReprojectionStartLiveCapture(const HmdLiveCaptureParameter*
|
||||
}
|
||||
|
||||
bool APS5_VABI sceHmdInternalIsGameVr2d(void) {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
return 0;
|
||||
return false;
|
||||
}
|
||||
|
||||
int APS5_VABI sceHmdGetAssyError(HmdAssemblyError* data) {
|
||||
@@ -727,8 +760,8 @@ int APS5_VABI sceHmdInternalMmapGetModeId(std::uint32_t* modeId) {
|
||||
}
|
||||
|
||||
int APS5_VABI sceHmdDistortionGet2dVrCommand(std::int32_t handle, const Hmd2dVrCommandParameter* parameter, HmdCommandBuffer* commandBuffer) {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
return 0;
|
||||
if (const auto result = Vr2dCommandArguments(parameter, commandBuffer); result != 0) return result;
|
||||
return CommandQueryHandle(handle, __func__);
|
||||
}
|
||||
|
||||
int APS5_VABI sceHmdInternalDfuSendSize(std::int32_t size) {
|
||||
@@ -737,8 +770,9 @@ int APS5_VABI sceHmdInternalDfuSendSize(std::int32_t size) {
|
||||
}
|
||||
|
||||
int APS5_VABI sceHmdGetWideNearDistortionCorrectionCommand(std::int32_t handle, const HmdWideNearDistortionCommandParameter* parameter, HmdCommandBuffer* commandBuffer) {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
return 0;
|
||||
(void)parameter;
|
||||
(void)commandBuffer;
|
||||
return CommandQueryHandle(handle, __func__);
|
||||
}
|
||||
|
||||
int APS5_VABI sceHmdReprojectionStartMultilayer2(const HmdReprojectionMultilayerParameter* layers, std::uint32_t layerCount, const HmdReprojectionSubmissionParameter* submission, std::uint64_t flipArg, const void* reserved) {
|
||||
@@ -747,8 +781,9 @@ int APS5_VABI sceHmdReprojectionStartMultilayer2(const HmdReprojectionMultilayer
|
||||
}
|
||||
|
||||
int APS5_VABI sceHmdGetDistortionCorrectionCommand(std::int32_t handle, const HmdDistortionCommandParameter* parameter, HmdCommandBuffer* commandBuffer) {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
return 0;
|
||||
(void)parameter;
|
||||
(void)commandBuffer;
|
||||
return CommandQueryHandle(handle, __func__);
|
||||
}
|
||||
|
||||
int APS5_VABI sceHmdInternalSetDeviceConnection(std::uint64_t connection) {
|
||||
@@ -962,8 +997,8 @@ int APS5_VABI sceHmdReprojectionQueryGarlicBuffSize(void) {
|
||||
}
|
||||
|
||||
int APS5_VABI sceHmdGet2dVrCommand(std::int32_t handle, const Hmd2dVrCommandParameter* parameter, HmdCommandBuffer* commandBuffer) {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
return 0;
|
||||
if (const auto result = Vr2dCommandArguments(parameter, commandBuffer); result != 0) return result;
|
||||
return CommandQueryHandle(handle, __func__);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -15,6 +15,7 @@ inline constexpr std::int32_t DeviceDisconnected = static_cast<std::int32_t>(0x8
|
||||
inline constexpr std::int32_t ParameterNull = static_cast<std::int32_t>(0x81110008);
|
||||
inline constexpr std::int32_t ParameterInvalid = static_cast<std::int32_t>(0x81110009);
|
||||
inline constexpr std::int32_t UnsupportedFeature = static_cast<std::int32_t>(0x81110016);
|
||||
inline constexpr std::uint32_t StartupStateSdkVersion = 0x04500000;
|
||||
|
||||
enum class DeviceStatus : std::uint32_t {
|
||||
Ready = 0,
|
||||
@@ -55,6 +56,10 @@ struct HmdFieldOfView;
|
||||
struct HmdEyeOffset;
|
||||
struct HmdInertialSensorData;
|
||||
struct HmdAssemblyError;
|
||||
struct HmdDistortionCommandParameter;
|
||||
struct HmdWideNearDistortionCommandParameter;
|
||||
struct Hmd2dVrCommandParameter;
|
||||
struct HmdCommandBuffer;
|
||||
|
||||
extern "C" {
|
||||
std::int32_t APS5_VABI sceHmdInitialize(const Hmd::InitializeParam* param);
|
||||
@@ -78,6 +83,16 @@ int APS5_VABI sceHmdGetFieldOfView(std::int32_t handle, HmdFieldOfView* fieldOfV
|
||||
int APS5_VABI sceHmdGet2DEyeOffset(std::int32_t handle, HmdEyeOffset* leftOffset, HmdEyeOffset* rightOffset);
|
||||
int APS5_VABI sceHmdGetInertialSensorData(std::int32_t handle, HmdInertialSensorData* data, std::uint32_t count);
|
||||
int APS5_VABI sceHmdGetAssyError(HmdAssemblyError* data);
|
||||
int APS5_VABI sceHmdDistortionGet2dVrCommand(std::int32_t handle, const Hmd2dVrCommandParameter* parameter, HmdCommandBuffer* commandBuffer);
|
||||
int APS5_VABI sceHmdDistortionGetCorrectionCommand(std::int32_t handle, const HmdDistortionCommandParameter* parameter, HmdCommandBuffer* commandBuffer);
|
||||
int APS5_VABI sceHmdDistortionGetWideNearCorrectionCommand(std::int32_t handle, const HmdWideNearDistortionCommandParameter* parameter, HmdCommandBuffer* commandBuffer);
|
||||
int APS5_VABI sceHmdGet2dVrCommand(std::int32_t handle, const Hmd2dVrCommandParameter* parameter, HmdCommandBuffer* commandBuffer);
|
||||
int APS5_VABI sceHmdGetDistortionCorrectionCommand(std::int32_t handle, const HmdDistortionCommandParameter* parameter, HmdCommandBuffer* commandBuffer);
|
||||
int APS5_VABI sceHmdGetWideNearDistortionCorrectionCommand(std::int32_t handle, const HmdWideNearDistortionCommandParameter* parameter, HmdCommandBuffer* commandBuffer);
|
||||
bool APS5_VABI sceHmdInternalIsGameVr2d(void);
|
||||
bool APS5_VABI sceHmdInternalIsMiniAppVr2d(void);
|
||||
bool APS5_VABI sceHmdInternalIsCommonDlgVr2d(void);
|
||||
bool APS5_VABI sceHmdInternalIsCommonDlgMiniAppVr2d(void);
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -14,3 +14,15 @@ if(BUILD_TESTING)
|
||||
"PATH=path_list_prepend:$<TARGET_FILE_DIR:libSceHmd2>")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(BUILD_TESTING)
|
||||
add_test_executable(guest_hmd2_gaze_tests ${LIBS_INCLUDE_DIR}/tests/GuestHmd2Gaze.cpp)
|
||||
target_include_directories(guest_hmd2_gaze_tests PRIVATE ${LIBS_INCLUDE_DIR})
|
||||
target_link_libraries(guest_hmd2_gaze_tests PRIVATE libSceHmd2 libc)
|
||||
configure_windows_unwind(guest_hmd2_gaze_tests)
|
||||
add_test(NAME guest_hmd2_gaze COMMAND guest_hmd2_gaze_tests)
|
||||
if(WIN32)
|
||||
set_tests_properties(guest_hmd2_gaze PROPERTIES ENVIRONMENT_MODIFICATION
|
||||
"PATH=path_list_prepend:$<TARGET_FILE_DIR:libSceHmd2>")
|
||||
endif()
|
||||
endif()
|
||||
@@ -291,14 +291,40 @@ std::int32_t APS5_VABI sceHmd2Close(std::int32_t handle) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int APS5_VABI sceHmd2GazeGetResult(const Hmd2::GazeResultParameter* parameter, Hmd2::GazeResult* result) {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
static std::int32_t Hmd2GazeHandle(const Hmd2::GazeResultParameter* param, const void* result, std::uint32_t resultSize, const char* name) {
|
||||
if (!param || !result) return Hmd2::ParameterNull;
|
||||
std::uint32_t size;
|
||||
std::memcpy(&size, result, sizeof(size));
|
||||
if (param->size != sizeof(Hmd2::GazeResultParameter) || size != resultSize) return Hmd2::ParameterInvalid;
|
||||
std::lock_guard lock(stateMutex);
|
||||
if (openHandle == 0 || param->handle != openHandle) return Hmd2::InvalidHandle;
|
||||
NotImplemented_nid_no_patch(name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int APS5_VABI sceHmd2GazeGetResultForFoveatedRendering(const Hmd2::GazeResultParameter* parameter, Hmd2::FoveatedRenderingResult* result) {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
return 0;
|
||||
static void Hmd2StoreInvalidGaze(std::byte* result, std::size_t offset) {
|
||||
const std::int32_t invalidIndex = -1;
|
||||
const float invalidPair[2] = {-0.0f, 0.0f};
|
||||
const float invalidScalar = -1.0f;
|
||||
std::memcpy(result + 4, &invalidIndex, sizeof(invalidIndex));
|
||||
std::memcpy(result + offset, invalidPair, sizeof(invalidPair));
|
||||
std::memcpy(result + offset + sizeof(invalidPair), &invalidScalar, sizeof(invalidScalar));
|
||||
}
|
||||
|
||||
int APS5_VABI sceHmd2GazeGetResult(const Hmd2::GazeResultParameter* param, Hmd2::GazeResult* result) {
|
||||
const std::int32_t status = Hmd2GazeHandle(param, result, 0x38, __func__);
|
||||
if (status != Hmd2::InvalidHandle) return status;
|
||||
auto* bytes = reinterpret_cast<std::byte*>(result);
|
||||
std::memset(bytes + 4, 0, 0x38 - 4);
|
||||
Hmd2StoreInvalidGaze(bytes, 0x14);
|
||||
return status;
|
||||
}
|
||||
|
||||
int APS5_VABI sceHmd2GazeGetResultForFoveatedRendering(const Hmd2::GazeResultParameter* param, Hmd2::FoveatedRenderingResult* result) {
|
||||
const std::int32_t status = Hmd2GazeHandle(param, result, 0x18, __func__);
|
||||
if (status != Hmd2::InvalidHandle) return status;
|
||||
Hmd2StoreInvalidGaze(reinterpret_cast<std::byte*>(result), 8);
|
||||
return status;
|
||||
}
|
||||
|
||||
std::int32_t APS5_VABI sceHmd2GetDeviceInformation(Hmd2::DeviceInformation* info) {
|
||||
|
||||
@@ -317,9 +317,8 @@ int APS5_VABI sceHttpSendRequest(int request_id, const void* post_data, size_t s
|
||||
}
|
||||
|
||||
int APS5_VABI sceHttpSetAuthEnabled(int id, int enable) {
|
||||
(void)id;
|
||||
(void)enable;
|
||||
return 0;
|
||||
if (!HttpInitialised()) return ERROR_BEFORE_INIT;
|
||||
return SetHttpOption(id, &HttpOptions::authEnabled, enable != 0) ? 0 : ERROR_INVALID_ID;
|
||||
}
|
||||
|
||||
int APS5_VABI sceHttpSetAuthInfoCallback(int id, HttpAuthInfoCallback callback, void* userArg) {
|
||||
@@ -727,12 +726,17 @@ int APS5_VABI sceHttpAddRequestHeaderRaw(int id, const char* header, int mode) {
|
||||
}
|
||||
|
||||
int APS5_VABI sceHttpRemoveRequestHeader(int id, const char* name) {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
(void)id;
|
||||
(void)name;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int APS5_VABI sceHttpGetAuthEnabled(int id, int* enabled) {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
int APS5_VABI sceHttpGetAuthEnabled(int id, int* enable) {
|
||||
if (!HttpInitialised()) return ERROR_BEFORE_INIT;
|
||||
if (!enable) return ERROR_INVALID_VALUE;
|
||||
const auto options = FindHttpOptions(id);
|
||||
if (!options) return ERROR_INVALID_ID;
|
||||
*enable = options->authEnabled ? 1 : 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
|
||||
struct HttpOptions {
|
||||
bool autoRedirect = true;
|
||||
bool authEnabled = false;
|
||||
bool nonblock = false;
|
||||
bool acceptEncodingGzip = false;
|
||||
HttpEpollHandle epoll = nullptr;
|
||||
|
||||
@@ -11,10 +11,10 @@ bool isAsciiDigit(char c) {
|
||||
return c >= '0' && c <= '9';
|
||||
}
|
||||
|
||||
bool parseVersionNumber(const char* line, size_t lineLen, size_t& index, int32_t* value) {
|
||||
if (index >= lineLen || !isAsciiDigit(line[index])) return false;
|
||||
bool parseVersionNumber(const char* line, size_t& index, int32_t* value) {
|
||||
if (!isAsciiDigit(line[index])) return false;
|
||||
uint32_t number = 0;
|
||||
while (index < lineLen && isAsciiDigit(line[index])) {
|
||||
while (isAsciiDigit(line[index])) {
|
||||
number = number * 10 + static_cast<uint32_t>(line[index] - '0');
|
||||
++index;
|
||||
}
|
||||
@@ -36,11 +36,11 @@ int APS5_VABI sceHttpParseStatusLine(const char* statusLine, size_t lineLen, int
|
||||
if (lineLen < 8 || std::memcmp(statusLine, "HTTP/", 5) != 0) return ERROR_PARSE_HTTP_INVALID_RESPONSE;
|
||||
|
||||
size_t index = 5;
|
||||
if (!parseVersionNumber(statusLine, lineLen, index, httpMajorVer)) return ERROR_PARSE_HTTP_INVALID_RESPONSE;
|
||||
if (index >= lineLen || statusLine[index] != '.') return ERROR_PARSE_HTTP_INVALID_RESPONSE;
|
||||
if (!parseVersionNumber(statusLine, index, httpMajorVer)) return ERROR_PARSE_HTTP_INVALID_RESPONSE;
|
||||
if (statusLine[index] != '.') return ERROR_PARSE_HTTP_INVALID_RESPONSE;
|
||||
++index;
|
||||
if (!parseVersionNumber(statusLine, lineLen, index, httpMinorVer)) return ERROR_PARSE_HTTP_INVALID_RESPONSE;
|
||||
if (index >= lineLen || statusLine[index] != ' ') return ERROR_PARSE_HTTP_INVALID_RESPONSE;
|
||||
if (!parseVersionNumber(statusLine, index, httpMinorVer)) return ERROR_PARSE_HTTP_INVALID_RESPONSE;
|
||||
if (statusLine[index] != ' ') return ERROR_PARSE_HTTP_INVALID_RESPONSE;
|
||||
++index;
|
||||
|
||||
if (lineLen - index < 3) return ERROR_PARSE_HTTP_INVALID_RESPONSE;
|
||||
@@ -51,10 +51,11 @@ int APS5_VABI sceHttpParseStatusLine(const char* statusLine, size_t lineLen, int
|
||||
index += 3;
|
||||
|
||||
const char* phrase = statusLine + index;
|
||||
const void* lineFeed = std::memchr(phrase, '\n', lineLen - index);
|
||||
if (!lineFeed) return ERROR_PARSE_HTTP_INVALID_RESPONSE;
|
||||
const size_t searched = lineLen - index + 1;
|
||||
size_t length = 0;
|
||||
while (length != searched && phrase[length] != '\n') ++length;
|
||||
if (length == searched) return ERROR_PARSE_HTTP_INVALID_RESPONSE;
|
||||
|
||||
size_t length = static_cast<size_t>(static_cast<const char*>(lineFeed) - phrase);
|
||||
const size_t consumed = index + length + 1;
|
||||
if (consumed > static_cast<size_t>(INT32_MAX)) {
|
||||
throw std::out_of_range("sceHttpParseStatusLine: consumed byte count exceeds int");
|
||||
|
||||
@@ -10,6 +10,8 @@
|
||||
#include "prx/libc/include/ApplicationHeap.hpp"
|
||||
#include "prx/libSceHttp/src/HttpErrors.hpp"
|
||||
|
||||
extern "C" int APS5_VABI sceHttpUriSweepPath(char* dst, const char* src, size_t srcSize);
|
||||
|
||||
namespace {
|
||||
|
||||
constexpr uint32_t URI_BUILD_WITH_SCHEME = 0x01;
|
||||
@@ -29,6 +31,7 @@ struct UriParts {
|
||||
std::string_view password;
|
||||
std::string_view hostname;
|
||||
std::string path;
|
||||
size_t pathSpace = 0;
|
||||
std::string_view query;
|
||||
std::string_view fragment;
|
||||
uint16_t port = 0;
|
||||
@@ -55,8 +58,8 @@ bool equalsIgnoreCase(std::string_view left, std::string_view right) {
|
||||
}
|
||||
|
||||
uint16_t defaultPort(std::string_view scheme) {
|
||||
if (equalsIgnoreCase(scheme, "http")) return 80;
|
||||
if (equalsIgnoreCase(scheme, "https")) return 443;
|
||||
if (scheme.size() >= 5 && equalsIgnoreCase(scheme.substr(0, 5), "https")) return 443;
|
||||
if (scheme.size() >= 4 && equalsIgnoreCase(scheme.substr(0, 4), "http")) return 80;
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -64,31 +67,21 @@ bool isHostCharacter(char c) {
|
||||
return isAsciiAlpha(c) || isAsciiDigit(c) || c == '-' || c == '.' || c == '_';
|
||||
}
|
||||
|
||||
std::string removeDotSegments(std::string_view input) {
|
||||
std::string output;
|
||||
while (!input.empty()) {
|
||||
if (input.starts_with("../")) input.remove_prefix(3);
|
||||
else if (input.starts_with("./")) input.remove_prefix(2);
|
||||
else if (input.starts_with("/./")) input.remove_prefix(2);
|
||||
else if (input == "/.") input = "/";
|
||||
else if (input.starts_with("/../") || input == "/..") {
|
||||
input = input.size() == 3 ? std::string_view("/") : input.substr(3);
|
||||
const size_t slash = output.rfind('/');
|
||||
output.erase(slash == std::string::npos ? 0 : slash);
|
||||
} else if (input == "." || input == "..") input = {};
|
||||
else {
|
||||
const size_t end = input.find('/', 1);
|
||||
const size_t length = end == std::string_view::npos ? input.size() : end;
|
||||
output.append(input.substr(0, length));
|
||||
input.remove_prefix(length);
|
||||
}
|
||||
}
|
||||
return output;
|
||||
bool isUserinfoCharacter(char c) {
|
||||
return isAsciiAlpha(c) || isAsciiDigit(c) || std::string_view("-._~!$&'()*+,;=%:").find(c) != std::string_view::npos;
|
||||
}
|
||||
|
||||
std::string sweptPath(std::string_view path) {
|
||||
const std::string source(path);
|
||||
std::string swept(source.size() + 1, '\0');
|
||||
sceHttpUriSweepPath(swept.data(), source.c_str(), source.size() + 1);
|
||||
swept.resize(std::strlen(swept.c_str()));
|
||||
return swept;
|
||||
}
|
||||
|
||||
size_t schemeLength(std::string_view uri) {
|
||||
size_t schemeEnd = 0;
|
||||
if (!uri.empty() && isAsciiAlpha(uri[0])) {
|
||||
if (!uri.empty() && (isAsciiAlpha(uri[0]) || uri[0] == '+' || uri[0] == '-' || uri[0] == '.')) {
|
||||
schemeEnd = 1;
|
||||
while (schemeEnd < uri.size() && (isAsciiAlpha(uri[schemeEnd]) || isAsciiDigit(uri[schemeEnd]) || uri[schemeEnd] == '+'
|
||||
|| uri[schemeEnd] == '-' || uri[schemeEnd] == '.')) ++schemeEnd;
|
||||
@@ -110,49 +103,51 @@ int parseUri(std::string_view uri, UriParts& parts) {
|
||||
parts.opaque = !uri.starts_with("//");
|
||||
if (!parts.opaque) uri.remove_prefix(2);
|
||||
|
||||
std::string_view authority = uri.substr(0, uri.find_first_of("/?#"));
|
||||
uri.remove_prefix(authority.size());
|
||||
|
||||
const size_t at = authority.rfind('@');
|
||||
if (at != std::string_view::npos) {
|
||||
const std::string_view userinfo = authority.substr(0, at);
|
||||
size_t userinfoEnd = 0;
|
||||
while (userinfoEnd < uri.size() && isUserinfoCharacter(uri[userinfoEnd])) ++userinfoEnd;
|
||||
if (userinfoEnd < uri.size() && uri[userinfoEnd] == '@') {
|
||||
const std::string_view userinfo = uri.substr(0, userinfoEnd);
|
||||
const size_t colon = userinfo.find(':');
|
||||
parts.username = userinfo.substr(0, colon);
|
||||
if (colon != std::string_view::npos) parts.password = userinfo.substr(colon + 1);
|
||||
authority.remove_prefix(at + 1);
|
||||
uri.remove_prefix(userinfoEnd + 1);
|
||||
}
|
||||
|
||||
std::string_view port;
|
||||
if (authority.starts_with('[')) {
|
||||
const size_t close = authority.find(']');
|
||||
if (uri.starts_with('[')) {
|
||||
const size_t close = uri.find(']');
|
||||
if (close == std::string_view::npos) return ERROR_INVALID_URL;
|
||||
parts.hostname = authority.substr(1, close - 1);
|
||||
authority.remove_prefix(close + 1);
|
||||
if (!authority.empty() && authority[0] != ':') return ERROR_INVALID_URL;
|
||||
if (!authority.empty()) port = authority.substr(1);
|
||||
parts.hostname = uri.substr(1, close - 1);
|
||||
for (const char c : parts.hostname) {
|
||||
if (!isHostCharacter(c) && c != ':') return ERROR_INVALID_URL;
|
||||
}
|
||||
uri.remove_prefix(close + 1);
|
||||
} else {
|
||||
const size_t colon = authority.find(':');
|
||||
parts.hostname = authority.substr(0, colon);
|
||||
if (colon != std::string_view::npos) port = authority.substr(colon + 1);
|
||||
for (const char c : parts.hostname) {
|
||||
if (!isHostCharacter(c)) return ERROR_INVALID_URL;
|
||||
size_t hostEnd = 0;
|
||||
if (!uri.starts_with('.')) {
|
||||
while (hostEnd < uri.size() && isHostCharacter(uri[hostEnd])) ++hostEnd;
|
||||
}
|
||||
parts.hostname = uri.substr(0, hostEnd);
|
||||
uri.remove_prefix(hostEnd);
|
||||
}
|
||||
|
||||
if (port.size() > 5) return ERROR_INVALID_URL;
|
||||
uint32_t portValue = 0;
|
||||
for (const char c : port) {
|
||||
if (!isAsciiDigit(c)) return ERROR_INVALID_URL;
|
||||
portValue = portValue * 10 + static_cast<uint32_t>(c - '0');
|
||||
parts.port = defaultPort(parts.scheme);
|
||||
if (uri.starts_with(':')) {
|
||||
uri.remove_prefix(1);
|
||||
const std::string_view port = uri.substr(0, uri.find('/'));
|
||||
uri.remove_prefix(port.size());
|
||||
if (port.size() > 5) return ERROR_INVALID_URL;
|
||||
uint32_t portValue = 0;
|
||||
for (const char c : port) {
|
||||
if (!isAsciiDigit(c)) return ERROR_INVALID_URL;
|
||||
portValue = portValue * 10 + static_cast<uint32_t>(c - '0');
|
||||
}
|
||||
if (portValue > 0x10000) return ERROR_INVALID_URL;
|
||||
if (!port.empty()) parts.port = static_cast<uint16_t>(portValue);
|
||||
}
|
||||
if (portValue > 0xFFFF) return ERROR_INVALID_URL;
|
||||
parts.port = port.empty() ? defaultPort(parts.scheme) : static_cast<uint16_t>(portValue);
|
||||
|
||||
const std::string_view path = uri.substr(0, uri.find_first_of("?#"));
|
||||
parts.path = removeDotSegments(path);
|
||||
parts.path = sweptPath(path);
|
||||
parts.pathSpace = path.size();
|
||||
uri.remove_prefix(path.size());
|
||||
|
||||
if (uri.starts_with('?')) {
|
||||
@@ -164,8 +159,8 @@ int parseUri(std::string_view uri, UriParts& parts) {
|
||||
}
|
||||
|
||||
size_t poolSize(const UriParts& parts) {
|
||||
const std::string_view fields[] = {parts.scheme, parts.username, parts.password, parts.hostname, parts.path, parts.query, parts.fragment};
|
||||
size_t size = 0;
|
||||
const std::string_view fields[] = {parts.scheme, parts.username, parts.password, parts.hostname, parts.query, parts.fragment};
|
||||
size_t size = parts.pathSpace + 1;
|
||||
for (const std::string_view field : fields) size += field.size() + 1;
|
||||
return size;
|
||||
}
|
||||
@@ -345,10 +340,12 @@ int APS5_VABI sceHttpUriParse(SceHttpUriElement* out, const char* src_url, void*
|
||||
if (const int result = parseUri(src_url, parts); result != 0) return result;
|
||||
|
||||
const std::string_view fields[] = {parts.scheme, parts.username, parts.password, parts.hostname, parts.path, parts.query, parts.fragment};
|
||||
const size_t spaces[] = {parts.scheme.size(), parts.username.size(), parts.password.size(), parts.hostname.size(), parts.pathSpace, parts.query.size(),
|
||||
parts.fragment.size()};
|
||||
const size_t size = poolSize(parts);
|
||||
if (write && prepare < size) return ERROR_OUT_OF_MEMORY;
|
||||
if (require) *require = size;
|
||||
if (!write) return 0;
|
||||
if (prepare < size) return ERROR_OUT_OF_MEMORY;
|
||||
|
||||
char* next = static_cast<char*>(pool);
|
||||
char* strings[7];
|
||||
@@ -356,7 +353,7 @@ int APS5_VABI sceHttpUriParse(SceHttpUriElement* out, const char* src_url, void*
|
||||
strings[i] = next;
|
||||
if (!fields[i].empty()) std::memcpy(next, fields[i].data(), fields[i].size());
|
||||
next[fields[i].size()] = '\0';
|
||||
next += fields[i].size() + 1;
|
||||
next += spaces[i] + 1;
|
||||
}
|
||||
*out = {};
|
||||
out->opaque = parts.opaque;
|
||||
@@ -376,31 +373,38 @@ int APS5_VABI sceHttpUriCopy(SceHttpUriElement* out, const SceHttpUriElement* sr
|
||||
const bool write = out && pool;
|
||||
if (!write && !require) return ERROR_INVALID_VALUE;
|
||||
|
||||
if (write) {
|
||||
std::memset(out, 0, sizeof(*out));
|
||||
std::memset(pool, 0, prepare);
|
||||
}
|
||||
const char* const fields[] = {src->scheme, src->hostname, src->path, src->username, src->password};
|
||||
SceHttpUriElement copy{};
|
||||
char** const slots[] = {©.scheme, ©.hostname, ©.path, ©.username, ©.password};
|
||||
if (write) std::memset(pool, 0, prepare);
|
||||
const uint16_t port = src->port;
|
||||
size_t lengths[5];
|
||||
size_t used = 0;
|
||||
for (size_t i = 0; i < 5; ++i) {
|
||||
const size_t length = fields[i] ? std::strlen(fields[i]) : 0;
|
||||
const size_t needed = length + 1;
|
||||
if (write) {
|
||||
if (needed > prepare - used) {
|
||||
*out = {};
|
||||
std::memset(pool, 0, prepare);
|
||||
return ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
char* next = static_cast<char*>(pool) + used;
|
||||
if (length != 0) std::memcpy(next, fields[i], length);
|
||||
next[length] = '\0';
|
||||
*slots[i] = next;
|
||||
}
|
||||
used += needed;
|
||||
lengths[i] = fields[i] ? std::strlen(fields[i]) : 0;
|
||||
used += lengths[i] + 1;
|
||||
}
|
||||
if (write) {
|
||||
copy.port = src->port;
|
||||
*out = copy;
|
||||
if (!write) {
|
||||
*require = used;
|
||||
return 0;
|
||||
}
|
||||
if (used > prepare) return ERROR_OUT_OF_MEMORY;
|
||||
|
||||
char* next = static_cast<char*>(pool);
|
||||
char* strings[5];
|
||||
for (size_t i = 0; i < 5; ++i) {
|
||||
strings[i] = next;
|
||||
if (lengths[i] != 0) std::memcpy(next, fields[i], lengths[i]);
|
||||
next[lengths[i]] = '\0';
|
||||
next += lengths[i] + 1;
|
||||
}
|
||||
out->scheme = strings[0];
|
||||
out->hostname = strings[1];
|
||||
out->path = strings[2];
|
||||
out->username = strings[3];
|
||||
out->password = strings[4];
|
||||
out->port = port;
|
||||
if (require) *require = used;
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -17,6 +17,7 @@ constexpr std::uint32_t EndStatusUserCanceled = 1;
|
||||
constexpr std::uint32_t EndStatusAborted = 2;
|
||||
constexpr std::uint32_t MaxTextLength = 2048;
|
||||
constexpr int ErrorBusy = static_cast<int>(0x80bc0001u);
|
||||
constexpr int ErrorSuspending = static_cast<int>(0x80bc0009u);
|
||||
constexpr int ErrorNotOpened = static_cast<int>(0x80bc0002u);
|
||||
constexpr int ErrorNotInUse = static_cast<int>(0x80bc0107u);
|
||||
constexpr int ErrorInvalidMaxTextLength = static_cast<int>(0x80bc0016u);
|
||||
@@ -190,18 +191,20 @@ int APS5_VABI sceImeDialogForceClose(void) {
|
||||
}
|
||||
|
||||
int APS5_VABI sceImeDialogGetCurrentStarState(int64_t state) {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
std::lock_guard lock(g_mutex);
|
||||
if (g_dialog.status == StatusNone) return ErrorNotInUse;
|
||||
if (state == 0) return ErrorInvalidAddress;
|
||||
*reinterpret_cast<std::uint32_t*>(state) = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int APS5_VABI sceImeDialogInitInternal(Param* param, ExtendedParam* extended) {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
return 0;
|
||||
return sceImeDialogInit(param, extended);
|
||||
}
|
||||
|
||||
int APS5_VABI sceImeDialogSetPanelPosition(int32_t posx, int32_t posy) {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
return 0;
|
||||
int APS5_VABI sceImeDialogSetPanelPosition(int32_t, int32_t) {
|
||||
std::lock_guard lock(g_mutex);
|
||||
return g_dialog.status == StatusNone ? ErrorNotInUse : ErrorSuspending;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -1,10 +1,58 @@
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include "SceTypes.hpp"
|
||||
#include "prx/libc/include/General.hpp"
|
||||
|
||||
extern "C" {
|
||||
|
||||
APS5_DUMMY_FUN
|
||||
int APS5_VABI sceJemspaceCalloc() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
}
|
||||
|
||||
int APS5_VABI sceJemspaceCreate() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
}
|
||||
|
||||
int APS5_VABI sceJemspaceDestroy() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
}
|
||||
|
||||
int APS5_VABI sceJemspaceFree() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
}
|
||||
|
||||
int APS5_VABI sceJemspaceGetStats() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
}
|
||||
|
||||
int APS5_VABI sceJemspaceMalloc() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
}
|
||||
|
||||
int APS5_VABI sceJemspaceMallocUsableSize() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
}
|
||||
|
||||
int APS5_VABI sceJemspaceMemalign() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
}
|
||||
|
||||
int APS5_VABI sceJemspacePosixMemalign() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
}
|
||||
|
||||
int APS5_VABI sceJemspacePrintStats() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
}
|
||||
|
||||
int APS5_VABI sceJemspacePurge() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
}
|
||||
|
||||
int APS5_VABI sceJemspaceRealloc() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
}
|
||||
|
||||
int APS5_VABI sceJemspaceReallocalign() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -763,6 +763,11 @@ const Value* APS5_VABI _ZNK3sce4Json5Array4backEv(const Array* self) {
|
||||
if (self->items->empty()) throw std::out_of_range("sce::Json::Array::back: empty array");
|
||||
return &self->items->back();
|
||||
}
|
||||
void APS5_VABI _ZN3sce4Json5Array9pop_frontEv(Array* self) {
|
||||
if (self->items->empty()) throw std::out_of_range("sce::Json::Array::pop_front: empty array");
|
||||
Destroy(self->items->front());
|
||||
self->items->pop_front();
|
||||
}
|
||||
void APS5_VABI _ZN3sce4Json5Array8iteratorD1Ev(ArrayIterator* self) { delete self->state; self->state = nullptr; }
|
||||
ArrayIterator* APS5_VABI _ZN3sce4Json5Array8iteratorppEv(ArrayIterator* self) {
|
||||
if (self->state && self->state->position != self->state->end) ++self->state->position;
|
||||
|
||||
@@ -0,0 +1,15 @@
|
||||
add_library(libSceJxr SHARED EXCLUDE_FROM_ALL Export.cpp)
|
||||
target_include_directories(libSceJxr PRIVATE ${LIBS_INCLUDE_DIR})
|
||||
configure_windows_unwind(libSceJxr)
|
||||
|
||||
if(BUILD_TESTING)
|
||||
add_test_executable(guest_jxr_tests ${LIBS_INCLUDE_DIR}/tests/GuestJxr.cpp)
|
||||
target_include_directories(guest_jxr_tests PRIVATE ${LIBS_INCLUDE_DIR})
|
||||
target_link_libraries(guest_jxr_tests PRIVATE libSceJxr libc)
|
||||
configure_windows_unwind(guest_jxr_tests)
|
||||
add_test(NAME guest_jxr COMMAND guest_jxr_tests)
|
||||
if(WIN32)
|
||||
set_tests_properties(guest_jxr PROPERTIES ENVIRONMENT_MODIFICATION
|
||||
"PATH=path_list_prepend:$<TARGET_FILE_DIR:libSceJxr>")
|
||||
endif()
|
||||
endif()
|
||||
@@ -3,12 +3,21 @@
|
||||
#include "SceTypes.hpp"
|
||||
#include "prx/libc/include/General.hpp"
|
||||
|
||||
namespace {
|
||||
constexpr std::int64_t WmpErrSuccess = 0;
|
||||
}
|
||||
|
||||
extern "C" {
|
||||
|
||||
void APS5_VABI free_nid_postfix(void* memory);
|
||||
|
||||
APS5_DUMMY_FUN
|
||||
int APS5_VABI PKFree_nid_postfix(void) {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
return 0;
|
||||
std::int64_t APS5_VABI PKFree_nid_postfix(void** memory) {
|
||||
if (memory != nullptr) {
|
||||
free_nid_postfix(*memory);
|
||||
*memory = nullptr;
|
||||
}
|
||||
return WmpErrSuccess;
|
||||
}
|
||||
|
||||
int APS5_VABI PixelFormatLookup_nid_postfix(void) {
|
||||
|
||||
@@ -27,6 +27,10 @@ int APS5_VABI sceKeyboardReadState(int32_t handle, KeyboardData* data) {
|
||||
return Keyboard::ReadState(handle, data);
|
||||
}
|
||||
|
||||
int APS5_VABI sceKeyboardGetConnection(std::int32_t handle, bool* connected) {
|
||||
return Keyboard::GetConnection(handle, connected);
|
||||
}
|
||||
|
||||
int APS5_VABI sceKeyboardGetKey2Char(std::int32_t handle, std::int32_t arrange, std::uint8_t led, std::uint8_t modifierKey, std::uint16_t keyCode, KeyboardCharData* charData) {
|
||||
return Keyboard::GetKey2Char(handle, arrange, led, modifierKey, keyCode, charData);
|
||||
}
|
||||
@@ -47,8 +51,7 @@ int APS5_VABI sceKeyboardDeviceOpen(std::uint64_t deviceId, std::int32_t index,
|
||||
}
|
||||
|
||||
int APS5_VABI sceKeyboardDisconnectAll(void) {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
return 0;
|
||||
return Keyboard::DisconnectAll();
|
||||
}
|
||||
|
||||
int APS5_VABI sceKeyboardDisconnectDevice(std::int32_t deviceId) {
|
||||
@@ -61,11 +64,6 @@ int APS5_VABI sceKeyboardDisconnectPort(std::int32_t first, std::int32_t second)
|
||||
return 0;
|
||||
}
|
||||
|
||||
int APS5_VABI sceKeyboardGetConnection(std::int32_t handle, bool* connected) {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int APS5_VABI sceKeyboardGetDeviceInfo(std::int32_t deviceId, KeyboardDeviceInfo* info) {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
return 0;
|
||||
|
||||
@@ -18,6 +18,8 @@ int Open(int userId, std::int32_t type, std::int32_t index);
|
||||
int Close(std::int32_t handle);
|
||||
int Read(std::int32_t handle, KeyboardData* data, std::int32_t num);
|
||||
int ReadState(std::int32_t handle, KeyboardData* data);
|
||||
int GetConnection(std::int32_t handle, bool* connected);
|
||||
int DisconnectAll();
|
||||
int GetKey2Char(std::int32_t handle, std::int32_t arrange, std::uint32_t led, std::uint32_t modifierKey, std::uint16_t keyCode, KeyboardCharData* charData);
|
||||
void Publish(const KeyboardInputEvent& event);
|
||||
}
|
||||
|
||||
@@ -154,6 +154,23 @@ int ReadState(std::int32_t handle, KeyboardData* data) {
|
||||
return KEYBOARD_OK;
|
||||
}
|
||||
|
||||
int GetConnection(std::int32_t handle, bool* isConnected) {
|
||||
std::lock_guard lock(keyboardMutex);
|
||||
if (!initialized) return KEYBOARD_ERROR_NOT_INITIALIZED;
|
||||
if (handle != KEYBOARD_HANDLE || !opened) return KEYBOARD_ERROR_INVALID_HANDLE;
|
||||
if (isConnected == nullptr) return KEYBOARD_ERROR_INVALID_ARG;
|
||||
*isConnected = connected;
|
||||
return KEYBOARD_OK;
|
||||
}
|
||||
|
||||
int DisconnectAll() {
|
||||
KeyboardInputEvent event{};
|
||||
event.connectionChange = true;
|
||||
event.connected = false;
|
||||
Publish(event);
|
||||
return KEYBOARD_OK;
|
||||
}
|
||||
|
||||
int GetKey2Char(std::int32_t handle, std::int32_t arrange, std::uint32_t ledState, std::uint32_t modifierKey, std::uint16_t keyCode, KeyboardCharData* charData) {
|
||||
{
|
||||
std::lock_guard lock(keyboardMutex);
|
||||
|
||||
@@ -13,6 +13,7 @@ int APS5_VABI sceKeyboardOpen(int, std::int32_t, std::int32_t, const void*);
|
||||
int APS5_VABI sceKeyboardClose(std::int32_t);
|
||||
int APS5_VABI sceKeyboardRead(std::int32_t, KeyboardData*, std::int32_t);
|
||||
int APS5_VABI sceKeyboardReadState(std::int32_t, KeyboardData*);
|
||||
int APS5_VABI sceKeyboardGetConnection(std::int32_t, bool*);
|
||||
int APS5_VABI sceKeyboardGetKey2Char(std::int32_t, std::int32_t, std::uint8_t, std::uint8_t, std::uint16_t, KeyboardCharData*);
|
||||
int APS5_VABI sceKeyboardConnectPort(void);
|
||||
int APS5_VABI sceKeyboardDisconnectAll(void);
|
||||
@@ -44,14 +45,20 @@ static std::uint16_t Jis(std::uint32_t modifierKey, std::uint16_t keyCode, std::
|
||||
int main() {
|
||||
KeyboardData data[16]{};
|
||||
KeyboardCharData charData{};
|
||||
bool connected = false;
|
||||
Require(sceKeyboardOpen(1, 0, 0, nullptr) == KEYBOARD_ERROR_NOT_INITIALIZED);
|
||||
Require(sceKeyboardGetConnection(KEYBOARD_HANDLE, &connected) == KEYBOARD_ERROR_NOT_INITIALIZED);
|
||||
Require(sceKeyboardInit() == KEYBOARD_OK);
|
||||
Require(sceKeyboardInit() == KEYBOARD_OK);
|
||||
Require(sceKeyboardOpen(1, 0, 1, nullptr) == KEYBOARD_ERROR_INVALID_ARG);
|
||||
Require(sceKeyboardOpen(1, 1, 0, nullptr) == KEYBOARD_ERROR_INVALID_ARG);
|
||||
Require(sceKeyboardGetKey2Char(KEYBOARD_HANDLE, KEYBOARD_ARRANGEMENT_101, 0, 0, 0x04, &charData) == KEYBOARD_ERROR_INVALID_HANDLE);
|
||||
Require(sceKeyboardGetConnection(KEYBOARD_HANDLE, &connected) == KEYBOARD_ERROR_INVALID_HANDLE);
|
||||
Require(sceKeyboardOpen(1, 0, 0, nullptr) == KEYBOARD_HANDLE);
|
||||
Require(sceKeyboardOpen(1, 0, 0, nullptr) == KEYBOARD_ERROR_ALREADY_OPENED);
|
||||
Require(sceKeyboardGetConnection(42, &connected) == KEYBOARD_ERROR_INVALID_HANDLE);
|
||||
Require(sceKeyboardGetConnection(KEYBOARD_HANDLE, nullptr) == KEYBOARD_ERROR_INVALID_ARG);
|
||||
Require(sceKeyboardGetConnection(KEYBOARD_HANDLE, &connected) == KEYBOARD_OK && connected);
|
||||
Require(sceKeyboardRead(42, data, 1) == KEYBOARD_ERROR_INVALID_HANDLE);
|
||||
Require(sceKeyboardRead(KEYBOARD_HANDLE, nullptr, 1) == KEYBOARD_ERROR_INVALID_ARG);
|
||||
Require(sceKeyboardRead(KEYBOARD_HANDLE, data, 17) == KEYBOARD_ERROR_INVALID_ARG);
|
||||
@@ -96,9 +103,11 @@ int main() {
|
||||
window.window.event = SDL_WINDOWEVENT_CLOSE;
|
||||
input.HandleEvent(window, 7);
|
||||
Require(sceKeyboardRead(KEYBOARD_HANDLE, data, 1) == 1 && !data[0].connected && data[0].length == 1 && data[0].key_code[0] == 0);
|
||||
Require(sceKeyboardGetConnection(KEYBOARD_HANDLE, &connected) == KEYBOARD_OK && !connected);
|
||||
window.window.event = SDL_WINDOWEVENT_FOCUS_GAINED;
|
||||
input.HandleEvent(window, 7);
|
||||
Require(sceKeyboardRead(KEYBOARD_HANDLE, data, 1) == 1 && data[0].connected);
|
||||
Require(sceKeyboardGetConnection(KEYBOARD_HANDLE, &connected) == KEYBOARD_OK && connected);
|
||||
|
||||
for (std::uint16_t key = 0x04; key < 0x04 + 20; ++key) {
|
||||
KeyboardInputEvent press{};
|
||||
@@ -143,11 +152,31 @@ int main() {
|
||||
Require(sceKeyboardGetKey2Char(KEYBOARD_HANDLE, 2, 0, 0, 0x04, &charData) == KEYBOARD_ERROR_INVALID_ARG);
|
||||
|
||||
Require(sceKeyboardClose(KEYBOARD_HANDLE) == KEYBOARD_OK);
|
||||
Require(sceKeyboardGetConnection(KEYBOARD_HANDLE, &connected) == KEYBOARD_ERROR_INVALID_HANDLE);
|
||||
Require(sceKeyboardRead(KEYBOARD_HANDLE, data, 1) == KEYBOARD_ERROR_INVALID_HANDLE);
|
||||
Require(sceKeyboardReadState(KEYBOARD_HANDLE, data) == KEYBOARD_ERROR_INVALID_HANDLE);
|
||||
Require(sceKeyboardClose(KEYBOARD_HANDLE) == KEYBOARD_ERROR_INVALID_HANDLE);
|
||||
Require(sceKeyboardOpen(1, 0, 0, nullptr) == KEYBOARD_HANDLE);
|
||||
Require(sceKeyboardRead(KEYBOARD_HANDLE, data, 1) == 1 && data[0].length == 1 && data[0].key_code[0] == 0);
|
||||
Require(data[0].connected);
|
||||
KeyboardInputEvent pressed{};
|
||||
pressed.keyCode = 0x04;
|
||||
pressed.pressed = true;
|
||||
KeyboardPublishInput_nid_postfix(pressed);
|
||||
Require(sceKeyboardRead(KEYBOARD_HANDLE, data, 1) == 1 && data[0].key_code[0] == 0x04);
|
||||
Require(sceKeyboardDisconnectAll() == KEYBOARD_OK);
|
||||
Require(sceKeyboardRead(KEYBOARD_HANDLE, data, 1) == 1 && !data[0].connected && data[0].length == 1 && data[0].key_code[0] == 0);
|
||||
Require(sceKeyboardReadState(KEYBOARD_HANDLE, data) == KEYBOARD_OK && !data[0].connected && data[0].key_code[0] == 0);
|
||||
Require(sceKeyboardDisconnectAll() == KEYBOARD_OK);
|
||||
Require(sceKeyboardRead(KEYBOARD_HANDLE, data, 1) == 0);
|
||||
pressed.keyCode = 0x05;
|
||||
KeyboardPublishInput_nid_postfix(pressed);
|
||||
Require(sceKeyboardRead(KEYBOARD_HANDLE, data, 1) == 0);
|
||||
window.window.event = SDL_WINDOWEVENT_FOCUS_LOST;
|
||||
input.HandleEvent(window, 7);
|
||||
window.window.event = SDL_WINDOWEVENT_FOCUS_GAINED;
|
||||
input.HandleEvent(window, 7);
|
||||
Require(sceKeyboardRead(KEYBOARD_HANDLE, data, 1) == 1 && data[0].connected);
|
||||
Require(sceKeyboardClose(KEYBOARD_HANDLE) == KEYBOARD_OK);
|
||||
|
||||
bool threwConnect = false;
|
||||
@@ -157,12 +186,4 @@ int main() {
|
||||
threwConnect = true;
|
||||
}
|
||||
Require(threwConnect);
|
||||
|
||||
bool threwDisconnect = false;
|
||||
try {
|
||||
sceKeyboardDisconnectAll();
|
||||
} catch (const std::runtime_error&) {
|
||||
threwDisconnect = true;
|
||||
}
|
||||
Require(threwDisconnect);
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
add_library(libSceLibreSsl SHARED EXCLUDE_FROM_ALL ${CMAKE_CURRENT_SOURCE_DIR}/Export.cpp ${CMAKE_CURRENT_SOURCE_DIR}/src/Digest.cpp)
|
||||
target_include_directories(libSceLibreSsl PRIVATE ${LIBS_INCLUDE_DIR})
|
||||
configure_windows_unwind(libSceLibreSsl)
|
||||
|
||||
if(BUILD_TESTING)
|
||||
add_test_executable(guest_libressl_digest_tests ${LIBS_INCLUDE_DIR}/tests/GuestLibreSslDigest.cpp)
|
||||
target_include_directories(guest_libressl_digest_tests PRIVATE ${LIBS_INCLUDE_DIR})
|
||||
target_link_libraries(guest_libressl_digest_tests PRIVATE libSceLibreSsl libc)
|
||||
configure_windows_unwind(guest_libressl_digest_tests)
|
||||
add_test(NAME guest_libressl_digest COMMAND guest_libressl_digest_tests)
|
||||
set_tests_properties(guest_libressl_digest PROPERTIES TIMEOUT 30)
|
||||
if(WIN32)
|
||||
set_tests_properties(guest_libressl_digest PROPERTIES ENVIRONMENT_MODIFICATION
|
||||
"PATH=path_list_prepend:$<TARGET_FILE_DIR:libSceLibreSsl>")
|
||||
endif()
|
||||
endif()
|
||||
@@ -846,36 +846,6 @@ int APS5_VABI HMAC_Update_nid_postfix(void) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int APS5_VABI MD4_Final_nid_postfix(void) {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int APS5_VABI MD4_Init_nid_postfix(void) {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int APS5_VABI MD4_Update_nid_postfix(void) {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int APS5_VABI MD5_Final_nid_postfix(void) {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int APS5_VABI MD5_Init_nid_postfix(void) {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int APS5_VABI MD5_Update_nid_postfix(void) {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int APS5_VABI OBJ_cleanup_nid_postfix(void) {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
return 0;
|
||||
@@ -1116,86 +1086,6 @@ int APS5_VABI RSA_verify_PKCS1_PSS_nid_postfix(void) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int APS5_VABI SHA1_Final_nid_postfix(void) {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int APS5_VABI SHA1_Init_nid_postfix(void) {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int APS5_VABI SHA1_Update_nid_postfix(void) {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int APS5_VABI SHA224_Final_nid_postfix(void) {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int APS5_VABI SHA224_Init_nid_postfix(void) {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int APS5_VABI SHA224_Update_nid_postfix(void) {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int APS5_VABI SHA256_nid_postfix(void) {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int APS5_VABI SHA256_Final_nid_postfix(void) {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int APS5_VABI SHA256_Init_nid_postfix(void) {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int APS5_VABI SHA256_Update_nid_postfix(void) {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int APS5_VABI SHA384_Final_nid_postfix(void) {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int APS5_VABI SHA384_Init_nid_postfix(void) {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int APS5_VABI SHA384_Update_nid_postfix(void) {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int APS5_VABI SHA512_Final_nid_postfix(void) {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int APS5_VABI SHA512_Init_nid_postfix(void) {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int APS5_VABI SHA512_Update_nid_postfix(void) {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int APS5_VABI SSL_CIPHER_get_bits_nid_postfix(void) {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
return 0;
|
||||
|
||||
@@ -0,0 +1,549 @@
|
||||
#include <bit>
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <cstring>
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
#include "prx/libc/include/General.hpp"
|
||||
|
||||
namespace {
|
||||
struct Md4Context {
|
||||
std::uint32_t A, B, C, D;
|
||||
std::uint32_t Nl, Nh;
|
||||
std::uint32_t data[16];
|
||||
std::uint32_t num;
|
||||
};
|
||||
|
||||
struct Md5Context {
|
||||
std::uint32_t A, B, C, D;
|
||||
std::uint32_t Nl, Nh;
|
||||
std::uint32_t data[16];
|
||||
std::uint32_t num;
|
||||
};
|
||||
|
||||
struct Sha1Context {
|
||||
std::uint32_t h[5];
|
||||
std::uint32_t Nl, Nh;
|
||||
std::uint32_t data[16];
|
||||
std::uint32_t num;
|
||||
};
|
||||
|
||||
struct Sha256Context {
|
||||
std::uint32_t h[8];
|
||||
std::uint32_t Nl, Nh;
|
||||
std::uint32_t data[16];
|
||||
std::uint32_t num, mdLength;
|
||||
};
|
||||
|
||||
struct Sha512Context {
|
||||
std::uint64_t h[8];
|
||||
std::uint64_t Nl, Nh;
|
||||
std::uint64_t data[16];
|
||||
std::uint32_t num, mdLength;
|
||||
};
|
||||
|
||||
static_assert(sizeof(Md4Context) == 92);
|
||||
static_assert(sizeof(Md5Context) == 92);
|
||||
static_assert(sizeof(Sha1Context) == 96);
|
||||
static_assert(sizeof(Sha256Context) == 112);
|
||||
static_assert(sizeof(Sha512Context) == 216);
|
||||
|
||||
constexpr std::size_t Sha224Length = 28;
|
||||
constexpr std::size_t Sha256Length = 32;
|
||||
constexpr std::size_t Sha384Length = 48;
|
||||
constexpr std::size_t Sha512Length = 64;
|
||||
|
||||
std::uint32_t LoadLittle32(const unsigned char* p) {
|
||||
return std::uint32_t(p[0]) | std::uint32_t(p[1]) << 8 | std::uint32_t(p[2]) << 16 | std::uint32_t(p[3]) << 24;
|
||||
}
|
||||
|
||||
std::uint32_t LoadBig32(const unsigned char* p) {
|
||||
return std::uint32_t(p[0]) << 24 | std::uint32_t(p[1]) << 16 | std::uint32_t(p[2]) << 8 | std::uint32_t(p[3]);
|
||||
}
|
||||
|
||||
std::uint64_t LoadBig64(const unsigned char* p) {
|
||||
return std::uint64_t(LoadBig32(p)) << 32 | LoadBig32(p + 4);
|
||||
}
|
||||
|
||||
void StoreLittle32(unsigned char* p, std::uint32_t value) {
|
||||
for (int i = 0; i < 4; ++i) p[i] = static_cast<unsigned char>(value >> (8 * i));
|
||||
}
|
||||
|
||||
void StoreBig32(unsigned char* p, std::uint32_t value) {
|
||||
for (int i = 0; i < 4; ++i) p[i] = static_cast<unsigned char>(value >> (24 - 8 * i));
|
||||
}
|
||||
|
||||
void StoreBig64(unsigned char* p, std::uint64_t value) {
|
||||
StoreBig32(p, static_cast<std::uint32_t>(value >> 32));
|
||||
StoreBig32(p + 4, static_cast<std::uint32_t>(value));
|
||||
}
|
||||
|
||||
void Md4Block(Md4Context& c, const unsigned char* block) {
|
||||
std::uint32_t x[16];
|
||||
for (int i = 0; i < 16; ++i) x[i] = LoadLittle32(block + 4 * i);
|
||||
std::uint32_t a = c.A, b = c.B, cc = c.C, d = c.D;
|
||||
const auto f = [](std::uint32_t x1, std::uint32_t y, std::uint32_t z) { return (x1 & y) | (~x1 & z); };
|
||||
const auto g = [](std::uint32_t x1, std::uint32_t y, std::uint32_t z) { return (x1 & y) | (x1 & z) | (y & z); };
|
||||
const auto h = [](std::uint32_t x1, std::uint32_t y, std::uint32_t z) { return x1 ^ y ^ z; };
|
||||
static constexpr int shifts1[4] {3, 7, 11, 19};
|
||||
static constexpr int shifts2[4] {3, 5, 9, 13};
|
||||
static constexpr int shifts3[4] {3, 9, 11, 15};
|
||||
static constexpr int order2[16] {0, 4, 8, 12, 1, 5, 9, 13, 2, 6, 10, 14, 3, 7, 11, 15};
|
||||
static constexpr int order3[16] {0, 8, 4, 12, 2, 10, 6, 14, 1, 9, 5, 13, 3, 11, 7, 15};
|
||||
for (int i = 0; i < 16; ++i) {
|
||||
const auto t = std::rotl(a + f(b, cc, d) + x[i], shifts1[i % 4]);
|
||||
a = d; d = cc; cc = b; b = t;
|
||||
}
|
||||
for (int i = 0; i < 16; ++i) {
|
||||
const auto t = std::rotl(a + g(b, cc, d) + x[order2[i]] + 0x5a827999u, shifts2[i % 4]);
|
||||
a = d; d = cc; cc = b; b = t;
|
||||
}
|
||||
for (int i = 0; i < 16; ++i) {
|
||||
const auto t = std::rotl(a + h(b, cc, d) + x[order3[i]] + 0x6ed9eba1u, shifts3[i % 4]);
|
||||
a = d; d = cc; cc = b; b = t;
|
||||
}
|
||||
c.A += a; c.B += b; c.C += cc; c.D += d;
|
||||
}
|
||||
|
||||
void Md5Block(Md5Context& c, const unsigned char* block) {
|
||||
static constexpr std::uint32_t constants[64] {
|
||||
0xd76aa478, 0xe8c7b756, 0x242070db, 0xc1bdceee, 0xf57c0faf, 0x4787c62a, 0xa8304613, 0xfd469501,
|
||||
0x698098d8, 0x8b44f7af, 0xffff5bb1, 0x895cd7be, 0x6b901122, 0xfd987193, 0xa679438e, 0x49b40821,
|
||||
0xf61e2562, 0xc040b340, 0x265e5a51, 0xe9b6c7aa, 0xd62f105d, 0x02441453, 0xd8a1e681, 0xe7d3fbc8,
|
||||
0x21e1cde6, 0xc33707d6, 0xf4d50d87, 0x455a14ed, 0xa9e3e905, 0xfcefa3f8, 0x676f02d9, 0x8d2a4c8a,
|
||||
0xfffa3942, 0x8771f681, 0x6d9d6122, 0xfde5380c, 0xa4beea44, 0x4bdecfa9, 0xf6bb4b60, 0xbebfbc70,
|
||||
0x289b7ec6, 0xeaa127fa, 0xd4ef3085, 0x04881d05, 0xd9d4d039, 0xe6db99e5, 0x1fa27cf8, 0xc4ac5665,
|
||||
0xf4292244, 0x432aff97, 0xab9423a7, 0xfc93a039, 0x655b59c3, 0x8f0ccc92, 0xffeff47d, 0x85845dd1,
|
||||
0x6fa87e4f, 0xfe2ce6e0, 0xa3014314, 0x4e0811a1, 0xf7537e82, 0xbd3af235, 0x2ad7d2bb, 0xeb86d391,
|
||||
};
|
||||
static constexpr int shifts[16] {7, 12, 17, 22, 5, 9, 14, 20, 4, 11, 16, 23, 6, 10, 15, 21};
|
||||
std::uint32_t x[16];
|
||||
for (int i = 0; i < 16; ++i) x[i] = LoadLittle32(block + 4 * i);
|
||||
std::uint32_t a = c.A, b = c.B, cc = c.C, d = c.D;
|
||||
for (int i = 0; i < 64; ++i) {
|
||||
std::uint32_t mix;
|
||||
int index;
|
||||
switch (i / 16) {
|
||||
case 0: mix = (b & cc) | (~b & d); index = i; break;
|
||||
case 1: mix = (d & b) | (~d & cc); index = (5 * i + 1) % 16; break;
|
||||
case 2: mix = b ^ cc ^ d; index = (3 * i + 5) % 16; break;
|
||||
default: mix = cc ^ (b | ~d); index = (7 * i) % 16; break;
|
||||
}
|
||||
const auto t = d;
|
||||
d = cc;
|
||||
cc = b;
|
||||
b += std::rotl(a + mix + constants[i] + x[index], shifts[(i / 16) * 4 + i % 4]);
|
||||
a = t;
|
||||
}
|
||||
c.A += a; c.B += b; c.C += cc; c.D += d;
|
||||
}
|
||||
|
||||
void Sha1Block(Sha1Context& c, const unsigned char* block) {
|
||||
std::uint32_t w[80];
|
||||
for (int i = 0; i < 16; ++i) w[i] = LoadBig32(block + 4 * i);
|
||||
for (int i = 16; i < 80; ++i) w[i] = std::rotl(w[i - 3] ^ w[i - 8] ^ w[i - 14] ^ w[i - 16], 1);
|
||||
std::uint32_t a = c.h[0], b = c.h[1], cc = c.h[2], d = c.h[3], e = c.h[4];
|
||||
for (int i = 0; i < 80; ++i) {
|
||||
std::uint32_t f, k;
|
||||
if (i < 20) { f = (b & cc) | (~b & d); k = 0x5a827999; }
|
||||
else if (i < 40) { f = b ^ cc ^ d; k = 0x6ed9eba1; }
|
||||
else if (i < 60) { f = (b & cc) | (b & d) | (cc & d); k = 0x8f1bbcdc; }
|
||||
else { f = b ^ cc ^ d; k = 0xca62c1d6; }
|
||||
const auto t = std::rotl(a, 5) + f + e + k + w[i];
|
||||
e = d; d = cc; cc = std::rotl(b, 30); b = a; a = t;
|
||||
}
|
||||
c.h[0] += a; c.h[1] += b; c.h[2] += cc; c.h[3] += d; c.h[4] += e;
|
||||
}
|
||||
|
||||
void Sha256Block(Sha256Context& c, const unsigned char* block) {
|
||||
static constexpr std::uint32_t constants[64] {
|
||||
0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5,
|
||||
0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174,
|
||||
0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da,
|
||||
0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967,
|
||||
0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85,
|
||||
0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070,
|
||||
0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3,
|
||||
0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2,
|
||||
};
|
||||
std::uint32_t w[64];
|
||||
for (int i = 0; i < 16; ++i) w[i] = LoadBig32(block + 4 * i);
|
||||
for (int i = 16; i < 64; ++i) {
|
||||
const auto s0 = std::rotr(w[i - 15], 7) ^ std::rotr(w[i - 15], 18) ^ (w[i - 15] >> 3);
|
||||
const auto s1 = std::rotr(w[i - 2], 17) ^ std::rotr(w[i - 2], 19) ^ (w[i - 2] >> 10);
|
||||
w[i] = w[i - 16] + s0 + w[i - 7] + s1;
|
||||
}
|
||||
std::uint32_t v[8];
|
||||
std::memcpy(v, c.h, sizeof(v));
|
||||
for (int i = 0; i < 64; ++i) {
|
||||
const auto s1 = std::rotr(v[4], 6) ^ std::rotr(v[4], 11) ^ std::rotr(v[4], 25);
|
||||
const auto choice = (v[4] & v[5]) ^ (~v[4] & v[6]);
|
||||
const auto t1 = v[7] + s1 + choice + constants[i] + w[i];
|
||||
const auto s0 = std::rotr(v[0], 2) ^ std::rotr(v[0], 13) ^ std::rotr(v[0], 22);
|
||||
const auto majority = (v[0] & v[1]) ^ (v[0] & v[2]) ^ (v[1] & v[2]);
|
||||
std::memmove(v + 1, v, 7 * sizeof(v[0]));
|
||||
v[4] += t1;
|
||||
v[0] = t1 + s0 + majority;
|
||||
}
|
||||
for (int i = 0; i < 8; ++i) c.h[i] += v[i];
|
||||
}
|
||||
|
||||
void Sha512Block(Sha512Context& c, const unsigned char* block) {
|
||||
static constexpr std::uint64_t constants[80] {
|
||||
0x428a2f98d728ae22, 0x7137449123ef65cd, 0xb5c0fbcfec4d3b2f, 0xe9b5dba58189dbbc, 0x3956c25bf348b538,
|
||||
0x59f111f1b605d019, 0x923f82a4af194f9b, 0xab1c5ed5da6d8118, 0xd807aa98a3030242, 0x12835b0145706fbe,
|
||||
0x243185be4ee4b28c, 0x550c7dc3d5ffb4e2, 0x72be5d74f27b896f, 0x80deb1fe3b1696b1, 0x9bdc06a725c71235,
|
||||
0xc19bf174cf692694, 0xe49b69c19ef14ad2, 0xefbe4786384f25e3, 0x0fc19dc68b8cd5b5, 0x240ca1cc77ac9c65,
|
||||
0x2de92c6f592b0275, 0x4a7484aa6ea6e483, 0x5cb0a9dcbd41fbd4, 0x76f988da831153b5, 0x983e5152ee66dfab,
|
||||
0xa831c66d2db43210, 0xb00327c898fb213f, 0xbf597fc7beef0ee4, 0xc6e00bf33da88fc2, 0xd5a79147930aa725,
|
||||
0x06ca6351e003826f, 0x142929670a0e6e70, 0x27b70a8546d22ffc, 0x2e1b21385c26c926, 0x4d2c6dfc5ac42aed,
|
||||
0x53380d139d95b3df, 0x650a73548baf63de, 0x766a0abb3c77b2a8, 0x81c2c92e47edaee6, 0x92722c851482353b,
|
||||
0xa2bfe8a14cf10364, 0xa81a664bbc423001, 0xc24b8b70d0f89791, 0xc76c51a30654be30, 0xd192e819d6ef5218,
|
||||
0xd69906245565a910, 0xf40e35855771202a, 0x106aa07032bbd1b8, 0x19a4c116b8d2d0c8, 0x1e376c085141ab53,
|
||||
0x2748774cdf8eeb99, 0x34b0bcb5e19b48a8, 0x391c0cb3c5c95a63, 0x4ed8aa4ae3418acb, 0x5b9cca4f7763e373,
|
||||
0x682e6ff3d6b2b8a3, 0x748f82ee5defb2fc, 0x78a5636f43172f60, 0x84c87814a1f0ab72, 0x8cc702081a6439ec,
|
||||
0x90befffa23631e28, 0xa4506cebde82bde9, 0xbef9a3f7b2c67915, 0xc67178f2e372532b, 0xca273eceea26619c,
|
||||
0xd186b8c721c0c207, 0xeada7dd6cde0eb1e, 0xf57d4f7fee6ed178, 0x06f067aa72176fba, 0x0a637dc5a2c898a6,
|
||||
0x113f9804bef90dae, 0x1b710b35131c471b, 0x28db77f523047d84, 0x32caab7b40c72493, 0x3c9ebe0a15c9bebc,
|
||||
0x431d67c49c100d4c, 0x4cc5d4becb3e42b6, 0x597f299cfc657e2a, 0x5fcb6fab3ad6faec, 0x6c44198c4a475817,
|
||||
};
|
||||
std::uint64_t w[80];
|
||||
for (int i = 0; i < 16; ++i) w[i] = LoadBig64(block + 8 * i);
|
||||
for (int i = 16; i < 80; ++i) {
|
||||
const auto s0 = std::rotr(w[i - 15], 1) ^ std::rotr(w[i - 15], 8) ^ (w[i - 15] >> 7);
|
||||
const auto s1 = std::rotr(w[i - 2], 19) ^ std::rotr(w[i - 2], 61) ^ (w[i - 2] >> 6);
|
||||
w[i] = w[i - 16] + s0 + w[i - 7] + s1;
|
||||
}
|
||||
std::uint64_t v[8];
|
||||
std::memcpy(v, c.h, sizeof(v));
|
||||
for (int i = 0; i < 80; ++i) {
|
||||
const auto s1 = std::rotr(v[4], 14) ^ std::rotr(v[4], 18) ^ std::rotr(v[4], 41);
|
||||
const auto choice = (v[4] & v[5]) ^ (~v[4] & v[6]);
|
||||
const auto t1 = v[7] + s1 + choice + constants[i] + w[i];
|
||||
const auto s0 = std::rotr(v[0], 28) ^ std::rotr(v[0], 34) ^ std::rotr(v[0], 39);
|
||||
const auto majority = (v[0] & v[1]) ^ (v[0] & v[2]) ^ (v[1] & v[2]);
|
||||
std::memmove(v + 1, v, 7 * sizeof(v[0]));
|
||||
v[4] += t1;
|
||||
v[0] = t1 + s0 + majority;
|
||||
}
|
||||
for (int i = 0; i < 8; ++i) c.h[i] += v[i];
|
||||
}
|
||||
|
||||
template<class TContext> TContext& RequireContext(TContext* context, const char* function) {
|
||||
if (!context) throw std::invalid_argument(std::string(function) + ": null context");
|
||||
return *context;
|
||||
}
|
||||
|
||||
void RequireInput(const void* data, std::size_t length, const char* function) {
|
||||
if (!data && length) throw std::invalid_argument(std::string(function) + ": null input");
|
||||
}
|
||||
|
||||
void RequireDigest(const unsigned char* digest, const char* function) {
|
||||
if (!digest) throw std::invalid_argument(std::string(function) + ": null digest buffer");
|
||||
}
|
||||
|
||||
void RequireBuffered(std::uint32_t buffered, std::size_t block, const char* function) {
|
||||
if (buffered >= block) throw std::invalid_argument(std::string(function) + ": buffered byte count is not below the block size");
|
||||
}
|
||||
|
||||
template<class TContext, class TBlock> void Update32(TContext& c, const void* input, std::size_t length, TBlock block) {
|
||||
constexpr std::size_t blockSize = 64;
|
||||
auto* buffer = reinterpret_cast<unsigned char*>(c.data);
|
||||
auto* data = static_cast<const unsigned char*>(input);
|
||||
const std::uint64_t bits = (std::uint64_t(c.Nh) << 32 | c.Nl) + (std::uint64_t(length) << 3);
|
||||
c.Nl = static_cast<std::uint32_t>(bits);
|
||||
c.Nh = static_cast<std::uint32_t>(bits >> 32);
|
||||
if (c.num) {
|
||||
const std::size_t room = blockSize - c.num;
|
||||
if (length < room) {
|
||||
std::memcpy(buffer + c.num, data, length);
|
||||
c.num += static_cast<std::uint32_t>(length);
|
||||
return;
|
||||
}
|
||||
std::memcpy(buffer + c.num, data, room);
|
||||
block(c, buffer);
|
||||
data += room;
|
||||
length -= room;
|
||||
c.num = 0;
|
||||
std::memset(buffer, 0, blockSize);
|
||||
}
|
||||
for (; length >= blockSize; data += blockSize, length -= blockSize) block(c, data);
|
||||
if (length) {
|
||||
std::memcpy(buffer, data, length);
|
||||
c.num = static_cast<std::uint32_t>(length);
|
||||
}
|
||||
}
|
||||
|
||||
template<class TContext, class TBlock> void Final32(TContext& c, bool bigEndian, TBlock block) {
|
||||
constexpr std::size_t blockSize = 64;
|
||||
auto* buffer = reinterpret_cast<unsigned char*>(c.data);
|
||||
std::size_t n = c.num;
|
||||
buffer[n++] = 0x80;
|
||||
if (n > blockSize - 8) {
|
||||
std::memset(buffer + n, 0, blockSize - n);
|
||||
n = 0;
|
||||
block(c, buffer);
|
||||
}
|
||||
std::memset(buffer + n, 0, blockSize - 8 - n);
|
||||
if (bigEndian) {
|
||||
StoreBig32(buffer + 56, c.Nh);
|
||||
StoreBig32(buffer + 60, c.Nl);
|
||||
} else {
|
||||
StoreLittle32(buffer + 56, c.Nl);
|
||||
StoreLittle32(buffer + 60, c.Nh);
|
||||
}
|
||||
block(c, buffer);
|
||||
c.num = 0;
|
||||
std::memset(buffer, 0, blockSize);
|
||||
}
|
||||
|
||||
void Sha512Update(Sha512Context& c, const void* input, std::size_t length) {
|
||||
constexpr std::size_t blockSize = 128;
|
||||
auto* buffer = reinterpret_cast<unsigned char*>(c.data);
|
||||
auto* data = static_cast<const unsigned char*>(input);
|
||||
const std::uint64_t low = c.Nl + (std::uint64_t(length) << 3);
|
||||
if (low < c.Nl) ++c.Nh;
|
||||
c.Nh += std::uint64_t(length) >> 61;
|
||||
c.Nl = low;
|
||||
if (c.num) {
|
||||
const std::size_t room = blockSize - c.num;
|
||||
if (length < room) {
|
||||
std::memcpy(buffer + c.num, data, length);
|
||||
c.num += static_cast<std::uint32_t>(length);
|
||||
return;
|
||||
}
|
||||
std::memcpy(buffer + c.num, data, room);
|
||||
Sha512Block(c, buffer);
|
||||
data += room;
|
||||
length -= room;
|
||||
c.num = 0;
|
||||
}
|
||||
for (; length >= blockSize; data += blockSize, length -= blockSize) Sha512Block(c, data);
|
||||
if (length) {
|
||||
std::memcpy(buffer, data, length);
|
||||
c.num = static_cast<std::uint32_t>(length);
|
||||
}
|
||||
}
|
||||
|
||||
int Sha512Final(unsigned char* digest, Sha512Context& c) {
|
||||
constexpr std::size_t blockSize = 128;
|
||||
auto* buffer = reinterpret_cast<unsigned char*>(c.data);
|
||||
std::size_t n = c.num;
|
||||
buffer[n++] = 0x80;
|
||||
if (n > blockSize - 16) {
|
||||
std::memset(buffer + n, 0, blockSize - n);
|
||||
n = 0;
|
||||
Sha512Block(c, buffer);
|
||||
}
|
||||
std::memset(buffer + n, 0, blockSize - 16 - n);
|
||||
StoreBig64(buffer + 112, c.Nh);
|
||||
StoreBig64(buffer + 120, c.Nl);
|
||||
Sha512Block(c, buffer);
|
||||
if (!digest) return 0;
|
||||
if (c.mdLength == Sha224Length || c.mdLength == Sha256Length)
|
||||
NotImplemented_nid_no_patch("SHA512_Final: SHA-512/224 and SHA-512/256 digest lengths");
|
||||
if (c.mdLength != Sha384Length && c.mdLength != Sha512Length) return 0;
|
||||
for (std::size_t i = 0; i < c.mdLength / 8; ++i) StoreBig64(digest + 8 * i, c.h[i]);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int Sha256Final(unsigned char* digest, Sha256Context& c, const char* function) {
|
||||
RequireDigest(digest, function);
|
||||
RequireBuffered(c.num, 64, function);
|
||||
Final32(c, true, Sha256Block);
|
||||
if (c.mdLength > Sha256Length) return 0;
|
||||
for (std::size_t i = 0; i < c.mdLength / 4; ++i) StoreBig32(digest + 4 * i, c.h[i]);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
extern "C" {
|
||||
|
||||
int APS5_VABI MD4_Init_nid_postfix(Md4Context* context) {
|
||||
auto& c = RequireContext(context, __func__);
|
||||
std::memset(&c, 0, sizeof(c));
|
||||
c.A = 0x67452301;
|
||||
c.B = 0xefcdab89;
|
||||
c.C = 0x98badcfe;
|
||||
c.D = 0x10325476;
|
||||
return 1;
|
||||
}
|
||||
|
||||
int APS5_VABI MD4_Update_nid_postfix(Md4Context* context, const void* data, std::size_t length) {
|
||||
auto& c = RequireContext(context, __func__);
|
||||
if (!length) return 1;
|
||||
RequireInput(data, length, __func__);
|
||||
RequireBuffered(c.num, 64, __func__);
|
||||
Update32(c, data, length, Md4Block);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int APS5_VABI MD4_Final_nid_postfix(unsigned char* digest, Md4Context* context) {
|
||||
auto& c = RequireContext(context, __func__);
|
||||
RequireDigest(digest, __func__);
|
||||
RequireBuffered(c.num, 64, __func__);
|
||||
Final32(c, false, Md4Block);
|
||||
StoreLittle32(digest, c.A);
|
||||
StoreLittle32(digest + 4, c.B);
|
||||
StoreLittle32(digest + 8, c.C);
|
||||
StoreLittle32(digest + 12, c.D);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int APS5_VABI MD5_Init_nid_postfix(Md5Context* context) {
|
||||
auto& c = RequireContext(context, __func__);
|
||||
std::memset(&c, 0, sizeof(c));
|
||||
c.A = 0x67452301;
|
||||
c.B = 0xefcdab89;
|
||||
c.C = 0x98badcfe;
|
||||
c.D = 0x10325476;
|
||||
return 1;
|
||||
}
|
||||
|
||||
int APS5_VABI MD5_Update_nid_postfix(Md5Context* context, const void* data, std::size_t length) {
|
||||
auto& c = RequireContext(context, __func__);
|
||||
if (!length) return 1;
|
||||
RequireInput(data, length, __func__);
|
||||
RequireBuffered(c.num, 64, __func__);
|
||||
Update32(c, data, length, Md5Block);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int APS5_VABI MD5_Final_nid_postfix(unsigned char* digest, Md5Context* context) {
|
||||
auto& c = RequireContext(context, __func__);
|
||||
RequireDigest(digest, __func__);
|
||||
RequireBuffered(c.num, 64, __func__);
|
||||
Final32(c, false, Md5Block);
|
||||
StoreLittle32(digest, c.A);
|
||||
StoreLittle32(digest + 4, c.B);
|
||||
StoreLittle32(digest + 8, c.C);
|
||||
StoreLittle32(digest + 12, c.D);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int APS5_VABI SHA1_Init_nid_postfix(Sha1Context* context) {
|
||||
auto& c = RequireContext(context, __func__);
|
||||
std::memset(&c, 0, sizeof(c));
|
||||
c.h[0] = 0x67452301;
|
||||
c.h[1] = 0xefcdab89;
|
||||
c.h[2] = 0x98badcfe;
|
||||
c.h[3] = 0x10325476;
|
||||
c.h[4] = 0xc3d2e1f0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
int APS5_VABI SHA1_Update_nid_postfix(Sha1Context* context, const void* data, std::size_t length) {
|
||||
auto& c = RequireContext(context, __func__);
|
||||
if (!length) return 1;
|
||||
RequireInput(data, length, __func__);
|
||||
RequireBuffered(c.num, 64, __func__);
|
||||
Update32(c, data, length, Sha1Block);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int APS5_VABI SHA1_Final_nid_postfix(unsigned char* digest, Sha1Context* context) {
|
||||
auto& c = RequireContext(context, __func__);
|
||||
RequireDigest(digest, __func__);
|
||||
RequireBuffered(c.num, 64, __func__);
|
||||
Final32(c, true, Sha1Block);
|
||||
for (int i = 0; i < 5; ++i) StoreBig32(digest + 4 * i, c.h[i]);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int APS5_VABI SHA224_Init_nid_postfix(Sha256Context* context) {
|
||||
static constexpr std::uint32_t initial[8] {0xc1059ed8, 0x367cd507, 0x3070dd17, 0xf70e5939, 0xffc00b31, 0x68581511, 0x64f98fa7, 0xbefa4fa4};
|
||||
auto& c = RequireContext(context, __func__);
|
||||
std::memset(&c, 0, sizeof(c));
|
||||
std::memcpy(c.h, initial, sizeof(initial));
|
||||
c.mdLength = Sha224Length;
|
||||
return 1;
|
||||
}
|
||||
|
||||
int APS5_VABI SHA256_Init_nid_postfix(Sha256Context* context) {
|
||||
static constexpr std::uint32_t initial[8] {0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a, 0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19};
|
||||
auto& c = RequireContext(context, __func__);
|
||||
std::memset(&c, 0, sizeof(c));
|
||||
std::memcpy(c.h, initial, sizeof(initial));
|
||||
c.mdLength = Sha256Length;
|
||||
return 1;
|
||||
}
|
||||
|
||||
int APS5_VABI SHA256_Update_nid_postfix(Sha256Context* context, const void* data, std::size_t length) {
|
||||
auto& c = RequireContext(context, __func__);
|
||||
if (!length) return 1;
|
||||
RequireInput(data, length, __func__);
|
||||
RequireBuffered(c.num, 64, __func__);
|
||||
Update32(c, data, length, Sha256Block);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int APS5_VABI SHA224_Update_nid_postfix(Sha256Context* context, const void* data, std::size_t length) {
|
||||
return SHA256_Update_nid_postfix(context, data, length);
|
||||
}
|
||||
|
||||
int APS5_VABI SHA256_Final_nid_postfix(unsigned char* digest, Sha256Context* context) {
|
||||
return Sha256Final(digest, RequireContext(context, __func__), __func__);
|
||||
}
|
||||
|
||||
int APS5_VABI SHA224_Final_nid_postfix(unsigned char* digest, Sha256Context* context) {
|
||||
return Sha256Final(digest, RequireContext(context, __func__), __func__);
|
||||
}
|
||||
|
||||
unsigned char* APS5_VABI SHA256_nid_postfix(const unsigned char* data, std::size_t length, unsigned char* digest) {
|
||||
RequireInput(data, length, __func__);
|
||||
if (!digest) NotImplemented_nid_no_patch("SHA256: null digest buffer");
|
||||
Sha256Context c;
|
||||
SHA256_Init_nid_postfix(&c);
|
||||
if (length) Update32(c, data, length, Sha256Block);
|
||||
Sha256Final(digest, c, __func__);
|
||||
return digest;
|
||||
}
|
||||
|
||||
int APS5_VABI SHA384_Init_nid_postfix(Sha512Context* context) {
|
||||
static constexpr std::uint64_t initial[8] {
|
||||
0xcbbb9d5dc1059ed8, 0x629a292a367cd507, 0x9159015a3070dd17, 0x152fecd8f70e5939,
|
||||
0x67332667ffc00b31, 0x8eb44a8768581511, 0xdb0c2e0d64f98fa7, 0x47b5481dbefa4fa4,
|
||||
};
|
||||
auto& c = RequireContext(context, __func__);
|
||||
std::memset(&c, 0, sizeof(c));
|
||||
std::memcpy(c.h, initial, sizeof(initial));
|
||||
c.mdLength = Sha384Length;
|
||||
return 1;
|
||||
}
|
||||
|
||||
int APS5_VABI SHA512_Init_nid_postfix(Sha512Context* context) {
|
||||
static constexpr std::uint64_t initial[8] {
|
||||
0x6a09e667f3bcc908, 0xbb67ae8584caa73b, 0x3c6ef372fe94f82b, 0xa54ff53a5f1d36f1,
|
||||
0x510e527fade682d1, 0x9b05688c2b3e6c1f, 0x1f83d9abfb41bd6b, 0x5be0cd19137e2179,
|
||||
};
|
||||
auto& c = RequireContext(context, __func__);
|
||||
std::memset(&c, 0, sizeof(c));
|
||||
std::memcpy(c.h, initial, sizeof(initial));
|
||||
c.mdLength = Sha512Length;
|
||||
return 1;
|
||||
}
|
||||
|
||||
int APS5_VABI SHA512_Update_nid_postfix(Sha512Context* context, const void* data, std::size_t length) {
|
||||
auto& c = RequireContext(context, __func__);
|
||||
if (!length) return 1;
|
||||
RequireInput(data, length, __func__);
|
||||
RequireBuffered(c.num, 128, __func__);
|
||||
Sha512Update(c, data, length);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int APS5_VABI SHA384_Update_nid_postfix(Sha512Context* context, const void* data, std::size_t length) {
|
||||
return SHA512_Update_nid_postfix(context, data, length);
|
||||
}
|
||||
|
||||
int APS5_VABI SHA512_Final_nid_postfix(unsigned char* digest, Sha512Context* context) {
|
||||
auto& c = RequireContext(context, __func__);
|
||||
RequireBuffered(c.num, 128, __func__);
|
||||
return Sha512Final(digest, c);
|
||||
}
|
||||
|
||||
int APS5_VABI SHA384_Final_nid_postfix(unsigned char* digest, Sha512Context* context) {
|
||||
return SHA512_Final_nid_postfix(digest, context);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
add_library(libSceLibreSsl3 SHARED EXCLUDE_FROM_ALL ${CMAKE_CURRENT_SOURCE_DIR}/Export.cpp ${CMAKE_CURRENT_SOURCE_DIR}/src/Digest.cpp)
|
||||
target_include_directories(libSceLibreSsl3 PRIVATE ${LIBS_INCLUDE_DIR})
|
||||
target_link_libraries(libSceLibreSsl3 PRIVATE libSceLibreSsl)
|
||||
configure_windows_unwind(libSceLibreSsl3)
|
||||
|
||||
if(BUILD_TESTING)
|
||||
add_test_executable(guest_crypto_memcmp_tests ${LIBS_INCLUDE_DIR}/tests/GuestCryptoMemcmp.cpp)
|
||||
target_include_directories(guest_crypto_memcmp_tests PRIVATE ${LIBS_INCLUDE_DIR})
|
||||
target_link_libraries(guest_crypto_memcmp_tests PRIVATE libSceLibreSsl3)
|
||||
add_test(NAME guest_crypto_memcmp COMMAND guest_crypto_memcmp_tests)
|
||||
set_tests_properties(guest_crypto_memcmp PROPERTIES TIMEOUT 20)
|
||||
add_test_executable(guest_libressl3_digest_tests ${LIBS_INCLUDE_DIR}/tests/GuestLibreSsl3Digest.cpp)
|
||||
target_include_directories(guest_libressl3_digest_tests PRIVATE ${LIBS_INCLUDE_DIR})
|
||||
target_link_libraries(guest_libressl3_digest_tests PRIVATE libSceLibreSsl3 libc)
|
||||
configure_windows_unwind(guest_libressl3_digest_tests)
|
||||
add_test(NAME guest_libressl3_digest COMMAND guest_libressl3_digest_tests)
|
||||
set_tests_properties(guest_libressl3_digest PROPERTIES TIMEOUT 30)
|
||||
if(WIN32)
|
||||
set_tests_properties(guest_crypto_memcmp guest_libressl3_digest PROPERTIES ENVIRONMENT_MODIFICATION
|
||||
"PATH=path_list_prepend:$<TARGET_FILE_DIR:libSceLibreSsl3>")
|
||||
endif()
|
||||
endif()
|
||||
@@ -31,9 +31,13 @@ int APS5_VABI BIO_vfree_nid_postfix(void) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int APS5_VABI CRYPTO_memcmp_nid_postfix(void) {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
return 0;
|
||||
int APS5_VABI CRYPTO_memcmp_nid_postfix(const void* first, const void* second, std::size_t length) {
|
||||
const auto* firstBytes = static_cast<const volatile unsigned char*>(first);
|
||||
const auto* secondBytes = static_cast<const volatile unsigned char*>(second);
|
||||
unsigned int difference = 0;
|
||||
for (std::size_t index = 0; index < length; ++index)
|
||||
difference |= firstBytes[index] ^ secondBytes[index];
|
||||
return static_cast<int>(difference);
|
||||
}
|
||||
|
||||
int APS5_VABI DH_get0_key_nid_postfix(void) {
|
||||
@@ -216,11 +220,6 @@ int APS5_VABI EVP_sha224_nid_postfix(void) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int APS5_VABI MD5_nid_postfix(void) {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int APS5_VABI OBJ_cmp_nid_postfix(void) {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
return 0;
|
||||
@@ -281,11 +280,6 @@ int APS5_VABI RSA_up_ref_nid_postfix(void) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int APS5_VABI SHA1_nid_postfix(void) {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int APS5_VABI SSL_CTX_add0_chain_cert_nid_postfix(void) {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
return 0;
|
||||
|
||||
@@ -0,0 +1,30 @@
|
||||
#include <cstddef>
|
||||
#include "prx/libc/include/General.hpp"
|
||||
|
||||
extern "C" {
|
||||
int APS5_VABI MD5_Init_nid_postfix(void* context);
|
||||
int APS5_VABI MD5_Update_nid_postfix(void* context, const void* data, std::size_t length);
|
||||
int APS5_VABI MD5_Final_nid_postfix(unsigned char* digest, void* context);
|
||||
int APS5_VABI SHA1_Init_nid_postfix(void* context);
|
||||
int APS5_VABI SHA1_Update_nid_postfix(void* context, const void* data, std::size_t length);
|
||||
int APS5_VABI SHA1_Final_nid_postfix(unsigned char* digest, void* context);
|
||||
|
||||
unsigned char* APS5_VABI MD5_nid_postfix(const unsigned char* data, std::size_t length, unsigned char* digest) {
|
||||
if (!digest) NotImplemented_nid_no_patch("MD5: null digest buffer");
|
||||
alignas(8) unsigned char context[92];
|
||||
MD5_Init_nid_postfix(context);
|
||||
MD5_Update_nid_postfix(context, data, length);
|
||||
MD5_Final_nid_postfix(digest, context);
|
||||
return digest;
|
||||
}
|
||||
|
||||
unsigned char* APS5_VABI SHA1_nid_postfix(const unsigned char* data, std::size_t length, unsigned char* digest) {
|
||||
if (!digest) NotImplemented_nid_no_patch("SHA1: null digest buffer");
|
||||
alignas(8) unsigned char context[96];
|
||||
SHA1_Init_nid_postfix(context);
|
||||
SHA1_Update_nid_postfix(context, data, length);
|
||||
SHA1_Final_nid_postfix(digest, context);
|
||||
return digest;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -5,6 +5,754 @@
|
||||
|
||||
extern "C" {
|
||||
|
||||
APS5_DUMMY_FUN
|
||||
int APS5_VABI sceNKWebKitUnknown____URPJNZ18_nid_no_patch() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
}
|
||||
APS5_EXPORT("++-URPJNZ18", sceNKWebKitUnknown____URPJNZ18_nid_no_patch);
|
||||
|
||||
int APS5_VABI sceNKWebKitUnknown___67uYkhqBU_nid_no_patch() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
}
|
||||
APS5_EXPORT("++67uYkhqBU", sceNKWebKitUnknown___67uYkhqBU_nid_no_patch);
|
||||
|
||||
int APS5_VABI sceNKWebKitUnknown___8RYr2gjrw_nid_no_patch() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
}
|
||||
APS5_EXPORT("++8RYr2gjrw", sceNKWebKitUnknown___8RYr2gjrw_nid_no_patch);
|
||||
|
||||
int APS5_VABI sceNKWebKitUnknown___BntMcao1o_nid_no_patch() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
}
|
||||
APS5_EXPORT("++BntMcao1o", sceNKWebKitUnknown___BntMcao1o_nid_no_patch);
|
||||
|
||||
int APS5_VABI sceNKWebKitUnknown___R8IXi10PI_nid_no_patch() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
}
|
||||
APS5_EXPORT("++R8IXi10PI", sceNKWebKitUnknown___R8IXi10PI_nid_no_patch);
|
||||
|
||||
int APS5_VABI sceNKWebKitUnknown___j2h_QO22w_nid_no_patch() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
}
|
||||
APS5_EXPORT("++j2h+QO22w", sceNKWebKitUnknown___j2h_QO22w_nid_no_patch);
|
||||
|
||||
int APS5_VABI sceNKWebKitUnknown____7XwmYLnI_nid_no_patch() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
}
|
||||
APS5_EXPORT("+-+7XwmYLnI", sceNKWebKitUnknown____7XwmYLnI_nid_no_patch);
|
||||
|
||||
int APS5_VABI sceNKWebKitUnknown___wmVyLhgm0_nid_no_patch() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
}
|
||||
APS5_EXPORT("+-wmVyLhgm0", sceNKWebKitUnknown___wmVyLhgm0_nid_no_patch);
|
||||
|
||||
int APS5_VABI sceNKWebKitUnknown__0QEt8ZQWgg_nid_no_patch() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
}
|
||||
APS5_EXPORT("+0QEt8ZQWgg", sceNKWebKitUnknown__0QEt8ZQWgg_nid_no_patch);
|
||||
|
||||
int APS5_VABI sceNKWebKitUnknown__0YNxcA_duk_nid_no_patch() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
}
|
||||
APS5_EXPORT("+0YNxcA-duk", sceNKWebKitUnknown__0YNxcA_duk_nid_no_patch);
|
||||
|
||||
int APS5_VABI sceNKWebKitUnknown__0ZZzGYxx_I_nid_no_patch() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
}
|
||||
APS5_EXPORT("+0ZZzGYxx+I", sceNKWebKitUnknown__0ZZzGYxx_I_nid_no_patch);
|
||||
|
||||
int APS5_VABI sceNKWebKitUnknown__0rdnkSicqk_nid_no_patch() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
}
|
||||
APS5_EXPORT("+0rdnkSicqk", sceNKWebKitUnknown__0rdnkSicqk_nid_no_patch);
|
||||
|
||||
int APS5_VABI sceNKWebKitUnknown__1Ex5GCP8Xs_nid_no_patch() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
}
|
||||
APS5_EXPORT("+1Ex5GCP8Xs", sceNKWebKitUnknown__1Ex5GCP8Xs_nid_no_patch);
|
||||
|
||||
int APS5_VABI sceNKWebKitUnknown__1FfZ_0sxvQ_nid_no_patch() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
}
|
||||
APS5_EXPORT("+1FfZ+0sxvQ", sceNKWebKitUnknown__1FfZ_0sxvQ_nid_no_patch);
|
||||
|
||||
int APS5_VABI sceNKWebKitUnknown__1ObAtzCrYE_nid_no_patch() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
}
|
||||
APS5_EXPORT("+1ObAtzCrYE", sceNKWebKitUnknown__1ObAtzCrYE_nid_no_patch);
|
||||
|
||||
int APS5_VABI sceNKWebKitUnknown__1n_h4FUu9E_nid_no_patch() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
}
|
||||
APS5_EXPORT("+1n+h4FUu9E", sceNKWebKitUnknown__1n_h4FUu9E_nid_no_patch);
|
||||
|
||||
int APS5_VABI sceNKWebKitUnknown__26aZpK535w_nid_no_patch() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
}
|
||||
APS5_EXPORT("+26aZpK535w", sceNKWebKitUnknown__26aZpK535w_nid_no_patch);
|
||||
|
||||
int APS5_VABI sceNKWebKitUnknown__2XuBaAXb_4_nid_no_patch() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
}
|
||||
APS5_EXPORT("+2XuBaAXb+4", sceNKWebKitUnknown__2XuBaAXb_4_nid_no_patch);
|
||||
|
||||
int APS5_VABI sceNKWebKitUnknown__2rTX2KM7Ms_nid_no_patch() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
}
|
||||
APS5_EXPORT("+2rTX2KM7Ms", sceNKWebKitUnknown__2rTX2KM7Ms_nid_no_patch);
|
||||
|
||||
int APS5_VABI sceNKWebKitUnknown__31dbB3S_6Y_nid_no_patch() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
}
|
||||
APS5_EXPORT("+31dbB3S-6Y", sceNKWebKitUnknown__31dbB3S_6Y_nid_no_patch);
|
||||
|
||||
int APS5_VABI sceNKWebKitUnknown__3p6wRzzzlQ_nid_no_patch() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
}
|
||||
APS5_EXPORT("+3p6wRzzzlQ", sceNKWebKitUnknown__3p6wRzzzlQ_nid_no_patch);
|
||||
|
||||
int APS5_VABI sceNKWebKitUnknown__4_GNOUIBt0_nid_no_patch() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
}
|
||||
APS5_EXPORT("+4-GNOUIBt0", sceNKWebKitUnknown__4_GNOUIBt0_nid_no_patch);
|
||||
|
||||
int APS5_VABI sceNKWebKitUnknown__45BiDnCTxw_nid_no_patch() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
}
|
||||
APS5_EXPORT("+45BiDnCTxw", sceNKWebKitUnknown__45BiDnCTxw_nid_no_patch);
|
||||
|
||||
int APS5_VABI sceNKWebKitUnknown__4lVmXsIwqM_nid_no_patch() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
}
|
||||
APS5_EXPORT("+4lVmXsIwqM", sceNKWebKitUnknown__4lVmXsIwqM_nid_no_patch);
|
||||
|
||||
int APS5_VABI sceNKWebKitUnknown__5E2YZZIstM_nid_no_patch() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
}
|
||||
APS5_EXPORT("+5E2YZZIstM", sceNKWebKitUnknown__5E2YZZIstM_nid_no_patch);
|
||||
|
||||
int APS5_VABI sceNKWebKitUnknown__5V_UOk8zS4_nid_no_patch() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
}
|
||||
APS5_EXPORT("+5V-UOk8zS4", sceNKWebKitUnknown__5V_UOk8zS4_nid_no_patch);
|
||||
|
||||
int APS5_VABI sceNKWebKitUnknown__63IB3UdMOY_nid_no_patch() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
}
|
||||
APS5_EXPORT("+63IB3UdMOY", sceNKWebKitUnknown__63IB3UdMOY_nid_no_patch);
|
||||
|
||||
int APS5_VABI sceNKWebKitUnknown__6boXsT6XFA_nid_no_patch() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
}
|
||||
APS5_EXPORT("+6boXsT6XFA", sceNKWebKitUnknown__6boXsT6XFA_nid_no_patch);
|
||||
|
||||
int APS5_VABI sceNKWebKitUnknown__79w68212vg_nid_no_patch() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
}
|
||||
APS5_EXPORT("+79w68212vg", sceNKWebKitUnknown__79w68212vg_nid_no_patch);
|
||||
|
||||
int APS5_VABI sceNKWebKitUnknown__7HpqmfJz48_nid_no_patch() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
}
|
||||
APS5_EXPORT("+7HpqmfJz48", sceNKWebKitUnknown__7HpqmfJz48_nid_no_patch);
|
||||
|
||||
int APS5_VABI sceNKWebKitUnknown__8T1y8Y_lgQ_nid_no_patch() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
}
|
||||
APS5_EXPORT("+8T1y8Y-lgQ", sceNKWebKitUnknown__8T1y8Y_lgQ_nid_no_patch);
|
||||
|
||||
int APS5_VABI sceNKWebKitUnknown__8VuTEFp13s_nid_no_patch() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
}
|
||||
APS5_EXPORT("+8VuTEFp13s", sceNKWebKitUnknown__8VuTEFp13s_nid_no_patch);
|
||||
|
||||
int APS5_VABI sceNKWebKitUnknown__9TKACifR2g_nid_no_patch() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
}
|
||||
APS5_EXPORT("+9TKACifR2g", sceNKWebKitUnknown__9TKACifR2g_nid_no_patch);
|
||||
|
||||
int APS5_VABI sceNKWebKitUnknown__9ZBRWNf4og_nid_no_patch() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
}
|
||||
APS5_EXPORT("+9ZBRWNf4og", sceNKWebKitUnknown__9ZBRWNf4og_nid_no_patch);
|
||||
|
||||
int APS5_VABI sceNKWebKitUnknown__9us0nrDaCU_nid_no_patch() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
}
|
||||
APS5_EXPORT("+9us0nrDaCU", sceNKWebKitUnknown__9us0nrDaCU_nid_no_patch);
|
||||
|
||||
int APS5_VABI sceNKWebKitUnknown__AIEKk6K05M_nid_no_patch() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
}
|
||||
APS5_EXPORT("+AIEKk6K05M", sceNKWebKitUnknown__AIEKk6K05M_nid_no_patch);
|
||||
|
||||
int APS5_VABI sceNKWebKitUnknown__Abk7CfTivU_nid_no_patch() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
}
|
||||
APS5_EXPORT("+Abk7CfTivU", sceNKWebKitUnknown__Abk7CfTivU_nid_no_patch);
|
||||
|
||||
int APS5_VABI sceNKWebKitUnknown__AnsPWo12m8_nid_no_patch() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
}
|
||||
APS5_EXPORT("+AnsPWo12m8", sceNKWebKitUnknown__AnsPWo12m8_nid_no_patch);
|
||||
|
||||
int APS5_VABI sceNKWebKitUnknown__BDqCDede1o_nid_no_patch() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
}
|
||||
APS5_EXPORT("+BDqCDede1o", sceNKWebKitUnknown__BDqCDede1o_nid_no_patch);
|
||||
|
||||
int APS5_VABI sceNKWebKitUnknown__BSUP6XSeAw_nid_no_patch() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
}
|
||||
APS5_EXPORT("+BSUP6XSeAw", sceNKWebKitUnknown__BSUP6XSeAw_nid_no_patch);
|
||||
|
||||
int APS5_VABI sceNKWebKitUnknown__BZCJi3OIiQ_nid_no_patch() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
}
|
||||
APS5_EXPORT("+BZCJi3OIiQ", sceNKWebKitUnknown__BZCJi3OIiQ_nid_no_patch);
|
||||
|
||||
int APS5_VABI sceNKWebKitUnknown__ByVxWl1pW8_nid_no_patch() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
}
|
||||
APS5_EXPORT("+ByVxWl1pW8", sceNKWebKitUnknown__ByVxWl1pW8_nid_no_patch);
|
||||
|
||||
int APS5_VABI sceNKWebKitUnknown__CgSI_4D534_nid_no_patch() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
}
|
||||
APS5_EXPORT("+CgSI-4D534", sceNKWebKitUnknown__CgSI_4D534_nid_no_patch);
|
||||
|
||||
int APS5_VABI sceNKWebKitUnknown__CpPA9_CKUA_nid_no_patch() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
}
|
||||
APS5_EXPORT("+CpPA9+CKUA", sceNKWebKitUnknown__CpPA9_CKUA_nid_no_patch);
|
||||
|
||||
int APS5_VABI sceNKWebKitUnknown__DcUw5YwkSY_nid_no_patch() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
}
|
||||
APS5_EXPORT("+DcUw5YwkSY", sceNKWebKitUnknown__DcUw5YwkSY_nid_no_patch);
|
||||
|
||||
int APS5_VABI sceNKWebKitUnknown__DpDBrSZWUc_nid_no_patch() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
}
|
||||
APS5_EXPORT("+DpDBrSZWUc", sceNKWebKitUnknown__DpDBrSZWUc_nid_no_patch);
|
||||
|
||||
int APS5_VABI sceNKWebKitUnknown__E3D_W4kpl8_nid_no_patch() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
}
|
||||
APS5_EXPORT("+E3D-W4kpl8", sceNKWebKitUnknown__E3D_W4kpl8_nid_no_patch);
|
||||
|
||||
int APS5_VABI sceNKWebKitUnknown__EN6MgNmVv4_nid_no_patch() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
}
|
||||
APS5_EXPORT("+EN6MgNmVv4", sceNKWebKitUnknown__EN6MgNmVv4_nid_no_patch);
|
||||
|
||||
int APS5_VABI sceNKWebKitUnknown__ErgockOJwc_nid_no_patch() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
}
|
||||
APS5_EXPORT("+ErgockOJwc", sceNKWebKitUnknown__ErgockOJwc_nid_no_patch);
|
||||
|
||||
int APS5_VABI sceNKWebKitUnknown__FKudG3uS8A_nid_no_patch() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
}
|
||||
APS5_EXPORT("+FKudG3uS8A", sceNKWebKitUnknown__FKudG3uS8A_nid_no_patch);
|
||||
|
||||
int APS5_VABI sceNKWebKitUnknown__FWUl_T8yG8_nid_no_patch() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
}
|
||||
APS5_EXPORT("+FWUl-T8yG8", sceNKWebKitUnknown__FWUl_T8yG8_nid_no_patch);
|
||||
|
||||
int APS5_VABI sceNKWebKitUnknown__Fca5Eyr4BU_nid_no_patch() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
}
|
||||
APS5_EXPORT("+Fca5Eyr4BU", sceNKWebKitUnknown__Fca5Eyr4BU_nid_no_patch);
|
||||
|
||||
int APS5_VABI sceNKWebKitUnknown__FcvpbbdrZM_nid_no_patch() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
}
|
||||
APS5_EXPORT("+FcvpbbdrZM", sceNKWebKitUnknown__FcvpbbdrZM_nid_no_patch);
|
||||
|
||||
int APS5_VABI sceNKWebKitUnknown__FvUhrQaiJQ_nid_no_patch() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
}
|
||||
APS5_EXPORT("+FvUhrQaiJQ", sceNKWebKitUnknown__FvUhrQaiJQ_nid_no_patch);
|
||||
|
||||
int APS5_VABI sceNKWebKitUnknown__GOwQvxqztE_nid_no_patch() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
}
|
||||
APS5_EXPORT("+GOwQvxqztE", sceNKWebKitUnknown__GOwQvxqztE_nid_no_patch);
|
||||
|
||||
int APS5_VABI sceNKWebKitUnknown__Gp0M0sPj9I_nid_no_patch() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
}
|
||||
APS5_EXPORT("+Gp0M0sPj9I", sceNKWebKitUnknown__Gp0M0sPj9I_nid_no_patch);
|
||||
|
||||
int APS5_VABI sceNKWebKitUnknown__H_bnpXdWtk_nid_no_patch() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
}
|
||||
APS5_EXPORT("+H-bnpXdWtk", sceNKWebKitUnknown__H_bnpXdWtk_nid_no_patch);
|
||||
|
||||
int APS5_VABI sceNKWebKitUnknown__H5PTMieXNE_nid_no_patch() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
}
|
||||
APS5_EXPORT("+H5PTMieXNE", sceNKWebKitUnknown__H5PTMieXNE_nid_no_patch);
|
||||
|
||||
int APS5_VABI sceNKWebKitUnknown__HuPyGuX_jY_nid_no_patch() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
}
|
||||
APS5_EXPORT("+HuPyGuX+jY", sceNKWebKitUnknown__HuPyGuX_jY_nid_no_patch);
|
||||
|
||||
int APS5_VABI sceNKWebKitUnknown__IMGO_dXHis_nid_no_patch() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
}
|
||||
APS5_EXPORT("+IMGO+dXHis", sceNKWebKitUnknown__IMGO_dXHis_nid_no_patch);
|
||||
|
||||
int APS5_VABI sceNKWebKitUnknown__ImJ026_DAw_nid_no_patch() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
}
|
||||
APS5_EXPORT("+ImJ026-DAw", sceNKWebKitUnknown__ImJ026_DAw_nid_no_patch);
|
||||
|
||||
int APS5_VABI sceNKWebKitUnknown__IoqHgIw0PM_nid_no_patch() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
}
|
||||
APS5_EXPORT("+IoqHgIw0PM", sceNKWebKitUnknown__IoqHgIw0PM_nid_no_patch);
|
||||
|
||||
int APS5_VABI sceNKWebKitUnknown__JnngM7WyHI_nid_no_patch() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
}
|
||||
APS5_EXPORT("+JnngM7WyHI", sceNKWebKitUnknown__JnngM7WyHI_nid_no_patch);
|
||||
|
||||
int APS5_VABI sceNKWebKitUnknown__Kb7j57jDzs_nid_no_patch() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
}
|
||||
APS5_EXPORT("+Kb7j57jDzs", sceNKWebKitUnknown__Kb7j57jDzs_nid_no_patch);
|
||||
|
||||
int APS5_VABI sceNKWebKitUnknown__Kx_IV_21hk_nid_no_patch() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
}
|
||||
APS5_EXPORT("+Kx-IV+21hk", sceNKWebKitUnknown__Kx_IV_21hk_nid_no_patch);
|
||||
|
||||
int APS5_VABI sceNKWebKitUnknown__LUabdo811U_nid_no_patch() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
}
|
||||
APS5_EXPORT("+LUabdo811U", sceNKWebKitUnknown__LUabdo811U_nid_no_patch);
|
||||
|
||||
int APS5_VABI sceNKWebKitUnknown__LiOmqon2ZI_nid_no_patch() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
}
|
||||
APS5_EXPORT("+LiOmqon2ZI", sceNKWebKitUnknown__LiOmqon2ZI_nid_no_patch);
|
||||
|
||||
int APS5_VABI sceNKWebKitUnknown__LoAenYdWlM_nid_no_patch() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
}
|
||||
APS5_EXPORT("+LoAenYdWlM", sceNKWebKitUnknown__LoAenYdWlM_nid_no_patch);
|
||||
|
||||
int APS5_VABI sceNKWebKitUnknown__LrmM3KN3N8_nid_no_patch() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
}
|
||||
APS5_EXPORT("+LrmM3KN3N8", sceNKWebKitUnknown__LrmM3KN3N8_nid_no_patch);
|
||||
|
||||
int APS5_VABI sceNKWebKitUnknown__MzGFuNN348_nid_no_patch() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
}
|
||||
APS5_EXPORT("+MzGFuNN348", sceNKWebKitUnknown__MzGFuNN348_nid_no_patch);
|
||||
|
||||
int APS5_VABI sceNKWebKitUnknown__N_GwpCV4yk_nid_no_patch() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
}
|
||||
APS5_EXPORT("+N-GwpCV4yk", sceNKWebKitUnknown__N_GwpCV4yk_nid_no_patch);
|
||||
|
||||
int APS5_VABI sceNKWebKitUnknown__N6UhRaLrJE_nid_no_patch() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
}
|
||||
APS5_EXPORT("+N6UhRaLrJE", sceNKWebKitUnknown__N6UhRaLrJE_nid_no_patch);
|
||||
|
||||
int APS5_VABI sceNKWebKitUnknown__NGrXdCa0q8_nid_no_patch() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
}
|
||||
APS5_EXPORT("+NGrXdCa0q8", sceNKWebKitUnknown__NGrXdCa0q8_nid_no_patch);
|
||||
|
||||
int APS5_VABI sceNKWebKitUnknown__NiLTGGKF_E_nid_no_patch() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
}
|
||||
APS5_EXPORT("+NiLTGGKF+E", sceNKWebKitUnknown__NiLTGGKF_E_nid_no_patch);
|
||||
|
||||
int APS5_VABI sceNKWebKitUnknown__Nqfy8HVG84_nid_no_patch() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
}
|
||||
APS5_EXPORT("+Nqfy8HVG84", sceNKWebKitUnknown__Nqfy8HVG84_nid_no_patch);
|
||||
|
||||
int APS5_VABI sceNKWebKitUnknown__NuhuZH75ak_nid_no_patch() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
}
|
||||
APS5_EXPORT("+NuhuZH75ak", sceNKWebKitUnknown__NuhuZH75ak_nid_no_patch);
|
||||
|
||||
int APS5_VABI sceNKWebKitUnknown__OCxbaKiBUo_nid_no_patch() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
}
|
||||
APS5_EXPORT("+OCxbaKiBUo", sceNKWebKitUnknown__OCxbaKiBUo_nid_no_patch);
|
||||
|
||||
int APS5_VABI sceNKWebKitUnknown__OOjOkuWL6g_nid_no_patch() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
}
|
||||
APS5_EXPORT("+OOjOkuWL6g", sceNKWebKitUnknown__OOjOkuWL6g_nid_no_patch);
|
||||
|
||||
int APS5_VABI sceNKWebKitUnknown__OkTn3_PBxM_nid_no_patch() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
}
|
||||
APS5_EXPORT("+OkTn3+PBxM", sceNKWebKitUnknown__OkTn3_PBxM_nid_no_patch);
|
||||
|
||||
int APS5_VABI sceNKWebKitUnknown__PDx3sfB_l4_nid_no_patch() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
}
|
||||
APS5_EXPORT("+PDx3sfB-l4", sceNKWebKitUnknown__PDx3sfB_l4_nid_no_patch);
|
||||
|
||||
int APS5_VABI sceNKWebKitUnknown__POsWAWjXo8_nid_no_patch() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
}
|
||||
APS5_EXPORT("+POsWAWjXo8", sceNKWebKitUnknown__POsWAWjXo8_nid_no_patch);
|
||||
|
||||
int APS5_VABI sceNKWebKitUnknown__PeIrQMgYpw_nid_no_patch() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
}
|
||||
APS5_EXPORT("+PeIrQMgYpw", sceNKWebKitUnknown__PeIrQMgYpw_nid_no_patch);
|
||||
|
||||
int APS5_VABI sceNKWebKitUnknown__Q7xLvpc0PA_nid_no_patch() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
}
|
||||
APS5_EXPORT("+Q7xLvpc0PA", sceNKWebKitUnknown__Q7xLvpc0PA_nid_no_patch);
|
||||
|
||||
int APS5_VABI sceNKWebKitUnknown__QL3zQ6ZNy4_nid_no_patch() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
}
|
||||
APS5_EXPORT("+QL3zQ6ZNy4", sceNKWebKitUnknown__QL3zQ6ZNy4_nid_no_patch);
|
||||
|
||||
int APS5_VABI sceNKWebKitUnknown__QqzEnc5c80_nid_no_patch() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
}
|
||||
APS5_EXPORT("+QqzEnc5c80", sceNKWebKitUnknown__QqzEnc5c80_nid_no_patch);
|
||||
|
||||
int APS5_VABI sceNKWebKitUnknown__R0GXLrsPM0_nid_no_patch() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
}
|
||||
APS5_EXPORT("+R0GXLrsPM0", sceNKWebKitUnknown__R0GXLrsPM0_nid_no_patch);
|
||||
|
||||
int APS5_VABI sceNKWebKitUnknown__R2eXISeSvw_nid_no_patch() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
}
|
||||
APS5_EXPORT("+R2eXISeSvw", sceNKWebKitUnknown__R2eXISeSvw_nid_no_patch);
|
||||
|
||||
int APS5_VABI sceNKWebKitUnknown__RkwSDm5kGU_nid_no_patch() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
}
|
||||
APS5_EXPORT("+RkwSDm5kGU", sceNKWebKitUnknown__RkwSDm5kGU_nid_no_patch);
|
||||
|
||||
int APS5_VABI sceNKWebKitUnknown__RtBREW92M0_nid_no_patch() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
}
|
||||
APS5_EXPORT("+RtBREW92M0", sceNKWebKitUnknown__RtBREW92M0_nid_no_patch);
|
||||
|
||||
int APS5_VABI sceNKWebKitUnknown__S72K_fa2_8_nid_no_patch() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
}
|
||||
APS5_EXPORT("+S72K+fa2-8", sceNKWebKitUnknown__S72K_fa2_8_nid_no_patch);
|
||||
|
||||
int APS5_VABI sceNKWebKitUnknown__S7ftAAWhoQ_nid_no_patch() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
}
|
||||
APS5_EXPORT("+S7ftAAWhoQ", sceNKWebKitUnknown__S7ftAAWhoQ_nid_no_patch);
|
||||
|
||||
int APS5_VABI sceNKWebKitUnknown__SHzgUiuQDE_nid_no_patch() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
}
|
||||
APS5_EXPORT("+SHzgUiuQDE", sceNKWebKitUnknown__SHzgUiuQDE_nid_no_patch);
|
||||
|
||||
int APS5_VABI sceNKWebKitUnknown__Sgy63JgEgQ_nid_no_patch() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
}
|
||||
APS5_EXPORT("+Sgy63JgEgQ", sceNKWebKitUnknown__Sgy63JgEgQ_nid_no_patch);
|
||||
|
||||
int APS5_VABI sceNKWebKitUnknown__Sozphy1Wa8_nid_no_patch() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
}
|
||||
APS5_EXPORT("+Sozphy1Wa8", sceNKWebKitUnknown__Sozphy1Wa8_nid_no_patch);
|
||||
|
||||
int APS5_VABI sceNKWebKitUnknown__TPntL1OK80_nid_no_patch() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
}
|
||||
APS5_EXPORT("+TPntL1OK80", sceNKWebKitUnknown__TPntL1OK80_nid_no_patch);
|
||||
|
||||
int APS5_VABI sceNKWebKitUnknown__TT_AplhQWA_nid_no_patch() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
}
|
||||
APS5_EXPORT("+TT+AplhQWA", sceNKWebKitUnknown__TT_AplhQWA_nid_no_patch);
|
||||
|
||||
int APS5_VABI sceNKWebKitUnknown__TjNmuhxdBQ_nid_no_patch() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
}
|
||||
APS5_EXPORT("+TjNmuhxdBQ", sceNKWebKitUnknown__TjNmuhxdBQ_nid_no_patch);
|
||||
|
||||
int APS5_VABI sceNKWebKitUnknown__U_nxwdrnDY_nid_no_patch() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
}
|
||||
APS5_EXPORT("+U-nxwdrnDY", sceNKWebKitUnknown__U_nxwdrnDY_nid_no_patch);
|
||||
|
||||
int APS5_VABI sceNKWebKitUnknown__UKI_MUuiCU_nid_no_patch() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
}
|
||||
APS5_EXPORT("+UKI-MUuiCU", sceNKWebKitUnknown__UKI_MUuiCU_nid_no_patch);
|
||||
|
||||
int APS5_VABI sceNKWebKitUnknown__VvktcfIouQ_nid_no_patch() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
}
|
||||
APS5_EXPORT("+VvktcfIouQ", sceNKWebKitUnknown__VvktcfIouQ_nid_no_patch);
|
||||
|
||||
int APS5_VABI sceNKWebKitUnknown__WS2yRv5aBI_nid_no_patch() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
}
|
||||
APS5_EXPORT("+WS2yRv5aBI", sceNKWebKitUnknown__WS2yRv5aBI_nid_no_patch);
|
||||
|
||||
int APS5_VABI sceNKWebKitUnknown__XZfnHByVO0_nid_no_patch() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
}
|
||||
APS5_EXPORT("+XZfnHByVO0", sceNKWebKitUnknown__XZfnHByVO0_nid_no_patch);
|
||||
|
||||
int APS5_VABI sceNKWebKitUnknown__YBfWz5udq4_nid_no_patch() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
}
|
||||
APS5_EXPORT("+YBfWz5udq4", sceNKWebKitUnknown__YBfWz5udq4_nid_no_patch);
|
||||
|
||||
int APS5_VABI sceNKWebKitUnknown__YPwmEWTZwE_nid_no_patch() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
}
|
||||
APS5_EXPORT("+YPwmEWTZwE", sceNKWebKitUnknown__YPwmEWTZwE_nid_no_patch);
|
||||
|
||||
int APS5_VABI sceNKWebKitUnknown__YYEOsi3IMk_nid_no_patch() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
}
|
||||
APS5_EXPORT("+YYEOsi3IMk", sceNKWebKitUnknown__YYEOsi3IMk_nid_no_patch);
|
||||
|
||||
int APS5_VABI sceNKWebKitUnknown__YyqQTUIQJQ_nid_no_patch() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
}
|
||||
APS5_EXPORT("+YyqQTUIQJQ", sceNKWebKitUnknown__YyqQTUIQJQ_nid_no_patch);
|
||||
|
||||
int APS5_VABI sceNKWebKitUnknown__ZgGbFykhls_nid_no_patch() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
}
|
||||
APS5_EXPORT("+ZgGbFykhls", sceNKWebKitUnknown__ZgGbFykhls_nid_no_patch);
|
||||
|
||||
int APS5_VABI sceNKWebKitUnknown__ZwjLJ74Y38_nid_no_patch() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
}
|
||||
APS5_EXPORT("+ZwjLJ74Y38", sceNKWebKitUnknown__ZwjLJ74Y38_nid_no_patch);
|
||||
|
||||
int APS5_VABI sceNKWebKitUnknown__b1xwU7aUwU_nid_no_patch() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
}
|
||||
APS5_EXPORT("+b1xwU7aUwU", sceNKWebKitUnknown__b1xwU7aUwU_nid_no_patch);
|
||||
|
||||
int APS5_VABI sceNKWebKitUnknown__b5TfVQ3_4s_nid_no_patch() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
}
|
||||
APS5_EXPORT("+b5TfVQ3-4s", sceNKWebKitUnknown__b5TfVQ3_4s_nid_no_patch);
|
||||
|
||||
int APS5_VABI sceNKWebKitUnknown__bDb7iby5NI_nid_no_patch() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
}
|
||||
APS5_EXPORT("+bDb7iby5NI", sceNKWebKitUnknown__bDb7iby5NI_nid_no_patch);
|
||||
|
||||
int APS5_VABI sceNKWebKitUnknown__baqz7ahOng_nid_no_patch() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
}
|
||||
APS5_EXPORT("+baqz7ahOng", sceNKWebKitUnknown__baqz7ahOng_nid_no_patch);
|
||||
|
||||
int APS5_VABI sceNKWebKitUnknown__bvtn3pCtek_nid_no_patch() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
}
|
||||
APS5_EXPORT("+bvtn3pCtek", sceNKWebKitUnknown__bvtn3pCtek_nid_no_patch);
|
||||
|
||||
int APS5_VABI sceNKWebKitUnknown__byORTSkWQo_nid_no_patch() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
}
|
||||
APS5_EXPORT("+byORTSkWQo", sceNKWebKitUnknown__byORTSkWQo_nid_no_patch);
|
||||
|
||||
int APS5_VABI sceNKWebKitUnknown__dAwquupevQ_nid_no_patch() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
}
|
||||
APS5_EXPORT("+dAwquupevQ", sceNKWebKitUnknown__dAwquupevQ_nid_no_patch);
|
||||
|
||||
int APS5_VABI sceNKWebKitUnknown__dTlroLZao8_nid_no_patch() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
}
|
||||
APS5_EXPORT("+dTlroLZao8", sceNKWebKitUnknown__dTlroLZao8_nid_no_patch);
|
||||
|
||||
int APS5_VABI sceNKWebKitUnknown__eVN0UdRT8c_nid_no_patch() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
}
|
||||
APS5_EXPORT("+eVN0UdRT8c", sceNKWebKitUnknown__eVN0UdRT8c_nid_no_patch);
|
||||
|
||||
int APS5_VABI sceNKWebKitUnknown__fTKZiGqo8E_nid_no_patch() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
}
|
||||
APS5_EXPORT("+fTKZiGqo8E", sceNKWebKitUnknown__fTKZiGqo8E_nid_no_patch);
|
||||
|
||||
int APS5_VABI sceNKWebKitUnknown__feeFP8Y2_c_nid_no_patch() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
}
|
||||
APS5_EXPORT("+feeFP8Y2+c", sceNKWebKitUnknown__feeFP8Y2_c_nid_no_patch);
|
||||
|
||||
int APS5_VABI sceNKWebKitUnknown__iLBOBrdx5A_nid_no_patch() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
}
|
||||
APS5_EXPORT("+iLBOBrdx5A", sceNKWebKitUnknown__iLBOBrdx5A_nid_no_patch);
|
||||
|
||||
int APS5_VABI sceNKWebKitUnknown__iLdIVuhDhY_nid_no_patch() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
}
|
||||
APS5_EXPORT("+iLdIVuhDhY", sceNKWebKitUnknown__iLdIVuhDhY_nid_no_patch);
|
||||
|
||||
int APS5_VABI sceNKWebKitUnknown__jG4wqqA8yg_nid_no_patch() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
}
|
||||
APS5_EXPORT("+jG4wqqA8yg", sceNKWebKitUnknown__jG4wqqA8yg_nid_no_patch);
|
||||
|
||||
int APS5_VABI sceNKWebKitUnknown__jLvgfDA97c_nid_no_patch() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
}
|
||||
APS5_EXPORT("+jLvgfDA97c", sceNKWebKitUnknown__jLvgfDA97c_nid_no_patch);
|
||||
|
||||
int APS5_VABI sceNKWebKitUnknown__ji7IBGwnCM_nid_no_patch() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
}
|
||||
APS5_EXPORT("+ji7IBGwnCM", sceNKWebKitUnknown__ji7IBGwnCM_nid_no_patch);
|
||||
|
||||
int APS5_VABI sceNKWebKitUnknown__k3JGU_UUXo_nid_no_patch() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
}
|
||||
APS5_EXPORT("+k3JGU-UUXo", sceNKWebKitUnknown__k3JGU_UUXo_nid_no_patch);
|
||||
|
||||
int APS5_VABI sceNKWebKitUnknown__kX_CdbguB0_nid_no_patch() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
}
|
||||
APS5_EXPORT("+kX-CdbguB0", sceNKWebKitUnknown__kX_CdbguB0_nid_no_patch);
|
||||
|
||||
int APS5_VABI sceNKWebKitUnknown__keSg8ay8cE_nid_no_patch() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
}
|
||||
APS5_EXPORT("+keSg8ay8cE", sceNKWebKitUnknown__keSg8ay8cE_nid_no_patch);
|
||||
|
||||
int APS5_VABI sceNKWebKitUnknown__lI9zCCS_HQ_nid_no_patch() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
}
|
||||
APS5_EXPORT("+lI9zCCS-HQ", sceNKWebKitUnknown__lI9zCCS_HQ_nid_no_patch);
|
||||
|
||||
int APS5_VABI sceNKWebKitUnknown__lwLqZJLo3g_nid_no_patch() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
}
|
||||
APS5_EXPORT("+lwLqZJLo3g", sceNKWebKitUnknown__lwLqZJLo3g_nid_no_patch);
|
||||
|
||||
int APS5_VABI sceNKWebKitUnknown__mS029ncrbo_nid_no_patch() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
}
|
||||
APS5_EXPORT("+mS029ncrbo", sceNKWebKitUnknown__mS029ncrbo_nid_no_patch);
|
||||
|
||||
int APS5_VABI sceNKWebKitUnknown__mYy22Ucg7Y_nid_no_patch() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
}
|
||||
APS5_EXPORT("+mYy22Ucg7Y", sceNKWebKitUnknown__mYy22Ucg7Y_nid_no_patch);
|
||||
|
||||
int APS5_VABI sceNKWebKitUnknown__nHWcLWOmb4_nid_no_patch() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
}
|
||||
APS5_EXPORT("+nHWcLWOmb4", sceNKWebKitUnknown__nHWcLWOmb4_nid_no_patch);
|
||||
|
||||
int APS5_VABI sceNKWebKitUnknown__nSg5kHtXkg_nid_no_patch() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
}
|
||||
APS5_EXPORT("+nSg5kHtXkg", sceNKWebKitUnknown__nSg5kHtXkg_nid_no_patch);
|
||||
|
||||
int APS5_VABI sceNKWebKitUnknown__nc3IouJMEA_nid_no_patch() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
}
|
||||
APS5_EXPORT("+nc3IouJMEA", sceNKWebKitUnknown__nc3IouJMEA_nid_no_patch);
|
||||
|
||||
int APS5_VABI sceNKWebKitUnknown__ndmq8LhAjA_nid_no_patch() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
}
|
||||
APS5_EXPORT("+ndmq8LhAjA", sceNKWebKitUnknown__ndmq8LhAjA_nid_no_patch);
|
||||
|
||||
int APS5_VABI sceNKWebKitUnknown__nrEMsyYHiw_nid_no_patch() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
}
|
||||
APS5_EXPORT("+nrEMsyYHiw", sceNKWebKitUnknown__nrEMsyYHiw_nid_no_patch);
|
||||
|
||||
int APS5_VABI sceNKWebKitUnknown__oJHrfcyJJM_nid_no_patch() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
}
|
||||
APS5_EXPORT("+oJHrfcyJJM", sceNKWebKitUnknown__oJHrfcyJJM_nid_no_patch);
|
||||
|
||||
int APS5_VABI sceNKWebKitUnknown__ovAafdG0O8_nid_no_patch() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
}
|
||||
APS5_EXPORT("+ovAafdG0O8", sceNKWebKitUnknown__ovAafdG0O8_nid_no_patch);
|
||||
|
||||
int APS5_VABI sceNKWebKitUnknown__pWGccNXto8_nid_no_patch() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
}
|
||||
APS5_EXPORT("+pWGccNXto8", sceNKWebKitUnknown__pWGccNXto8_nid_no_patch);
|
||||
|
||||
int APS5_VABI sceNKWebKitUnknown__q0GELad_mY_nid_no_patch() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
}
|
||||
APS5_EXPORT("+q0GELad-mY", sceNKWebKitUnknown__q0GELad_mY_nid_no_patch);
|
||||
|
||||
int APS5_VABI sceNKWebKitUnknown__qXuNlEFSRQ_nid_no_patch() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
}
|
||||
APS5_EXPORT("+qXuNlEFSRQ", sceNKWebKitUnknown__qXuNlEFSRQ_nid_no_patch);
|
||||
|
||||
int APS5_VABI sceNKWebKitUnknown__qsTbJFS86A_nid_no_patch() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
}
|
||||
APS5_EXPORT("+qsTbJFS86A", sceNKWebKitUnknown__qsTbJFS86A_nid_no_patch);
|
||||
|
||||
int APS5_VABI sceNKWebKitUnknown__r_TJDA2yIM_nid_no_patch() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
}
|
||||
APS5_EXPORT("+r+TJDA2yIM", sceNKWebKitUnknown__r_TJDA2yIM_nid_no_patch);
|
||||
|
||||
int APS5_VABI sceNKWebKitUnknown__r0UH41I1dI_nid_no_patch() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
}
|
||||
APS5_EXPORT("+r0UH41I1dI", sceNKWebKitUnknown__r0UH41I1dI_nid_no_patch);
|
||||
|
||||
int APS5_VABI sceNKWebKitUnknown__r8OGkuL4dc_nid_no_patch() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
}
|
||||
APS5_EXPORT("+r8OGkuL4dc", sceNKWebKitUnknown__r8OGkuL4dc_nid_no_patch);
|
||||
|
||||
int APS5_VABI sceNKWebKitUnknown__rFA8ZR_qaI_nid_no_patch() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
}
|
||||
APS5_EXPORT("+rFA8ZR+qaI", sceNKWebKitUnknown__rFA8ZR_qaI_nid_no_patch);
|
||||
|
||||
int APS5_VABI sceNKWebKitUnknown__rPvFDsPbXM_nid_no_patch() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
}
|
||||
APS5_EXPORT("+rPvFDsPbXM", sceNKWebKitUnknown__rPvFDsPbXM_nid_no_patch);
|
||||
|
||||
int APS5_VABI sceNKWebKitUnknown__sUvE9LF80k_nid_no_patch() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
}
|
||||
APS5_EXPORT("+sUvE9LF80k", sceNKWebKitUnknown__sUvE9LF80k_nid_no_patch);
|
||||
|
||||
int APS5_VABI sceNKWebKitUnknown__suuwfNT5Oc_nid_no_patch() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
}
|
||||
APS5_EXPORT("+suuwfNT5Oc", sceNKWebKitUnknown__suuwfNT5Oc_nid_no_patch);
|
||||
|
||||
int APS5_VABI sceNKWebKitUnknown__t_MaTLADe4_nid_no_patch() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
}
|
||||
APS5_EXPORT("+t-MaTLADe4", sceNKWebKitUnknown__t_MaTLADe4_nid_no_patch);
|
||||
|
||||
}
|
||||
@@ -131,7 +131,7 @@ static bool HasIpv4Callback() {
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool HostHasAddress(int family) {
|
||||
static bool QueryHostHasAddress(int family) {
|
||||
#ifdef _WIN32
|
||||
static const int socket_status = [] {
|
||||
WSADATA data{};
|
||||
@@ -188,6 +188,74 @@ struct HostIpv4Interface {
|
||||
std::vector<in_addr> dns;
|
||||
};
|
||||
|
||||
#ifdef _WIN32
|
||||
namespace {
|
||||
|
||||
struct HostAddressCache {
|
||||
std::mutex lock;
|
||||
bool registered = false;
|
||||
bool tried = false;
|
||||
std::atomic<std::uint64_t> generation{1};
|
||||
std::uint64_t seen[3]{};
|
||||
bool value[3]{};
|
||||
std::uint64_t interfaceSeen = 0;
|
||||
bool interfaceFound = false;
|
||||
HostIpv4Interface interfaceValue;
|
||||
};
|
||||
|
||||
HostAddressCache& AddressCache() {
|
||||
static HostAddressCache cache;
|
||||
return cache;
|
||||
}
|
||||
|
||||
void CALLBACK HostAddressChanged(PVOID, PMIB_UNICASTIPADDRESS_ROW, MIB_NOTIFICATION_TYPE) {
|
||||
AddressCache().generation.fetch_add(1, std::memory_order_acq_rel);
|
||||
}
|
||||
|
||||
void CALLBACK HostInterfaceChanged(PVOID, PMIB_IPINTERFACE_ROW, MIB_NOTIFICATION_TYPE) {
|
||||
AddressCache().generation.fetch_add(1, std::memory_order_acq_rel);
|
||||
}
|
||||
|
||||
void CALLBACK HostRouteChanged(PVOID, PMIB_IPFORWARD_ROW2, MIB_NOTIFICATION_TYPE) {
|
||||
AddressCache().generation.fetch_add(1, std::memory_order_acq_rel);
|
||||
}
|
||||
|
||||
void WatchHostAddresses(HostAddressCache& cache) {
|
||||
if (cache.tried) return;
|
||||
cache.tried = true;
|
||||
HANDLE addresses = nullptr;
|
||||
HANDLE interfaces = nullptr;
|
||||
HANDLE routes = nullptr;
|
||||
cache.registered = NotifyUnicastIpAddressChange(AF_UNSPEC, HostAddressChanged, nullptr, FALSE, &addresses) == NO_ERROR &&
|
||||
NotifyIpInterfaceChange(AF_UNSPEC, HostInterfaceChanged, nullptr, FALSE, &interfaces) == NO_ERROR &&
|
||||
NotifyRouteChange2(AF_UNSPEC, HostRouteChanged, nullptr, FALSE, &routes) == NO_ERROR;
|
||||
if (!cache.registered) {
|
||||
if (addresses != nullptr) CancelMibChangeNotify2(addresses);
|
||||
if (interfaces != nullptr) CancelMibChangeNotify2(interfaces);
|
||||
if (routes != nullptr) CancelMibChangeNotify2(routes);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
#endif
|
||||
|
||||
static bool HostHasAddress(int family) {
|
||||
#ifdef _WIN32
|
||||
auto& cache = AddressCache();
|
||||
const int slot = family == AF_INET ? 0 : family == AF_INET6 ? 1 : 2;
|
||||
std::lock_guard guard(cache.lock);
|
||||
WatchHostAddresses(cache);
|
||||
const auto generation = cache.generation.load(std::memory_order_acquire);
|
||||
if (cache.registered && cache.seen[slot] == generation) return cache.value[slot];
|
||||
const bool value = QueryHostHasAddress(family);
|
||||
cache.value[slot] = value;
|
||||
cache.seen[slot] = generation;
|
||||
return value;
|
||||
#else
|
||||
return QueryHostHasAddress(family);
|
||||
#endif
|
||||
}
|
||||
|
||||
static bool UsableIpv4(in_addr address) {
|
||||
const auto host = ntohl(address.s_addr);
|
||||
return host != 0 && (host >> 24) != 127;
|
||||
@@ -310,7 +378,7 @@ static std::vector<in_addr> HostDnsServers() {
|
||||
}
|
||||
#endif
|
||||
|
||||
static bool FindHostIpv4Interface(HostIpv4Interface& found) {
|
||||
static bool QueryHostIpv4Interface(HostIpv4Interface& found) {
|
||||
#ifdef _WIN32
|
||||
ULONG size = 0;
|
||||
const ULONG flags = GAA_FLAG_SKIP_ANYCAST | GAA_FLAG_SKIP_MULTICAST | GAA_FLAG_INCLUDE_GATEWAYS;
|
||||
@@ -371,6 +439,25 @@ static bool FindHostIpv4Interface(HostIpv4Interface& found) {
|
||||
#endif
|
||||
}
|
||||
|
||||
static bool FindHostIpv4Interface(HostIpv4Interface& found) {
|
||||
#ifdef _WIN32
|
||||
auto& cache = AddressCache();
|
||||
std::lock_guard guard(cache.lock);
|
||||
WatchHostAddresses(cache);
|
||||
const auto generation = cache.generation.load(std::memory_order_acquire);
|
||||
if (!cache.registered || cache.interfaceSeen != generation) {
|
||||
HostIpv4Interface value;
|
||||
cache.interfaceFound = QueryHostIpv4Interface(value);
|
||||
cache.interfaceValue = std::move(value);
|
||||
cache.interfaceSeen = generation;
|
||||
}
|
||||
if (cache.interfaceFound) found = cache.interfaceValue;
|
||||
return cache.interfaceFound;
|
||||
#else
|
||||
return QueryHostIpv4Interface(found);
|
||||
#endif
|
||||
}
|
||||
|
||||
extern "C" std::size_t NetCtlHostDnsServers_nid_no_patch(std::uint32_t* servers, std::size_t capacity) {
|
||||
HostIpv4Interface host;
|
||||
if (!FindHostIpv4Interface(host)) return 0;
|
||||
|
||||
@@ -21,6 +21,13 @@ static constexpr int SCE_NGS2_ERROR_INVALID_VOICE_HANDLE = static_cast<int>(0x80
|
||||
static constexpr int SCE_NGS2_ERROR_NULL_PARAM_LIST = static_cast<int>(0x804A8360);
|
||||
static constexpr int SCE_NGS2_ERROR_INVALID_GEOM_LISTENER_ADDRESS = static_cast<int>(0x804A8461);
|
||||
static constexpr int SCE_NGS2_ERROR_INVALID_GEOM_FLAG = static_cast<int>(0x804A8463);
|
||||
static constexpr int SCE_NGS2_ERROR_INVALID_OPTION_SIZE = static_cast<int>(0x804A8013);
|
||||
static constexpr int SCE_NGS2_ERROR_INVALID_NUM_CHANNELS = static_cast<int>(0x804A8052);
|
||||
static constexpr int SCE_NGS2_ERROR_INVALID_PITCH_SHIFT_OPTION = static_cast<int>(0x804A8098);
|
||||
static constexpr int SCE_NGS2_ERROR_INVALID_REVERB_OPTION = static_cast<int>(0x804A8099);
|
||||
static constexpr int SCE_NGS2_ERROR_INVALID_STATE_SIZE = static_cast<int>(0x804A8302);
|
||||
static constexpr int SCE_NGS2_ERROR_INVALID_BUFFER_INDEX = static_cast<int>(0x804A8306);
|
||||
static constexpr int SCE_NGS2_ERROR_INVALID_NUM_BUFFERS = static_cast<int>(0x804A830B);
|
||||
|
||||
static constexpr std::uint32_t SCE_NGS2_RACK_ID_SAMPLER = 0x1000;
|
||||
static constexpr std::uint32_t SCE_NGS2_RACK_ID_SUBMIXER = 0x2000;
|
||||
@@ -71,14 +78,25 @@ static constexpr std::uint32_t SCE_NGS2_CUSTOM_SAMPLER_VOICE_PARAM_EXIT_LOOP = 0
|
||||
static constexpr std::uint32_t SCE_NGS2_CUSTOM_SAMPLER_VOICE_PARAM_PITCH = 0x40010005;
|
||||
static constexpr std::uint32_t SCE_NGS2_CUSTOM_SUBMIXER_VOICE_PARAM_SETUP = 0x40020000;
|
||||
static constexpr std::uint32_t SCE_NGS2_CUSTOM_VOICE_PARAM_FILTER = 0x40001300;
|
||||
static constexpr std::uint32_t SCE_NGS2_CUSTOM_VOICE_PARAM_GAIN = 0x40001500;
|
||||
static constexpr std::uint32_t SCE_NGS2_CUSTOM_VOICE_PARAM_USER_FX = 0x40001d00;
|
||||
static constexpr std::uint32_t SCE_NGS2_CUSTOM_VOICE_PARAM_USER_FX2 = 0x40001f00;
|
||||
|
||||
static constexpr std::uint32_t SCE_NGS2_CUSTOM_MAX_MODULES = 24;
|
||||
static constexpr std::uint32_t SCE_NGS2_CUSTOM_MAX_PORTS = 16;
|
||||
static constexpr std::uint32_t SCE_NGS2_CUSTOM_MAX_BUFFERS = 4;
|
||||
static constexpr std::uint32_t SCE_NGS2_CUSTOM_SUBMIXER_MAX_CHANNELS = 37;
|
||||
static constexpr std::uint32_t SCE_NGS2_CUSTOM_SUBMIXER_MAX_INPUTS = 2;
|
||||
static constexpr std::uint32_t SCE_NGS2_CUSTOM_REVERB_OPTION_SIZE = 12;
|
||||
static constexpr std::uint32_t SCE_NGS2_CUSTOM_PITCH_SHIFT_OPTION_SIZE = 8;
|
||||
static constexpr std::uint32_t SCE_NGS2_CUSTOM_PITCH_SHIFT_STATE_SIZE = 8;
|
||||
static constexpr std::uint32_t SCE_NGS2_CUSTOM_MODULE_ID_FILTER = 0x13;
|
||||
static constexpr std::uint32_t SCE_NGS2_CUSTOM_MODULE_ID_GAIN = 0x15;
|
||||
static constexpr std::uint32_t SCE_NGS2_CUSTOM_MODULE_ID_REVERB = 0x1b;
|
||||
static constexpr std::uint32_t SCE_NGS2_CUSTOM_MODULE_ID_USER_FX = 0x1d;
|
||||
static constexpr std::uint32_t SCE_NGS2_CUSTOM_MODULE_ID_USER_FX2 = 0x1f;
|
||||
static constexpr std::uint32_t SCE_NGS2_CUSTOM_MODULE_ID_PITCH_SHIFT = 0x20;
|
||||
static constexpr std::uint32_t SCE_NGS2_CUSTOM_MODULE_ID_CONVOLUTION = 0x23;
|
||||
|
||||
static constexpr std::uint32_t SCE_NGS2_WAVEFORM_BLOCKS_FLAG_CONTINUE = 1;
|
||||
static constexpr std::uint32_t SCE_NGS2_WAVEFORM_BLOCKS_FLAG_APPEND = 2;
|
||||
@@ -527,6 +545,12 @@ struct Ngs2CustomVoiceUserFx2Param {
|
||||
};
|
||||
static_assert(sizeof(Ngs2CustomVoiceUserFx2Param) == 24);
|
||||
|
||||
struct Ngs2CustomVoiceGainParam {
|
||||
Ngs2VoiceParamHeader header;
|
||||
float gain[SCE_NGS2_CUSTOM_SUBMIXER_MAX_CHANNELS];
|
||||
};
|
||||
static_assert(sizeof(Ngs2CustomVoiceGainParam) == 156);
|
||||
|
||||
struct Ngs2CustomVoiceFilterParam {
|
||||
Ngs2VoiceParamHeader header;
|
||||
std::uint32_t type;
|
||||
|
||||
@@ -26,6 +26,7 @@ static constexpr std::uint32_t MAX_SAMPLE_RATE = 192000;
|
||||
static constexpr std::uint32_t WAVEFORM_TYPE_PCM_FIRST = 0x10;
|
||||
static constexpr std::uint32_t WAVEFORM_TYPE_PCM_LAST = 0x1b;
|
||||
static constexpr std::uint32_t WAVEFORM_TYPE_VAG = 0x1c;
|
||||
static constexpr std::uint32_t VAG_FRAME_SAMPLES = 28;
|
||||
static constexpr std::uint32_t PCM_BYTES_PER_SAMPLE[] = {1, 1, 2, 2, 3, 3, 4, 4, 4, 4, 8, 8};
|
||||
|
||||
static bool IsPcmType(std::uint32_t type) {
|
||||
@@ -43,6 +44,18 @@ static Ngs2WaveformBlock PcmBlock(std::uint32_t type, std::uint32_t channels, st
|
||||
return block;
|
||||
}
|
||||
|
||||
static Ngs2WaveformBlock VagBlock(std::uint32_t channels, std::uint32_t pos, std::uint32_t count) {
|
||||
const std::uint32_t frameBytes = 16u * channels;
|
||||
const std::uint32_t first = pos / VAG_FRAME_SAMPLES;
|
||||
const std::uint32_t past = (pos + count + VAG_FRAME_SAMPLES - 1u) / VAG_FRAME_SAMPLES;
|
||||
const auto offset = static_cast<std::uint32_t>(static_cast<std::uint64_t>(first) * frameBytes);
|
||||
Ngs2WaveformBlock block{};
|
||||
block.data_offset = offset;
|
||||
block.data_size = static_cast<std::uint32_t>(past * frameBytes - offset);
|
||||
block.num_samples = (past - first) * VAG_FRAME_SAMPLES;
|
||||
return block;
|
||||
}
|
||||
|
||||
void Ngs2Atrac9DecoderDeleter::operator()(void* handle) const {
|
||||
Atrac9ReleaseHandle(handle);
|
||||
}
|
||||
@@ -432,7 +445,10 @@ int APS5_VABI sceNgs2CalcWaveformBlock(const Ngs2WaveformFormat* format, uint32_
|
||||
*block = PcmBlock(type, format->num_channels, sample_pos, num_samples);
|
||||
return SCE_NGS2_OK;
|
||||
}
|
||||
if (type == WAVEFORM_TYPE_VAG) throw std::runtime_error("NGS2: waveform blocks of type " + Ngs2Hex(type) + " are not implemented");
|
||||
if (type == WAVEFORM_TYPE_VAG) {
|
||||
*block = VagBlock(format->num_channels, sample_pos, num_samples);
|
||||
return SCE_NGS2_OK;
|
||||
}
|
||||
if (type != SCE_NGS2_WAVEFORM_TYPE_ATRAC9) return SCE_NGS2_ERROR_UNKNOWN_WAVEFORM_FORMAT;
|
||||
if (format->num_channels == 0 || format->num_channels > NGS2_MAX_CHANNELS || format->sample_rate == 0 || format->sample_rate > MAX_SAMPLE_RATE) {
|
||||
return SCE_NGS2_ERROR_INVALID_WAVEFORM_FORMAT;
|
||||
@@ -450,6 +466,28 @@ int APS5_VABI sceNgs2CalcWaveformBlock(const Ngs2WaveformFormat* format, uint32_
|
||||
return SCE_NGS2_OK;
|
||||
}
|
||||
|
||||
int APS5_VABI sceNgs2GetWaveformFrameInfo(const Ngs2WaveformFormat* format, uint32_t* out_frame_size, uint32_t* out_num_frame_samples, uint32_t* out_units_per_frame, uint32_t* out_num_delay_samples) {
|
||||
if (out_frame_size == nullptr || out_num_frame_samples == nullptr || out_units_per_frame == nullptr || out_num_delay_samples == nullptr) return SCE_NGS2_ERROR_INVALID_OUT_ADDRESS;
|
||||
if (format == nullptr || format->num_channels == 0 || format->num_channels > NGS2_MAX_CHANNELS || format->sample_rate == 0 || format->sample_rate > MAX_SAMPLE_RATE) {
|
||||
return SCE_NGS2_ERROR_INVALID_WAVEFORM_FORMAT;
|
||||
}
|
||||
if (format->waveform_type == SCE_NGS2_WAVEFORM_TYPE_PCM_I16L) {
|
||||
*out_frame_size = format->num_channels * sizeof(std::int16_t);
|
||||
*out_num_frame_samples = 1;
|
||||
*out_units_per_frame = 1;
|
||||
*out_num_delay_samples = 0;
|
||||
return SCE_NGS2_OK;
|
||||
}
|
||||
if (format->waveform_type != SCE_NGS2_WAVEFORM_TYPE_ATRAC9) throw std::runtime_error("NGS2: the frame info of waveform type " + Ngs2Hex(format->waveform_type) + " is not implemented");
|
||||
Atrac9CodecInfo codec{};
|
||||
if (!MatchingCodecInfo(*format, codec)) return SCE_NGS2_ERROR_INVALID_WAVEFORM_FORMAT;
|
||||
*out_frame_size = static_cast<std::uint32_t>(codec.superframeSize);
|
||||
*out_num_frame_samples = static_cast<std::uint32_t>(codec.frameSamples * codec.framesInSuperframe);
|
||||
*out_units_per_frame = static_cast<std::uint32_t>(codec.framesInSuperframe);
|
||||
*out_num_delay_samples = static_cast<std::uint32_t>(codec.frameSamples);
|
||||
return SCE_NGS2_OK;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#pragma GCC visibility pop
|
||||
@@ -12,28 +12,75 @@
|
||||
static constexpr std::uint32_t USER_FX2_FLAG_FIRST_PROCESS = 1;
|
||||
static constexpr std::uint32_t USER_FX2_FLAG_PARAM_CHANGED = 2;
|
||||
|
||||
void Ngs2CheckCustomRack(const Ngs2CustomRackOption& option) {
|
||||
if (option.num_buffers != 1) throw std::runtime_error("NGS2: custom racks with " + std::to_string(option.num_buffers) + " buffers are not implemented");
|
||||
static const char* BuiltInModuleName(std::uint32_t moduleId) {
|
||||
switch (moduleId) {
|
||||
case SCE_NGS2_CUSTOM_MODULE_ID_GAIN: return "Gain";
|
||||
case SCE_NGS2_CUSTOM_MODULE_ID_REVERB: return "Reverb";
|
||||
case SCE_NGS2_CUSTOM_MODULE_ID_PITCH_SHIFT: return "PitchShift";
|
||||
case SCE_NGS2_CUSTOM_MODULE_ID_CONVOLUTION: return "Convolution";
|
||||
default: return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
static std::uint32_t OptionWord(const Ngs2CustomModuleOption& option) {
|
||||
std::uint32_t word = 0;
|
||||
std::memcpy(&word, reinterpret_cast<const std::uint8_t*>(&option) + sizeof(option), sizeof(word));
|
||||
return word;
|
||||
}
|
||||
|
||||
static int CheckBuiltInModule(const Ngs2CustomRackModuleInfo& info) {
|
||||
const auto stateSizeIs = [&info](std::uint32_t size) { return info.state_size == 0 || info.state_size == size; };
|
||||
if (info.module_id == SCE_NGS2_CUSTOM_MODULE_ID_GAIN) {
|
||||
if (!stateSizeIs(0)) return SCE_NGS2_ERROR_INVALID_STATE_SIZE;
|
||||
} else if (info.module_id == SCE_NGS2_CUSTOM_MODULE_ID_REVERB) {
|
||||
if (!stateSizeIs(0)) return SCE_NGS2_ERROR_INVALID_STATE_SIZE;
|
||||
if (info.option != nullptr && info.option->size != SCE_NGS2_CUSTOM_REVERB_OPTION_SIZE) return SCE_NGS2_ERROR_INVALID_OPTION_SIZE;
|
||||
if (info.option != nullptr && OptionWord(*info.option) > 1) return SCE_NGS2_ERROR_INVALID_REVERB_OPTION;
|
||||
} else if (info.module_id == SCE_NGS2_CUSTOM_MODULE_ID_PITCH_SHIFT) {
|
||||
if (!stateSizeIs(SCE_NGS2_CUSTOM_PITCH_SHIFT_STATE_SIZE)) return SCE_NGS2_ERROR_INVALID_STATE_SIZE;
|
||||
if (info.option != nullptr && info.option->size == SCE_NGS2_CUSTOM_PITCH_SHIFT_OPTION_SIZE && OptionWord(*info.option) != 0) {
|
||||
return SCE_NGS2_ERROR_INVALID_PITCH_SHIFT_OPTION;
|
||||
}
|
||||
}
|
||||
return SCE_NGS2_OK;
|
||||
}
|
||||
|
||||
int Ngs2CheckCustomRack(std::uint32_t rackId, const Ngs2CustomRackOption& option, std::uint32_t maxInputs) {
|
||||
if (option.num_buffers == 0 || option.num_buffers > SCE_NGS2_CUSTOM_MAX_BUFFERS || option.num_buffers < maxInputs) {
|
||||
return SCE_NGS2_ERROR_INVALID_NUM_BUFFERS;
|
||||
}
|
||||
if (option.num_modules > SCE_NGS2_CUSTOM_MAX_MODULES || option.rack_option.max_ports > SCE_NGS2_CUSTOM_MAX_PORTS) APS5_INVALID_ARG_EX;
|
||||
for (std::uint32_t m = 0; m < option.num_modules; m++) {
|
||||
const auto& info = option.module[m];
|
||||
if (info.module_id == SCE_NGS2_CUSTOM_MODULE_ID_USER_FX2) {
|
||||
if (info.option == nullptr || info.option->size != sizeof(Ngs2CustomUserFx2ModuleOption)) APS5_INVALID_ARG_EX;
|
||||
if (info.source_buffer_id != 0 || info.dest_buffer_id != 0) APS5_INVALID_ARG_EX;
|
||||
if (reinterpret_cast<const Ngs2CustomUserFx2ModuleOption*>(info.option)->process_handler == nullptr) APS5_INVALID_ARG_EX;
|
||||
} else if (info.module_id == SCE_NGS2_CUSTOM_MODULE_ID_FILTER) {
|
||||
if (info.option != nullptr || info.state_size != 0 || info.state_offset != 0) APS5_INVALID_ARG_EX;
|
||||
if (info.source_buffer_id != 0 || info.extra_buffer_id != 0 || info.dest_buffer_id != 0) APS5_INVALID_ARG_EX;
|
||||
} else if (info.module_id == SCE_NGS2_CUSTOM_MODULE_ID_USER_FX) {
|
||||
if (info.source_buffer_id != 0 || info.dest_buffer_id != 0) APS5_INVALID_ARG_EX;
|
||||
if (info.option != nullptr && info.option->size < sizeof(Ngs2CustomModuleOption)) APS5_INVALID_ARG_EX;
|
||||
} else {
|
||||
} else if (BuiltInModuleName(info.module_id) == nullptr) {
|
||||
throw std::runtime_error("NGS2: custom module id " + Ngs2Hex(info.module_id) + " is not implemented");
|
||||
}
|
||||
if (info.source_buffer_id >= option.num_buffers || info.extra_buffer_id >= option.num_buffers || info.dest_buffer_id >= option.num_buffers) {
|
||||
return SCE_NGS2_ERROR_INVALID_BUFFER_INDEX;
|
||||
}
|
||||
const int result = CheckBuiltInModule(info);
|
||||
if (result != SCE_NGS2_OK) return result;
|
||||
}
|
||||
if (option.num_buffers != 1) throw std::runtime_error("NGS2: custom racks with " + std::to_string(option.num_buffers) + " buffers are not implemented");
|
||||
for (std::uint32_t m = 0; m < option.num_modules; m++) {
|
||||
const auto moduleId = option.module[m].module_id;
|
||||
if (moduleId == SCE_NGS2_CUSTOM_MODULE_ID_GAIN && option.module[m].option != nullptr) throw std::runtime_error("NGS2: an option for the custom Gain module is not implemented");
|
||||
if (moduleId == SCE_NGS2_CUSTOM_MODULE_ID_GAIN && rackId == SCE_NGS2_RACK_ID_CUSTOM_SUBMIXER) continue;
|
||||
if (moduleId == SCE_NGS2_CUSTOM_MODULE_ID_GAIN) throw std::runtime_error("NGS2: the custom Gain module on a custom sampler rack is not implemented");
|
||||
const char* name = BuiltInModuleName(moduleId);
|
||||
if (name != nullptr) throw std::runtime_error(std::string("NGS2: the custom ") + name + " module is not implemented");
|
||||
}
|
||||
for (std::uint32_t p = 0; p < option.rack_option.max_ports; p++) {
|
||||
if (option.port[p].source_buffer_id != 0) APS5_INVALID_ARG_EX;
|
||||
}
|
||||
return SCE_NGS2_OK;
|
||||
}
|
||||
|
||||
static Ngs2UserFx2SetupContext UserFxContext(Ngs2Rack& rack, std::size_t module, std::uint32_t voiceIndex) {
|
||||
@@ -49,6 +96,7 @@ void Ngs2SetupUserFx(Ngs2Rack& rack, const Ngs2CustomRackOption& option) {
|
||||
for (auto& voice : rack.voices) {
|
||||
voice.userFx.resize(option.num_modules);
|
||||
voice.customUserFx.resize(option.num_modules);
|
||||
voice.customGain.assign(option.num_modules, {});
|
||||
}
|
||||
for (std::uint32_t m = 0; m < option.num_modules; m++) {
|
||||
rack.customModuleIds[m] = option.module[m].module_id;
|
||||
@@ -116,6 +164,26 @@ static void SetCustomUserFxParam(Ngs2Voice& voice, std::uint32_t index, const Ng
|
||||
fx.flags = 1;
|
||||
}
|
||||
|
||||
static void SetGainParam(Ngs2Voice& voice, std::uint32_t index, const Ngs2CustomVoiceGainParam& param) {
|
||||
if (index >= voice.customGain.size() || voice.rack->customModuleIds[index] != SCE_NGS2_CUSTOM_MODULE_ID_GAIN) APS5_INVALID_ARG_EX;
|
||||
for (const float gain : param.gain) {
|
||||
if (!(gain >= -32.0f && gain <= 32.0f)) throw std::runtime_error("NGS2: a custom Gain level outside -32 to 32 is not implemented");
|
||||
}
|
||||
std::copy(std::begin(param.gain), std::end(param.gain), voice.customGain[index].target.begin());
|
||||
}
|
||||
|
||||
static void ProcessGain(Ngs2Voice& voice, Ngs2VoiceCustomGain& gain, const std::vector<float*>& channels, std::uint32_t grain) {
|
||||
if (voice.hasSamples) {
|
||||
for (std::uint32_t c = 0; c < voice.channels; c++) {
|
||||
const float from = gain.current[c];
|
||||
const float step = (gain.target[c] - from) / static_cast<float>(grain);
|
||||
for (std::uint32_t i = 0; i < grain; i++) channels[c][i] *= from + step * static_cast<float>(i + 1);
|
||||
}
|
||||
voice.hasSamples = std::any_of(voice.samples.begin(), voice.samples.end(), [](float sample) { return sample != 0.0f; });
|
||||
}
|
||||
gain.current = gain.target;
|
||||
}
|
||||
|
||||
void Ngs2ApplyCustomParam(Ngs2Voice& voice, const Ngs2VoiceParamHeader& param) {
|
||||
const auto rackId = voice.rack->rackId;
|
||||
if (param.id == SCE_NGS2_CUSTOM_SUBMIXER_VOICE_PARAM_SETUP) {
|
||||
@@ -148,6 +216,11 @@ void Ngs2ApplyCustomParam(Ngs2Voice& voice, const Ngs2VoiceParamHeader& param) {
|
||||
Ngs2SetFilter(voice, filter);
|
||||
return;
|
||||
}
|
||||
if ((param.id & ~0x1fu) == SCE_NGS2_CUSTOM_VOICE_PARAM_GAIN) {
|
||||
if (rackId != SCE_NGS2_RACK_ID_CUSTOM_SUBMIXER) throw std::invalid_argument("NGS2: voice param " + Ngs2Hex(param.id) + " belongs to another rack");
|
||||
SetGainParam(voice, param.id & 0x1f, ParamAs<Ngs2CustomVoiceGainParam>(param));
|
||||
return;
|
||||
}
|
||||
if ((param.id & ~0x1fu) == SCE_NGS2_CUSTOM_VOICE_PARAM_USER_FX2) {
|
||||
if (rackId != SCE_NGS2_RACK_ID_CUSTOM_SAMPLER && rackId != SCE_NGS2_RACK_ID_CUSTOM_SUBMIXER) {
|
||||
throw std::invalid_argument("NGS2: voice param " + Ngs2Hex(param.id) + " belongs to another rack");
|
||||
@@ -169,7 +242,9 @@ void Ngs2ProcessUserFx(Ngs2Voice& voice, std::uint32_t grain, std::uint32_t samp
|
||||
std::vector<float*> channels(voice.channels);
|
||||
for (std::uint32_t c = 0; c < voice.channels; c++) channels[c] = voice.samples.data() + static_cast<std::size_t>(c) * grain;
|
||||
for (std::size_t m = 0; m < voice.rack->customModuleIds.size(); m++) {
|
||||
if (voice.rack->customModuleIds[m] == SCE_NGS2_CUSTOM_MODULE_ID_USER_FX2) {
|
||||
if (voice.rack->customModuleIds[m] == SCE_NGS2_CUSTOM_MODULE_ID_GAIN) {
|
||||
ProcessGain(voice, voice.customGain[m], channels, grain);
|
||||
} else if (voice.rack->customModuleIds[m] == SCE_NGS2_CUSTOM_MODULE_ID_USER_FX2) {
|
||||
if (!voice.hasSamples) continue;
|
||||
auto& fx = voice.userFx[m];
|
||||
const auto& module = voice.rack->userFx[m];
|
||||
|
||||
@@ -108,6 +108,11 @@ struct Ngs2VoiceCustomUserFx {
|
||||
std::uint32_t flags = 0;
|
||||
};
|
||||
|
||||
struct Ngs2VoiceCustomGain {
|
||||
std::array<float, SCE_NGS2_CUSTOM_SUBMIXER_MAX_CHANNELS> current{};
|
||||
std::array<float, SCE_NGS2_CUSTOM_SUBMIXER_MAX_CHANNELS> target{};
|
||||
};
|
||||
|
||||
struct Ngs2Voice {
|
||||
Ngs2Rack* rack = nullptr;
|
||||
Ngs2PlayState state = Ngs2PlayState::Empty;
|
||||
@@ -136,6 +141,7 @@ struct Ngs2Voice {
|
||||
float lfeLevel = 1.0f;
|
||||
std::vector<Ngs2UserFx2> userFx;
|
||||
std::vector<Ngs2VoiceCustomUserFx> customUserFx;
|
||||
std::vector<Ngs2VoiceCustomGain> customGain;
|
||||
Ngs2UserFxProcessHandler userFxHandler = nullptr;
|
||||
std::array<std::uintptr_t, 3> userFxData{};
|
||||
std::uint32_t userFxFlags = 0;
|
||||
@@ -229,7 +235,7 @@ std::size_t Ngs2Atrac9BlockBytes(const Ngs2Voice& voice, const Ngs2WaveformBlock
|
||||
void Ngs2RestartAtrac9(Ngs2Voice& voice);
|
||||
void Ngs2ConsumeAtrac9(Ngs2Voice& voice, std::uint32_t grain, std::uint32_t systemRate);
|
||||
bool Ngs2FinishBlock(Ngs2Voice& voice);
|
||||
void Ngs2CheckCustomRack(const Ngs2CustomRackOption& option);
|
||||
int Ngs2CheckCustomRack(std::uint32_t rackId, const Ngs2CustomRackOption& option, std::uint32_t maxInputs);
|
||||
void Ngs2SetupUserFx(Ngs2Rack& rack, const Ngs2CustomRackOption& option);
|
||||
void Ngs2CleanupUserFx(Ngs2Rack& rack);
|
||||
void Ngs2ApplyCustomParam(Ngs2Voice& voice, const Ngs2VoiceParamHeader& param);
|
||||
|
||||
@@ -87,22 +87,35 @@ static std::uint32_t RackMaxChannels(std::uint32_t rackId, const RackOptions& op
|
||||
return NGS2_MAX_CHANNELS;
|
||||
}
|
||||
|
||||
static RackOptions CheckedRackOption(std::uint32_t rackId, const Ngs2RackOption* option) {
|
||||
static int CheckedRackOption(std::uint32_t rackId, const Ngs2RackOption* option, RackOptions& options) {
|
||||
const auto size = RackOptionSize(rackId);
|
||||
if (option == nullptr) return DefaultRackOption(rackId);
|
||||
if (option == nullptr) {
|
||||
options = DefaultRackOption(rackId);
|
||||
return SCE_NGS2_OK;
|
||||
}
|
||||
if (option->size != size) throw std::invalid_argument("NGS2: unexpected rack option size " + std::to_string(option->size));
|
||||
RackOptions options{};
|
||||
options = {};
|
||||
std::memcpy(&options, option, size);
|
||||
const auto maxChannels = RackMaxChannels(rackId, options);
|
||||
if (options.common.max_voices == 0 || maxChannels == 0 || maxChannels > NGS2_MAX_CHANNELS) {
|
||||
if (rackId == SCE_NGS2_RACK_ID_CUSTOM_SUBMIXER && maxChannels > SCE_NGS2_CUSTOM_SUBMIXER_MAX_CHANNELS) return SCE_NGS2_ERROR_INVALID_NUM_CHANNELS;
|
||||
if (rackId == SCE_NGS2_RACK_ID_CUSTOM_SUBMIXER && (options.customSubmixer.max_inputs == 0 || options.customSubmixer.max_inputs > SCE_NGS2_CUSTOM_SUBMIXER_MAX_INPUTS)) {
|
||||
throw std::runtime_error("NGS2: custom submixer racks with " + std::to_string(options.customSubmixer.max_inputs) + " inputs are not implemented");
|
||||
}
|
||||
if (options.common.max_voices == 0 || maxChannels == 0) throw std::invalid_argument("NGS2: invalid rack voice or channel count");
|
||||
int result = SCE_NGS2_OK;
|
||||
if (rackId == SCE_NGS2_RACK_ID_CUSTOM_SAMPLER) result = Ngs2CheckCustomRack(rackId, options.customSampler.custom_rack_option, 0);
|
||||
if (rackId == SCE_NGS2_RACK_ID_CUSTOM_SUBMIXER) result = Ngs2CheckCustomRack(rackId, options.customSubmixer.custom_rack_option, options.customSubmixer.max_inputs);
|
||||
if (result != SCE_NGS2_OK) return result;
|
||||
if (maxChannels > NGS2_MAX_CHANNELS) {
|
||||
if (rackId == SCE_NGS2_RACK_ID_CUSTOM_SUBMIXER) {
|
||||
throw std::runtime_error("NGS2: custom submixer racks with " + std::to_string(maxChannels) + " channels are not implemented");
|
||||
}
|
||||
throw std::invalid_argument("NGS2: invalid rack voice or channel count");
|
||||
}
|
||||
if (rackId == SCE_NGS2_RACK_ID_CUSTOM_SAMPLER) Ngs2CheckCustomRack(options.customSampler.custom_rack_option);
|
||||
if (rackId == SCE_NGS2_RACK_ID_CUSTOM_SUBMIXER) Ngs2CheckCustomRack(options.customSubmixer.custom_rack_option);
|
||||
if (rackId == SCE_NGS2_RACK_ID_REVERB && options.reverb.reverb_size != 1) {
|
||||
throw std::runtime_error("NGS2: reverb rack size " + std::to_string(options.reverb.reverb_size) + " is not implemented");
|
||||
}
|
||||
return options;
|
||||
return SCE_NGS2_OK;
|
||||
}
|
||||
|
||||
static int CreateRack(Ngs2Handle systemHandle, std::uint32_t rackId, const RackOptions& options, const Ngs2ContextBufferInfo& bufferInfo,
|
||||
@@ -165,7 +178,9 @@ extern "C" {
|
||||
|
||||
int APS5_VABI sceNgs2RackQueryBufferSize(uint32_t rack_id, const Ngs2RackOption* option, Ngs2ContextBufferInfo* buffer_info) {
|
||||
if (buffer_info == nullptr) return SCE_NGS2_ERROR_INVALID_OUT_ADDRESS;
|
||||
CheckedRackOption(rack_id, option);
|
||||
RackOptions options{};
|
||||
const int result = CheckedRackOption(rack_id, option, options);
|
||||
if (result != SCE_NGS2_OK) throw std::invalid_argument("NGS2: invalid rack option, rejected at creation with " + Ngs2Hex(static_cast<std::uint32_t>(result)));
|
||||
*buffer_info = {};
|
||||
buffer_info->host_buffer_size = sizeof(Ngs2Rack);
|
||||
return SCE_NGS2_OK;
|
||||
@@ -173,16 +188,20 @@ int APS5_VABI sceNgs2RackQueryBufferSize(uint32_t rack_id, const Ngs2RackOption*
|
||||
|
||||
int APS5_VABI sceNgs2RackCreate(uintptr_t system_handle, uint32_t rack_id, const Ngs2RackOption* option, const Ngs2ContextBufferInfo* buffer_info, uintptr_t* handle) {
|
||||
if (handle == nullptr) return SCE_NGS2_ERROR_INVALID_OUT_ADDRESS;
|
||||
const auto options = CheckedRackOption(rack_id, option);
|
||||
if (buffer_info == nullptr) APS5_INVALID_ARG_EX;
|
||||
RackOptions options{};
|
||||
const int result = CheckedRackOption(rack_id, option, options);
|
||||
if (result != SCE_NGS2_OK) return result;
|
||||
const Ngs2Lock lock;
|
||||
return CreateRack(system_handle, rack_id, options, *buffer_info, {}, handle);
|
||||
}
|
||||
|
||||
int APS5_VABI sceNgs2RackCreateWithAllocator(uintptr_t system_handle, uint32_t rack_id, const Ngs2RackOption* option, const Ngs2BufferAllocator* allocator, uintptr_t* handle) {
|
||||
if (handle == nullptr) return SCE_NGS2_ERROR_INVALID_OUT_ADDRESS;
|
||||
const auto options = CheckedRackOption(rack_id, option);
|
||||
if (allocator == nullptr || allocator->alloc_handler == nullptr || allocator->free_handler == nullptr) APS5_INVALID_ARG_EX;
|
||||
RackOptions options{};
|
||||
const int checked = CheckedRackOption(rack_id, option, options);
|
||||
if (checked != SCE_NGS2_OK) return checked;
|
||||
const Ngs2Lock lock;
|
||||
if (Ngs2FindSystem(system_handle) == nullptr) return SCE_NGS2_ERROR_INVALID_SYSTEM_HANDLE;
|
||||
Ngs2ContextBufferInfo bufferInfo{};
|
||||
|
||||
@@ -195,6 +195,45 @@ static void TestCalcBlock() {
|
||||
Require(sceNgs2CalcWaveformBlock(&silent, 0, 1, &block) == SCE_NGS2_ERROR_INVALID_WAVEFORM_FORMAT);
|
||||
}
|
||||
|
||||
static void TestFrameInfo() {
|
||||
const Ngs2WaveformFormat supported[] = {
|
||||
{SCE_NGS2_WAVEFORM_TYPE_ATRAC9, 1, 48000, Config, 0, 0},
|
||||
{SCE_NGS2_WAVEFORM_TYPE_ATRAC9, 1, 48000, Config, 7, 9},
|
||||
};
|
||||
const Ngs2WaveformFormat rejected[] = {
|
||||
{SCE_NGS2_WAVEFORM_TYPE_ATRAC9, 2, 48000, Config, 0, 0},
|
||||
{SCE_NGS2_WAVEFORM_TYPE_ATRAC9, 0, 48000, Config, 0, 0},
|
||||
{SCE_NGS2_WAVEFORM_TYPE_ATRAC9, 9, 48000, Config, 0, 0},
|
||||
{SCE_NGS2_WAVEFORM_TYPE_ATRAC9, 1, 44100, Config, 0, 0},
|
||||
{SCE_NGS2_WAVEFORM_TYPE_ATRAC9, 1, 0, Config, 0, 0},
|
||||
{SCE_NGS2_WAVEFORM_TYPE_ATRAC9, 1, 192001, Config, 0, 0},
|
||||
{SCE_NGS2_WAVEFORM_TYPE_ATRAC9, 1, 48000, 0, 0, 0},
|
||||
};
|
||||
for (const auto& format : supported) {
|
||||
Ngs2WaveformBlock block{};
|
||||
Require(sceNgs2CalcWaveformBlock(&format, 0, SuperframeSamples, &block) == SCE_NGS2_OK && block.data_size == SuperframeBytes);
|
||||
std::uint32_t values[4] = {0xa1, 0xa2, 0xa3, 0xa4};
|
||||
Require(sceNgs2GetWaveformFrameInfo(&format, &values[0], &values[1], &values[2], &values[3]) == SCE_NGS2_OK);
|
||||
Require(values[0] == SuperframeBytes && values[1] == SuperframeSamples && values[2] == 4 && values[3] == SuperframeSamples / 4);
|
||||
}
|
||||
for (const auto& format : rejected) {
|
||||
Ngs2WaveformBlock block{};
|
||||
const int calc = sceNgs2CalcWaveformBlock(&format, 0, SuperframeSamples, &block);
|
||||
Require(calc == SCE_NGS2_ERROR_INVALID_WAVEFORM_FORMAT);
|
||||
std::uint32_t values[4] = {0xa1, 0xa2, 0xa3, 0xa4};
|
||||
Require(sceNgs2GetWaveformFrameInfo(&format, &values[0], &values[1], &values[2], &values[3]) == calc);
|
||||
Require(values[0] == 0xa1 && values[1] == 0xa2 && values[2] == 0xa3 && values[3] == 0xa4);
|
||||
}
|
||||
std::uint32_t values[4] = {0xa1, 0xa2, 0xa3, 0xa4};
|
||||
Require(sceNgs2GetWaveformFrameInfo(nullptr, &values[0], &values[1], &values[2], &values[3]) == SCE_NGS2_ERROR_INVALID_WAVEFORM_FORMAT);
|
||||
Require(sceNgs2GetWaveformFrameInfo(&supported[0], nullptr, &values[1], &values[2], &values[3]) == SCE_NGS2_ERROR_INVALID_OUT_ADDRESS);
|
||||
Require(sceNgs2GetWaveformFrameInfo(&supported[0], &values[0], nullptr, &values[2], &values[3]) == SCE_NGS2_ERROR_INVALID_OUT_ADDRESS);
|
||||
Require(sceNgs2GetWaveformFrameInfo(&supported[0], &values[0], &values[1], nullptr, &values[3]) == SCE_NGS2_ERROR_INVALID_OUT_ADDRESS);
|
||||
Require(sceNgs2GetWaveformFrameInfo(&supported[0], &values[0], &values[1], &values[2], nullptr) == SCE_NGS2_ERROR_INVALID_OUT_ADDRESS);
|
||||
Require(sceNgs2GetWaveformFrameInfo(nullptr, nullptr, nullptr, nullptr, nullptr) == SCE_NGS2_ERROR_INVALID_OUT_ADDRESS);
|
||||
Require(values[0] == 0xa1 && values[1] == 0xa2 && values[2] == 0xa3 && values[3] == 0xa4);
|
||||
}
|
||||
|
||||
static void RequirePcmBlock(std::uint32_t type, std::uint32_t channels, std::uint32_t pos, std::uint32_t count, std::uint64_t offset, std::uint64_t size) {
|
||||
const Ngs2WaveformFormat format{type, channels, 48000, 0, 0, 0};
|
||||
Ngs2WaveformBlock block;
|
||||
@@ -229,6 +268,26 @@ static void TestCalcPcmBlock() {
|
||||
Require(sceNgs2CalcWaveformBlock(nullptr, 0, 1, &block) == SCE_NGS2_ERROR_INVALID_WAVEFORM_FORMAT && block.data_size == 0 && block.num_samples == 0);
|
||||
}
|
||||
|
||||
static void RequireVagBlock(std::uint32_t channels, std::uint32_t pos, std::uint32_t count, std::uint64_t offset, std::uint64_t size, std::uint32_t samples) {
|
||||
const Ngs2WaveformFormat format{0x1c, channels, 48000, 0, 0, 0};
|
||||
Ngs2WaveformBlock block;
|
||||
std::memset(&block, 0xab, sizeof(block));
|
||||
Require(sceNgs2CalcWaveformBlock(&format, pos, count, &block) == SCE_NGS2_OK);
|
||||
Require(block.data_offset == offset && block.data_size == size && block.num_samples == samples);
|
||||
Require(block.num_repeats == 0 && block.num_skip_samples == 0 && block.reserved == 0 && block.user_data == 0);
|
||||
}
|
||||
|
||||
static void TestCalcVagBlock() {
|
||||
RequireVagBlock(1, 0, 28, 0, 16, 28);
|
||||
RequireVagBlock(1, 27, 2, 0, 32, 56);
|
||||
RequireVagBlock(1, 28, 28, 16, 16, 28);
|
||||
RequireVagBlock(2, 30, 1, 32, 32, 28);
|
||||
RequireVagBlock(6, 56, 57, 192, 288, 84);
|
||||
RequireVagBlock(1, 0, 0, 0, 0, 0);
|
||||
RequireVagBlock(1, 5, 0, 0, 16, 28);
|
||||
RequireVagBlock(0, 100, 50, 0, 0, 84);
|
||||
}
|
||||
|
||||
static void Set32(std::vector<std::uint8_t>& bytes, std::size_t offset, std::uint32_t value) {
|
||||
for (int i = 0; i < 4; ++i) bytes[offset + i] = static_cast<std::uint8_t>(value >> (i * 8));
|
||||
}
|
||||
@@ -538,7 +597,9 @@ int main() {
|
||||
TestParseLoops();
|
||||
TestMalformedLoops();
|
||||
TestCalcBlock();
|
||||
TestFrameInfo();
|
||||
TestCalcPcmBlock();
|
||||
TestCalcVagBlock();
|
||||
TestCorruptSuperframeAtPageEnd();
|
||||
TestStreamPartitions();
|
||||
TestRefill(reference);
|
||||
|
||||
@@ -356,6 +356,153 @@ static void TestCustomFilter() {
|
||||
}
|
||||
|
||||
|
||||
struct ModuleOptionWords {
|
||||
std::uint32_t size;
|
||||
std::uint32_t words[15];
|
||||
};
|
||||
|
||||
static int allocCalls = 0;
|
||||
|
||||
static std::int32_t APS5_VABI CountAlloc(Ngs2ContextBufferInfo*) {
|
||||
allocCalls++;
|
||||
return SCE_NGS2_OK;
|
||||
}
|
||||
|
||||
static std::int32_t APS5_VABI CountFree(Ngs2ContextBufferInfo*) {
|
||||
return SCE_NGS2_OK;
|
||||
}
|
||||
|
||||
static Ngs2CustomSubmixerRackOption BuiltInRackOption(const Ngs2CustomUserFx2ModuleOption& userFx2, std::uint32_t moduleId,
|
||||
const ModuleOptionWords* moduleOption, std::uint32_t stateSize) {
|
||||
auto option = RackOption(&userFx2, 1);
|
||||
auto& module = option.custom_rack_option.module[0];
|
||||
module.module_id = moduleId;
|
||||
module.option = reinterpret_cast<const Ngs2CustomModuleOption*>(moduleOption);
|
||||
module.state_size = stateSize;
|
||||
return option;
|
||||
}
|
||||
|
||||
static void TestCustomRackChecks() {
|
||||
calls = {};
|
||||
const auto system = CreateSystem();
|
||||
const auto userFx2 = Module(Gain);
|
||||
const auto good = RackOption(&userFx2, 1);
|
||||
Ngs2ContextBufferInfo query{};
|
||||
Require(sceNgs2RackQueryBufferSize(SCE_NGS2_RACK_ID_CUSTOM_SUBMIXER, &good.custom_rack_option.rack_option, &query) == SCE_NGS2_OK);
|
||||
const auto info = Buffer(query);
|
||||
const auto create = [&](const Ngs2CustomSubmixerRackOption& option) {
|
||||
uintptr_t rack = 0;
|
||||
const int result = sceNgs2RackCreate(system, SCE_NGS2_RACK_ID_CUSTOM_SUBMIXER, &option.custom_rack_option.rack_option, &info, &rack);
|
||||
Require(rack == 0);
|
||||
return result;
|
||||
};
|
||||
|
||||
auto option = good;
|
||||
option.custom_rack_option.num_buffers = 0;
|
||||
Require(create(option) == SCE_NGS2_ERROR_INVALID_NUM_BUFFERS);
|
||||
Require(CreateThrows<std::invalid_argument>(option));
|
||||
option.custom_rack_option.num_buffers = SCE_NGS2_CUSTOM_MAX_BUFFERS + 1;
|
||||
Require(create(option) == SCE_NGS2_ERROR_INVALID_NUM_BUFFERS);
|
||||
option = good;
|
||||
option.max_inputs = 2;
|
||||
Require(create(option) == SCE_NGS2_ERROR_INVALID_NUM_BUFFERS);
|
||||
option.custom_rack_option.num_buffers = 2;
|
||||
Require(CreateThrows<std::runtime_error>(option));
|
||||
option.custom_rack_option.num_buffers = SCE_NGS2_CUSTOM_MAX_BUFFERS;
|
||||
option.custom_rack_option.module[0].dest_buffer_id = SCE_NGS2_CUSTOM_MAX_BUFFERS - 1;
|
||||
Require(CreateThrows<std::runtime_error>(option));
|
||||
option.custom_rack_option.module[0].dest_buffer_id = SCE_NGS2_CUSTOM_MAX_BUFFERS;
|
||||
Require(create(option) == SCE_NGS2_ERROR_INVALID_BUFFER_INDEX);
|
||||
option = good;
|
||||
option.max_inputs = 0;
|
||||
Require(CreateThrows<std::runtime_error>(option));
|
||||
option.max_inputs = SCE_NGS2_CUSTOM_SUBMIXER_MAX_INPUTS + 1;
|
||||
Require(CreateThrows<std::runtime_error>(option));
|
||||
|
||||
option = good;
|
||||
option.custom_rack_option.module[0].source_buffer_id = 1;
|
||||
Require(create(option) == SCE_NGS2_ERROR_INVALID_BUFFER_INDEX);
|
||||
option = good;
|
||||
option.custom_rack_option.module[0].extra_buffer_id = 1;
|
||||
Require(create(option) == SCE_NGS2_ERROR_INVALID_BUFFER_INDEX);
|
||||
|
||||
option = good;
|
||||
option.max_channels = SCE_NGS2_CUSTOM_SUBMIXER_MAX_CHANNELS + 1;
|
||||
Require(create(option) == SCE_NGS2_ERROR_INVALID_NUM_CHANNELS);
|
||||
option.max_channels = 16;
|
||||
Require(CreateThrows<std::runtime_error>(option));
|
||||
option.max_channels = SCE_NGS2_CUSTOM_SUBMIXER_MAX_CHANNELS;
|
||||
Require(CreateThrows<std::runtime_error>(option));
|
||||
|
||||
Require(!CreateThrows<std::runtime_error>(BuiltInRackOption(userFx2, SCE_NGS2_CUSTOM_MODULE_ID_GAIN, nullptr, 0)));
|
||||
Require(create(BuiltInRackOption(userFx2, SCE_NGS2_CUSTOM_MODULE_ID_GAIN, nullptr, 4)) == SCE_NGS2_ERROR_INVALID_STATE_SIZE);
|
||||
const ModuleOptionWords gainOption{sizeof(Ngs2CustomModuleOption), {}};
|
||||
Require(CreateThrows<std::runtime_error>(BuiltInRackOption(userFx2, SCE_NGS2_CUSTOM_MODULE_ID_GAIN, &gainOption, 0)));
|
||||
|
||||
const ModuleOptionWords reverb{SCE_NGS2_CUSTOM_REVERB_OPTION_SIZE, {1}};
|
||||
const ModuleOptionWords reverbOff{SCE_NGS2_CUSTOM_REVERB_OPTION_SIZE, {0}};
|
||||
const ModuleOptionWords reverbSize{16, {1}};
|
||||
const ModuleOptionWords reverbWord{SCE_NGS2_CUSTOM_REVERB_OPTION_SIZE, {2}};
|
||||
Require(CreateThrows<std::runtime_error>(BuiltInRackOption(userFx2, SCE_NGS2_CUSTOM_MODULE_ID_REVERB, &reverb, 0)));
|
||||
Require(CreateThrows<std::runtime_error>(BuiltInRackOption(userFx2, SCE_NGS2_CUSTOM_MODULE_ID_REVERB, &reverbOff, 0)));
|
||||
Require(create(BuiltInRackOption(userFx2, SCE_NGS2_CUSTOM_MODULE_ID_REVERB, &reverbSize, 0)) == SCE_NGS2_ERROR_INVALID_OPTION_SIZE);
|
||||
Require(create(BuiltInRackOption(userFx2, SCE_NGS2_CUSTOM_MODULE_ID_REVERB, &reverbWord, 0)) == SCE_NGS2_ERROR_INVALID_REVERB_OPTION);
|
||||
Require(create(BuiltInRackOption(userFx2, SCE_NGS2_CUSTOM_MODULE_ID_REVERB, &reverb, 4)) == SCE_NGS2_ERROR_INVALID_STATE_SIZE);
|
||||
|
||||
const ModuleOptionWords pitchShift{SCE_NGS2_CUSTOM_PITCH_SHIFT_OPTION_SIZE, {0}};
|
||||
const ModuleOptionWords pitchShiftWord{SCE_NGS2_CUSTOM_PITCH_SHIFT_OPTION_SIZE, {1}};
|
||||
const auto pitchShiftState = SCE_NGS2_CUSTOM_PITCH_SHIFT_STATE_SIZE;
|
||||
Require(CreateThrows<std::runtime_error>(BuiltInRackOption(userFx2, SCE_NGS2_CUSTOM_MODULE_ID_PITCH_SHIFT, &pitchShift, pitchShiftState)));
|
||||
Require(CreateThrows<std::runtime_error>(BuiltInRackOption(userFx2, SCE_NGS2_CUSTOM_MODULE_ID_PITCH_SHIFT, &pitchShift, 0)));
|
||||
Require(create(BuiltInRackOption(userFx2, SCE_NGS2_CUSTOM_MODULE_ID_PITCH_SHIFT, &pitchShift, 4)) == SCE_NGS2_ERROR_INVALID_STATE_SIZE);
|
||||
Require(create(BuiltInRackOption(userFx2, SCE_NGS2_CUSTOM_MODULE_ID_PITCH_SHIFT, &pitchShiftWord, pitchShiftState)) == SCE_NGS2_ERROR_INVALID_PITCH_SHIFT_OPTION);
|
||||
|
||||
const ModuleOptionWords convolution{64, {}};
|
||||
Require(CreateThrows<std::runtime_error>(BuiltInRackOption(userFx2, SCE_NGS2_CUSTOM_MODULE_ID_CONVOLUTION, &convolution, 64)));
|
||||
option = BuiltInRackOption(userFx2, SCE_NGS2_CUSTOM_MODULE_ID_CONVOLUTION, &convolution, 64);
|
||||
option.custom_rack_option.module[0].dest_buffer_id = 1;
|
||||
Require(create(option) == SCE_NGS2_ERROR_INVALID_BUFFER_INDEX);
|
||||
|
||||
option = BuiltInRackOption(userFx2, SCE_NGS2_CUSTOM_MODULE_ID_GAIN, nullptr, 0);
|
||||
option.custom_rack_option.num_modules = 2;
|
||||
option.custom_rack_option.module[1] = good.custom_rack_option.module[0];
|
||||
option.custom_rack_option.module[1].dest_buffer_id = 1;
|
||||
Require(create(option) == SCE_NGS2_ERROR_INVALID_BUFFER_INDEX);
|
||||
Require(CreateThrows<std::runtime_error>(BuiltInRackOption(userFx2, 0x19, nullptr, 0)));
|
||||
|
||||
option = good;
|
||||
option.custom_rack_option.num_buffers = 0;
|
||||
bool rejected = false;
|
||||
uintptr_t rack = 0;
|
||||
try {
|
||||
sceNgs2RackCreate(system, SCE_NGS2_RACK_ID_CUSTOM_SUBMIXER, &option.custom_rack_option.rack_option, nullptr, &rack);
|
||||
} catch (const std::invalid_argument&) {
|
||||
rejected = true;
|
||||
}
|
||||
Require(rejected);
|
||||
const Ngs2BufferAllocator allocator{CountAlloc, CountFree, 0};
|
||||
Require(sceNgs2RackCreateWithAllocator(system, SCE_NGS2_RACK_ID_CUSTOM_SUBMIXER, &option.custom_rack_option.rack_option, &allocator, &rack) == SCE_NGS2_ERROR_INVALID_NUM_BUFFERS);
|
||||
Require(rack == 0 && allocCalls == 0 && calls.setupVoices.empty());
|
||||
|
||||
Ngs2CustomSamplerRackOption sampler{};
|
||||
sampler.custom_rack_option.rack_option.size = sizeof(sampler);
|
||||
sampler.custom_rack_option.rack_option.max_grain_samples = 512;
|
||||
sampler.custom_rack_option.rack_option.max_voices = 1;
|
||||
sampler.custom_rack_option.num_modules = 1;
|
||||
sampler.custom_rack_option.module[0].module_id = SCE_NGS2_CUSTOM_MODULE_ID_FILTER;
|
||||
sampler.max_channel_works = 1;
|
||||
Require(sceNgs2RackCreate(system, SCE_NGS2_RACK_ID_CUSTOM_SAMPLER, &sampler.custom_rack_option.rack_option, &info, &rack) == SCE_NGS2_ERROR_INVALID_NUM_BUFFERS);
|
||||
sampler.custom_rack_option.num_buffers = 1;
|
||||
sampler.custom_rack_option.module[0].extra_buffer_id = 1;
|
||||
Require(sceNgs2RackCreate(system, SCE_NGS2_RACK_ID_CUSTOM_SAMPLER, &sampler.custom_rack_option.rack_option, &info, &rack) == SCE_NGS2_ERROR_INVALID_BUFFER_INDEX);
|
||||
Require(rack == 0);
|
||||
sampler.custom_rack_option.module[0].extra_buffer_id = 0;
|
||||
Require(sceNgs2RackCreate(system, SCE_NGS2_RACK_ID_CUSTOM_SAMPLER, &sampler.custom_rack_option.rack_option, &info, &rack) == SCE_NGS2_OK);
|
||||
sampler.custom_rack_option.module[0].module_id = SCE_NGS2_CUSTOM_MODULE_ID_GAIN;
|
||||
Require(CreateSamplerThrows<std::runtime_error>(sampler));
|
||||
Require(sceNgs2SystemDestroy(system, nullptr) == SCE_NGS2_OK);
|
||||
}
|
||||
|
||||
struct LegacyUserFxState {
|
||||
std::uint32_t calls = 0;
|
||||
std::uint32_t flags = 0;
|
||||
@@ -467,11 +614,62 @@ static void TestCustomLegacyUserFx() {
|
||||
Require(sceNgs2SystemDestroy(system, nullptr) == SCE_NGS2_OK);
|
||||
}
|
||||
|
||||
static void TestCustomGain() {
|
||||
const auto system = CreateSystem();
|
||||
const auto master = Mastering(system, 2);
|
||||
const auto userFx2 = Module(Gain);
|
||||
const auto rack = CustomRack(system, BuiltInRackOption(userFx2, SCE_NGS2_CUSTOM_MODULE_ID_GAIN, nullptr, 0));
|
||||
const auto custom = Voice(rack);
|
||||
Control(custom, SCE_NGS2_CUSTOM_SUBMIXER_VOICE_PARAM_SETUP, Ngs2CustomSubmixerVoiceSetupParam{{}, 2, 2, 0, 0});
|
||||
Patch(custom, master);
|
||||
Event(custom, SCE_NGS2_VOICE_EVENT_PLAY);
|
||||
std::vector<std::int16_t> pcm(Grain * 2 * 8, 16384);
|
||||
const auto sampler = Sampler(system, pcm);
|
||||
Patch(sampler, custom);
|
||||
Event(sampler, SCE_NGS2_VOICE_EVENT_PLAY);
|
||||
|
||||
auto out = Render(system);
|
||||
for (std::uint32_t i = 0; i < Grain; i++) Require(out[i * 2] == 0.0f && out[i * 2 + 1] == 0.0f);
|
||||
|
||||
Ngs2CustomVoiceGainParam gain{};
|
||||
gain.gain[0] = 2.0f;
|
||||
gain.gain[1] = -0.5f;
|
||||
Control(custom, SCE_NGS2_CUSTOM_VOICE_PARAM_GAIN | 0, gain);
|
||||
out = Render(system);
|
||||
for (std::uint32_t i = 0; i < Grain; i++) {
|
||||
Require(out[i * 2] == 0.5f * 2.0f * static_cast<float>(i + 1) / Grain);
|
||||
Require(out[i * 2 + 1] == 0.5f * -0.5f * static_cast<float>(i + 1) / Grain);
|
||||
}
|
||||
out = Render(system);
|
||||
for (std::uint32_t i = 0; i < Grain; i++) Require(out[i * 2] == 1.0f && out[i * 2 + 1] == -0.25f);
|
||||
|
||||
gain.gain[0] = 1.0f;
|
||||
Control(custom, SCE_NGS2_CUSTOM_VOICE_PARAM_GAIN | 0, gain);
|
||||
out = Render(system);
|
||||
for (std::uint32_t i = 0; i < Grain; i++) Require(out[i * 2] == 0.5f * (2.0f - static_cast<float>(i + 1) / Grain));
|
||||
|
||||
auto outside = gain;
|
||||
outside.gain[2] = 33.0f;
|
||||
Require(ControlThrows<std::runtime_error>(custom, SCE_NGS2_CUSTOM_VOICE_PARAM_GAIN | 0, outside));
|
||||
Require(ControlThrows<std::invalid_argument>(custom, SCE_NGS2_CUSTOM_VOICE_PARAM_GAIN | 1, gain));
|
||||
Require(ControlThrows<std::invalid_argument>(sampler, SCE_NGS2_CUSTOM_VOICE_PARAM_GAIN | 0, gain));
|
||||
struct ShortGainParam {
|
||||
Ngs2VoiceParamHeader header;
|
||||
float gain[2];
|
||||
};
|
||||
Require(ControlThrows<std::invalid_argument>(custom, SCE_NGS2_CUSTOM_VOICE_PARAM_GAIN | 0, ShortGainParam{}));
|
||||
|
||||
Require(sceNgs2RackDestroy(rack, nullptr) == SCE_NGS2_OK);
|
||||
Require(sceNgs2SystemDestroy(system, nullptr) == SCE_NGS2_OK);
|
||||
}
|
||||
|
||||
int main() {
|
||||
TestUserFxChain();
|
||||
TestRackOptions();
|
||||
TestCustomRackChecks();
|
||||
TestCustomSampler();
|
||||
TestCustomFilter();
|
||||
TestCustomLegacyUserFx();
|
||||
TestCustomGain();
|
||||
return 0;
|
||||
}
|
||||
@@ -113,9 +113,59 @@ static void TestParseFileBank() {
|
||||
std::filesystem::remove(path);
|
||||
}
|
||||
|
||||
static void TestFrameInfoPcm() {
|
||||
for (std::uint32_t channels = 1; channels <= 8; channels++) {
|
||||
for (const std::uint32_t rate : {1u, 22050u, 48000u, 192000u}) {
|
||||
const Ngs2WaveformFormat format{SCE_NGS2_WAVEFORM_TYPE_PCM_I16L, channels, rate, 0, 0, 0};
|
||||
std::uint32_t frameSize = 0xa1, frameSamples = 0xa2, units = 0xa3, delay = 0xa4;
|
||||
Require(sceNgs2GetWaveformFrameInfo(&format, &frameSize, &frameSamples, &units, &delay) == SCE_NGS2_OK);
|
||||
Require(frameSize == channels * 2 && frameSamples == 1 && units == 1 && delay == 0);
|
||||
const auto file = PcmFile(channels, rate, 16, 10);
|
||||
Ngs2WaveformInfo info{};
|
||||
Require(sceNgs2ParseWaveformData(file.data(), file.size(), &info) == SCE_NGS2_OK);
|
||||
Require(info.audio_frame_size == frameSize && info.num_audio_frame_samples == frameSamples);
|
||||
Require(info.num_audio_unit_per_frame == units && info.num_delay_samples == delay);
|
||||
}
|
||||
}
|
||||
const Ngs2WaveformFormat ignored{SCE_NGS2_WAVEFORM_TYPE_PCM_I16L, 2, 48000, 0x12345678, 3, 5};
|
||||
std::uint32_t frameSize = 0xa1, frameSamples = 0xa2, units = 0xa3, delay = 0xa4;
|
||||
Require(sceNgs2GetWaveformFrameInfo(&ignored, &frameSize, &frameSamples, &units, &delay) == SCE_NGS2_OK);
|
||||
Require(frameSize == 4 && frameSamples == 1 && units == 1 && delay == 0);
|
||||
}
|
||||
|
||||
static void TestFrameInfoErrors() {
|
||||
const Ngs2WaveformFormat pcm{SCE_NGS2_WAVEFORM_TYPE_PCM_I16L, 2, 48000, 0, 0, 0};
|
||||
std::uint32_t values[4] = {0xa1, 0xa2, 0xa3, 0xa4};
|
||||
const auto untouched = [&] { return values[0] == 0xa1 && values[1] == 0xa2 && values[2] == 0xa3 && values[3] == 0xa4; };
|
||||
Require(sceNgs2GetWaveformFrameInfo(&pcm, nullptr, &values[1], &values[2], &values[3]) == SCE_NGS2_ERROR_INVALID_OUT_ADDRESS);
|
||||
Require(sceNgs2GetWaveformFrameInfo(&pcm, &values[0], nullptr, &values[2], &values[3]) == SCE_NGS2_ERROR_INVALID_OUT_ADDRESS);
|
||||
Require(sceNgs2GetWaveformFrameInfo(&pcm, &values[0], &values[1], nullptr, &values[3]) == SCE_NGS2_ERROR_INVALID_OUT_ADDRESS);
|
||||
Require(sceNgs2GetWaveformFrameInfo(&pcm, &values[0], &values[1], &values[2], nullptr) == SCE_NGS2_ERROR_INVALID_OUT_ADDRESS);
|
||||
Require(sceNgs2GetWaveformFrameInfo(nullptr, nullptr, nullptr, nullptr, nullptr) == SCE_NGS2_ERROR_INVALID_OUT_ADDRESS);
|
||||
Require(sceNgs2GetWaveformFrameInfo(nullptr, &values[0], &values[1], &values[2], &values[3]) == SCE_NGS2_ERROR_INVALID_WAVEFORM_FORMAT);
|
||||
Require(untouched());
|
||||
const Ngs2WaveformFormat invalid[] = {
|
||||
{SCE_NGS2_WAVEFORM_TYPE_PCM_I16L, 0, 48000, 0, 0, 0},
|
||||
{SCE_NGS2_WAVEFORM_TYPE_PCM_I16L, 9, 48000, 0, 0, 0},
|
||||
{SCE_NGS2_WAVEFORM_TYPE_PCM_I16L, 2, 0, 0, 0, 0},
|
||||
{SCE_NGS2_WAVEFORM_TYPE_PCM_I16L, 2, 192001, 0, 0, 0},
|
||||
{0x99, 0, 48000, 0, 0, 0},
|
||||
{SCE_NGS2_WAVEFORM_TYPE_PCM_F32L, 2, 0, 0, 0, 0},
|
||||
};
|
||||
for (const auto& format : invalid) {
|
||||
Require(sceNgs2GetWaveformFrameInfo(&format, &values[0], &values[1], &values[2], &values[3]) == SCE_NGS2_ERROR_INVALID_WAVEFORM_FORMAT);
|
||||
Require(untouched());
|
||||
}
|
||||
for (const std::uint32_t type : {0u, 0x10u, 0x11u, 0x13u, 0x14u, 0x16u, SCE_NGS2_WAVEFORM_TYPE_PCM_F32L, 0x19u, 0x41u, 0xffffffffu}) {
|
||||
Require(FrameInfoThrows({type, 2, 48000, 0, 0, 0}));
|
||||
}
|
||||
}
|
||||
|
||||
int main() {
|
||||
TestParsePcm();
|
||||
TestParseFile();
|
||||
TestParseFileBank();
|
||||
TestFrameInfoPcm();
|
||||
TestFrameInfoErrors();
|
||||
return 0;
|
||||
}
|
||||
@@ -6,12 +6,14 @@
|
||||
#include <cstdint>
|
||||
#include <cstdio>
|
||||
#include <cstdlib>
|
||||
#include <exception>
|
||||
#include <vector>
|
||||
|
||||
extern "C" {
|
||||
int APS5_VABI sceNgs2ParseWaveformData(const void*, size_t, Ngs2WaveformInfo*);
|
||||
int APS5_VABI sceNgs2ParseWaveformFile(const char*, uint32_t, Ngs2WaveformInfo*);
|
||||
int APS5_VABI sceNgs2CalcWaveformBlock(const Ngs2WaveformFormat*, uint32_t, uint32_t, Ngs2WaveformBlock*);
|
||||
int APS5_VABI sceNgs2GetWaveformFrameInfo(const Ngs2WaveformFormat*, uint32_t*, uint32_t*, uint32_t*, uint32_t*);
|
||||
int APS5_VABI sceNgs2SystemResetOption(Ngs2SystemOption*);
|
||||
int APS5_VABI sceNgs2SystemQueryBufferSize(const Ngs2SystemOption*, Ngs2ContextBufferInfo*);
|
||||
int APS5_VABI sceNgs2SystemCreate(const Ngs2SystemOption*, const Ngs2ContextBufferInfo*, uintptr_t*);
|
||||
@@ -60,6 +62,18 @@ inline void Check(bool value, int line) {
|
||||
}
|
||||
#define Require(value) Check((value), __LINE__)
|
||||
|
||||
inline bool FrameInfoThrows(const Ngs2WaveformFormat& format) {
|
||||
std::uint32_t values[4] = {0xa1, 0xa2, 0xa3, 0xa4};
|
||||
bool threw = false;
|
||||
try {
|
||||
sceNgs2GetWaveformFrameInfo(&format, &values[0], &values[1], &values[2], &values[3]);
|
||||
} catch (const std::exception&) {
|
||||
threw = true;
|
||||
}
|
||||
Require(values[0] == 0xa1 && values[1] == 0xa2 && values[2] == 0xa3 && values[3] == 0xa4);
|
||||
return threw;
|
||||
}
|
||||
|
||||
inline constexpr std::uint32_t Grain = 8;
|
||||
|
||||
inline std::vector<std::vector<std::uint64_t>> buffers;
|
||||
|
||||
@@ -21,10 +21,6 @@ int APS5_VABI sceNgs2FftQuerySize() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
return 0;
|
||||
}
|
||||
int APS5_VABI sceNgs2GetWaveformFrameInfo(void* format, std::uint32_t* outFrameSize, std::uint32_t* outNumFrameSamples, std::uint32_t* outUnitsPerFrame, std::uint32_t* outNumDelaySamples) {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
return 0;
|
||||
}
|
||||
int APS5_VABI sceNgs2ParseWaveformUser(std::uintptr_t handler, std::uintptr_t userData, void* outInfo) {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
return 0;
|
||||
|
||||
@@ -1890,4 +1890,471 @@ std::uint64_t APS5_VABI _ZNK3sce2Np9CppWebApi17TitleCloudStorage2V15Owner12getAc
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int APS5_VABI _ZN3sce2Np9CppWebApi11UserProfile2V110FriendsApi10getFriendsEiRKNS4_21ParameterToGetFriendsERNS1_6Common11TransactionINS8_12IntrusivePtrINS3_18GetFriendsResponseEEENSA_INS8_18ResponseHeaderBaseEEEEE() {
|
||||
return SCE_NP_WEBAPI_ERROR_NOT_SIGNED_IN;
|
||||
}
|
||||
|
||||
int APS5_VABI _ZN3sce2Np9CppWebApi11UserProfile2V110FriendsApi21ParameterToGetFriends10initializeEPNS1_6Common10LibContextEPKc() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int APS5_VABI _ZN3sce2Np9CppWebApi11UserProfile2V110FriendsApi21ParameterToGetFriends9terminateEv() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int APS5_VABI _ZN3sce2Np9CppWebApi11UserProfile2V110FriendsApi21ParameterToGetFriendsC1Ev(void* self) {
|
||||
(void)self;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int APS5_VABI _ZN3sce2Np9CppWebApi11UserProfile2V110FriendsApi21ParameterToGetFriendsD1Ev(void* self) {
|
||||
(void)self;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int APS5_VABI _ZN3sce2Np9CppWebApi11UserProfile2V111PresenceApi17getBasicPresencesEiRKNS4_28ParameterToGetBasicPresencesERNS1_6Common11TransactionINS8_12IntrusivePtrINS3_25GetBasicPresencesResponseEEENSA_INS8_18ResponseHeaderBaseEEEEE() {
|
||||
return SCE_NP_WEBAPI_ERROR_NOT_SIGNED_IN;
|
||||
}
|
||||
|
||||
int APS5_VABI _ZN3sce2Np9CppWebApi11UserProfile2V111PresenceApi28ParameterToGetBasicPresences10initializeEPNS1_6Common10LibContextEPKc() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int APS5_VABI _ZN3sce2Np9CppWebApi11UserProfile2V111PresenceApi28ParameterToGetBasicPresences9terminateEv() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int APS5_VABI _ZN3sce2Np9CppWebApi11UserProfile2V111PresenceApi28ParameterToGetBasicPresencesC1Ev(void* self) {
|
||||
(void)self;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int APS5_VABI _ZN3sce2Np9CppWebApi11UserProfile2V111PresenceApi28ParameterToGetBasicPresencesD1Ev(void* self) {
|
||||
(void)self;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int APS5_VABI _ZN3sce2Np9CppWebApi11UserProfile2V118GetFriendsResponse10getFriendsEv() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int APS5_VABI _ZN3sce2Np9CppWebApi11UserProfile2V124GetBlockingUsersResponse9getBlocksEv() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int APS5_VABI _ZN3sce2Np9CppWebApi11UserProfile2V125GetBasicPresencesResponse17getBasicPresencesEv() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int APS5_VABI _ZN3sce2Np9CppWebApi11UserProfile2V19BlocksApi16getBlockingUsersEiRKNS4_27ParameterToGetBlockingUsersERNS1_6Common11TransactionINS8_12IntrusivePtrINS3_24GetBlockingUsersResponseEEENSA_INS8_18ResponseHeaderBaseEEEEE() {
|
||||
return SCE_NP_WEBAPI_ERROR_NOT_SIGNED_IN;
|
||||
}
|
||||
|
||||
int APS5_VABI _ZN3sce2Np9CppWebApi11UserProfile2V19BlocksApi27ParameterToGetBlockingUsers10initializeEPNS1_6Common10LibContextE() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int APS5_VABI _ZN3sce2Np9CppWebApi11UserProfile2V19BlocksApi27ParameterToGetBlockingUsers9terminateEv() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int APS5_VABI _ZN3sce2Np9CppWebApi11UserProfile2V19BlocksApi27ParameterToGetBlockingUsersC1Ev(void* self) {
|
||||
(void)self;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int APS5_VABI _ZN3sce2Np9CppWebApi11UserProfile2V19BlocksApi27ParameterToGetBlockingUsersD1Ev(void* self) {
|
||||
(void)self;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int APS5_VABI _ZN3sce2Np9CppWebApi15ProfanityFilter2V212ProfanityApi15filterProfanityEiRKNS4_26ParameterToFilterProfanityERNS1_6Common11TransactionINS8_12IntrusivePtrINS3_23FilterProfanityResponseEEENSA_INS8_18ResponseHeaderBaseEEEEE() {
|
||||
return SCE_NP_WEBAPI_ERROR_NOT_SIGNED_IN;
|
||||
}
|
||||
|
||||
int APS5_VABI _ZN3sce2Np9CppWebApi15ProfanityFilter2V212ProfanityApi26ParameterToFilterProfanity10initializeEPNS1_6Common10LibContextEPKcSA_NS6_12IntrusivePtrINS3_19WebApiFilterRequestEEE() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int APS5_VABI _ZN3sce2Np9CppWebApi15ProfanityFilter2V212ProfanityApi26ParameterToFilterProfanity9terminateEv() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int APS5_VABI _ZN3sce2Np9CppWebApi15ProfanityFilter2V212ProfanityApi26ParameterToFilterProfanityC1Ev(void* self) {
|
||||
(void)self;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int APS5_VABI _ZN3sce2Np9CppWebApi15ProfanityFilter2V212ProfanityApi26ParameterToFilterProfanityD1Ev(void* self) {
|
||||
(void)self;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int APS5_VABI _ZN3sce2Np9CppWebApi15ProfanityFilter2V226WebApiFilterRequestFactory6createEPNS1_6Common10LibContextEPKcPNS5_12IntrusivePtrINS3_19WebApiFilterRequestEEE() {
|
||||
return SCE_NP_WEBAPI_ERROR_NOT_SIGNED_IN;
|
||||
}
|
||||
|
||||
int APS5_VABI _ZN3sce2Np9CppWebApi30CommunicationRestrictionStatus2V333CommunicationRestrictionStatusApi33getCommunicationRestrictionStatusEiRKNS4_44ParameterToGetCommunicationRestrictionStatusERNS1_6Common11TransactionINS8_12IntrusivePtrINS3_38CommunicationRestrictionStatusResponseEEENSA_INS8_18ResponseHeaderBaseEEEEE() {
|
||||
return SCE_NP_WEBAPI_ERROR_NOT_SIGNED_IN;
|
||||
}
|
||||
|
||||
int APS5_VABI _ZN3sce2Np9CppWebApi30CommunicationRestrictionStatus2V333CommunicationRestrictionStatusApi44ParameterToGetCommunicationRestrictionStatus10initializeEPNS1_6Common10LibContextEm() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int APS5_VABI _ZN3sce2Np9CppWebApi30CommunicationRestrictionStatus2V333CommunicationRestrictionStatusApi44ParameterToGetCommunicationRestrictionStatus9terminateEv() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int APS5_VABI _ZN3sce2Np9CppWebApi30CommunicationRestrictionStatus2V333CommunicationRestrictionStatusApi44ParameterToGetCommunicationRestrictionStatusC1Ev(void* self) {
|
||||
(void)self;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int APS5_VABI _ZN3sce2Np9CppWebApi30CommunicationRestrictionStatus2V333CommunicationRestrictionStatusApi44ParameterToGetCommunicationRestrictionStatusD1Ev(void* self) {
|
||||
(void)self;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int APS5_VABI _ZN3sce2Np9CppWebApi6Common11TransactionINS2_12IntrusivePtrINS1_11UserProfile2V118GetFriendsResponseEEENS4_INS2_18ResponseHeaderBaseEEEE21setOnFinishedCallbackEPFvliS8_PvEPFvliSC_ESC_() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int APS5_VABI _ZN3sce2Np9CppWebApi6Common11TransactionINS2_12IntrusivePtrINS1_11UserProfile2V118GetFriendsResponseEEENS4_INS2_18ResponseHeaderBaseEEEEC1Ev(void* self) {
|
||||
(void)self;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int APS5_VABI _ZN3sce2Np9CppWebApi6Common11TransactionINS2_12IntrusivePtrINS1_11UserProfile2V118GetFriendsResponseEEENS4_INS2_18ResponseHeaderBaseEEEED1Ev(void* self) {
|
||||
(void)self;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int APS5_VABI _ZN3sce2Np9CppWebApi6Common11TransactionINS2_12IntrusivePtrINS1_11UserProfile2V124GetBlockingUsersResponseEEENS4_INS2_18ResponseHeaderBaseEEEE21setOnFinishedCallbackEPFvliS8_PvEPFvliSC_ESC_() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int APS5_VABI _ZN3sce2Np9CppWebApi6Common11TransactionINS2_12IntrusivePtrINS1_11UserProfile2V124GetBlockingUsersResponseEEENS4_INS2_18ResponseHeaderBaseEEEEC1Ev(void* self) {
|
||||
(void)self;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int APS5_VABI _ZN3sce2Np9CppWebApi6Common11TransactionINS2_12IntrusivePtrINS1_11UserProfile2V124GetBlockingUsersResponseEEENS4_INS2_18ResponseHeaderBaseEEEED1Ev(void* self) {
|
||||
(void)self;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int APS5_VABI _ZN3sce2Np9CppWebApi6Common11TransactionINS2_12IntrusivePtrINS1_11UserProfile2V125GetBasicPresencesResponseEEENS4_INS2_18ResponseHeaderBaseEEEE21setOnFinishedCallbackEPFvliS8_PvEPFvliSC_ESC_() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int APS5_VABI _ZN3sce2Np9CppWebApi6Common11TransactionINS2_12IntrusivePtrINS1_11UserProfile2V125GetBasicPresencesResponseEEENS4_INS2_18ResponseHeaderBaseEEEEC1Ev(void* self) {
|
||||
(void)self;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int APS5_VABI _ZN3sce2Np9CppWebApi6Common11TransactionINS2_12IntrusivePtrINS1_11UserProfile2V125GetBasicPresencesResponseEEENS4_INS2_18ResponseHeaderBaseEEEED1Ev(void* self) {
|
||||
(void)self;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int APS5_VABI _ZN3sce2Np9CppWebApi6Common11TransactionINS2_12IntrusivePtrINS1_15ProfanityFilter2V223FilterProfanityResponseEEENS4_INS2_18ResponseHeaderBaseEEEE21setOnFinishedCallbackEPFvliS8_PvEPFvliSC_ESC_() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int APS5_VABI _ZN3sce2Np9CppWebApi6Common11TransactionINS2_12IntrusivePtrINS1_15ProfanityFilter2V223FilterProfanityResponseEEENS4_INS2_18ResponseHeaderBaseEEEEC1Ev(void* self) {
|
||||
(void)self;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int APS5_VABI _ZN3sce2Np9CppWebApi6Common11TransactionINS2_12IntrusivePtrINS1_15ProfanityFilter2V223FilterProfanityResponseEEENS4_INS2_18ResponseHeaderBaseEEEED1Ev(void* self) {
|
||||
(void)self;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int APS5_VABI _ZN3sce2Np9CppWebApi6Common11TransactionINS2_12IntrusivePtrINS1_30CommunicationRestrictionStatus2V338CommunicationRestrictionStatusResponseEEENS4_INS2_18ResponseHeaderBaseEEEE21setOnFinishedCallbackEPFvliS8_PvEPFvliSC_ESC_() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int APS5_VABI _ZN3sce2Np9CppWebApi6Common11TransactionINS2_12IntrusivePtrINS1_30CommunicationRestrictionStatus2V338CommunicationRestrictionStatusResponseEEENS4_INS2_18ResponseHeaderBaseEEEEC1Ev(void* self) {
|
||||
(void)self;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int APS5_VABI _ZN3sce2Np9CppWebApi6Common11TransactionINS2_12IntrusivePtrINS1_30CommunicationRestrictionStatus2V338CommunicationRestrictionStatusResponseEEENS4_INS2_18ResponseHeaderBaseEEEED1Ev(void* self) {
|
||||
(void)self;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void APS5_VABI _ZN3sce2Np9CppWebApi6Common12IntrusivePtrINS1_15ProfanityFilter2V219WebApiFilterRequestEEC1ERS7_(IntrusivePtr* self, const IntrusivePtr* source) {
|
||||
CopyIntrusivePtr(self, source, ReferenceCountOffset);
|
||||
}
|
||||
|
||||
void APS5_VABI _ZN3sce2Np9CppWebApi6Common12IntrusivePtrINS1_15ProfanityFilter2V219WebApiFilterRequestEEC1Ev(IntrusivePtr* self) {
|
||||
*self = {};
|
||||
}
|
||||
|
||||
void APS5_VABI _ZN3sce2Np9CppWebApi6Common12IntrusivePtrINS1_15ProfanityFilter2V219WebApiFilterRequestEED1Ev(IntrusivePtr* self) {
|
||||
ReleaseIntrusivePtr(self, ReferenceCountOffset, __func__);
|
||||
}
|
||||
|
||||
void APS5_VABI _ZN3sce2Np9CppWebApi6Common12IntrusivePtrINS2_18ResponseHeaderBaseEEC1Ev(IntrusivePtr* self) {
|
||||
*self = {};
|
||||
}
|
||||
|
||||
void APS5_VABI _ZN3sce2Np9CppWebApi6Common12IntrusivePtrINS2_18ResponseHeaderBaseEED1Ev(IntrusivePtr* self) {
|
||||
ReleaseIntrusivePtr(self, ReferenceCountOffset, __func__);
|
||||
}
|
||||
|
||||
void APS5_VABI _ZN3sce2Np9CppWebApi6Common12IntrusivePtrINS2_6StringEEC1Ev(IntrusivePtr* self) {
|
||||
*self = {};
|
||||
}
|
||||
|
||||
void APS5_VABI _ZN3sce2Np9CppWebApi6Common12IntrusivePtrINS2_6StringEED1Ev(IntrusivePtr* self) {
|
||||
ReleaseIntrusivePtr(self, ReferenceCountOffset, __func__);
|
||||
}
|
||||
|
||||
void APS5_VABI _ZN3sce2Np9CppWebApi6Common12IntrusivePtrINS2_6VectorINS3_INS1_11UserProfile2V113BasicPresenceEEEEEED1Ev(IntrusivePtr* self) {
|
||||
ReleaseIntrusivePtr(self, VectorReferenceCountOffset, __func__);
|
||||
}
|
||||
|
||||
int APS5_VABI _ZN3sce2Np9CppWebApi6Common13ConstIteratorINS2_12IntrusivePtrINS1_11UserProfile2V113BasicPresenceEEEED2Ev(void* self) {
|
||||
(void)self;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int APS5_VABI _ZN3sce2Np9CppWebApi6Common13ConstIteratorImED2Ev(void* self) {
|
||||
(void)self;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int APS5_VABI _ZN3sce2Np9CppWebApi6Common15TransactionBaseINS2_12IntrusivePtrINS1_11UserProfile2V118GetFriendsResponseEEENS4_INS2_18ResponseHeaderBaseEEEE28setResponseInformationOptionEP37SceNpWebApi2ResponseInformationOption() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int APS5_VABI _ZN3sce2Np9CppWebApi6Common15TransactionBaseINS2_12IntrusivePtrINS1_11UserProfile2V118GetFriendsResponseEEENS4_INS2_18ResponseHeaderBaseEEEE5startEPNS2_10LibContextE() {
|
||||
return SCE_NP_WEBAPI_ERROR_NOT_SIGNED_IN;
|
||||
}
|
||||
|
||||
int APS5_VABI _ZN3sce2Np9CppWebApi6Common15TransactionBaseINS2_12IntrusivePtrINS1_11UserProfile2V118GetFriendsResponseEEENS4_INS2_18ResponseHeaderBaseEEEE6finishEv() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int APS5_VABI _ZN3sce2Np9CppWebApi6Common15TransactionBaseINS2_12IntrusivePtrINS1_11UserProfile2V124GetBlockingUsersResponseEEENS4_INS2_18ResponseHeaderBaseEEEE28setResponseInformationOptionEP37SceNpWebApi2ResponseInformationOption() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int APS5_VABI _ZN3sce2Np9CppWebApi6Common15TransactionBaseINS2_12IntrusivePtrINS1_11UserProfile2V124GetBlockingUsersResponseEEENS4_INS2_18ResponseHeaderBaseEEEE5startEPNS2_10LibContextE() {
|
||||
return SCE_NP_WEBAPI_ERROR_NOT_SIGNED_IN;
|
||||
}
|
||||
|
||||
int APS5_VABI _ZN3sce2Np9CppWebApi6Common15TransactionBaseINS2_12IntrusivePtrINS1_11UserProfile2V124GetBlockingUsersResponseEEENS4_INS2_18ResponseHeaderBaseEEEE6finishEv() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int APS5_VABI _ZN3sce2Np9CppWebApi6Common15TransactionBaseINS2_12IntrusivePtrINS1_11UserProfile2V125GetBasicPresencesResponseEEENS4_INS2_18ResponseHeaderBaseEEEE28setResponseInformationOptionEP37SceNpWebApi2ResponseInformationOption() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int APS5_VABI _ZN3sce2Np9CppWebApi6Common15TransactionBaseINS2_12IntrusivePtrINS1_11UserProfile2V125GetBasicPresencesResponseEEENS4_INS2_18ResponseHeaderBaseEEEE5startEPNS2_10LibContextE() {
|
||||
return SCE_NP_WEBAPI_ERROR_NOT_SIGNED_IN;
|
||||
}
|
||||
|
||||
int APS5_VABI _ZN3sce2Np9CppWebApi6Common15TransactionBaseINS2_12IntrusivePtrINS1_11UserProfile2V125GetBasicPresencesResponseEEENS4_INS2_18ResponseHeaderBaseEEEE6finishEv() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int APS5_VABI _ZN3sce2Np9CppWebApi6Common15TransactionBaseINS2_12IntrusivePtrINS1_15ProfanityFilter2V223FilterProfanityResponseEEENS4_INS2_18ResponseHeaderBaseEEEE28setResponseInformationOptionEP37SceNpWebApi2ResponseInformationOption() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int APS5_VABI _ZN3sce2Np9CppWebApi6Common15TransactionBaseINS2_12IntrusivePtrINS1_15ProfanityFilter2V223FilterProfanityResponseEEENS4_INS2_18ResponseHeaderBaseEEEE5startEPNS2_10LibContextE() {
|
||||
return SCE_NP_WEBAPI_ERROR_NOT_SIGNED_IN;
|
||||
}
|
||||
|
||||
int APS5_VABI _ZN3sce2Np9CppWebApi6Common15TransactionBaseINS2_12IntrusivePtrINS1_15ProfanityFilter2V223FilterProfanityResponseEEENS4_INS2_18ResponseHeaderBaseEEEE6finishEv() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int APS5_VABI _ZN3sce2Np9CppWebApi6Common15TransactionBaseINS2_12IntrusivePtrINS1_30CommunicationRestrictionStatus2V338CommunicationRestrictionStatusResponseEEENS4_INS2_18ResponseHeaderBaseEEEE28setResponseInformationOptionEP37SceNpWebApi2ResponseInformationOption() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int APS5_VABI _ZN3sce2Np9CppWebApi6Common15TransactionBaseINS2_12IntrusivePtrINS1_30CommunicationRestrictionStatus2V338CommunicationRestrictionStatusResponseEEENS4_INS2_18ResponseHeaderBaseEEEE5startEPNS2_10LibContextE() {
|
||||
return SCE_NP_WEBAPI_ERROR_NOT_SIGNED_IN;
|
||||
}
|
||||
|
||||
int APS5_VABI _ZN3sce2Np9CppWebApi6Common15TransactionBaseINS2_12IntrusivePtrINS1_30CommunicationRestrictionStatus2V338CommunicationRestrictionStatusResponseEEENS4_INS2_18ResponseHeaderBaseEEEE6finishEv() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int APS5_VABI _ZN3sce2Np9CppWebApi6Common18ResponseHeaderBase14getHeaderValueEPKcRNS2_12IntrusivePtrINS2_6StringEEE() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int APS5_VABI _ZN3sce2Np9CppWebApi6Common6VectorINS2_12IntrusivePtrINS1_11UserProfile2V113BasicPresenceEEEE3endEv() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int APS5_VABI _ZN3sce2Np9CppWebApi6Common6VectorINS2_12IntrusivePtrINS1_11UserProfile2V113BasicPresenceEEEE5beginEv() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int APS5_VABI _ZN3sce2Np9CppWebApi6Common6VectorImE3endEv() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int APS5_VABI _ZN3sce2Np9CppWebApi6Common6VectorImE5beginEv() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int APS5_VABI _ZN3sce2Np9CppWebApi6Common8IteratorINS2_12IntrusivePtrINS1_11UserProfile2V113BasicPresenceEEEEppEv() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int APS5_VABI _ZN3sce2Np9CppWebApi6Common8IteratorImEppEv() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int APS5_VABI _ZNK3sce2Np9CppWebApi11UserProfile2V113BasicPresence12getAccountIdEv() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int APS5_VABI _ZNK3sce2Np9CppWebApi11UserProfile2V113BasicPresence12getInContextEv() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int APS5_VABI _ZNK3sce2Np9CppWebApi11UserProfile2V113BasicPresence15getOnlineStatusEv() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int APS5_VABI _ZNK3sce2Np9CppWebApi15ProfanityFilter2V223FilterProfanityResponse10getMessageEv() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int APS5_VABI _ZNK3sce2Np9CppWebApi30CommunicationRestrictionStatus2V338CommunicationRestrictionStatusResponse13getRestrictedEv() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void* APS5_VABI _ZNK3sce2Np9CppWebApi6Common12IntrusivePtrINS1_11UserProfile2V113BasicPresenceEEptEv(const IntrusivePtr* self) {
|
||||
return self->object;
|
||||
}
|
||||
|
||||
void* APS5_VABI _ZNK3sce2Np9CppWebApi6Common12IntrusivePtrINS1_11UserProfile2V118GetFriendsResponseEEptEv(const IntrusivePtr* self) {
|
||||
return self->object;
|
||||
}
|
||||
|
||||
void* APS5_VABI _ZNK3sce2Np9CppWebApi6Common12IntrusivePtrINS1_11UserProfile2V124GetBlockingUsersResponseEEptEv(const IntrusivePtr* self) {
|
||||
return self->object;
|
||||
}
|
||||
|
||||
void* APS5_VABI _ZNK3sce2Np9CppWebApi6Common12IntrusivePtrINS1_11UserProfile2V125GetBasicPresencesResponseEEptEv(const IntrusivePtr* self) {
|
||||
return self->object;
|
||||
}
|
||||
|
||||
void* APS5_VABI _ZNK3sce2Np9CppWebApi6Common12IntrusivePtrINS1_15ProfanityFilter2V223FilterProfanityResponseEEptEv(const IntrusivePtr* self) {
|
||||
return self->object;
|
||||
}
|
||||
|
||||
void* APS5_VABI _ZNK3sce2Np9CppWebApi6Common12IntrusivePtrINS1_30CommunicationRestrictionStatus2V338CommunicationRestrictionStatusResponseEEptEv(const IntrusivePtr* self) {
|
||||
return self->object;
|
||||
}
|
||||
|
||||
void* APS5_VABI _ZNK3sce2Np9CppWebApi6Common12IntrusivePtrINS2_18ResponseHeaderBaseEE3getEv(const IntrusivePtr* self) {
|
||||
return self->object;
|
||||
}
|
||||
|
||||
void* APS5_VABI _ZNK3sce2Np9CppWebApi6Common12IntrusivePtrINS2_18ResponseHeaderBaseEEptEv(const IntrusivePtr* self) {
|
||||
return self->object;
|
||||
}
|
||||
|
||||
void* APS5_VABI _ZNK3sce2Np9CppWebApi6Common12IntrusivePtrINS2_6StringEE3getEv(const IntrusivePtr* self) {
|
||||
return self->object;
|
||||
}
|
||||
|
||||
void* APS5_VABI _ZNK3sce2Np9CppWebApi6Common12IntrusivePtrINS2_6StringEEptEv(const IntrusivePtr* self) {
|
||||
return self->object;
|
||||
}
|
||||
|
||||
void* APS5_VABI _ZNK3sce2Np9CppWebApi6Common12IntrusivePtrINS2_6VectorINS3_INS1_11UserProfile2V113BasicPresenceEEEEEEdeEv(const IntrusivePtr* self) {
|
||||
return self->object;
|
||||
}
|
||||
|
||||
void* APS5_VABI _ZNK3sce2Np9CppWebApi6Common12IntrusivePtrINS2_6VectorINS3_INS1_11UserProfile2V113BasicPresenceEEEEEEptEv(const IntrusivePtr* self) {
|
||||
return self->object;
|
||||
}
|
||||
|
||||
void* APS5_VABI _ZNK3sce2Np9CppWebApi6Common12IntrusivePtrINS2_6VectorImEEEdeEv(const IntrusivePtr* self) {
|
||||
return self->object;
|
||||
}
|
||||
|
||||
void* APS5_VABI _ZNK3sce2Np9CppWebApi6Common12IntrusivePtrINS2_6VectorImEEEptEv(const IntrusivePtr* self) {
|
||||
return self->object;
|
||||
}
|
||||
|
||||
int APS5_VABI _ZNK3sce2Np9CppWebApi6Common15TransactionBaseINS2_12IntrusivePtrINS1_11UserProfile2V118GetFriendsResponseEEENS4_INS2_18ResponseHeaderBaseEEEE18getResponseHeadersERSA_() {
|
||||
return SCE_NP_WEBAPI_ERROR_NOT_SIGNED_IN;
|
||||
}
|
||||
|
||||
int APS5_VABI _ZNK3sce2Np9CppWebApi6Common15TransactionBaseINS2_12IntrusivePtrINS1_11UserProfile2V124GetBlockingUsersResponseEEENS4_INS2_18ResponseHeaderBaseEEEE18getResponseHeadersERSA_() {
|
||||
return SCE_NP_WEBAPI_ERROR_NOT_SIGNED_IN;
|
||||
}
|
||||
|
||||
int APS5_VABI _ZNK3sce2Np9CppWebApi6Common15TransactionBaseINS2_12IntrusivePtrINS1_11UserProfile2V125GetBasicPresencesResponseEEENS4_INS2_18ResponseHeaderBaseEEEE18getResponseHeadersERSA_() {
|
||||
return SCE_NP_WEBAPI_ERROR_NOT_SIGNED_IN;
|
||||
}
|
||||
|
||||
int APS5_VABI _ZNK3sce2Np9CppWebApi6Common15TransactionBaseINS2_12IntrusivePtrINS1_15ProfanityFilter2V223FilterProfanityResponseEEENS4_INS2_18ResponseHeaderBaseEEEE18getResponseHeadersERSA_() {
|
||||
return SCE_NP_WEBAPI_ERROR_NOT_SIGNED_IN;
|
||||
}
|
||||
|
||||
int APS5_VABI _ZNK3sce2Np9CppWebApi6Common15TransactionBaseINS2_12IntrusivePtrINS1_30CommunicationRestrictionStatus2V338CommunicationRestrictionStatusResponseEEENS4_INS2_18ResponseHeaderBaseEEEE18getResponseHeadersERSA_() {
|
||||
return SCE_NP_WEBAPI_ERROR_NOT_SIGNED_IN;
|
||||
}
|
||||
|
||||
int APS5_VABI _ZNK3sce2Np9CppWebApi6Common6VectorINS2_12IntrusivePtrINS1_11UserProfile2V113BasicPresenceEEEE4sizeEv() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int APS5_VABI _ZNK3sce2Np9CppWebApi6Common6VectorImE4sizeEv() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int APS5_VABI _ZNK3sce2Np9CppWebApi6Common8IteratorINS2_12IntrusivePtrINS1_11UserProfile2V113BasicPresenceEEEEdeEv() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int APS5_VABI _ZNK3sce2Np9CppWebApi6Common8IteratorINS2_12IntrusivePtrINS1_11UserProfile2V113BasicPresenceEEEEneERKS9_() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int APS5_VABI _ZNK3sce2Np9CppWebApi6Common8IteratorImEdeEv() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int APS5_VABI _ZNK3sce2Np9CppWebApi6Common8IteratorImEneERKS4_() {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
@@ -23,8 +23,14 @@ static constexpr uint32_t SKU_FLAG_FULL = 3;
|
||||
|
||||
namespace {
|
||||
|
||||
#ifdef _WIN32
|
||||
const wchar_t* ConfiguredEntitlements() { return _wgetenv(L"ANYPS5_ENTITLEMENTS"); }
|
||||
#else
|
||||
const char* ConfiguredEntitlements() { return std::getenv("ANYPS5_ENTITLEMENTS"); }
|
||||
#endif
|
||||
|
||||
std::filesystem::path EntitlementsPath() {
|
||||
if (const char* configured = std::getenv("ANYPS5_ENTITLEMENTS"); configured != nullptr && configured[0] != '\0') return configured;
|
||||
if (const auto* configured = ConfiguredEntitlements(); configured != nullptr && configured[0] != 0) return configured;
|
||||
#ifdef _WIN32
|
||||
wchar_t module[MAX_PATH];
|
||||
const auto length = GetModuleFileNameW(nullptr, module, MAX_PATH);
|
||||
@@ -50,7 +56,7 @@ const std::vector<NpEntitlementAccessAddcontEntitlementInfo>& OwnedAddons() {
|
||||
const auto path = EntitlementsPath();
|
||||
std::ifstream file(path);
|
||||
if (!file) {
|
||||
if (std::getenv("ANYPS5_ENTITLEMENTS") != nullptr || std::filesystem::exists(path)) throw std::runtime_error("NpEntitlementAccess: cannot read " + path.string());
|
||||
if (ConfiguredEntitlements() != nullptr || std::filesystem::exists(path)) throw std::runtime_error("NpEntitlementAccess: cannot read " + path.string());
|
||||
return addons;
|
||||
}
|
||||
std::string line;
|
||||
|
||||
@@ -20,6 +20,7 @@ static constexpr int SCE_NP_ERROR_CALLBACK_MAX = static_cast<int>(0x8055001D);
|
||||
static constexpr uint32_t NP_STATE_SIGNED_OUT = 1;
|
||||
static constexpr int NP_POLL_ASYNC_FINISHED = 0;
|
||||
static constexpr uint32_t NP_REACHABILITY_STATE_UNAVAILABLE = 0;
|
||||
static constexpr uint32_t NP_GAME_PRESENCE_STATUS_OFFLINE = 0;
|
||||
|
||||
static std::atomic<int> g_nextRequest{1};
|
||||
|
||||
@@ -37,6 +38,12 @@ int AddRequest() {
|
||||
return reqId;
|
||||
}
|
||||
|
||||
int SignedOutRequest(int reqId) {
|
||||
if (reqId == 0) return SCE_NP_ERROR_INVALID_ARGUMENT;
|
||||
std::lock_guard lock(requestMutex);
|
||||
return liveRequests.count(reqId) ? SCE_NP_ERROR_SIGNED_OUT : SCE_NP_ERROR_REQUEST_NOT_FOUND;
|
||||
}
|
||||
|
||||
using NpStateCallbackA = void (APS5_VABI *)(int userId, uint32_t state, void* userdata);
|
||||
using NpStateCallback = void (APS5_VABI *)(int userId, uint32_t state, NpId* npId, void* userdata);
|
||||
|
||||
@@ -253,29 +260,31 @@ int APS5_VABI sceNpAsmTerminate(void) {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
return 0;
|
||||
}
|
||||
int APS5_VABI sceNpCheckNpAvailabilityA(void) {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
int APS5_VABI sceNpCheckNpAvailabilityA(int reqId, int userId) {
|
||||
if (userId == USER_SERVICE_USER_ID_INVALID) return SCE_NP_ERROR_INVALID_ARGUMENT;
|
||||
return SignedOutRequest(reqId);
|
||||
}
|
||||
int APS5_VABI sceNpGetAccountDateOfBirthA(int userId, void* dateOfBirth) {
|
||||
if (!dateOfBirth || userId == USER_SERVICE_USER_ID_INVALID) return SCE_NP_ERROR_INVALID_ARGUMENT;
|
||||
return SCE_NP_ERROR_SIGNED_OUT;
|
||||
}
|
||||
int APS5_VABI sceNpGetAccountLanguageA(int reqId, int userId, void* language) {
|
||||
if (!language || userId == USER_SERVICE_USER_ID_INVALID) return SCE_NP_ERROR_INVALID_ARGUMENT;
|
||||
return SignedOutRequest(reqId);
|
||||
}
|
||||
int APS5_VABI sceNpGetGamePresenceStatus(const NpOnlineId* onlineId, uint32_t* status) {
|
||||
if (!onlineId || !status) return SCE_NP_ERROR_INVALID_ARGUMENT;
|
||||
*status = NP_GAME_PRESENCE_STATUS_OFFLINE;
|
||||
return 0;
|
||||
}
|
||||
int APS5_VABI sceNpGetAccountDateOfBirthA(void) {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
int APS5_VABI sceNpGetGamePresenceStatusA(int userId, uint32_t* status) {
|
||||
if (!status || userId == USER_SERVICE_USER_ID_INVALID) return SCE_NP_ERROR_INVALID_ARGUMENT;
|
||||
*status = NP_GAME_PRESENCE_STATUS_OFFLINE;
|
||||
return 0;
|
||||
}
|
||||
int APS5_VABI sceNpGetAccountLanguageA(void) {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
return 0;
|
||||
}
|
||||
int APS5_VABI sceNpGetGamePresenceStatus(void) {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
return 0;
|
||||
}
|
||||
int APS5_VABI sceNpGetGamePresenceStatusA(void) {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
return 0;
|
||||
}
|
||||
int APS5_VABI sceNpGetParentalControlInfoA(void) {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
return 0;
|
||||
int APS5_VABI sceNpGetParentalControlInfoA(int reqId, int userId, int8_t* age, void* info) {
|
||||
if (!age || !info || userId == USER_SERVICE_USER_ID_INVALID) return SCE_NP_ERROR_INVALID_ARGUMENT;
|
||||
return SignedOutRequest(reqId);
|
||||
}
|
||||
int APS5_VABI sceNpIdMapperAbortRequest(void) {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
#include <atomic>
|
||||
#include <cstdint>
|
||||
#include <cstddef>
|
||||
#include "SceTypes.hpp"
|
||||
@@ -5,9 +6,19 @@
|
||||
|
||||
namespace {
|
||||
|
||||
constexpr int NP_PARTY_ERROR_ALREADY_INITIALIZED = static_cast<int>(0x80552502u);
|
||||
constexpr int NP_PARTY_ERROR_NOT_INITIALIZED = static_cast<int>(0x80552503u);
|
||||
constexpr int NP_PARTY_ERROR_INVALID_ARGUMENT = static_cast<int>(0x80552504u);
|
||||
constexpr int NP_PARTY_ERROR_NOT_IN_PARTY = static_cast<int>(0x80552506u);
|
||||
constexpr std::uint16_t NP_PARTY_STATE_NOT_IN_PARTY = 2;
|
||||
|
||||
std::atomic<bool> g_initialized{false};
|
||||
|
||||
int notInParty(const void* out) {
|
||||
if (!out) return NP_PARTY_ERROR_INVALID_ARGUMENT;
|
||||
return NP_PARTY_ERROR_NOT_IN_PARTY;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
extern "C" {
|
||||
@@ -17,8 +28,9 @@ int APS5_VABI sceNpPartyGetState(std::uint16_t* state) {
|
||||
*state = NP_PARTY_STATE_NOT_IN_PARTY;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int APS5_VABI sceNpPartyCheckCallback(void) {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
if (!g_initialized) return NP_PARTY_ERROR_NOT_INITIALIZED;
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -32,9 +44,8 @@ int APS5_VABI sceNpPartyCreateA(void) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int APS5_VABI sceNpPartyGetId(void) {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
return 0;
|
||||
int APS5_VABI sceNpPartyGetId(void* id) {
|
||||
return notInParty(id);
|
||||
}
|
||||
|
||||
int APS5_VABI sceNpPartyGetMemberInfo(void) {
|
||||
@@ -42,19 +53,16 @@ int APS5_VABI sceNpPartyGetMemberInfo(void) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int APS5_VABI sceNpPartyGetMemberInfoA(void) {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
return 0;
|
||||
int APS5_VABI sceNpPartyGetMemberInfoA(std::uint16_t, void* memberInfo) {
|
||||
return notInParty(memberInfo);
|
||||
}
|
||||
|
||||
int APS5_VABI sceNpPartyGetMemberSessionInfo(void) {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
return 0;
|
||||
int APS5_VABI sceNpPartyGetMemberSessionInfo(std::uint16_t, void* memberGameSessionInfo) {
|
||||
return notInParty(memberGameSessionInfo);
|
||||
}
|
||||
|
||||
int APS5_VABI sceNpPartyGetMemberVoiceInfo(void) {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
return 0;
|
||||
int APS5_VABI sceNpPartyGetMemberVoiceInfo(std::uint16_t, std::uint16_t, std::uint8_t* memberVoiceState) {
|
||||
return notInParty(memberVoiceState);
|
||||
}
|
||||
|
||||
int APS5_VABI sceNpPartyGetMembers(void) {
|
||||
@@ -62,9 +70,8 @@ int APS5_VABI sceNpPartyGetMembers(void) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int APS5_VABI sceNpPartyGetMembersA(void) {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
return 0;
|
||||
int APS5_VABI sceNpPartyGetMembersA(void* memberList) {
|
||||
return notInParty(memberList);
|
||||
}
|
||||
|
||||
int APS5_VABI sceNpPartyGetStateAsUser(void) {
|
||||
@@ -72,9 +79,8 @@ int APS5_VABI sceNpPartyGetStateAsUser(void) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int APS5_VABI sceNpPartyGetStateAsUserA(void) {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
return 0;
|
||||
int APS5_VABI sceNpPartyGetStateAsUserA(std::int32_t, std::uint16_t* state) {
|
||||
return sceNpPartyGetState(state);
|
||||
}
|
||||
|
||||
int APS5_VABI sceNpPartyGetVoiceChatPriority(void) {
|
||||
@@ -82,8 +88,10 @@ int APS5_VABI sceNpPartyGetVoiceChatPriority(void) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int APS5_VABI sceNpPartyInitialize(void) {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
int APS5_VABI sceNpPartyInitialize(const void* param) {
|
||||
if (!param) return NP_PARTY_ERROR_INVALID_ARGUMENT;
|
||||
bool expected = false;
|
||||
if (!g_initialized.compare_exchange_strong(expected, true)) return NP_PARTY_ERROR_ALREADY_INITIALIZED;
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -102,8 +110,9 @@ int APS5_VABI sceNpPartyRegisterHandler(void) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int APS5_VABI sceNpPartyRegisterHandlerA(void) {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
int APS5_VABI sceNpPartyRegisterHandlerA(const void* handlers, void*) {
|
||||
if (!g_initialized) return NP_PARTY_ERROR_NOT_INITIALIZED;
|
||||
if (!handlers) return NP_PARTY_ERROR_INVALID_ARGUMENT;
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -112,9 +121,8 @@ int APS5_VABI sceNpPartyRegisterPrivateHandler(void) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int APS5_VABI sceNpPartySendBinaryMessage(void) {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
return 0;
|
||||
int APS5_VABI sceNpPartySendBinaryMessage(const void* sendParams) {
|
||||
return notInParty(sendParams);
|
||||
}
|
||||
|
||||
int APS5_VABI sceNpPartySetVoiceChatPriority(void) {
|
||||
@@ -133,7 +141,7 @@ int APS5_VABI sceNpPartyShowInvitationListA(void) {
|
||||
}
|
||||
|
||||
int APS5_VABI sceNpPartyTerminate(void) {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
if (!g_initialized.exchange(false)) return NP_PARTY_ERROR_NOT_INITIALIZED;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -88,6 +88,16 @@ int Complete(int reqId, int asyncResult) {
|
||||
if (const int error = WaitOffline(reqId, &result)) return error;
|
||||
return result;
|
||||
}
|
||||
|
||||
constexpr std::uint32_t INVALID_SERVICE_LABEL = 0xFFFFFFFF;
|
||||
|
||||
int CreateTitleContext() {
|
||||
std::lock_guard lock(tusMutex);
|
||||
if (titleContexts.size() >= MAX_TITLE_CONTEXTS) return SCE_NP_COMMUNITY_ERROR_TOO_MANY_OBJECTS;
|
||||
const int contextId = nextTitleContext++;
|
||||
titleContexts.insert(contextId);
|
||||
return contextId;
|
||||
}
|
||||
}
|
||||
|
||||
extern "C" {
|
||||
@@ -95,11 +105,7 @@ extern "C" {
|
||||
int APS5_VABI sceNpTusCreateNpTitleCtxA(std::uint32_t serviceLabel, int userId) {
|
||||
(void)serviceLabel;
|
||||
(void)userId;
|
||||
std::lock_guard lock(tusMutex);
|
||||
if (titleContexts.size() >= MAX_TITLE_CONTEXTS) return SCE_NP_COMMUNITY_ERROR_TOO_MANY_OBJECTS;
|
||||
const int contextId = nextTitleContext++;
|
||||
titleContexts.insert(contextId);
|
||||
return contextId;
|
||||
return CreateTitleContext();
|
||||
}
|
||||
|
||||
int APS5_VABI sceNpTusCreateRequest(int titleCtxId) {
|
||||
@@ -177,14 +183,14 @@ int APS5_VABI sceNpTusSetThreadParam(void) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int APS5_VABI sceNpTssCreateNpTitleCtx(void) {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
return 0;
|
||||
int APS5_VABI sceNpTssCreateNpTitleCtx(std::uint32_t serviceLabel, const NpId* npId) {
|
||||
if (!npId) return SCE_NP_COMMUNITY_ERROR_INSUFFICIENT_ARGUMENT;
|
||||
if (serviceLabel == INVALID_SERVICE_LABEL) return SCE_NP_COMMUNITY_ERROR_INVALID_ARGUMENT;
|
||||
return CreateTitleContext();
|
||||
}
|
||||
|
||||
int APS5_VABI sceNpTssCreateNpTitleCtxA(void) {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
return 0;
|
||||
int APS5_VABI sceNpTssCreateNpTitleCtxA(std::uint32_t serviceLabel, int userId) {
|
||||
return sceNpTusCreateNpTitleCtxA(serviceLabel, userId);
|
||||
}
|
||||
|
||||
int APS5_VABI sceNpTusCreateTitleCtx(void) {
|
||||
|
||||
@@ -923,18 +923,18 @@ bool APS5_VABI scePadIsValidHandle(std::int32_t handle, std::int32_t portType) {
|
||||
}
|
||||
|
||||
bool APS5_VABI scePadIsDS4Connected(std::int32_t handle) {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
return 0;
|
||||
(void)handle;
|
||||
return false;
|
||||
}
|
||||
|
||||
bool APS5_VABI scePadIsBlasterConnected(std::int32_t handle) {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
return 0;
|
||||
(void)handle;
|
||||
return false;
|
||||
}
|
||||
|
||||
bool APS5_VABI scePadIsMoveConnected(std::int32_t handle) {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
return 0;
|
||||
(void)handle;
|
||||
return false;
|
||||
}
|
||||
|
||||
int APS5_VABI scePadGetBluetoothAddress(std::int32_t handle, std::uint64_t* address) {
|
||||
|
||||
Loaded 100 of 247 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user