Merge branch 'main' into Feature/initial-ps4-ime-keyboard

This commit is contained in:
georgemoralis 2025-04-04 15:13:35 +03:00 committed by GitHub
commit 16b04c7c01
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
37 changed files with 838 additions and 1049 deletions

3
.gitmodules vendored
View file

@ -107,3 +107,6 @@
path = externals/MoltenVK/cereal
url = https://github.com/USCiLab/cereal
shallow = true
[submodule "externals/libusb"]
path = externals/libusb
url = https://github.com/libusb/libusb-cmake.git

View file

@ -9,7 +9,8 @@ set(CMAKE_CXX_STANDARD_REQUIRED True)
if(APPLE)
list(APPEND ADDITIONAL_LANGUAGES OBJC)
set(CMAKE_OSX_DEPLOYMENT_TARGET 14)
# Starting with 15.4, Rosetta 2 has support for all the necessary instruction sets.
set(CMAKE_OSX_DEPLOYMENT_TARGET 15.4)
endif()
if (NOT CMAKE_BUILD_TYPE)
@ -53,8 +54,8 @@ else()
endif()
if (ARCHITECTURE STREQUAL "x86_64")
# Set x86_64 target level to Sandy Bridge to generally match what is supported for PS4 guest code with CPU patches.
add_compile_options(-march=sandybridge)
# Target the same x86_64 feature set as the PS4 CPU to match requirements.
add_compile_options(-march=btver2 -mno-sse4a)
endif()
if (APPLE AND ARCHITECTURE STREQUAL "x86_64" AND CMAKE_HOST_SYSTEM_PROCESSOR STREQUAL "arm64")
@ -224,10 +225,7 @@ find_package(xxHash 0.8.2 MODULE)
find_package(ZLIB 1.3 MODULE)
find_package(Zydis 5.0.0 CONFIG)
find_package(pugixml 1.14 CONFIG)
if (NOT CMAKE_CXX_COMPILER_ID STREQUAL "Clang" OR NOT MSVC)
find_package(cryptopp 8.9.0 MODULE)
endif()
find_package(libusb 1.0.27 MODULE)
if (APPLE)
find_package(date 3.0.1 CONFIG)
@ -585,6 +583,8 @@ set(MISC_LIBS src/core/libraries/screenshot/screenshot.cpp
src/core/libraries/screenshot/screenshot.h
src/core/libraries/move/move.cpp
src/core/libraries/move/move.h
src/core/libraries/ulobjmgr/ulobjmgr.cpp
src/core/libraries/ulobjmgr/ulobjmgr.h
)
set(DEV_TOOLS src/core/devtools/layer.cpp
@ -1065,7 +1065,7 @@ endif()
create_target_directory_groups(shadps4)
target_link_libraries(shadps4 PRIVATE magic_enum::magic_enum fmt::fmt toml11::toml11 tsl::robin_map xbyak::xbyak Tracy::TracyClient RenderDoc::API FFmpeg::ffmpeg Dear_ImGui gcn half::half ZLIB::ZLIB PNG::PNG)
target_link_libraries(shadps4 PRIVATE Boost::headers GPUOpen::VulkanMemoryAllocator LibAtrac9 sirit Vulkan::Headers xxHash::xxhash Zydis::Zydis glslang::glslang SDL3::SDL3 pugixml::pugixml stb::headers)
target_link_libraries(shadps4 PRIVATE Boost::headers GPUOpen::VulkanMemoryAllocator LibAtrac9 sirit Vulkan::Headers xxHash::xxhash Zydis::Zydis glslang::glslang SDL3::SDL3 pugixml::pugixml stb::headers libusb::usb)
target_compile_definitions(shadps4 PRIVATE IMGUI_USER_CONFIG="imgui/imgui_config.h")
target_compile_definitions(Dear_ImGui PRIVATE IMGUI_USER_CONFIG="${PROJECT_SOURCE_DIR}/src/imgui/imgui_config.h")

View file

@ -71,7 +71,7 @@ Check the build instructions for [**Linux**](https://github.com/shadps4-emu/shad
Check the build instructions for [**macOS**](https://github.com/shadps4-emu/shadPS4/blob/main/documents/building-macos.md).
> [!IMPORTANT]
> macOS users need at least macOS 15 on Apple Silicon-based Mac devices and at least macOS 14 on Intel-based Mac devices.
> macOS users need at least macOS 15.4 to run shadPS4. Due to GPU issues there are currently heavy bugs on Intel Macs.
# Debugging and reporting issues

View file

@ -1,15 +0,0 @@
# SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
# SPDX-License-Identifier: GPL-2.0-or-later
find_package(PkgConfig QUIET)
pkg_search_module(CRYPTOPP QUIET IMPORTED_TARGET libcryptopp)
include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(cryptopp
REQUIRED_VARS CRYPTOPP_LINK_LIBRARIES
VERSION_VAR CRYPTOPP_VERSION
)
if (cryptopp_FOUND AND NOT TARGET cryptopp::cryptopp)
add_library(cryptopp::cryptopp ALIAS PkgConfig::CRYPTOPP)
endif()

15
cmake/Findlibusb.cmake Normal file
View file

@ -0,0 +1,15 @@
# SPDX-FileCopyrightText: Copyright 2025 shadPS4 Emulator Project
# SPDX-License-Identifier: GPL-2.0-or-later
find_package(PkgConfig QUIET)
pkg_search_module(LIBUSB QUIET IMPORTED_TARGET libusb-1.0)
include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(libusb
REQUIRED_VARS LIBUSB_LINK_LIBRARIES
VERSION_VAR LIBUSB_VERSION
)
if (libusb_FOUND AND NOT TARGET libusb::usb)
add_library(libusb::usb ALIAS PkgConfig::LIBUSB)
endif()

View file

@ -201,6 +201,12 @@ if (NOT TARGET pugixml::pugixml)
add_subdirectory(pugixml)
endif()
# libusb
if (NOT TARGET libusb::usb)
add_subdirectory(libusb)
add_library(libusb::usb ALIAS usb-1.0)
endif()
# Discord RPC
if (ENABLE_DISCORD_RPC)
add_subdirectory(discord-rpc)

@ -1 +1 @@
Subproject commit 51b09d426a4a1bcfa6ee6d4894e57d669f4a2e65
Subproject commit d3b5af8827031f3bccbf8c15d5dc1bfdc9467f17

1
externals/libusb vendored Submodule

@ -0,0 +1 @@
Subproject commit 8f0b4a38fc3eefa2b26a99dff89e1c12bf37afd4

2
externals/sirit vendored

@ -1 +1 @@
Subproject commit 8b9b12c2089505ac8b10fa56bf56b3ed49d9d7b0
Subproject commit 427a42c9ed99b38204d9107bc3dc14e92458acf1

View file

@ -22,10 +22,6 @@
#include <windows.h>
#else
#include <pthread.h>
#ifdef __APPLE__
#include <half.hpp>
#include <sys/sysctl.h>
#endif
#endif
using namespace Xbyak::util;
@ -81,538 +77,6 @@ static Xbyak::Address ZydisToXbyakMemoryOperand(const ZydisDecodedOperand& opera
return ptr[expression];
}
static u64 ZydisToXbyakImmediateOperand(const ZydisDecodedOperand& operand) {
ASSERT_MSG(operand.type == ZYDIS_OPERAND_TYPE_IMMEDIATE,
"Expected immediate operand, got type: {}", static_cast<u32>(operand.type));
return operand.imm.value.u;
}
static std::unique_ptr<Xbyak::Operand> ZydisToXbyakOperand(const ZydisDecodedOperand& operand) {
switch (operand.type) {
case ZYDIS_OPERAND_TYPE_REGISTER: {
return std::make_unique<Xbyak::Reg>(ZydisToXbyakRegisterOperand(operand));
}
case ZYDIS_OPERAND_TYPE_MEMORY: {
return std::make_unique<Xbyak::Address>(ZydisToXbyakMemoryOperand(operand));
}
default:
UNREACHABLE_MSG("Unsupported operand type: {}", static_cast<u32>(operand.type));
}
}
static bool OperandUsesRegister(const Xbyak::Operand* operand, int index) {
if (operand->isREG()) {
return operand->getIdx() == index;
}
if (operand->isMEM()) {
const Xbyak::RegExp& reg_exp = operand->getAddress().getRegExp();
return reg_exp.getBase().getIdx() == index || reg_exp.getIndex().getIdx() == index;
}
UNREACHABLE_MSG("Unsupported operand kind: {}", static_cast<u32>(operand->getKind()));
}
static bool IsRegisterAllocated(
const std::initializer_list<const Xbyak::Operand*>& allocated_registers, const int index) {
return std::ranges::find_if(allocated_registers.begin(), allocated_registers.end(),
[index](const Xbyak::Operand* operand) {
return OperandUsesRegister(operand, index);
}) != allocated_registers.end();
}
static Xbyak::Reg AllocateScratchRegister(
const std::initializer_list<const Xbyak::Operand*> allocated_registers, const u32 bits) {
for (int index = Xbyak::Operand::R8; index <= Xbyak::Operand::R15; index++) {
if (!IsRegisterAllocated(allocated_registers, index)) {
return Xbyak::Reg32e(index, static_cast<int>(bits));
}
}
UNREACHABLE_MSG("Out of scratch registers!");
}
#ifdef __APPLE__
static pthread_key_t stack_pointer_slot;
static pthread_key_t patch_stack_slot;
static std::once_flag patch_context_slots_init_flag;
static constexpr u32 patch_stack_size = 0x1000;
static_assert(sizeof(void*) == sizeof(u64),
"Cannot fit a register inside a thread local storage slot.");
static void FreePatchStack(void* patch_stack) {
// Subtract back to the bottom of the stack for free.
std::free(static_cast<u8*>(patch_stack) - patch_stack_size);
}
static void InitializePatchContextSlots() {
ASSERT_MSG(pthread_key_create(&stack_pointer_slot, nullptr) == 0,
"Unable to allocate thread-local register for stack pointer.");
ASSERT_MSG(pthread_key_create(&patch_stack_slot, FreePatchStack) == 0,
"Unable to allocate thread-local register for patch stack.");
}
void InitializeThreadPatchStack() {
std::call_once(patch_context_slots_init_flag, InitializePatchContextSlots);
pthread_setspecific(patch_stack_slot,
static_cast<u8*>(std::malloc(patch_stack_size)) + patch_stack_size);
}
/// Saves the stack pointer to thread local storage and loads the patch stack.
static void SaveStack(Xbyak::CodeGenerator& c) {
std::call_once(patch_context_slots_init_flag, InitializePatchContextSlots);
// Save original stack pointer and load patch stack.
c.putSeg(gs);
c.mov(qword[reinterpret_cast<void*>(stack_pointer_slot * sizeof(void*))], rsp);
c.putSeg(gs);
c.mov(rsp, qword[reinterpret_cast<void*>(patch_stack_slot * sizeof(void*))]);
}
/// Restores the stack pointer from thread local storage.
static void RestoreStack(Xbyak::CodeGenerator& c) {
std::call_once(patch_context_slots_init_flag, InitializePatchContextSlots);
// Save patch stack pointer and load original stack.
c.putSeg(gs);
c.mov(qword[reinterpret_cast<void*>(patch_stack_slot * sizeof(void*))], rsp);
c.putSeg(gs);
c.mov(rsp, qword[reinterpret_cast<void*>(stack_pointer_slot * sizeof(void*))]);
}
/// Validates that the dst register is supported given the SaveStack/RestoreStack implementation.
static void ValidateDst(const Xbyak::Reg& dst) {
// No restrictions.
}
#else
void InitializeThreadPatchStack() {
// No-op
}
// NOTE: Since stack pointer here is subtracted through safe zone and not saved anywhere,
// it must not be modified during the instruction. Otherwise, we will not be able to find
// and load registers back from where they were saved. Thus, a limitation is placed on
// instructions, that they must not use the stack pointer register as a destination.
/// Saves the stack pointer to thread local storage and loads the patch stack.
static void SaveStack(Xbyak::CodeGenerator& c) {
c.lea(rsp, ptr[rsp - 128]); // red zone
}
/// Restores the stack pointer from thread local storage.
static void RestoreStack(Xbyak::CodeGenerator& c) {
c.lea(rsp, ptr[rsp + 128]); // red zone
}
/// Validates that the dst register is supported given the SaveStack/RestoreStack implementation.
static void ValidateDst(const Xbyak::Reg& dst) {
// Stack pointer is not preserved, so it can't be used as a dst.
ASSERT_MSG(dst.getIdx() != rsp.getIdx(), "Stack pointer not supported as destination.");
}
#endif
/// Switches to the patch stack, saves registers, and restores the original stack.
static void SaveRegisters(Xbyak::CodeGenerator& c, const std::initializer_list<Xbyak::Reg> regs) {
// Uses a more robust solution for saving registers on MacOS to avoid potential stack corruption
// if games decide to not follow the ABI and use the red zone.
SaveStack(c);
for (const auto& reg : regs) {
c.push(reg.cvt64());
}
RestoreStack(c);
}
/// Switches to the patch stack, restores registers, and restores the original stack.
static void RestoreRegisters(Xbyak::CodeGenerator& c,
const std::initializer_list<Xbyak::Reg> regs) {
SaveStack(c);
for (const auto& reg : regs) {
c.pop(reg.cvt64());
}
RestoreStack(c);
}
/// Switches to the patch stack and stores all registers.
static void SaveContext(Xbyak::CodeGenerator& c, bool save_flags = false) {
SaveStack(c);
for (int reg = Xbyak::Operand::RAX; reg <= Xbyak::Operand::R15; reg++) {
c.push(Xbyak::Reg64(reg));
}
c.lea(rsp, ptr[rsp - 32 * 16]);
for (int reg = 0; reg <= 15; reg++) {
c.vmovdqu(ptr[rsp + 32 * reg], Xbyak::Ymm(reg));
}
if (save_flags) {
c.pushfq();
}
}
/// Restores all registers and restores the original stack.
/// If the destination is a register, it is not restored to preserve the output.
static void RestoreContext(Xbyak::CodeGenerator& c, const Xbyak::Operand& dst,
bool restore_flags = false) {
if (restore_flags) {
c.popfq();
}
for (int reg = 15; reg >= 0; reg--) {
if ((!dst.isXMM() && !dst.isYMM()) || dst.getIdx() != reg) {
c.vmovdqu(Xbyak::Ymm(reg), ptr[rsp + 32 * reg]);
}
}
c.lea(rsp, ptr[rsp + 32 * 16]);
for (int reg = Xbyak::Operand::R15; reg >= Xbyak::Operand::RAX; reg--) {
if (!dst.isREG() || dst.getIdx() != reg) {
c.pop(Xbyak::Reg64(reg));
} else {
c.lea(rsp, ptr[rsp + 8]);
}
}
RestoreStack(c);
}
static void GenerateANDN(const ZydisDecodedOperand* operands, Xbyak::CodeGenerator& c) {
const auto dst = ZydisToXbyakRegisterOperand(operands[0]);
const auto src1 = ZydisToXbyakRegisterOperand(operands[1]);
const auto src2 = ZydisToXbyakOperand(operands[2]);
ValidateDst(dst);
// Check if src2 is a memory operand or a register different to dst.
// In those cases, we don't need to use a temporary register and are free to modify dst.
// In cases where dst and src2 are the same register, a temporary needs to be used to avoid
// modifying src2.
bool src2_uses_dst = false;
if (src2->isMEM()) {
const auto base = src2->getAddress().getRegExp().getBase().getIdx();
const auto index = src2->getAddress().getRegExp().getIndex().getIdx();
src2_uses_dst = base == dst.getIdx() || index == dst.getIdx();
} else {
ASSERT(src2->isREG());
src2_uses_dst = src2->getReg() == dst;
}
if (!src2_uses_dst) {
if (dst != src1)
c.mov(dst, src1);
c.not_(dst);
c.and_(dst, *src2);
} else {
const auto scratch = AllocateScratchRegister({&dst, &src1, src2.get()}, dst.getBit());
SaveRegisters(c, {scratch});
c.mov(scratch, src1);
c.not_(scratch);
c.and_(scratch, *src2);
c.mov(dst, scratch);
RestoreRegisters(c, {scratch});
}
}
static void GenerateBEXTR(const ZydisDecodedOperand* operands, Xbyak::CodeGenerator& c) {
const auto dst = ZydisToXbyakRegisterOperand(operands[0]);
const auto src = ZydisToXbyakOperand(operands[1]);
const auto start_len = ZydisToXbyakRegisterOperand(operands[2]);
ValidateDst(dst);
const Xbyak::Reg32e shift(Xbyak::Operand::RCX, static_cast<int>(start_len.getBit()));
const auto scratch1 =
AllocateScratchRegister({&dst, src.get(), &start_len, &shift}, dst.getBit());
const auto scratch2 =
AllocateScratchRegister({&dst, src.get(), &start_len, &shift, &scratch1}, dst.getBit());
if (dst.getIdx() == shift.getIdx()) {
SaveRegisters(c, {scratch1, scratch2});
} else {
SaveRegisters(c, {scratch1, scratch2, shift});
}
c.mov(scratch1, *src);
if (shift.getIdx() != start_len.getIdx()) {
c.mov(shift, start_len);
}
c.shr(scratch1, shift.cvt8());
c.shr(shift, 8);
c.mov(scratch2, 1);
c.shl(scratch2, shift.cvt8());
c.dec(scratch2);
c.mov(dst, scratch1);
c.and_(dst, scratch2);
if (dst.getIdx() == shift.getIdx()) {
RestoreRegisters(c, {scratch2, scratch1});
} else {
RestoreRegisters(c, {shift, scratch2, scratch1});
}
}
static void GenerateBLSI(const ZydisDecodedOperand* operands, Xbyak::CodeGenerator& c) {
const auto dst = ZydisToXbyakRegisterOperand(operands[0]);
const auto src = ZydisToXbyakOperand(operands[1]);
ValidateDst(dst);
const auto scratch = AllocateScratchRegister({&dst, src.get()}, dst.getBit());
SaveRegisters(c, {scratch});
// BLSI sets CF to zero if source is zero, otherwise it sets CF to one.
Xbyak::Label clear_carry, end;
c.mov(scratch, *src);
c.neg(scratch); // NEG, like BLSI, clears CF if the source is zero and sets it otherwise
c.jnc(clear_carry);
c.and_(scratch, *src);
c.stc(); // setting/clearing carry needs to happen after the AND because that clears CF
c.jmp(end);
c.L(clear_carry);
c.and_(scratch, *src);
// We don't need to clear carry here since AND does that for us
c.L(end);
c.mov(dst, scratch);
RestoreRegisters(c, {scratch});
}
static void GenerateBLSMSK(const ZydisDecodedOperand* operands, Xbyak::CodeGenerator& c) {
const auto dst = ZydisToXbyakRegisterOperand(operands[0]);
const auto src = ZydisToXbyakOperand(operands[1]);
ValidateDst(dst);
const auto scratch = AllocateScratchRegister({&dst, src.get()}, dst.getBit());
SaveRegisters(c, {scratch});
Xbyak::Label clear_carry, end;
// BLSMSK sets CF to zero if source is NOT zero, otherwise it sets CF to one.
c.mov(scratch, *src);
c.test(scratch, scratch);
c.jnz(clear_carry);
c.dec(scratch);
c.xor_(scratch, *src);
c.stc();
c.jmp(end);
c.L(clear_carry);
c.dec(scratch);
c.xor_(scratch, *src);
// We don't need to clear carry here since XOR does that for us
c.L(end);
c.mov(dst, scratch);
RestoreRegisters(c, {scratch});
}
static void GenerateTZCNT(const ZydisDecodedOperand* operands, Xbyak::CodeGenerator& c) {
const auto dst = ZydisToXbyakRegisterOperand(operands[0]);
const auto src = ZydisToXbyakOperand(operands[1]);
ValidateDst(dst);
Xbyak::Label src_zero, end;
c.cmp(*src, 0);
c.je(src_zero);
// If src is not zero, functions like a BSF, but also clears the CF
c.bsf(dst, *src);
c.clc();
c.jmp(end);
c.L(src_zero);
c.mov(dst, operands[0].size);
// Since dst is not zero, also set ZF to zero. Testing dst with itself when we know
// it isn't zero is a good way to do this.
// Use cvt32 to avoid REX/Operand size prefixes.
c.test(dst.cvt32(), dst.cvt32());
// When source is zero, TZCNT also sets CF.
c.stc();
c.L(end);
}
static void GenerateBLSR(const ZydisDecodedOperand* operands, Xbyak::CodeGenerator& c) {
const auto dst = ZydisToXbyakRegisterOperand(operands[0]);
const auto src = ZydisToXbyakOperand(operands[1]);
ValidateDst(dst);
const auto scratch = AllocateScratchRegister({&dst, src.get()}, dst.getBit());
SaveRegisters(c, {scratch});
Xbyak::Label clear_carry, end;
// BLSR sets CF to zero if source is NOT zero, otherwise it sets CF to one.
c.mov(scratch, *src);
c.test(scratch, scratch);
c.jnz(clear_carry);
c.dec(scratch);
c.and_(scratch, *src);
c.stc();
c.jmp(end);
c.L(clear_carry);
c.dec(scratch);
c.and_(scratch, *src);
// We don't need to clear carry here since AND does that for us
c.L(end);
c.mov(dst, scratch);
RestoreRegisters(c, {scratch});
}
#ifdef __APPLE__
static __attribute__((sysv_abi)) void PerformVCVTPH2PS(float* out, const half_float::half* in,
const u32 count) {
for (u32 i = 0; i < count; i++) {
out[i] = half_float::half_cast<float>(in[i]);
}
}
static void GenerateVCVTPH2PS(const ZydisDecodedOperand* operands, Xbyak::CodeGenerator& c) {
const auto dst = ZydisToXbyakRegisterOperand(operands[0]);
const auto src = ZydisToXbyakOperand(operands[1]);
const auto float_count = dst.getBit() / 32;
const auto byte_count = float_count * 4;
SaveContext(c, true);
// Allocate stack space for outputs and load into first parameter.
c.sub(rsp, byte_count);
c.mov(rdi, rsp);
if (src->isXMM()) {
// Allocate stack space for inputs and load into second parameter.
c.sub(rsp, byte_count);
c.mov(rsi, rsp);
// Move input to the allocated space.
c.movdqu(ptr[rsp], *reinterpret_cast<Xbyak::Xmm*>(src.get()));
} else {
c.lea(rsi, src->getAddress());
}
// Load float count into third parameter.
c.mov(rdx, float_count);
c.mov(rax, reinterpret_cast<u64>(PerformVCVTPH2PS));
c.call(rax);
if (src->isXMM()) {
// Clean up after inputs space.
c.add(rsp, byte_count);
}
// Load outputs into destination register and clean up space.
if (dst.isYMM()) {
c.vmovdqu(*reinterpret_cast<const Xbyak::Ymm*>(&dst), ptr[rsp]);
} else {
c.movdqu(*reinterpret_cast<const Xbyak::Xmm*>(&dst), ptr[rsp]);
}
c.add(rsp, byte_count);
RestoreContext(c, dst, true);
}
using SingleToHalfFloatConverter = half_float::half (*)(float);
static const SingleToHalfFloatConverter SingleToHalfFloatConverters[4] = {
half_float::half_cast<half_float::half, std::round_to_nearest, float>,
half_float::half_cast<half_float::half, std::round_toward_neg_infinity, float>,
half_float::half_cast<half_float::half, std::round_toward_infinity, float>,
half_float::half_cast<half_float::half, std::round_toward_zero, float>,
};
static __attribute__((sysv_abi)) void PerformVCVTPS2PH(half_float::half* out, const float* in,
const u32 count, const u8 rounding_mode) {
const auto conversion_func = SingleToHalfFloatConverters[rounding_mode];
for (u32 i = 0; i < count; i++) {
out[i] = conversion_func(in[i]);
}
}
static void GenerateVCVTPS2PH(const ZydisDecodedOperand* operands, Xbyak::CodeGenerator& c) {
const auto dst = ZydisToXbyakOperand(operands[0]);
const auto src = ZydisToXbyakRegisterOperand(operands[1]);
const auto ctrl = ZydisToXbyakImmediateOperand(operands[2]);
const auto float_count = src.getBit() / 32;
const auto byte_count = float_count * 4;
SaveContext(c, true);
if (dst->isXMM()) {
// Allocate stack space for outputs and load into first parameter.
c.sub(rsp, byte_count);
c.mov(rdi, rsp);
} else {
c.lea(rdi, dst->getAddress());
}
// Allocate stack space for inputs and load into second parameter.
c.sub(rsp, byte_count);
c.mov(rsi, rsp);
// Move input to the allocated space.
if (src.isYMM()) {
c.vmovdqu(ptr[rsp], *reinterpret_cast<const Xbyak::Ymm*>(&src));
} else {
c.movdqu(ptr[rsp], *reinterpret_cast<const Xbyak::Xmm*>(&src));
}
// Load float count into third parameter.
c.mov(rdx, float_count);
// Load rounding mode into fourth parameter.
if (ctrl & 4) {
// Load from MXCSR.RC.
c.stmxcsr(ptr[rsp - 4]);
c.mov(rcx, ptr[rsp - 4]);
c.shr(rcx, 13);
c.and_(rcx, 3);
} else {
c.mov(rcx, ctrl & 3);
}
c.mov(rax, reinterpret_cast<u64>(PerformVCVTPS2PH));
c.call(rax);
// Clean up after inputs space.
c.add(rsp, byte_count);
if (dst->isXMM()) {
// Load outputs into destination register and clean up space.
c.movdqu(*reinterpret_cast<Xbyak::Xmm*>(dst.get()), ptr[rsp]);
c.add(rsp, byte_count);
}
RestoreContext(c, *dst, true);
}
static bool FilterRosetta2Only(const ZydisDecodedOperand*) {
int ret = 0;
size_t size = sizeof(ret);
if (sysctlbyname("sysctl.proc_translated", &ret, &size, nullptr, 0) != 0) {
return false;
}
return ret;
}
#else // __APPLE__
static bool FilterTcbAccess(const ZydisDecodedOperand* operands) {
const auto& dst_op = operands[0];
const auto& src_op = operands[1];
@ -657,18 +121,11 @@ static void GenerateTcbAccess(const ZydisDecodedOperand* operands, Xbyak::CodeGe
#endif
}
#endif // __APPLE__
static bool FilterNoSSE4a(const ZydisDecodedOperand*) {
Cpu cpu;
return !cpu.has(Cpu::tSSE4a);
}
static bool FilterNoBMI1(const ZydisDecodedOperand*) {
Cpu cpu;
return !cpu.has(Cpu::tBMI1);
}
static void GenerateEXTRQ(const ZydisDecodedOperand* operands, Xbyak::CodeGenerator& c) {
bool immediateForm = operands[1].type == ZYDIS_OPERAND_TYPE_IMMEDIATE &&
operands[2].type == ZYDIS_OPERAND_TYPE_IMMEDIATE;
@ -940,30 +397,16 @@ struct PatchInfo {
};
static const std::unordered_map<ZydisMnemonic, PatchInfo> Patches = {
// SSE4a
{ZYDIS_MNEMONIC_EXTRQ, {FilterNoSSE4a, GenerateEXTRQ, true}},
{ZYDIS_MNEMONIC_INSERTQ, {FilterNoSSE4a, GenerateINSERTQ, true}},
#if defined(_WIN32)
// Windows needs a trampoline.
{ZYDIS_MNEMONIC_MOV, {FilterTcbAccess, GenerateTcbAccess, true}},
#elif !defined(__APPLE__)
{ZYDIS_MNEMONIC_MOV, {FilterTcbAccess, GenerateTcbAccess, false}},
#endif
{ZYDIS_MNEMONIC_EXTRQ, {FilterNoSSE4a, GenerateEXTRQ, true}},
{ZYDIS_MNEMONIC_INSERTQ, {FilterNoSSE4a, GenerateINSERTQ, true}},
// BMI1
{ZYDIS_MNEMONIC_ANDN, {FilterNoBMI1, GenerateANDN, true}},
{ZYDIS_MNEMONIC_BEXTR, {FilterNoBMI1, GenerateBEXTR, true}},
{ZYDIS_MNEMONIC_BLSI, {FilterNoBMI1, GenerateBLSI, true}},
{ZYDIS_MNEMONIC_BLSMSK, {FilterNoBMI1, GenerateBLSMSK, true}},
{ZYDIS_MNEMONIC_BLSR, {FilterNoBMI1, GenerateBLSR, true}},
{ZYDIS_MNEMONIC_TZCNT, {FilterNoBMI1, GenerateTZCNT, true}},
#ifdef __APPLE__
// Patches for instruction sets not supported by Rosetta 2.
// F16C
{ZYDIS_MNEMONIC_VCVTPH2PS, {FilterRosetta2Only, GenerateVCVTPH2PS, true}},
{ZYDIS_MNEMONIC_VCVTPS2PH, {FilterRosetta2Only, GenerateVCVTPS2PH, true}},
#endif
};
static std::once_flag init_flag;
@ -1280,18 +723,7 @@ void RegisterPatchModule(void* module_ptr, u64 module_size, void* trampoline_are
}
void PrePatchInstructions(u64 segment_addr, u64 segment_size) {
#if defined(__APPLE__)
// HACK: For some reason patching in the signal handler at the start of a page does not work
// under Rosetta 2. Patch any instructions at the start of a page ahead of time.
if (!Patches.empty()) {
auto* code_page = reinterpret_cast<u8*>(Common::AlignUp(segment_addr, 0x1000));
const auto* end_page = code_page + Common::AlignUp(segment_size, 0x1000);
while (code_page < end_page) {
TryPatchJit(code_page);
code_page += 0x1000;
}
}
#elif !defined(_WIN32)
#if !defined(_WIN32) && !defined(__APPLE__)
// Linux and others have an FS segment pointing to valid memory, so continue to do full
// ahead-of-time patching for now until a better solution is worked out.
if (!Patches.empty()) {

View file

@ -7,12 +7,6 @@
namespace Core {
/// Initializes a stack for the current thread for use by patch implementations.
void InitializeThreadPatchStack();
/// Cleans up the patch stack for the current thread.
void CleanupThreadPatchStack();
/// Registers a module for patching, providing an area to generate trampoline code.
void RegisterPatchModule(void* module_ptr, u64 module_size, void* trampoline_area_ptr,
u64 trampoline_area_size);

View file

@ -190,16 +190,16 @@ s32 PS4_SYSV_ABI sceKernelOpen(const char* path, s32 flags, /* SceKernelMode*/ u
}
s32 PS4_SYSV_ABI close(s32 fd) {
if (fd < 3) {
// This is technically possible, but it's usually caused by some stubbed function instead.
LOG_WARNING(Kernel_Fs, "called on an std handle, fd = {}", fd);
}
auto* h = Common::Singleton<Core::FileSys::HandleTable>::Instance();
auto* file = h->GetFile(fd);
if (file == nullptr) {
*__Error() = POSIX_EBADF;
return -1;
}
if (fd < 3) {
// This is technically possible, but it's usually caused by some stubbed function instead.
LOG_WARNING(Kernel_Fs, "called on an std handle, fd = {}", fd);
}
if (file->type == Core::FileSys::FileType::Regular) {
file->f.Close();
}

View file

@ -50,6 +50,7 @@
#include "core/libraries/system/sysmodule.h"
#include "core/libraries/system/systemservice.h"
#include "core/libraries/system/userservice.h"
#include "core/libraries/ulobjmgr/ulobjmgr.h"
#include "core/libraries/usbd/usbd.h"
#include "core/libraries/videodec/videodec.h"
#include "core/libraries/videodec/videodec2.h"
@ -116,6 +117,7 @@ void InitHLELibs(Core::Loader::SymbolsResolver* sym) {
Libraries::Zlib::RegisterlibSceZlib(sym);
Libraries::Hmd::RegisterlibSceHmd(sym);
Libraries::DiscMap::RegisterlibSceDiscMap(sym);
Libraries::Ulobjmgr::RegisterlibSceUlobjmgr(sym);
}
} // namespace Libraries

View file

@ -18,36 +18,32 @@ namespace Libraries::Ngs2 {
s32 PS4_SYSV_ABI sceNgs2CalcWaveformBlock(const OrbisNgs2WaveformFormat* format, u32 samplePos,
u32 numSamples, OrbisNgs2WaveformBlock* outBlock) {
LOG_INFO(Lib_Ngs2, "samplePos = {}, numSamples = {}", samplePos, numSamples);
LOG_ERROR(Lib_Ngs2, "samplePos = {}, numSamples = {}", samplePos, numSamples);
return ORBIS_OK;
}
s32 PS4_SYSV_ABI sceNgs2GetWaveformFrameInfo(const OrbisNgs2WaveformFormat* format,
u32* outFrameSize, u32* outNumFrameSamples,
u32* outUnitsPerFrame, u32* outNumDelaySamples) {
LOG_INFO(Lib_Ngs2, "called");
LOG_ERROR(Lib_Ngs2, "called");
return ORBIS_OK;
}
s32 PS4_SYSV_ABI sceNgs2ParseWaveformData(const void* data, size_t dataSize,
OrbisNgs2WaveformInfo* outInfo) {
LOG_INFO(Lib_Ngs2, "dataSize = {}", dataSize);
LOG_ERROR(Lib_Ngs2, "dataSize = {}", dataSize);
return ORBIS_OK;
}
s32 PS4_SYSV_ABI sceNgs2ParseWaveformFile(const char* path, u64 offset,
OrbisNgs2WaveformInfo* outInfo) {
LOG_INFO(Lib_Ngs2, "path = {}, offset = {}", path, offset);
LOG_ERROR(Lib_Ngs2, "path = {}, offset = {}", path, offset);
return ORBIS_OK;
}
s32 PS4_SYSV_ABI sceNgs2ParseWaveformUser(OrbisNgs2ParseReadHandler handler, uintptr_t userData,
OrbisNgs2WaveformInfo* outInfo) {
LOG_INFO(Lib_Ngs2, "userData = {}", userData);
if (!handler) {
LOG_ERROR(Lib_Ngs2, "handler is nullptr");
return ORBIS_NGS2_ERROR_INVALID_HANDLE;
}
LOG_ERROR(Lib_Ngs2, "userData = {}", userData);
return ORBIS_OK;
}
@ -55,7 +51,7 @@ s32 PS4_SYSV_ABI sceNgs2RackCreate(OrbisNgs2Handle systemHandle, u32 rackId,
const OrbisNgs2RackOption* option,
const OrbisNgs2ContextBufferInfo* bufferInfo,
OrbisNgs2Handle* outHandle) {
LOG_INFO(Lib_Ngs2, "rackId = {}", rackId);
LOG_ERROR(Lib_Ngs2, "rackId = {}", rackId);
if (!systemHandle) {
LOG_ERROR(Lib_Ngs2, "systemHandle is nullptr");
return ORBIS_NGS2_ERROR_INVALID_SYSTEM_HANDLE;
@ -67,7 +63,7 @@ s32 PS4_SYSV_ABI sceNgs2RackCreateWithAllocator(OrbisNgs2Handle systemHandle, u3
const OrbisNgs2RackOption* option,
const OrbisNgs2BufferAllocator* allocator,
OrbisNgs2Handle* outHandle) {
LOG_INFO(Lib_Ngs2, "rackId = {}", rackId);
LOG_ERROR(Lib_Ngs2, "rackId = {}", rackId);
if (!systemHandle) {
LOG_ERROR(Lib_Ngs2, "systemHandle is nullptr");
return ORBIS_NGS2_ERROR_INVALID_SYSTEM_HANDLE;
@ -77,73 +73,45 @@ s32 PS4_SYSV_ABI sceNgs2RackCreateWithAllocator(OrbisNgs2Handle systemHandle, u3
s32 PS4_SYSV_ABI sceNgs2RackDestroy(OrbisNgs2Handle rackHandle,
OrbisNgs2ContextBufferInfo* outBufferInfo) {
if (!rackHandle) {
LOG_ERROR(Lib_Ngs2, "rackHandle is nullptr");
return ORBIS_NGS2_ERROR_INVALID_RACK_HANDLE;
}
LOG_INFO(Lib_Ngs2, "called");
LOG_ERROR(Lib_Ngs2, "called");
return ORBIS_OK;
}
s32 PS4_SYSV_ABI sceNgs2RackGetInfo(OrbisNgs2Handle rackHandle, OrbisNgs2RackInfo* outInfo,
size_t infoSize) {
LOG_INFO(Lib_Ngs2, "infoSize = {}", infoSize);
if (!rackHandle) {
LOG_ERROR(Lib_Ngs2, "rackHandle is nullptr");
return ORBIS_NGS2_ERROR_INVALID_RACK_HANDLE;
}
LOG_ERROR(Lib_Ngs2, "infoSize = {}", infoSize);
return ORBIS_OK;
}
s32 PS4_SYSV_ABI sceNgs2RackGetUserData(OrbisNgs2Handle rackHandle, uintptr_t* outUserData) {
if (!rackHandle) {
LOG_ERROR(Lib_Ngs2, "rackHandle is nullptr");
return ORBIS_NGS2_ERROR_INVALID_RACK_HANDLE;
}
LOG_INFO(Lib_Ngs2, "called");
LOG_ERROR(Lib_Ngs2, "called");
return ORBIS_OK;
}
s32 PS4_SYSV_ABI sceNgs2RackGetVoiceHandle(OrbisNgs2Handle rackHandle, u32 voiceIndex,
OrbisNgs2Handle* outHandle) {
LOG_INFO(Lib_Ngs2, "voiceIndex = {}", voiceIndex);
if (!rackHandle) {
LOG_ERROR(Lib_Ngs2, "rackHandle is nullptr");
return ORBIS_NGS2_ERROR_INVALID_RACK_HANDLE;
}
LOG_DEBUG(Lib_Ngs2, "(STUBBED) voiceIndex = {}", voiceIndex);
return ORBIS_OK;
}
s32 PS4_SYSV_ABI sceNgs2RackLock(OrbisNgs2Handle rackHandle) {
if (!rackHandle) {
LOG_ERROR(Lib_Ngs2, "rackHandle is nullptr");
return ORBIS_NGS2_ERROR_INVALID_RACK_HANDLE;
}
LOG_INFO(Lib_Ngs2, "called");
LOG_ERROR(Lib_Ngs2, "called");
return ORBIS_OK;
}
s32 PS4_SYSV_ABI sceNgs2RackQueryBufferSize(u32 rackId, const OrbisNgs2RackOption* option,
OrbisNgs2ContextBufferInfo* outBufferInfo) {
LOG_INFO(Lib_Ngs2, "rackId = {}", rackId);
LOG_ERROR(Lib_Ngs2, "rackId = {}", rackId);
return ORBIS_OK;
}
s32 PS4_SYSV_ABI sceNgs2RackSetUserData(OrbisNgs2Handle rackHandle, uintptr_t userData) {
LOG_INFO(Lib_Ngs2, "userData = {}", userData);
if (!rackHandle) {
LOG_ERROR(Lib_Ngs2, "rackHandle is nullptr");
return ORBIS_NGS2_ERROR_INVALID_RACK_HANDLE;
}
LOG_ERROR(Lib_Ngs2, "userData = {}", userData);
return ORBIS_OK;
}
s32 PS4_SYSV_ABI sceNgs2RackUnlock(OrbisNgs2Handle rackHandle) {
if (!rackHandle) {
LOG_ERROR(Lib_Ngs2, "rackHandle is nullptr");
return ORBIS_NGS2_ERROR_INVALID_RACK_HANDLE;
}
LOG_INFO(Lib_Ngs2, "called");
LOG_ERROR(Lib_Ngs2, "called");
return ORBIS_OK;
}
@ -188,17 +156,17 @@ s32 PS4_SYSV_ABI sceNgs2SystemCreateWithAllocator(const OrbisNgs2SystemOption* o
OrbisNgs2BufferAllocHandler hostAlloc = allocator->allocHandler;
if (outHandle) {
OrbisNgs2BufferFreeHandler hostFree = allocator->freeHandler;
OrbisNgs2ContextBufferInfo* bufferInfo = 0;
result = SystemSetup(option, bufferInfo, 0, 0);
OrbisNgs2ContextBufferInfo bufferInfo;
result = SystemSetup(option, &bufferInfo, 0, 0);
if (result >= 0) {
uintptr_t sysUserData = allocator->userData;
result = hostAlloc(bufferInfo);
result = Core::ExecuteGuest(hostAlloc, &bufferInfo);
if (result >= 0) {
OrbisNgs2Handle* handleCopy = outHandle;
result = SystemSetup(option, bufferInfo, hostFree, handleCopy);
result = SystemSetup(option, &bufferInfo, hostFree, handleCopy);
if (result < 0) {
if (hostFree) {
hostFree(bufferInfo);
Core::ExecuteGuest(hostFree, &bufferInfo);
}
}
}
@ -226,13 +194,13 @@ s32 PS4_SYSV_ABI sceNgs2SystemDestroy(OrbisNgs2Handle systemHandle,
}
s32 PS4_SYSV_ABI sceNgs2SystemEnumHandles(OrbisNgs2Handle* aOutHandle, u32 maxHandles) {
LOG_INFO(Lib_Ngs2, "maxHandles = {}", maxHandles);
LOG_ERROR(Lib_Ngs2, "maxHandles = {}", maxHandles);
return ORBIS_OK;
}
s32 PS4_SYSV_ABI sceNgs2SystemEnumRackHandles(OrbisNgs2Handle systemHandle,
OrbisNgs2Handle* aOutHandle, u32 maxHandles) {
LOG_INFO(Lib_Ngs2, "maxHandles = {}", maxHandles);
LOG_ERROR(Lib_Ngs2, "maxHandles = {}", maxHandles);
if (!systemHandle) {
LOG_ERROR(Lib_Ngs2, "systemHandle is nullptr");
return ORBIS_NGS2_ERROR_INVALID_SYSTEM_HANDLE;
@ -242,11 +210,7 @@ s32 PS4_SYSV_ABI sceNgs2SystemEnumRackHandles(OrbisNgs2Handle systemHandle,
s32 PS4_SYSV_ABI sceNgs2SystemGetInfo(OrbisNgs2Handle rackHandle, OrbisNgs2SystemInfo* outInfo,
size_t infoSize) {
LOG_INFO(Lib_Ngs2, "infoSize = {}", infoSize);
if (!rackHandle) {
LOG_ERROR(Lib_Ngs2, "rackHandle is nullptr");
return ORBIS_NGS2_ERROR_INVALID_RACK_HANDLE;
}
LOG_ERROR(Lib_Ngs2, "infoSize = {}", infoSize);
return ORBIS_OK;
}
@ -255,7 +219,7 @@ s32 PS4_SYSV_ABI sceNgs2SystemGetUserData(OrbisNgs2Handle systemHandle, uintptr_
LOG_ERROR(Lib_Ngs2, "systemHandle is nullptr");
return ORBIS_NGS2_ERROR_INVALID_SYSTEM_HANDLE;
}
LOG_INFO(Lib_Ngs2, "called");
LOG_ERROR(Lib_Ngs2, "called");
return ORBIS_OK;
}
@ -264,7 +228,7 @@ s32 PS4_SYSV_ABI sceNgs2SystemLock(OrbisNgs2Handle systemHandle) {
LOG_ERROR(Lib_Ngs2, "systemHandle is nullptr");
return ORBIS_NGS2_ERROR_INVALID_SYSTEM_HANDLE;
}
LOG_INFO(Lib_Ngs2, "called");
LOG_ERROR(Lib_Ngs2, "called");
return ORBIS_OK;
}
@ -285,7 +249,7 @@ s32 PS4_SYSV_ABI sceNgs2SystemQueryBufferSize(const OrbisNgs2SystemOption* optio
s32 PS4_SYSV_ABI sceNgs2SystemRender(OrbisNgs2Handle systemHandle,
const OrbisNgs2RenderBufferInfo* aBufferInfo,
u32 numBufferInfo) {
LOG_INFO(Lib_Ngs2, "numBufferInfo = {}", numBufferInfo);
LOG_DEBUG(Lib_Ngs2, "(STUBBED) numBufferInfo = {}", numBufferInfo);
if (!systemHandle) {
LOG_ERROR(Lib_Ngs2, "systemHandle is nullptr");
return ORBIS_NGS2_ERROR_INVALID_SYSTEM_HANDLE;
@ -308,7 +272,7 @@ static s32 PS4_SYSV_ABI sceNgs2SystemResetOption(OrbisNgs2SystemOption* outOptio
}
s32 PS4_SYSV_ABI sceNgs2SystemSetGrainSamples(OrbisNgs2Handle systemHandle, u32 numSamples) {
LOG_INFO(Lib_Ngs2, "numSamples = {}", numSamples);
LOG_ERROR(Lib_Ngs2, "numSamples = {}", numSamples);
if (!systemHandle) {
LOG_ERROR(Lib_Ngs2, "systemHandle is nullptr");
return ORBIS_NGS2_ERROR_INVALID_SYSTEM_HANDLE;
@ -317,7 +281,7 @@ s32 PS4_SYSV_ABI sceNgs2SystemSetGrainSamples(OrbisNgs2Handle systemHandle, u32
}
s32 PS4_SYSV_ABI sceNgs2SystemSetSampleRate(OrbisNgs2Handle systemHandle, u32 sampleRate) {
LOG_INFO(Lib_Ngs2, "sampleRate = {}", sampleRate);
LOG_ERROR(Lib_Ngs2, "sampleRate = {}", sampleRate);
if (!systemHandle) {
LOG_ERROR(Lib_Ngs2, "systemHandle is nullptr");
return ORBIS_NGS2_ERROR_INVALID_SYSTEM_HANDLE;
@ -326,7 +290,7 @@ s32 PS4_SYSV_ABI sceNgs2SystemSetSampleRate(OrbisNgs2Handle systemHandle, u32 sa
}
s32 PS4_SYSV_ABI sceNgs2SystemSetUserData(OrbisNgs2Handle systemHandle, uintptr_t userData) {
LOG_INFO(Lib_Ngs2, "userData = {}", userData);
LOG_ERROR(Lib_Ngs2, "userData = {}", userData);
if (!systemHandle) {
LOG_ERROR(Lib_Ngs2, "systemHandle is nullptr");
return ORBIS_NGS2_ERROR_INVALID_SYSTEM_HANDLE;
@ -339,66 +303,42 @@ s32 PS4_SYSV_ABI sceNgs2SystemUnlock(OrbisNgs2Handle systemHandle) {
LOG_ERROR(Lib_Ngs2, "systemHandle is nullptr");
return ORBIS_NGS2_ERROR_INVALID_SYSTEM_HANDLE;
}
LOG_INFO(Lib_Ngs2, "called");
LOG_ERROR(Lib_Ngs2, "called");
return ORBIS_OK;
}
s32 PS4_SYSV_ABI sceNgs2VoiceControl(OrbisNgs2Handle voiceHandle,
const OrbisNgs2VoiceParamHeader* paramList) {
if (!voiceHandle) {
LOG_ERROR(Lib_Ngs2, "voiceHandle is nullptr");
return ORBIS_NGS2_ERROR_INVALID_VOICE_HANDLE;
}
LOG_INFO(Lib_Ngs2, "called");
LOG_ERROR(Lib_Ngs2, "called");
return ORBIS_OK;
}
s32 PS4_SYSV_ABI sceNgs2VoiceGetMatrixInfo(OrbisNgs2Handle voiceHandle, u32 matrixId,
OrbisNgs2VoiceMatrixInfo* outInfo, size_t outInfoSize) {
LOG_INFO(Lib_Ngs2, "matrixId = {}, outInfoSize = {}", matrixId, outInfoSize);
if (!voiceHandle) {
LOG_ERROR(Lib_Ngs2, "voiceHandle is nullptr");
return ORBIS_NGS2_ERROR_INVALID_VOICE_HANDLE;
}
LOG_ERROR(Lib_Ngs2, "matrixId = {}, outInfoSize = {}", matrixId, outInfoSize);
return ORBIS_OK;
}
s32 PS4_SYSV_ABI sceNgs2VoiceGetOwner(OrbisNgs2Handle voiceHandle, OrbisNgs2Handle* outRackHandle,
u32* outVoiceId) {
if (!voiceHandle) {
LOG_ERROR(Lib_Ngs2, "voiceHandle is nullptr");
return ORBIS_NGS2_ERROR_INVALID_VOICE_HANDLE;
}
LOG_INFO(Lib_Ngs2, "called");
LOG_ERROR(Lib_Ngs2, "called");
return ORBIS_OK;
}
s32 PS4_SYSV_ABI sceNgs2VoiceGetPortInfo(OrbisNgs2Handle voiceHandle, u32 port,
OrbisNgs2VoicePortInfo* outInfo, size_t outInfoSize) {
LOG_INFO(Lib_Ngs2, "port = {}, outInfoSize = {}", port, outInfoSize);
if (!voiceHandle) {
LOG_ERROR(Lib_Ngs2, "voiceHandle is nullptr");
return ORBIS_NGS2_ERROR_INVALID_VOICE_HANDLE;
}
LOG_ERROR(Lib_Ngs2, "port = {}, outInfoSize = {}", port, outInfoSize);
return ORBIS_OK;
}
s32 PS4_SYSV_ABI sceNgs2VoiceGetState(OrbisNgs2Handle voiceHandle, OrbisNgs2VoiceState* outState,
size_t stateSize) {
LOG_INFO(Lib_Ngs2, "stateSize = {}", stateSize);
if (!voiceHandle) {
LOG_ERROR(Lib_Ngs2, "voiceHandle is nullptr");
return ORBIS_NGS2_ERROR_INVALID_VOICE_HANDLE;
}
LOG_ERROR(Lib_Ngs2, "stateSize = {}", stateSize);
return ORBIS_OK;
}
s32 PS4_SYSV_ABI sceNgs2VoiceGetStateFlags(OrbisNgs2Handle voiceHandle, u32* outStateFlags) {
if (!voiceHandle) {
LOG_ERROR(Lib_Ngs2, "voiceHandle is nullptr");
return ORBIS_NGS2_ERROR_INVALID_VOICE_HANDLE;
}
LOG_INFO(Lib_Ngs2, "called");
LOG_ERROR(Lib_Ngs2, "called");
return ORBIS_OK;
}
@ -407,36 +347,32 @@ s32 PS4_SYSV_ABI sceNgs2VoiceGetStateFlags(OrbisNgs2Handle voiceHandle, u32* out
s32 PS4_SYSV_ABI sceNgs2CustomRackGetModuleInfo(OrbisNgs2Handle rackHandle, u32 moduleIndex,
OrbisNgs2CustomModuleInfo* outInfo,
size_t infoSize) {
LOG_INFO(Lib_Ngs2, "moduleIndex = {}, infoSize = {}", moduleIndex, infoSize);
if (!rackHandle) {
LOG_ERROR(Lib_Ngs2, "rackHandle is nullptr");
return ORBIS_NGS2_ERROR_INVALID_RACK_HANDLE;
}
LOG_ERROR(Lib_Ngs2, "moduleIndex = {}, infoSize = {}", moduleIndex, infoSize);
return ORBIS_OK;
}
// Ngs2Geom
s32 PS4_SYSV_ABI sceNgs2GeomResetListenerParam(OrbisNgs2GeomListenerParam* outListenerParam) {
LOG_INFO(Lib_Ngs2, "called");
LOG_ERROR(Lib_Ngs2, "called");
return ORBIS_OK;
}
s32 PS4_SYSV_ABI sceNgs2GeomResetSourceParam(OrbisNgs2GeomSourceParam* outSourceParam) {
LOG_INFO(Lib_Ngs2, "called");
LOG_ERROR(Lib_Ngs2, "called");
return ORBIS_OK;
}
s32 PS4_SYSV_ABI sceNgs2GeomCalcListener(const OrbisNgs2GeomListenerParam* param,
OrbisNgs2GeomListenerWork* outWork, u32 flags) {
LOG_INFO(Lib_Ngs2, "flags = {}", flags);
LOG_ERROR(Lib_Ngs2, "flags = {}", flags);
return ORBIS_OK;
}
s32 PS4_SYSV_ABI sceNgs2GeomApply(const OrbisNgs2GeomListenerWork* listener,
const OrbisNgs2GeomSourceParam* source,
OrbisNgs2GeomAttribute* outAttrib, u32 flags) {
LOG_INFO(Lib_Ngs2, "flags = {}", flags);
LOG_ERROR(Lib_Ngs2, "flags = {}", flags);
return ORBIS_OK;
}
@ -444,15 +380,15 @@ s32 PS4_SYSV_ABI sceNgs2GeomApply(const OrbisNgs2GeomListenerWork* listener,
s32 PS4_SYSV_ABI sceNgs2PanInit(OrbisNgs2PanWork* work, const float* aSpeakerAngle, float unitAngle,
u32 numSpeakers) {
LOG_INFO(Lib_Ngs2, "aSpeakerAngle = {}, unitAngle = {}, numSpeakers = {}", *aSpeakerAngle,
unitAngle, numSpeakers);
LOG_ERROR(Lib_Ngs2, "aSpeakerAngle = {}, unitAngle = {}, numSpeakers = {}", *aSpeakerAngle,
unitAngle, numSpeakers);
return ORBIS_OK;
}
s32 PS4_SYSV_ABI sceNgs2PanGetVolumeMatrix(OrbisNgs2PanWork* work, const OrbisNgs2PanParam* aParam,
u32 numParams, u32 matrixFormat,
float* outVolumeMatrix) {
LOG_INFO(Lib_Ngs2, "numParams = {}, matrixFormat = {}", numParams, matrixFormat);
LOG_ERROR(Lib_Ngs2, "numParams = {}, matrixFormat = {}", numParams, matrixFormat);
return ORBIS_OK;
}

View file

@ -16,7 +16,8 @@ class SymbolsResolver;
namespace Libraries::Ngs2 {
typedef s32 (*OrbisNgs2ParseReadHandler)(uintptr_t userData, u32 offset, void* data, size_t size);
using OrbisNgs2ParseReadHandler = s32 PS4_SYSV_ABI (*)(uintptr_t user_data, u32 offset, void* data,
size_t size);
enum class OrbisNgs2HandleType : u32 {
Invalid = 0,
@ -90,7 +91,7 @@ struct OrbisNgs2UserFxProcessContext {
u32 sampleRate;
};
typedef s32 (*OrbisNgs2UserFxProcessHandler)(OrbisNgs2UserFxProcessContext* context);
using OrbisNgs2UserFxProcessHandler = s32 PS4_SYSV_ABI (*)(OrbisNgs2UserFxProcessContext* context);
struct OrbisNgs2UserFx2SetupContext {
void* common;
@ -102,7 +103,7 @@ struct OrbisNgs2UserFx2SetupContext {
u64 reserved[4];
};
typedef s32 (*OrbisNgs2UserFx2SetupHandler)(OrbisNgs2UserFx2SetupContext* context);
using OrbisNgs2UserFx2SetupHandler = s32 PS4_SYSV_ABI (*)(OrbisNgs2UserFx2SetupContext* context);
struct OrbisNgs2UserFx2CleanupContext {
void* common;
@ -114,7 +115,8 @@ struct OrbisNgs2UserFx2CleanupContext {
u64 reserved[4];
};
typedef s32 (*OrbisNgs2UserFx2CleanupHandler)(OrbisNgs2UserFx2CleanupContext* context);
using OrbisNgs2UserFx2CleanupHandler =
s32 PS4_SYSV_ABI (*)(OrbisNgs2UserFx2CleanupContext* context);
struct OrbisNgs2UserFx2ControlContext {
const void* data;
@ -125,7 +127,8 @@ struct OrbisNgs2UserFx2ControlContext {
u64 reserved[4];
};
typedef s32 (*OrbisNgs2UserFx2ControlHandler)(OrbisNgs2UserFx2ControlContext* context);
using OrbisNgs2UserFx2ControlHandler =
s32 PS4_SYSV_ABI (*)(OrbisNgs2UserFx2ControlContext* context);
struct OrbisNgs2UserFx2ProcessContext {
float** aChannelData;
@ -143,7 +146,8 @@ struct OrbisNgs2UserFx2ProcessContext {
u64 reserved2[4];
};
typedef s32 (*OrbisNgs2UserFx2ProcessHandler)(OrbisNgs2UserFx2ProcessContext* context);
using OrbisNgs2UserFx2ProcessHandler =
s32 PS4_SYSV_ABI (*)(OrbisNgs2UserFx2ProcessContext* context);
struct OrbisNgs2BufferAllocator {
OrbisNgs2BufferAllocHandler allocHandler;
@ -237,7 +241,7 @@ struct OrbisNgs2VoiceCallbackInfo {
} param;
};
typedef void (*OrbisNgs2VoiceCallbackHandler)(const OrbisNgs2VoiceCallbackInfo* info);
using OrbisNgs2VoiceCallbackHandler = void PS4_SYSV_ABI (*)(const OrbisNgs2VoiceCallbackInfo* info);
struct OrbisNgs2VoiceCallbackParam {
OrbisNgs2VoiceParamHeader header;

View file

@ -30,8 +30,9 @@ struct OrbisNgs2SystemOption {
u32 aReserved[6];
};
typedef s32 (*OrbisNgs2BufferAllocHandler)(OrbisNgs2ContextBufferInfo* ioBufferInfo);
typedef s32 (*OrbisNgs2BufferFreeHandler)(OrbisNgs2ContextBufferInfo* ioBufferInfo);
using OrbisNgs2BufferAllocHandler =
s32 PS4_SYSV_ABI (*)(OrbisNgs2ContextBufferInfo* io_buffer_info);
using OrbisNgs2BufferFreeHandler = s32 PS4_SYSV_ABI (*)(OrbisNgs2ContextBufferInfo* io_buffer_info);
struct OrbisNgs2SystemInfo {
char name[ORBIS_NGS2_SYSTEM_NAME_LENGTH]; // 0

View file

@ -18,7 +18,8 @@ struct OrbisNgs2ReportDataHeader {
s32 result;
};
typedef void (*OrbisNgs2ReportHandler)(const OrbisNgs2ReportDataHeader* data, uintptr_t userData);
using OrbisNgs2ReportHandler = void PS4_SYSV_ABI (*)(const OrbisNgs2ReportDataHeader* data,
uintptr_t user_data);
struct OrbisNgs2ReportMessageData {
OrbisNgs2ReportDataHeader header;

View file

@ -0,0 +1,45 @@
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include "common/logging/log.h"
#include "core/libraries/error_codes.h"
#include "core/libraries/kernel/posix_error.h"
#include "core/libraries/libs.h"
#include "core/libraries/ulobjmgr/ulobjmgr.h"
namespace Libraries::Ulobjmgr {
s32 PS4_SYSV_ABI Func_046DBA8411A2365C(u64 arg0, s32 arg1, u32* arg2) {
if (arg0 == 0 || arg1 == 0 || arg2 == nullptr) {
return POSIX_EINVAL;
}
*arg2 = 0;
return ORBIS_OK;
}
s32 PS4_SYSV_ABI Func_1D9F50D9CFB8054E() {
return ORBIS_OK;
}
s32 PS4_SYSV_ABI Func_4A67FE7D435B94F7(u32 arg0) {
if (arg0 >= 0x4000) {
return POSIX_EINVAL;
}
return ORBIS_OK;
}
s32 PS4_SYSV_ABI Func_4B07893BBB77A649(u64 arg0) {
if (arg0 == 0) {
return POSIX_EINVAL;
}
return ORBIS_OK;
}
void RegisterlibSceUlobjmgr(Core::Loader::SymbolsResolver* sym) {
LIB_FUNCTION("BG26hBGiNlw", "ulobjmgr", 1, "ulobjmgr", 1, 1, Func_046DBA8411A2365C);
LIB_FUNCTION("HZ9Q2c+4BU4", "ulobjmgr", 1, "ulobjmgr", 1, 1, Func_1D9F50D9CFB8054E);
LIB_FUNCTION("Smf+fUNblPc", "ulobjmgr", 1, "ulobjmgr", 1, 1, Func_4A67FE7D435B94F7);
LIB_FUNCTION("SweJO7t3pkk", "ulobjmgr", 1, "ulobjmgr", 1, 1, Func_4B07893BBB77A649);
};
} // namespace Libraries::Ulobjmgr

View file

@ -0,0 +1,14 @@
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
#include "common/types.h"
namespace Core::Loader {
class SymbolsResolver;
}
namespace Libraries::Ulobjmgr {
void RegisterlibSceUlobjmgr(Core::Loader::SymbolsResolver* sym);
} // namespace Libraries::Ulobjmgr

View file

@ -7,311 +7,455 @@
#include "core/libraries/libs.h"
#include "usbd.h"
#include <fmt/format.h>
#include <libusb.h>
namespace Libraries::Usbd {
int PS4_SYSV_ABI sceUsbdAllocTransfer() {
LOG_ERROR(Lib_Usbd, "(STUBBED) called");
return ORBIS_OK;
s32 libusb_to_orbis_error(int retVal) {
if (retVal == LIBUSB_ERROR_OTHER)
return 0x802400FF;
if (retVal < 0) {
LOG_ERROR(Lib_Usbd, "libusb returned: {}", libusb_error_name(retVal));
return 0x80240000 - retVal;
}
return retVal;
}
int PS4_SYSV_ABI sceUsbdAttachKernelDriver() {
LOG_ERROR(Lib_Usbd, "(STUBBED) called");
return ORBIS_OK;
libusb_context* g_libusb_context;
#if defined(_WIN32)
bool s_has_removed_driver = false;
#endif
s32 PS4_SYSV_ABI sceUsbdInit() {
LOG_DEBUG(Lib_Usbd, "called");
return libusb_to_orbis_error(libusb_init(&g_libusb_context));
}
int PS4_SYSV_ABI sceUsbdBulkTransfer() {
LOG_ERROR(Lib_Usbd, "(STUBBED) called");
return ORBIS_OK;
void PS4_SYSV_ABI sceUsbdExit() {
LOG_DEBUG(Lib_Usbd, "called");
libusb_exit(g_libusb_context);
}
int PS4_SYSV_ABI sceUsbdCancelTransfer() {
LOG_ERROR(Lib_Usbd, "(STUBBED) called");
return ORBIS_OK;
s64 PS4_SYSV_ABI sceUsbdGetDeviceList(SceUsbdDevice*** list) {
LOG_DEBUG(Lib_Usbd, "called");
return libusb_to_orbis_error(libusb_get_device_list(g_libusb_context, list));
}
int PS4_SYSV_ABI sceUsbdCheckConnected() {
LOG_ERROR(Lib_Usbd, "(STUBBED) called");
return ORBIS_OK;
void PS4_SYSV_ABI sceUsbdFreeDeviceList(SceUsbdDevice** list, s32 unref_devices) {
LOG_DEBUG(Lib_Usbd, "called");
libusb_free_device_list(list, unref_devices);
}
int PS4_SYSV_ABI sceUsbdClaimInterface() {
LOG_ERROR(Lib_Usbd, "(STUBBED) called");
return ORBIS_OK;
SceUsbdDevice* PS4_SYSV_ABI sceUsbdRefDevice(SceUsbdDevice* device) {
LOG_DEBUG(Lib_Usbd, "called");
return libusb_ref_device(device);
}
int PS4_SYSV_ABI sceUsbdClearHalt() {
LOG_ERROR(Lib_Usbd, "(STUBBED) called");
return ORBIS_OK;
void PS4_SYSV_ABI sceUsbdUnrefDevice(SceUsbdDevice* device) {
LOG_DEBUG(Lib_Usbd, "called");
libusb_unref_device(device);
}
int PS4_SYSV_ABI sceUsbdClose() {
LOG_ERROR(Lib_Usbd, "(STUBBED) called");
return ORBIS_OK;
s32 PS4_SYSV_ABI sceUsbdGetConfiguration(SceUsbdDeviceHandle* dev_handle, s32* config) {
LOG_DEBUG(Lib_Usbd, "called");
return libusb_to_orbis_error(libusb_get_configuration(dev_handle, config));
}
int PS4_SYSV_ABI sceUsbdControlTransfer() {
LOG_ERROR(Lib_Usbd, "(STUBBED) called");
return ORBIS_OK;
s32 PS4_SYSV_ABI sceUsbdGetDeviceDescriptor(SceUsbdDevice* device, SceUsbdDeviceDescriptor* desc) {
LOG_DEBUG(Lib_Usbd, "called");
return libusb_to_orbis_error(libusb_get_device_descriptor(device, desc));
}
int PS4_SYSV_ABI sceUsbdControlTransferGetData() {
LOG_ERROR(Lib_Usbd, "(STUBBED) called");
return ORBIS_OK;
s32 PS4_SYSV_ABI sceUsbdGetActiveConfigDescriptor(SceUsbdDevice* device,
SceUsbdConfigDescriptor** config) {
LOG_DEBUG(Lib_Usbd, "called");
return libusb_to_orbis_error(libusb_get_active_config_descriptor(device, config));
}
int PS4_SYSV_ABI sceUsbdControlTransferGetSetup() {
LOG_ERROR(Lib_Usbd, "(STUBBED) called");
return ORBIS_OK;
s32 PS4_SYSV_ABI sceUsbdGetConfigDescriptor(SceUsbdDevice* device, u8 config_index,
SceUsbdConfigDescriptor** config) {
LOG_DEBUG(Lib_Usbd, "called");
return libusb_to_orbis_error(libusb_get_config_descriptor(device, config_index, config));
}
int PS4_SYSV_ABI sceUsbdDetachKernelDriver() {
LOG_ERROR(Lib_Usbd, "(STUBBED) called");
return ORBIS_OK;
s32 PS4_SYSV_ABI sceUsbdGetConfigDescriptorByValue(SceUsbdDevice* device, u8 bConfigurationValue,
SceUsbdConfigDescriptor** config) {
LOG_DEBUG(Lib_Usbd, "called");
return libusb_to_orbis_error(
libusb_get_config_descriptor_by_value(device, bConfigurationValue, config));
}
int PS4_SYSV_ABI sceUsbdEventHandlerActive() {
LOG_ERROR(Lib_Usbd, "(STUBBED) called");
return ORBIS_OK;
void PS4_SYSV_ABI sceUsbdFreeConfigDescriptor(SceUsbdConfigDescriptor* config) {
LOG_DEBUG(Lib_Usbd, "called");
libusb_free_config_descriptor(config);
}
int PS4_SYSV_ABI sceUsbdEventHandlingOk() {
LOG_ERROR(Lib_Usbd, "(STUBBED) called");
return ORBIS_OK;
u8 PS4_SYSV_ABI sceUsbdGetBusNumber(SceUsbdDevice* device) {
LOG_DEBUG(Lib_Usbd, "called");
return libusb_get_bus_number(device);
}
int PS4_SYSV_ABI sceUsbdExit() {
LOG_ERROR(Lib_Usbd, "(STUBBED) called");
return ORBIS_OK;
u8 PS4_SYSV_ABI sceUsbdGetDeviceAddress(SceUsbdDevice* device) {
LOG_DEBUG(Lib_Usbd, "called");
return libusb_get_device_address(device);
}
int PS4_SYSV_ABI sceUsbdFillBulkTransfer() {
LOG_ERROR(Lib_Usbd, "(STUBBED) called");
return ORBIS_OK;
SceUsbdSpeed PS4_SYSV_ABI sceUsbdGetDeviceSpeed(SceUsbdDevice* device) {
LOG_DEBUG(Lib_Usbd, "called");
return static_cast<SceUsbdSpeed>(libusb_get_device_speed(device));
}
int PS4_SYSV_ABI sceUsbdFillControlSetup() {
LOG_ERROR(Lib_Usbd, "(STUBBED) called");
return ORBIS_OK;
s32 PS4_SYSV_ABI sceUsbdGetMaxPacketSize(SceUsbdDevice* device, u8 endpoint) {
LOG_DEBUG(Lib_Usbd, "called");
return libusb_to_orbis_error(libusb_get_max_packet_size(device, endpoint));
}
int PS4_SYSV_ABI sceUsbdFillControlTransfer() {
LOG_ERROR(Lib_Usbd, "(STUBBED) called");
return ORBIS_OK;
s32 PS4_SYSV_ABI sceUsbdGetMaxIsoPacketSize(SceUsbdDevice* device, u8 endpoint) {
LOG_DEBUG(Lib_Usbd, "called");
return libusb_to_orbis_error(libusb_get_max_iso_packet_size(device, endpoint));
}
int PS4_SYSV_ABI sceUsbdFillInterruptTransfer() {
LOG_ERROR(Lib_Usbd, "(STUBBED) called");
return ORBIS_OK;
s32 PS4_SYSV_ABI sceUsbdOpen(SceUsbdDevice* device, SceUsbdDeviceHandle** dev_handle) {
LOG_DEBUG(Lib_Usbd, "called");
return libusb_to_orbis_error(libusb_open(device, dev_handle));
}
int PS4_SYSV_ABI sceUsbdFillIsoTransfer() {
LOG_ERROR(Lib_Usbd, "(STUBBED) called");
return ORBIS_OK;
void PS4_SYSV_ABI sceUsbdClose(SceUsbdDeviceHandle* dev_handle) {
LOG_DEBUG(Lib_Usbd, "called");
libusb_close(dev_handle);
}
int PS4_SYSV_ABI sceUsbdFreeConfigDescriptor() {
LOG_ERROR(Lib_Usbd, "(STUBBED) called");
return ORBIS_OK;
SceUsbdDevice* PS4_SYSV_ABI sceUsbdGetDevice(SceUsbdDeviceHandle* dev_handle) {
LOG_DEBUG(Lib_Usbd, "called");
return libusb_get_device(dev_handle);
}
int PS4_SYSV_ABI sceUsbdFreeDeviceList() {
LOG_ERROR(Lib_Usbd, "(STUBBED) called");
return ORBIS_OK;
s32 PS4_SYSV_ABI sceUsbdSetConfiguration(SceUsbdDeviceHandle* dev_handle, s32 config) {
LOG_DEBUG(Lib_Usbd, "called");
return libusb_to_orbis_error(libusb_set_configuration(dev_handle, config));
}
int PS4_SYSV_ABI sceUsbdFreeTransfer() {
LOG_ERROR(Lib_Usbd, "(STUBBED) called");
return ORBIS_OK;
s32 PS4_SYSV_ABI sceUsbdClaimInterface(SceUsbdDeviceHandle* dev_handle, s32 interface_number) {
LOG_DEBUG(Lib_Usbd, "called");
if (sceUsbdKernelDriverActive(dev_handle, interface_number)) {
sceUsbdDetachKernelDriver(dev_handle, interface_number);
}
return libusb_to_orbis_error(libusb_claim_interface(dev_handle, interface_number));
}
int PS4_SYSV_ABI sceUsbdGetActiveConfigDescriptor() {
LOG_ERROR(Lib_Usbd, "(STUBBED) called");
return ORBIS_OK;
s32 PS4_SYSV_ABI sceUsbdReleaseInterface(SceUsbdDeviceHandle* dev_handle, s32 interface_number) {
LOG_DEBUG(Lib_Usbd, "called");
return libusb_to_orbis_error(libusb_release_interface(dev_handle, interface_number));
}
int PS4_SYSV_ABI sceUsbdGetBusNumber() {
LOG_ERROR(Lib_Usbd, "(STUBBED) called");
return ORBIS_OK;
SceUsbdDeviceHandle* PS4_SYSV_ABI sceUsbdOpenDeviceWithVidPid(u16 vendor_id, u16 product_id) {
LOG_DEBUG(Lib_Usbd, "called");
return libusb_open_device_with_vid_pid(g_libusb_context, vendor_id, product_id);
}
int PS4_SYSV_ABI sceUsbdGetConfigDescriptor() {
LOG_ERROR(Lib_Usbd, "(STUBBED) called");
return ORBIS_OK;
s32 PS4_SYSV_ABI sceUsbdSetInterfaceAltSetting(SceUsbdDeviceHandle* dev_handle,
int interface_number, int alternate_setting) {
LOG_DEBUG(Lib_Usbd, "called");
return libusb_to_orbis_error(
libusb_set_interface_alt_setting(dev_handle, interface_number, alternate_setting));
}
int PS4_SYSV_ABI sceUsbdGetConfigDescriptorByValue() {
LOG_ERROR(Lib_Usbd, "(STUBBED) called");
return ORBIS_OK;
s32 PS4_SYSV_ABI sceUsbdClearHalt(SceUsbdDeviceHandle* dev_handle, uint8_t endpoint) {
LOG_DEBUG(Lib_Usbd, "called");
return libusb_to_orbis_error(libusb_clear_halt(dev_handle, endpoint));
}
int PS4_SYSV_ABI sceUsbdGetConfiguration() {
LOG_ERROR(Lib_Usbd, "(STUBBED) called");
return ORBIS_OK;
s32 PS4_SYSV_ABI sceUsbdResetDevice(SceUsbdDeviceHandle* dev_handle) {
LOG_DEBUG(Lib_Usbd, "called");
return libusb_to_orbis_error(libusb_reset_device(dev_handle));
}
int PS4_SYSV_ABI sceUsbdGetDescriptor() {
LOG_ERROR(Lib_Usbd, "(STUBBED) called");
return ORBIS_OK;
s32 PS4_SYSV_ABI sceUsbdKernelDriverActive(SceUsbdDeviceHandle* dev_handle, int interface_number) {
LOG_DEBUG(Lib_Usbd, "called");
#if defined(_WIN32)
if (!s_has_removed_driver)
return 1;
else
return 0;
#endif
return libusb_to_orbis_error(libusb_kernel_driver_active(dev_handle, interface_number));
}
int PS4_SYSV_ABI sceUsbdGetDevice() {
LOG_ERROR(Lib_Usbd, "(STUBBED) called");
return ORBIS_OK;
s32 PS4_SYSV_ABI sceUsbdDetachKernelDriver(SceUsbdDeviceHandle* dev_handle, int interface_number) {
LOG_DEBUG(Lib_Usbd, "called");
#if defined(_WIN32)
s_has_removed_driver = true;
return 0;
#endif
return libusb_to_orbis_error(libusb_detach_kernel_driver(dev_handle, interface_number));
}
int PS4_SYSV_ABI sceUsbdGetDeviceAddress() {
LOG_ERROR(Lib_Usbd, "(STUBBED) called");
return ORBIS_OK;
s32 PS4_SYSV_ABI sceUsbdAttachKernelDriver(SceUsbdDeviceHandle* dev_handle, int interface_number) {
LOG_DEBUG(Lib_Usbd, "called");
#if defined(_WIN32)
s_has_removed_driver = false;
return 0;
#endif
return libusb_to_orbis_error(libusb_attach_kernel_driver(dev_handle, interface_number));
}
int PS4_SYSV_ABI sceUsbdGetDeviceDescriptor() {
LOG_ERROR(Lib_Usbd, "(STUBBED) called");
return ORBIS_OK;
u8* PS4_SYSV_ABI sceUsbdControlTransferGetData(SceUsbdTransfer* transfer) {
LOG_DEBUG(Lib_Usbd, "called");
return libusb_control_transfer_get_data(transfer);
}
int PS4_SYSV_ABI sceUsbdGetDeviceList() {
LOG_ERROR(Lib_Usbd, "(STUBBED) called");
return ORBIS_OK;
SceUsbdControlSetup* PS4_SYSV_ABI sceUsbdControlTransferGetSetup(SceUsbdTransfer* transfer) {
LOG_DEBUG(Lib_Usbd, "called");
return libusb_control_transfer_get_setup(transfer);
}
int PS4_SYSV_ABI sceUsbdGetDeviceSpeed() {
LOG_ERROR(Lib_Usbd, "(STUBBED) called");
return ORBIS_OK;
void PS4_SYSV_ABI sceUsbdFillControlSetup(u8* buf, u8 bmRequestType, u8 bRequest, u16 wValue,
u16 wIndex, u16 wLength) {
LOG_DEBUG(Lib_Usbd, "called");
return libusb_fill_control_setup(buf, bmRequestType, bRequest, wValue, wIndex, wLength);
}
int PS4_SYSV_ABI sceUsbdGetIsoPacketBuffer() {
LOG_ERROR(Lib_Usbd, "(STUBBED) called");
return ORBIS_OK;
SceUsbdTransfer* PS4_SYSV_ABI sceUsbdAllocTransfer(int iso_packets) {
LOG_DEBUG(Lib_Usbd, "called");
return libusb_alloc_transfer(iso_packets);
}
int PS4_SYSV_ABI sceUsbdGetMaxIsoPacketSize() {
LOG_ERROR(Lib_Usbd, "(STUBBED) called");
return ORBIS_OK;
s32 PS4_SYSV_ABI sceUsbdSubmitTransfer(SceUsbdTransfer* transfer) {
LOG_DEBUG(Lib_Usbd, "called");
return libusb_to_orbis_error(libusb_submit_transfer(transfer));
}
int PS4_SYSV_ABI sceUsbdGetMaxPacketSize() {
LOG_ERROR(Lib_Usbd, "(STUBBED) called");
return ORBIS_OK;
s32 PS4_SYSV_ABI sceUsbdCancelTransfer(SceUsbdTransfer* transfer) {
LOG_DEBUG(Lib_Usbd, "called");
return libusb_to_orbis_error(libusb_cancel_transfer(transfer));
}
int PS4_SYSV_ABI sceUsbdGetStringDescriptor() {
LOG_ERROR(Lib_Usbd, "(STUBBED) called");
return ORBIS_OK;
void PS4_SYSV_ABI sceUsbdFreeTransfer(SceUsbdTransfer* transfer) {
LOG_DEBUG(Lib_Usbd, "called");
libusb_free_transfer(transfer);
}
int PS4_SYSV_ABI sceUsbdGetStringDescriptorAscii() {
LOG_ERROR(Lib_Usbd, "(STUBBED) called");
return ORBIS_OK;
void PS4_SYSV_ABI sceUsbdFillControlTransfer(SceUsbdTransfer* transfer,
SceUsbdDeviceHandle* dev_handle, u8* buffer,
SceUsbdTransferCallback callback, void* user_data,
u32 timeout) {
LOG_DEBUG(Lib_Usbd, "called");
libusb_fill_control_transfer(transfer, dev_handle, buffer, callback, user_data, timeout);
}
int PS4_SYSV_ABI sceUsbdHandleEvents() {
LOG_ERROR(Lib_Usbd, "(STUBBED) called");
return ORBIS_OK;
void PS4_SYSV_ABI sceUsbdFillBulkTransfer(SceUsbdTransfer* transfer,
SceUsbdDeviceHandle* dev_handle, uint8_t endpoint,
u8* buffer, s32 length, SceUsbdTransferCallback callback,
void* user_data, u32 timeout) {
LOG_DEBUG(Lib_Usbd, "called");
libusb_fill_bulk_transfer(transfer, dev_handle, endpoint, buffer, length, callback, user_data,
timeout);
}
int PS4_SYSV_ABI sceUsbdHandleEventsLocked() {
LOG_ERROR(Lib_Usbd, "(STUBBED) called");
return ORBIS_OK;
void PS4_SYSV_ABI sceUsbdFillInterruptTransfer(SceUsbdTransfer* transfer,
SceUsbdDeviceHandle* dev_handle, uint8_t endpoint,
u8* buffer, s32 length,
SceUsbdTransferCallback callback, void* user_data,
u32 timeout) {
LOG_DEBUG(Lib_Usbd, "called");
libusb_fill_interrupt_transfer(transfer, dev_handle, endpoint, buffer, length, callback,
user_data, timeout);
}
int PS4_SYSV_ABI sceUsbdHandleEventsTimeout() {
LOG_DEBUG(Lib_Usbd, "(STUBBED) called");
return ORBIS_OK;
void PS4_SYSV_ABI sceUsbdFillIsoTransfer(SceUsbdTransfer* transfer, SceUsbdDeviceHandle* dev_handle,
uint8_t endpoint, u8* buffer, s32 length,
s32 num_iso_packets, SceUsbdTransferCallback callback,
void* user_data, u32 timeout) {
LOG_DEBUG(Lib_Usbd, "called");
libusb_fill_iso_transfer(transfer, dev_handle, endpoint, buffer, length, num_iso_packets,
callback, user_data, timeout);
}
int PS4_SYSV_ABI sceUsbdInit() {
LOG_ERROR(Lib_Usbd, "(STUBBED) called");
return 0x80240005; // Skip
void PS4_SYSV_ABI sceUsbdSetIsoPacketLengths(SceUsbdTransfer* transfer, u32 length) {
LOG_DEBUG(Lib_Usbd, "called");
libusb_set_iso_packet_lengths(transfer, length);
}
int PS4_SYSV_ABI sceUsbdInterruptTransfer() {
LOG_ERROR(Lib_Usbd, "(STUBBED) called");
return ORBIS_OK;
u8* PS4_SYSV_ABI sceUsbdGetIsoPacketBuffer(SceUsbdTransfer* transfer, u32 packet) {
LOG_DEBUG(Lib_Usbd, "called");
return libusb_get_iso_packet_buffer(transfer, packet);
}
int PS4_SYSV_ABI sceUsbdKernelDriverActive() {
LOG_ERROR(Lib_Usbd, "(STUBBED) called");
return ORBIS_OK;
s32 PS4_SYSV_ABI sceUsbdControlTransfer(SceUsbdDeviceHandle* dev_handle, u8 request_type,
u8 bRequest, u16 wValue, u16 wIndex, u8* data, s32 wLength,
u32 timeout) {
LOG_DEBUG(Lib_Usbd, "called");
return libusb_to_orbis_error(libusb_control_transfer(dev_handle, request_type, bRequest, wValue,
wIndex, data, wLength, timeout));
}
int PS4_SYSV_ABI sceUsbdLockEvents() {
LOG_ERROR(Lib_Usbd, "(STUBBED) called");
return ORBIS_OK;
s32 PS4_SYSV_ABI sceUsbdBulkTransfer(SceUsbdDeviceHandle* dev_handle, u8 endpoint, u8* data,
s32 length, s32* actual_length, u32 timeout) {
LOG_DEBUG(Lib_Usbd, "called");
return libusb_to_orbis_error(
libusb_bulk_transfer(dev_handle, endpoint, data, length, actual_length, timeout));
}
int PS4_SYSV_ABI sceUsbdLockEventWaiters() {
LOG_ERROR(Lib_Usbd, "(STUBBED) called");
return ORBIS_OK;
s32 PS4_SYSV_ABI sceUsbdInterruptTransfer(SceUsbdDeviceHandle* dev_handle, u8 endpoint, u8* data,
s32 length, s32* actual_length, u32 timeout) {
LOG_DEBUG(Lib_Usbd, "called");
return libusb_to_orbis_error(
libusb_interrupt_transfer(dev_handle, endpoint, data, length, actual_length, timeout));
}
int PS4_SYSV_ABI sceUsbdOpen() {
LOG_ERROR(Lib_Usbd, "(STUBBED) called");
return ORBIS_OK;
s32 PS4_SYSV_ABI sceUsbdGetDescriptor(SceUsbdDeviceHandle* dev_handle, u8 descType, u8 descIndex,
u8* data, s32 length) {
LOG_DEBUG(Lib_Usbd, "called");
return libusb_to_orbis_error(
libusb_get_descriptor(dev_handle, descType, descIndex, data, length));
}
int PS4_SYSV_ABI sceUsbdOpenDeviceWithVidPid() {
LOG_ERROR(Lib_Usbd, "(STUBBED) called");
return ORBIS_OK;
s32 PS4_SYSV_ABI sceUsbdGetStringDescriptor(SceUsbdDeviceHandle* dev_handle, u8 desc_index,
u16 langid, u8* data, s32 length) {
LOG_DEBUG(Lib_Usbd, "called");
return libusb_to_orbis_error(
libusb_get_string_descriptor(dev_handle, desc_index, langid, data, length));
}
int PS4_SYSV_ABI sceUsbdRefDevice() {
LOG_ERROR(Lib_Usbd, "(STUBBED) called");
return ORBIS_OK;
s32 PS4_SYSV_ABI sceUsbdGetStringDescriptorAscii(SceUsbdDeviceHandle* dev_handle, u8 desc_index,
u8* data, s32 length) {
LOG_DEBUG(Lib_Usbd, "called");
return libusb_to_orbis_error(
libusb_get_string_descriptor_ascii(dev_handle, desc_index, data, length));
}
int PS4_SYSV_ABI sceUsbdReleaseInterface() {
LOG_ERROR(Lib_Usbd, "(STUBBED) called");
return ORBIS_OK;
s32 PS4_SYSV_ABI sceUsbdTryLockEvents() {
LOG_DEBUG(Lib_Usbd, "called");
return libusb_try_lock_events(g_libusb_context);
}
int PS4_SYSV_ABI sceUsbdResetDevice() {
LOG_ERROR(Lib_Usbd, "(STUBBED) called");
return ORBIS_OK;
void PS4_SYSV_ABI sceUsbdLockEvents() {
LOG_DEBUG(Lib_Usbd, "called");
libusb_lock_events(g_libusb_context);
}
int PS4_SYSV_ABI sceUsbdSetConfiguration() {
LOG_ERROR(Lib_Usbd, "(STUBBED) called");
return ORBIS_OK;
void PS4_SYSV_ABI sceUsbdUnlockEvents() {
LOG_DEBUG(Lib_Usbd, "called");
libusb_unlock_events(g_libusb_context);
}
int PS4_SYSV_ABI sceUsbdSetInterfaceAltSetting() {
LOG_ERROR(Lib_Usbd, "(STUBBED) called");
return ORBIS_OK;
s32 PS4_SYSV_ABI sceUsbdEventHandlingOk() {
LOG_DEBUG(Lib_Usbd, "called");
return libusb_event_handling_ok(g_libusb_context);
}
int PS4_SYSV_ABI sceUsbdSetIsoPacketLengths() {
LOG_ERROR(Lib_Usbd, "(STUBBED) called");
return ORBIS_OK;
s32 PS4_SYSV_ABI sceUsbdEventHandlerActive() {
LOG_DEBUG(Lib_Usbd, "called");
return libusb_event_handler_active(g_libusb_context);
}
int PS4_SYSV_ABI sceUsbdSubmitTransfer() {
LOG_ERROR(Lib_Usbd, "(STUBBED) called");
return ORBIS_OK;
void PS4_SYSV_ABI sceUsbdLockEventWaiters() {
LOG_DEBUG(Lib_Usbd, "called");
libusb_lock_event_waiters(g_libusb_context);
}
int PS4_SYSV_ABI sceUsbdTryLockEvents() {
LOG_ERROR(Lib_Usbd, "(STUBBED) called");
return ORBIS_OK;
void PS4_SYSV_ABI sceUsbdUnlockEventWaiters() {
LOG_DEBUG(Lib_Usbd, "called");
libusb_unlock_event_waiters(g_libusb_context);
}
int PS4_SYSV_ABI sceUsbdUnlockEvents() {
LOG_ERROR(Lib_Usbd, "(STUBBED) called");
return ORBIS_OK;
s32 PS4_SYSV_ABI sceUsbdWaitForEvent(timeval* tv) {
LOG_DEBUG(Lib_Usbd, "called");
return libusb_to_orbis_error(libusb_wait_for_event(g_libusb_context, tv));
}
int PS4_SYSV_ABI sceUsbdUnlockEventWaiters() {
LOG_ERROR(Lib_Usbd, "(STUBBED) called");
return ORBIS_OK;
s32 PS4_SYSV_ABI sceUsbdHandleEventsTimeout(timeval* tv) {
LOG_DEBUG(Lib_Usbd, "called");
return libusb_to_orbis_error(libusb_handle_events_timeout(g_libusb_context, tv));
}
int PS4_SYSV_ABI sceUsbdUnrefDevice() {
LOG_ERROR(Lib_Usbd, "(STUBBED) called");
return ORBIS_OK;
s32 PS4_SYSV_ABI sceUsbdHandleEvents() {
LOG_DEBUG(Lib_Usbd, "called");
return libusb_to_orbis_error(libusb_handle_events(g_libusb_context));
}
int PS4_SYSV_ABI sceUsbdWaitForEvent() {
LOG_ERROR(Lib_Usbd, "(STUBBED) called");
return ORBIS_OK;
s32 PS4_SYSV_ABI sceUsbdHandleEventsLocked(timeval* tv) {
LOG_DEBUG(Lib_Usbd, "called");
return libusb_to_orbis_error(libusb_handle_events_locked(g_libusb_context, tv));
}
s32 PS4_SYSV_ABI sceUsbdCheckConnected(SceUsbdDeviceHandle* dev_handle) {
LOG_DEBUG(Lib_Usbd, "called");
// There's no libusb version of this function.
// Simulate by querying data.
int config;
int r = libusb_get_configuration(dev_handle, &config);
return libusb_to_orbis_error(r);
}
int PS4_SYSV_ABI Func_65F6EF33E38FFF50() {
@ -406,4 +550,4 @@ void RegisterlibSceUsbd(Core::Loader::SymbolsResolver* sym) {
LIB_FUNCTION("1WtDBgcgseA", "libSceUsbd", 1, "libSceUsbd", 1, 1, Func_D56B43060720B1E0);
};
} // namespace Libraries::Usbd
} // namespace Libraries::Usbd

View file

@ -1,76 +1,150 @@
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
// SPDX - FileCopyrightText : Copyright 2024 shadPS4 Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
#include "common/types.h"
extern "C" {
struct libusb_device;
struct libusb_device_handle;
struct libusb_device_descriptor;
struct libusb_config_descriptor;
struct libusb_transfer;
struct libusb_control_setup;
struct timeval;
}
namespace Core::Loader {
class SymbolsResolver;
}
namespace Libraries::Usbd {
int PS4_SYSV_ABI sceUsbdAllocTransfer();
int PS4_SYSV_ABI sceUsbdAttachKernelDriver();
int PS4_SYSV_ABI sceUsbdBulkTransfer();
int PS4_SYSV_ABI sceUsbdCancelTransfer();
int PS4_SYSV_ABI sceUsbdCheckConnected();
int PS4_SYSV_ABI sceUsbdClaimInterface();
int PS4_SYSV_ABI sceUsbdClearHalt();
int PS4_SYSV_ABI sceUsbdClose();
int PS4_SYSV_ABI sceUsbdControlTransfer();
int PS4_SYSV_ABI sceUsbdControlTransferGetData();
int PS4_SYSV_ABI sceUsbdControlTransferGetSetup();
int PS4_SYSV_ABI sceUsbdDetachKernelDriver();
int PS4_SYSV_ABI sceUsbdEventHandlerActive();
int PS4_SYSV_ABI sceUsbdEventHandlingOk();
int PS4_SYSV_ABI sceUsbdExit();
int PS4_SYSV_ABI sceUsbdFillBulkTransfer();
int PS4_SYSV_ABI sceUsbdFillControlSetup();
int PS4_SYSV_ABI sceUsbdFillControlTransfer();
int PS4_SYSV_ABI sceUsbdFillInterruptTransfer();
int PS4_SYSV_ABI sceUsbdFillIsoTransfer();
int PS4_SYSV_ABI sceUsbdFreeConfigDescriptor();
int PS4_SYSV_ABI sceUsbdFreeDeviceList();
int PS4_SYSV_ABI sceUsbdFreeTransfer();
int PS4_SYSV_ABI sceUsbdGetActiveConfigDescriptor();
int PS4_SYSV_ABI sceUsbdGetBusNumber();
int PS4_SYSV_ABI sceUsbdGetConfigDescriptor();
int PS4_SYSV_ABI sceUsbdGetConfigDescriptorByValue();
int PS4_SYSV_ABI sceUsbdGetConfiguration();
int PS4_SYSV_ABI sceUsbdGetDescriptor();
int PS4_SYSV_ABI sceUsbdGetDevice();
int PS4_SYSV_ABI sceUsbdGetDeviceAddress();
int PS4_SYSV_ABI sceUsbdGetDeviceDescriptor();
int PS4_SYSV_ABI sceUsbdGetDeviceList();
int PS4_SYSV_ABI sceUsbdGetDeviceSpeed();
int PS4_SYSV_ABI sceUsbdGetIsoPacketBuffer();
int PS4_SYSV_ABI sceUsbdGetMaxIsoPacketSize();
int PS4_SYSV_ABI sceUsbdGetMaxPacketSize();
int PS4_SYSV_ABI sceUsbdGetStringDescriptor();
int PS4_SYSV_ABI sceUsbdGetStringDescriptorAscii();
int PS4_SYSV_ABI sceUsbdHandleEvents();
int PS4_SYSV_ABI sceUsbdHandleEventsLocked();
int PS4_SYSV_ABI sceUsbdHandleEventsTimeout();
int PS4_SYSV_ABI sceUsbdInit();
int PS4_SYSV_ABI sceUsbdInterruptTransfer();
int PS4_SYSV_ABI sceUsbdKernelDriverActive();
int PS4_SYSV_ABI sceUsbdLockEvents();
int PS4_SYSV_ABI sceUsbdLockEventWaiters();
int PS4_SYSV_ABI sceUsbdOpen();
int PS4_SYSV_ABI sceUsbdOpenDeviceWithVidPid();
int PS4_SYSV_ABI sceUsbdRefDevice();
int PS4_SYSV_ABI sceUsbdReleaseInterface();
int PS4_SYSV_ABI sceUsbdResetDevice();
int PS4_SYSV_ABI sceUsbdSetConfiguration();
int PS4_SYSV_ABI sceUsbdSetInterfaceAltSetting();
int PS4_SYSV_ABI sceUsbdSetIsoPacketLengths();
int PS4_SYSV_ABI sceUsbdSubmitTransfer();
int PS4_SYSV_ABI sceUsbdTryLockEvents();
int PS4_SYSV_ABI sceUsbdUnlockEvents();
int PS4_SYSV_ABI sceUsbdUnlockEventWaiters();
int PS4_SYSV_ABI sceUsbdUnrefDevice();
int PS4_SYSV_ABI sceUsbdWaitForEvent();
using SceUsbdDevice = libusb_device;
using SceUsbdDeviceHandle = libusb_device_handle;
using SceUsbdDeviceDescriptor = libusb_device_descriptor;
using SceUsbdConfigDescriptor = libusb_config_descriptor;
using SceUsbdTransfer = libusb_transfer;
using SceUsbdControlSetup = libusb_control_setup;
using SceUsbdTransferCallback = void (*)(SceUsbdTransfer* transfer);
enum class SceUsbdSpeed : u32 {
UNKNOWN = 0,
LOW = 1,
FULL = 2,
HIGH = 3,
SUPER = 4,
SUPER_PLUS = 5
};
s32 PS4_SYSV_ABI sceUsbdInit();
void PS4_SYSV_ABI sceUsbdExit();
s64 PS4_SYSV_ABI sceUsbdGetDeviceList(SceUsbdDevice*** list);
void PS4_SYSV_ABI sceUsbdFreeDeviceList(SceUsbdDevice** list, s32 unref_devices);
SceUsbdDevice* PS4_SYSV_ABI sceUsbdRefDevice(SceUsbdDevice* device);
void PS4_SYSV_ABI sceUsbdUnrefDevice(SceUsbdDevice* device);
s32 PS4_SYSV_ABI sceUsbdGetConfiguration(SceUsbdDeviceHandle* dev_handle, s32* config);
s32 PS4_SYSV_ABI sceUsbdGetDeviceDescriptor(SceUsbdDevice* device, SceUsbdDeviceDescriptor* desc);
s32 PS4_SYSV_ABI sceUsbdGetActiveConfigDescriptor(SceUsbdDevice* device,
SceUsbdConfigDescriptor** config);
s32 PS4_SYSV_ABI sceUsbdGetConfigDescriptor(SceUsbdDevice* device, u8 config_index,
SceUsbdConfigDescriptor** config);
s32 PS4_SYSV_ABI sceUsbdGetConfigDescriptorByValue(SceUsbdDevice* device, u8 bConfigurationValue,
SceUsbdConfigDescriptor** config);
void PS4_SYSV_ABI sceUsbdFreeConfigDescriptor(SceUsbdConfigDescriptor* config);
u8 PS4_SYSV_ABI sceUsbdGetBusNumber(SceUsbdDevice* device);
u8 PS4_SYSV_ABI sceUsbdGetDeviceAddress(SceUsbdDevice* device);
SceUsbdSpeed PS4_SYSV_ABI sceUsbdGetDeviceSpeed(SceUsbdDevice* device);
s32 PS4_SYSV_ABI sceUsbdGetMaxPacketSize(SceUsbdDevice* device, u8 endpoint);
s32 PS4_SYSV_ABI sceUsbdGetMaxIsoPacketSize(SceUsbdDevice* device, u8 endpoint);
s32 PS4_SYSV_ABI sceUsbdOpen(SceUsbdDevice* device, SceUsbdDeviceHandle** dev_handle);
void PS4_SYSV_ABI sceUsbdClose(SceUsbdDeviceHandle* dev_handle);
SceUsbdDevice* PS4_SYSV_ABI sceUsbdGetDevice(SceUsbdDeviceHandle* dev_handle);
s32 PS4_SYSV_ABI sceUsbdSetConfiguration(SceUsbdDeviceHandle* dev_handle, s32 config);
s32 PS4_SYSV_ABI sceUsbdClaimInterface(SceUsbdDeviceHandle* dev_handle, s32 interface_number);
s32 PS4_SYSV_ABI sceUsbdReleaseInterface(SceUsbdDeviceHandle* dev_handle, s32 interface_number);
SceUsbdDeviceHandle* PS4_SYSV_ABI sceUsbdOpenDeviceWithVidPid(u16 vendor_id, u16 product_id);
s32 PS4_SYSV_ABI sceUsbdSetInterfaceAltSetting(SceUsbdDeviceHandle* dev_handle,
int interface_number, int alternate_setting);
s32 PS4_SYSV_ABI sceUsbdClearHalt(SceUsbdDeviceHandle* dev_handle, u8 endpoint);
s32 PS4_SYSV_ABI sceUsbdResetDevice(SceUsbdDeviceHandle* dev_handle);
s32 PS4_SYSV_ABI sceUsbdKernelDriverActive(SceUsbdDeviceHandle* dev_handle, int interface_number);
s32 PS4_SYSV_ABI sceUsbdDetachKernelDriver(SceUsbdDeviceHandle* dev_handle, int interface_number);
s32 PS4_SYSV_ABI sceUsbdAttachKernelDriver(SceUsbdDeviceHandle* dev_handle, int interface_number);
u8* PS4_SYSV_ABI sceUsbdControlTransferGetData(SceUsbdTransfer* transfer);
SceUsbdControlSetup* PS4_SYSV_ABI sceUsbdControlTransferGetSetup(SceUsbdTransfer* transfer);
void PS4_SYSV_ABI sceUsbdFillControlSetup(u8* buf, u8 bmRequestType, u8 bRequest, u16 wValue,
u16 wIndex, u16 wLength);
SceUsbdTransfer* PS4_SYSV_ABI sceUsbdAllocTransfer(int iso_packets);
s32 PS4_SYSV_ABI sceUsbdSubmitTransfer(SceUsbdTransfer* transfer);
s32 PS4_SYSV_ABI sceUsbdCancelTransfer(SceUsbdTransfer* transfer);
void PS4_SYSV_ABI sceUsbdFreeTransfer(SceUsbdTransfer* transfer);
void PS4_SYSV_ABI sceUsbdFillControlTransfer(SceUsbdTransfer* transfer,
SceUsbdDeviceHandle* dev_handle, u8* buffer,
SceUsbdTransferCallback callback, void* user_data,
u32 timeout);
void PS4_SYSV_ABI sceUsbdFillBulkTransfer(SceUsbdTransfer* transfer,
SceUsbdDeviceHandle* dev_handle, u8 endpoint, u8* buffer,
s32 length, SceUsbdTransferCallback callback,
void* user_data, u32 timeout);
void PS4_SYSV_ABI sceUsbdFillInterruptTransfer(SceUsbdTransfer* transfer,
SceUsbdDeviceHandle* dev_handle, u8 endpoint,
u8* buffer, s32 length,
SceUsbdTransferCallback callback, void* user_data,
u32 timeout);
void PS4_SYSV_ABI sceUsbdFillIsoTransfer(SceUsbdTransfer* transfer, SceUsbdDeviceHandle* dev_handle,
u8 endpoint, u8* buffer, s32 length, s32 num_iso_packets,
SceUsbdTransferCallback callback, void* userData,
u32 timeout);
void PS4_SYSV_ABI sceUsbdSetIsoPacketLengths(SceUsbdTransfer* transfer, u32 length);
u8* PS4_SYSV_ABI sceUsbdGetIsoPacketBuffer(SceUsbdTransfer* transfer, u32 packet);
s32 PS4_SYSV_ABI sceUsbdControlTransfer(SceUsbdDeviceHandle* dev_handle, u8 request_type,
u8 bRequest, u16 wValue, u16 wIndex, u8* data, s32 wLength,
u32 timeout);
s32 PS4_SYSV_ABI sceUsbdBulkTransfer(SceUsbdDeviceHandle* dev_handle, u8 endpoint, u8* data,
s32 length, s32* actual_length, u32 timeout);
s32 PS4_SYSV_ABI sceUsbdInterruptTransfer(SceUsbdDeviceHandle* dev_handle, u8 endpoint, u8* data,
s32 length, s32* actual_length, u32 timeout);
s32 PS4_SYSV_ABI sceUsbdGetDescriptor(SceUsbdDeviceHandle* dev_handle, u8 descType, u8 descIndex,
u8* data, s32 length);
s32 PS4_SYSV_ABI sceUsbdGetStringDescriptor(SceUsbdDeviceHandle* dev_handle, u8 desc_index,
u16 langid, u8* data, s32 length);
s32 PS4_SYSV_ABI sceUsbdGetStringDescriptorAscii(SceUsbdDeviceHandle* dev_handle, u8 desc_index,
u8* data, s32 length);
s32 PS4_SYSV_ABI sceUsbdTryLockEvents();
void PS4_SYSV_ABI sceUsbdLockEvents();
void PS4_SYSV_ABI sceUsbdUnlockEvents();
s32 PS4_SYSV_ABI sceUsbdEventHandlingOk();
s32 PS4_SYSV_ABI sceUsbdEventHandlerActive();
void PS4_SYSV_ABI sceUsbdLockEventWaiters();
void PS4_SYSV_ABI sceUsbdUnlockEventWaiters();
s32 PS4_SYSV_ABI sceUsbdWaitForEvent(timeval* tv);
s32 PS4_SYSV_ABI sceUsbdHandleEventsTimeout(timeval* tv);
s32 PS4_SYSV_ABI sceUsbdHandleEvents();
s32 PS4_SYSV_ABI sceUsbdHandleEventsLocked(timeval* tv);
s32 PS4_SYSV_ABI sceUsbdCheckConnected(SceUsbdDeviceHandle* dev_handle);
int PS4_SYSV_ABI Func_65F6EF33E38FFF50();
int PS4_SYSV_ABI Func_97F056BAD90AADE7();
int PS4_SYSV_ABI Func_C55104A33B35B264();

View file

@ -5,7 +5,6 @@
#include "common/arch.h"
#include "common/assert.h"
#include "common/types.h"
#include "core/cpu_patches.h"
#include "core/libraries/kernel/threads/pthread.h"
#include "core/tls.h"
@ -197,12 +196,7 @@ Tcb* GetTcbBase() {
thread_local std::once_flag init_tls_flag;
void EnsureThreadInitialized() {
std::call_once(init_tls_flag, [] {
#ifdef ARCH_X86_64
InitializeThreadPatchStack();
#endif
SetTcbBase(Libraries::Kernel::g_curthread->tcb);
});
std::call_once(init_tls_flag, [] { SetTcbBase(Libraries::Kernel::g_curthread->tcb); });
}
} // namespace Core

View file

@ -1126,7 +1126,7 @@
</message>
<message>
<source>Deadzone Offset (def 0.50):</source>
<translation>:</translation>
<translation> إزاحة المدى الغير فعال (الأصل ٠.٥٠).</translation>
</message>
<message>
<source>Speed Multiplier (def 1.0):</source>
@ -1704,7 +1704,7 @@
</message>
<message>
<source>Update Compatibility Database</source>
<translation type="unfinished">Update Compatibility Database</translation>
<translation>تحديث قاعدة بيانات التوافق</translation>
</message>
<message>
<source>Volume</source>
@ -1792,15 +1792,15 @@
</message>
<message>
<source>Display Compatibility Data:\nDisplays game compatibility information in table view. Enable &quot;Update Compatibility On Startup&quot; to get up-to-date information.</source>
<translation type="unfinished">Display Compatibility Data:\nDisplays game compatibility information in table view. Enable &quot;Update Compatibility On Startup&quot; to get up-to-date information.</translation>
<translation>عرض بيانات التوافق:\nيقوم بإظهار معلومات توافق اللعبة في طريقة عرض الطاولة. تشغيل&quot;تحديث التوافق عند التشغيل&quot; للحصول على معلومات محدثة.</translation>
</message>
<message>
<source>Update Compatibility On Startup:\nAutomatically update the compatibility database when shadPS4 starts.</source>
<translation type="unfinished">Update Compatibility On Startup:\nAutomatically update the compatibility database when shadPS4 starts.</translation>
<translation>تحديث التوافق عند التشغيل:\nتحديث قاعدة بيانات التوافق تلقائياً عند تشغيل shadps4.</translation>
</message>
<message>
<source>Update Compatibility Database:\nImmediately update the compatibility database.</source>
<translation type="unfinished">Update Compatibility Database:\nImmediately update the compatibility database.</translation>
<translation>تحديث قاعدة بيانات التوافق:\nقم بتحديث قاعدة بيانات التوافق حالاً.</translation>
</message>
<message>
<source>Never</source>
@ -1852,7 +1852,7 @@
</message>
<message>
<source>Enable HDR:\nEnables HDR in games that support it.\nYour monitor must have support for the BT2020 PQ color space and the RGB10A2 swapchain format.</source>
<translation type="unfinished">Enable HDR:\nEnables HDR in games that support it.\nYour monitor must have support for the BT2020 PQ color space and the RGB10A2 swapchain format.</translation>
<translation>تشغيل HDR:\n يقوم بتشغيل HDR في الألعاب المدعومة.\nيجب أن تدعم شاشتك أطياف ألوان BT2020 PQ و صيغة تنسيق المبادلة RGB10A2.</translation>
</message>
<message>
<source>Game Folders:\nThe list of folders to check for installed games.</source>
@ -1884,11 +1884,11 @@
</message>
<message>
<source>Collect Shaders:\nYou need this enabled to edit shaders with the debug menu (Ctrl + F10).</source>
<translation type="unfinished">Collect Shaders:\nYou need this enabled to edit shaders with the debug menu (Ctrl + F10).</translation>
<translation>تجميع برامج التظليل:\n يجب أن تقوم بتشغيل هذا لتعديل برامج التظليل باستخدام قائمة تصحيح الأخطاء (Ctrl + F10).</translation>
</message>
<message>
<source>Crash Diagnostics:\nCreates a .yaml file with info about the Vulkan state at the time of crashing.\nUseful for debugging &apos;Device lost&apos; errors. If you have this enabled, you should enable Host AND Guest Debug Markers.\nDoes not work on Intel GPUs.\nYou need Vulkan Validation Layers enabled and the Vulkan SDK for this to work.</source>
<translation type="unfinished">Crash Diagnostics:\nCreates a .yaml file with info about the Vulkan state at the time of crashing.\nUseful for debugging &apos;Device lost&apos; errors. If you have this enabled, you should enable Host AND Guest Debug Markers.\nDoes not work on Intel GPUs.\nYou need Vulkan Validation Layers enabled and the Vulkan SDK for this to work.</translation>
<translation>تشخيص الأعطال:\nيقوم بإنشاء ملف بصيغة .yaml يحتوي على معلومات عن حالة Vulkan في وقت حدوث العطل.\nمفيد لتصحيح أخطاء &apos;فصل الجهاز&apos;. إذا قمت بتشغيل هذا من الأفضل أن تقوم بتشغيل "استضافة علامات تصحيح الأخطاء" و "ضيف علامات تصحيح الأخطاء".\ا يعمل على وحدة معالجة رسوم إنتل.\nتحتاج لتشغيل التحقق من طبقات Vulkan و مجموعة تطوير البرامج الخاصة بـVulkan من أجل أن يعمل هذا.</translation>
</message>
<message>
<source>Copy GPU Buffers:\nGets around race conditions involving GPU submits.\nMay or may not help with PM4 type 0 crashes.</source>

View file

@ -1277,11 +1277,11 @@
</message>
<message>
<source>Trophy Viewer</source>
<translation type="unfinished">Trophy Viewer</translation>
<translation>Trophäenansicht</translation>
</message>
<message>
<source>No games found. Please add your games to your library first.</source>
<translation type="unfinished">No games found. Please add your games to your library first.</translation>
<translation>Keine Spiele gefunden. Bitte fügen Sie zuerst Ihre Spiele zu Ihrer Bibliothek hinzu.</translation>
</message>
<message>
<source>Search...</source>
@ -1409,43 +1409,43 @@
</message>
<message>
<source>Play</source>
<translation type="unfinished">Play</translation>
<translation>Spielen</translation>
</message>
<message>
<source>Pause</source>
<translation type="unfinished">Pause</translation>
<translation>Pause</translation>
</message>
<message>
<source>Stop</source>
<translation type="unfinished">Stop</translation>
<translation>Stopp</translation>
</message>
<message>
<source>Restart</source>
<translation type="unfinished">Restart</translation>
<translation>Neustarten</translation>
</message>
<message>
<source>Full Screen</source>
<translation type="unfinished">Full Screen</translation>
<translation>Vollbild</translation>
</message>
<message>
<source>Controllers</source>
<translation type="unfinished">Controllers</translation>
<translation>Controller</translation>
</message>
<message>
<source>Keyboard</source>
<translation type="unfinished">Keyboard</translation>
<translation>Tastatur</translation>
</message>
<message>
<source>Refresh List</source>
<translation type="unfinished">Refresh List</translation>
<translation>Liste aktualisieren</translation>
</message>
<message>
<source>Resume</source>
<translation type="unfinished">Resume</translation>
<translation>Fortsetzen</translation>
</message>
<message>
<source>Show Labels Under Icons</source>
<translation type="unfinished">Show Labels Under Icons</translation>
<translation>Etiketten unter Symbolen anzeigen</translation>
</message>
</context>
<context>
@ -2048,7 +2048,11 @@
</message>
<message>
<source>Open the custom trophy images/sounds folder:\nYou can add custom images to the trophies and an audio.\nAdd the files to custom_trophy with the following names:\ntrophy.wav OR trophy.mp3, bronze.png, gold.png, platinum.png, silver.png\nNote: The sound will only work in QT versions.</source>
<translation type="unfinished">Open the custom trophy images/sounds folder:\nYou can add custom images to the trophies and an audio.\nAdd the files to custom_trophy with the following names:\ntrophy.wav OR trophy.mp3, bronze.png, gold.png, platinum.png, silver.png\nNote: The sound will only work in QT versions.</translation>
<translation>Öffnen Sie den Ordner für benutzerdefinierte Trophäenbilder/-sounds:\n
Sie können benutzerdefinierte Bilder zu den Trophäen hinzufügen und einen Ton hinzufügen.\n
Fügen Sie die Dateien dem Ordner custom_trophy mit folgenden Namen hinzu:\n
trophy.wav ODER trophy.mp3, bronze.png, gold.png, platinum.png, silver.png\n
Hinweis: Der Sound funktioniert nur in Qt-Versionen.</translation>
</message>
</context>
<context>
@ -2059,23 +2063,23 @@
</message>
<message>
<source>Select Game:</source>
<translation type="unfinished">Select Game:</translation>
<translation>Spiel auswählen:</translation>
</message>
<message>
<source>Progress</source>
<translation type="unfinished">Progress</translation>
<translation>Fortschritt</translation>
</message>
<message>
<source>Show Earned Trophies</source>
<translation type="unfinished">Show Earned Trophies</translation>
<translation>Verdiente Trophäen anzeigen</translation>
</message>
<message>
<source>Show Not Earned Trophies</source>
<translation type="unfinished">Show Not Earned Trophies</translation>
<translation>Nicht verdiente Trophäen anzeigen</translation>
</message>
<message>
<source>Show Hidden Trophies</source>
<translation type="unfinished">Show Hidden Trophies</translation>
<translation>Verborgene Trophäen anzeigen</translation>
</message>
</context>
</TS>

View file

@ -1409,43 +1409,43 @@
</message>
<message>
<source>Play</source>
<translation type="unfinished">Play</translation>
<translation>Luaj</translation>
</message>
<message>
<source>Pause</source>
<translation type="unfinished">Pause</translation>
<translation>Pezullo</translation>
</message>
<message>
<source>Stop</source>
<translation type="unfinished">Stop</translation>
<translation>Ndalo</translation>
</message>
<message>
<source>Restart</source>
<translation type="unfinished">Restart</translation>
<translation>Rinis</translation>
</message>
<message>
<source>Full Screen</source>
<translation type="unfinished">Full Screen</translation>
<translation>Ekran i Plotë</translation>
</message>
<message>
<source>Controllers</source>
<translation type="unfinished">Controllers</translation>
<translation>Dorezat</translation>
</message>
<message>
<source>Keyboard</source>
<translation type="unfinished">Keyboard</translation>
<translation>Tastiera</translation>
</message>
<message>
<source>Refresh List</source>
<translation type="unfinished">Refresh List</translation>
<translation>Rifresko Listën</translation>
</message>
<message>
<source>Resume</source>
<translation type="unfinished">Resume</translation>
<translation>Rifillo</translation>
</message>
<message>
<source>Show Labels Under Icons</source>
<translation type="unfinished">Show Labels Under Icons</translation>
<translation>Shfaq Etiketat Poshtë Ikonave</translation>
</message>
</context>
<context>

View file

@ -75,6 +75,28 @@ Id EmitFPMin64(EmitContext& ctx, Id a, Id b) {
return ctx.OpFMin(ctx.F64[1], a, b);
}
Id EmitFPMinTri32(EmitContext& ctx, Id a, Id b, Id c) {
if (ctx.profile.supports_trinary_minmax) {
return ctx.OpFMin3AMD(ctx.F32[1], a, b, c);
}
return ctx.OpFMin(ctx.F32[1], a, ctx.OpFMin(ctx.F32[1], b, c));
}
Id EmitFPMaxTri32(EmitContext& ctx, Id a, Id b, Id c) {
if (ctx.profile.supports_trinary_minmax) {
return ctx.OpFMax3AMD(ctx.F32[1], a, b, c);
}
return ctx.OpFMax(ctx.F32[1], a, ctx.OpFMax(ctx.F32[1], b, c));
}
Id EmitFPMedTri32(EmitContext& ctx, Id a, Id b, Id c) {
if (ctx.profile.supports_trinary_minmax) {
return ctx.OpFMid3AMD(ctx.F32[1], a, b, c);
}
const Id mmx{ctx.OpFMin(ctx.F32[1], ctx.OpFMax(ctx.F32[1], a, b), c)};
return ctx.OpFMax(ctx.F32[1], ctx.OpFMin(ctx.F32[1], a, b), mmx);
}
Id EmitFPMul16(EmitContext& ctx, IR::Inst* inst, Id a, Id b) {
return Decorate(ctx, inst, ctx.OpFMul(ctx.F16[1], a, b));
}

View file

@ -247,6 +247,9 @@ Id EmitFPMax32(EmitContext& ctx, Id a, Id b, bool is_legacy = false);
Id EmitFPMax64(EmitContext& ctx, Id a, Id b);
Id EmitFPMin32(EmitContext& ctx, Id a, Id b, bool is_legacy = false);
Id EmitFPMin64(EmitContext& ctx, Id a, Id b);
Id EmitFPMinTri32(EmitContext& ctx, Id a, Id b, Id c);
Id EmitFPMaxTri32(EmitContext& ctx, Id a, Id b, Id c);
Id EmitFPMedTri32(EmitContext& ctx, Id a, Id b, Id c);
Id EmitFPMul16(EmitContext& ctx, IR::Inst* inst, Id a, Id b);
Id EmitFPMul32(EmitContext& ctx, IR::Inst* inst, Id a, Id b);
Id EmitFPMul64(EmitContext& ctx, IR::Inst* inst, Id a, Id b);
@ -372,6 +375,12 @@ Id EmitSMin32(EmitContext& ctx, Id a, Id b);
Id EmitUMin32(EmitContext& ctx, Id a, Id b);
Id EmitSMax32(EmitContext& ctx, Id a, Id b);
Id EmitUMax32(EmitContext& ctx, Id a, Id b);
Id EmitSMinTri32(EmitContext& ctx, Id a, Id b, Id c);
Id EmitUMinTri32(EmitContext& ctx, Id a, Id b, Id c);
Id EmitSMaxTri32(EmitContext& ctx, Id a, Id b, Id c);
Id EmitUMaxTri32(EmitContext& ctx, Id a, Id b, Id c);
Id EmitSMedTri32(EmitContext& ctx, Id a, Id b, Id c);
Id EmitUMedTri32(EmitContext& ctx, Id a, Id b, Id c);
Id EmitSClamp32(EmitContext& ctx, IR::Inst* inst, Id value, Id min, Id max);
Id EmitUClamp32(EmitContext& ctx, IR::Inst* inst, Id value, Id min, Id max);
Id EmitSLessThan32(EmitContext& ctx, Id lhs, Id rhs);

View file

@ -256,6 +256,50 @@ Id EmitUMax32(EmitContext& ctx, Id a, Id b) {
return ctx.OpUMax(ctx.U32[1], a, b);
}
Id EmitSMinTri32(EmitContext& ctx, Id a, Id b, Id c) {
if (ctx.profile.supports_trinary_minmax) {
return ctx.OpSMin3AMD(ctx.U32[1], a, b, c);
}
return ctx.OpSMin(ctx.U32[1], a, ctx.OpSMin(ctx.U32[1], b, c));
}
Id EmitUMinTri32(EmitContext& ctx, Id a, Id b, Id c) {
if (ctx.profile.supports_trinary_minmax) {
return ctx.OpUMin3AMD(ctx.U32[1], a, b, c);
}
return ctx.OpUMin(ctx.U32[1], a, ctx.OpUMin(ctx.U32[1], b, c));
}
Id EmitSMaxTri32(EmitContext& ctx, Id a, Id b, Id c) {
if (ctx.profile.supports_trinary_minmax) {
return ctx.OpSMax3AMD(ctx.U32[1], a, b, c);
}
return ctx.OpSMax(ctx.U32[1], a, ctx.OpSMax(ctx.U32[1], b, c));
}
Id EmitUMaxTri32(EmitContext& ctx, Id a, Id b, Id c) {
if (ctx.profile.supports_trinary_minmax) {
return ctx.OpUMax3AMD(ctx.U32[1], a, b, c);
}
return ctx.OpUMax(ctx.U32[1], a, ctx.OpUMax(ctx.U32[1], b, c));
}
Id EmitSMedTri32(EmitContext& ctx, Id a, Id b, Id c) {
if (ctx.profile.supports_trinary_minmax) {
return ctx.OpSMid3AMD(ctx.U32[1], a, b, c);
}
const Id mmx{ctx.OpSMin(ctx.U32[1], ctx.OpSMax(ctx.U32[1], a, b), c)};
return ctx.OpSMax(ctx.U32[1], ctx.OpSMin(ctx.U32[1], a, b), mmx);
}
Id EmitUMedTri32(EmitContext& ctx, Id a, Id b, Id c) {
if (ctx.profile.supports_trinary_minmax) {
return ctx.OpUMid3AMD(ctx.U32[1], a, b, c);
}
const Id mmx{ctx.OpUMin(ctx.U32[1], ctx.OpUMax(ctx.U32[1], a, b), c)};
return ctx.OpUMax(ctx.U32[1], ctx.OpUMin(ctx.U32[1], a, b), mmx);
}
Id EmitSClamp32(EmitContext& ctx, IR::Inst* inst, Id value, Id min, Id max) {
Id result{};
if (ctx.profile.has_broken_spirv_clamp) {

View file

@ -238,13 +238,11 @@ public:
void V_FMA_F32(const GcnInst& inst);
void V_FMA_F64(const GcnInst& inst);
void V_MIN3_F32(const GcnInst& inst);
void V_MIN3_I32(const GcnInst& inst);
void V_MIN3_U32(const GcnInst& inst);
void V_MIN3_U32(bool is_signed, const GcnInst& inst);
void V_MAX3_F32(const GcnInst& inst);
void V_MAX3_U32(bool is_signed, const GcnInst& inst);
void V_MED3_F32(const GcnInst& inst);
void V_MED3_I32(const GcnInst& inst);
void V_MED3_U32(const GcnInst& inst);
void V_MED3_U32(bool is_signed, const GcnInst& inst);
void V_SAD(const GcnInst& inst);
void V_SAD_U32(const GcnInst& inst);
void V_CVT_PK_U16_U32(const GcnInst& inst);

View file

@ -359,9 +359,9 @@ void Translator::EmitVectorAlu(const GcnInst& inst) {
case Opcode::V_MIN3_F32:
return V_MIN3_F32(inst);
case Opcode::V_MIN3_I32:
return V_MIN3_I32(inst);
return V_MIN3_U32(true, inst);
case Opcode::V_MIN3_U32:
return V_MIN3_U32(inst);
return V_MIN3_U32(false, inst);
case Opcode::V_MAX3_F32:
return V_MAX3_F32(inst);
case Opcode::V_MAX3_I32:
@ -371,9 +371,9 @@ void Translator::EmitVectorAlu(const GcnInst& inst) {
case Opcode::V_MED3_F32:
return V_MED3_F32(inst);
case Opcode::V_MED3_I32:
return V_MED3_I32(inst);
return V_MED3_U32(true, inst);
case Opcode::V_MED3_U32:
return V_MED3_U32(inst);
return V_MED3_U32(false, inst);
case Opcode::V_SAD_U32:
return V_SAD_U32(inst);
case Opcode::V_CVT_PK_U16_U32:
@ -1166,59 +1166,42 @@ void Translator::V_MIN3_F32(const GcnInst& inst) {
const IR::F32 src0{GetSrc<IR::F32>(inst.src[0])};
const IR::F32 src1{GetSrc<IR::F32>(inst.src[1])};
const IR::F32 src2{GetSrc<IR::F32>(inst.src[2])};
SetDst(inst.dst[0], ir.FPMin(src0, ir.FPMin(src1, src2)));
SetDst(inst.dst[0], ir.FPMinTri(src0, src1, src2));
}
void Translator::V_MIN3_I32(const GcnInst& inst) {
void Translator::V_MIN3_U32(bool is_signed, const GcnInst& inst) {
const IR::U32 src0{GetSrc(inst.src[0])};
const IR::U32 src1{GetSrc(inst.src[1])};
const IR::U32 src2{GetSrc(inst.src[2])};
SetDst(inst.dst[0], ir.SMin(src0, ir.SMin(src1, src2)));
}
void Translator::V_MIN3_U32(const GcnInst& inst) {
const IR::U32 src0{GetSrc(inst.src[0])};
const IR::U32 src1{GetSrc(inst.src[1])};
const IR::U32 src2{GetSrc(inst.src[2])};
SetDst(inst.dst[0], ir.UMin(src0, ir.UMin(src1, src2)));
SetDst(inst.dst[0], ir.IMinTri(src0, src1, src2, is_signed));
}
void Translator::V_MAX3_F32(const GcnInst& inst) {
const IR::F32 src0{GetSrc<IR::F32>(inst.src[0])};
const IR::F32 src1{GetSrc<IR::F32>(inst.src[1])};
const IR::F32 src2{GetSrc<IR::F32>(inst.src[2])};
SetDst(inst.dst[0], ir.FPMax(src0, ir.FPMax(src1, src2)));
SetDst(inst.dst[0], ir.FPMaxTri(src0, src1, src2));
}
void Translator::V_MAX3_U32(bool is_signed, const GcnInst& inst) {
const IR::U32 src0{GetSrc(inst.src[0])};
const IR::U32 src1{GetSrc(inst.src[1])};
const IR::U32 src2{GetSrc(inst.src[2])};
SetDst(inst.dst[0], ir.IMax(src0, ir.IMax(src1, src2, is_signed), is_signed));
SetDst(inst.dst[0], ir.IMaxTri(src0, src1, src2, is_signed));
}
void Translator::V_MED3_F32(const GcnInst& inst) {
const IR::F32 src0{GetSrc<IR::F32>(inst.src[0])};
const IR::F32 src1{GetSrc<IR::F32>(inst.src[1])};
const IR::F32 src2{GetSrc<IR::F32>(inst.src[2])};
const IR::F32 mmx = ir.FPMin(ir.FPMax(src0, src1), src2);
SetDst(inst.dst[0], ir.FPMax(ir.FPMin(src0, src1), mmx));
SetDst(inst.dst[0], ir.FPMedTri(src0, src1, src2));
}
void Translator::V_MED3_I32(const GcnInst& inst) {
void Translator::V_MED3_U32(bool is_signed, const GcnInst& inst) {
const IR::U32 src0{GetSrc(inst.src[0])};
const IR::U32 src1{GetSrc(inst.src[1])};
const IR::U32 src2{GetSrc(inst.src[2])};
const IR::U32 mmx = ir.SMin(ir.SMax(src0, src1), src2);
SetDst(inst.dst[0], ir.SMax(ir.SMin(src0, src1), mmx));
}
void Translator::V_MED3_U32(const GcnInst& inst) {
const IR::U32 src0{GetSrc(inst.src[0])};
const IR::U32 src1{GetSrc(inst.src[1])};
const IR::U32 src2{GetSrc(inst.src[2])};
const IR::U32 mmx = ir.UMin(ir.UMax(src0, src1), src2);
SetDst(inst.dst[0], ir.UMax(ir.UMin(src0, src1), mmx));
SetDst(inst.dst[0], ir.IMedTri(src0, src1, src2, is_signed));
}
void Translator::V_SAD(const GcnInst& inst) {

View file

@ -1336,6 +1336,18 @@ F32F64 IREmitter::FPMin(const F32F64& lhs, const F32F64& rhs, bool is_legacy) {
}
}
F32F64 IREmitter::FPMinTri(const F32F64& a, const F32F64& b, const F32F64& c) {
return Inst<F32>(Opcode::FPMinTri32, a, b, c);
}
F32F64 IREmitter::FPMaxTri(const F32F64& a, const F32F64& b, const F32F64& c) {
return Inst<F32>(Opcode::FPMaxTri32, a, b, c);
}
F32F64 IREmitter::FPMedTri(const F32F64& a, const F32F64& b, const F32F64& c) {
return Inst<F32>(Opcode::FPMedTri32, a, b, c);
}
U32U64 IREmitter::IAdd(const U32U64& a, const U32U64& b) {
if (a.Type() != b.Type()) {
UNREACHABLE_MSG("Mismatching types {} and {}", a.Type(), b.Type());
@ -1567,6 +1579,42 @@ U32 IREmitter::IMax(const U32& a, const U32& b, bool is_signed) {
return is_signed ? SMax(a, b) : UMax(a, b);
}
U32 IREmitter::SMinTri(const U32& a, const U32& b, const U32& c) {
return Inst<U32>(Opcode::SMinTri32, a, b, c);
}
U32 IREmitter::UMinTri(const U32& a, const U32& b, const U32& c) {
return Inst<U32>(Opcode::UMinTri32, a, b, c);
}
U32 IREmitter::IMinTri(const U32& a, const U32& b, const U32& c, bool is_signed) {
return is_signed ? SMinTri(a, b, c) : UMinTri(a, b, c);
}
U32 IREmitter::SMaxTri(const U32& a, const U32& b, const U32& c) {
return Inst<U32>(Opcode::SMaxTri32, a, b, c);
}
U32 IREmitter::UMaxTri(const U32& a, const U32& b, const U32& c) {
return Inst<U32>(Opcode::UMaxTri32, a, b, c);
}
U32 IREmitter::IMaxTri(const U32& a, const U32& b, const U32& c, bool is_signed) {
return is_signed ? SMaxTri(a, b, c) : UMaxTri(a, b, c);
}
U32 IREmitter::SMedTri(const U32& a, const U32& b, const U32& c) {
return Inst<U32>(Opcode::SMedTri32, a, b, c);
}
U32 IREmitter::UMedTri(const U32& a, const U32& b, const U32& c) {
return Inst<U32>(Opcode::UMedTri32, a, b, c);
}
U32 IREmitter::IMedTri(const U32& a, const U32& b, const U32& c, bool is_signed) {
return is_signed ? SMedTri(a, b, c) : UMedTri(a, b, c);
}
U32 IREmitter::SClamp(const U32& value, const U32& min, const U32& max) {
return Inst<U32>(Opcode::SClamp32, value, min, max);
}

View file

@ -233,6 +233,9 @@ public:
[[nodiscard]] U1 FPUnordered(const F32F64& lhs, const F32F64& rhs);
[[nodiscard]] F32F64 FPMax(const F32F64& lhs, const F32F64& rhs, bool is_legacy = false);
[[nodiscard]] F32F64 FPMin(const F32F64& lhs, const F32F64& rhs, bool is_legacy = false);
[[nodiscard]] F32F64 FPMinTri(const F32F64& a, const F32F64& b, const F32F64& c);
[[nodiscard]] F32F64 FPMaxTri(const F32F64& a, const F32F64& b, const F32F64& c);
[[nodiscard]] F32F64 FPMedTri(const F32F64& a, const F32F64& b, const F32F64& c);
[[nodiscard]] U32U64 IAdd(const U32U64& a, const U32U64& b);
[[nodiscard]] Value IAddCary(const U32& a, const U32& b);
@ -266,6 +269,15 @@ public:
[[nodiscard]] U32 SMax(const U32& a, const U32& b);
[[nodiscard]] U32 UMax(const U32& a, const U32& b);
[[nodiscard]] U32 IMax(const U32& a, const U32& b, bool is_signed);
[[nodiscard]] U32 SMinTri(const U32& a, const U32& b, const U32& c);
[[nodiscard]] U32 UMinTri(const U32& a, const U32& b, const U32& c);
[[nodiscard]] U32 IMinTri(const U32& a, const U32& b, const U32& c, bool is_signed);
[[nodiscard]] U32 SMaxTri(const U32& a, const U32& b, const U32& c);
[[nodiscard]] U32 UMaxTri(const U32& a, const U32& b, const U32& c);
[[nodiscard]] U32 IMaxTri(const U32& a, const U32& b, const U32& c, bool is_signed);
[[nodiscard]] U32 SMedTri(const U32& a, const U32& b, const U32& c);
[[nodiscard]] U32 UMedTri(const U32& a, const U32& b, const U32& c);
[[nodiscard]] U32 IMedTri(const U32& a, const U32& b, const U32& c, bool is_signed);
[[nodiscard]] U32 SClamp(const U32& value, const U32& min, const U32& max);
[[nodiscard]] U32 UClamp(const U32& value, const U32& min, const U32& max);

View file

@ -241,6 +241,9 @@ OPCODE(FPMax32, F32, F32,
OPCODE(FPMax64, F64, F64, F64, )
OPCODE(FPMin32, F32, F32, F32, U1, )
OPCODE(FPMin64, F64, F64, F64, )
OPCODE(FPMinTri32, F32, F32, F32, F32, )
OPCODE(FPMaxTri32, F32, F32, F32, F32, )
OPCODE(FPMedTri32, F32, F32, F32, F32, )
OPCODE(FPMul32, F32, F32, F32, )
OPCODE(FPMul64, F64, F64, F64, )
OPCODE(FPDiv32, F32, F32, F32, )
@ -350,6 +353,12 @@ OPCODE(SMin32, U32, U32,
OPCODE(UMin32, U32, U32, U32, )
OPCODE(SMax32, U32, U32, U32, )
OPCODE(UMax32, U32, U32, U32, )
OPCODE(SMinTri32, U32, U32, U32, U32, )
OPCODE(UMinTri32, U32, U32, U32, U32, )
OPCODE(SMaxTri32, U32, U32, U32, U32, )
OPCODE(UMaxTri32, U32, U32, U32, U32, )
OPCODE(SMedTri32, U32, U32, U32, U32, )
OPCODE(UMedTri32, U32, U32, U32, U32, )
OPCODE(SClamp32, U32, U32, U32, U32, )
OPCODE(UClamp32, U32, U32, U32, U32, )
OPCODE(SLessThan32, U1, U32, U32, )

View file

@ -26,6 +26,7 @@ struct Profile {
bool support_legacy_vertex_attributes{};
bool supports_image_load_store_lod{};
bool supports_native_cube_calc{};
bool supports_trinary_minmax{};
bool supports_robust_buffer_access{};
bool has_broken_spirv_clamp{};
bool lower_left_origin_mode{};

View file

@ -276,6 +276,7 @@ bool Instance::CreateDevice() {
shader_stencil_export = add_extension(VK_EXT_SHADER_STENCIL_EXPORT_EXTENSION_NAME);
image_load_store_lod = add_extension(VK_AMD_SHADER_IMAGE_LOAD_STORE_LOD_EXTENSION_NAME);
amd_gcn_shader = add_extension(VK_AMD_GCN_SHADER_EXTENSION_NAME);
amd_shader_trinary_minmax = add_extension(VK_AMD_SHADER_TRINARY_MINMAX_EXTENSION_NAME);
const bool calibrated_timestamps =
TRACY_GPU_ENABLED ? add_extension(VK_EXT_CALIBRATED_TIMESTAMPS_EXTENSION_NAME) : false;

View file

@ -145,6 +145,11 @@ public:
return amd_gcn_shader;
}
/// Returns true when VK_AMD_shader_trinary_minmax is supported.
bool IsAmdShaderTrinaryMinMaxSupported() const {
return amd_shader_trinary_minmax;
}
/// Returns true when geometry shaders are supported by the device
bool IsGeometryStageSupported() const {
return features.geometryShader;
@ -333,6 +338,7 @@ private:
bool shader_stencil_export{};
bool image_load_store_lod{};
bool amd_gcn_shader{};
bool amd_shader_trinary_minmax{};
bool portability_subset{};
};

View file

@ -201,6 +201,7 @@ PipelineCache::PipelineCache(const Instance& instance_, Scheduler& scheduler_,
.support_legacy_vertex_attributes = instance_.IsLegacyVertexAttributesSupported(),
.supports_image_load_store_lod = instance_.IsImageLoadStoreLodSupported(),
.supports_native_cube_calc = instance_.IsAmdGcnShaderSupported(),
.supports_trinary_minmax = instance_.IsAmdShaderTrinaryMinMaxSupported(),
.supports_robust_buffer_access = instance_.IsRobustBufferAccess2Supported(),
.needs_manual_interpolation = instance.IsFragmentShaderBarycentricSupported() &&
instance.GetDriverID() == vk::DriverId::eNvidiaProprietary,