From 31bd502764f1ac975fc55bd2a788a7e08a9f34ec Mon Sep 17 00:00:00 2001 From: TheTurtle <47210458+raphaelthegreat@users.noreply.github.com> Date: Fri, 14 Jun 2024 00:58:57 +0300 Subject: [PATCH 1/2] core: Fixup linux support (#195) * tls: Implement for linux * core: Implement memory manager for linux --- src/audio_core/sdl_audio.cpp | 4 - src/audio_core/sdl_audio.h | 1 - src/common/io_file.cpp | 5 +- src/common/path_util.cpp | 3 - src/core/address_space.cpp | 82 +++++++++++- src/core/file_format/pkg.cpp | 5 +- src/core/file_format/pkg.h | 1 - src/core/file_format/psf.cpp | 5 +- src/core/libraries/audio/audioout.cpp | 5 +- .../libraries/kernel/thread_management.cpp | 9 +- src/core/libraries/kernel/thread_management.h | 6 +- .../kernel/threads/kernel_threads_rwlock.cpp | 4 +- src/core/tls.cpp | 124 ++++++++++++------ src/emulator.cpp | 9 +- src/emulator.h | 4 +- src/sdl_window.cpp | 1 + src/video_core/amdgpu/liverpool.h | 2 +- src/video_core/amdgpu/resource.h | 2 +- 18 files changed, 184 insertions(+), 88 deletions(-) diff --git a/src/audio_core/sdl_audio.cpp b/src/audio_core/sdl_audio.cpp index 6507d694..188307e5 100644 --- a/src/audio_core/sdl_audio.cpp +++ b/src/audio_core/sdl_audio.cpp @@ -10,10 +10,6 @@ namespace Audio { -int SDLAudio::AudioInit() { - return SDL_InitSubSystem(SDL_INIT_AUDIO); -} - int SDLAudio::AudioOutOpen(int type, u32 samples_num, u32 freq, Libraries::AudioOut::OrbisAudioOutParam format) { using Libraries::AudioOut::OrbisAudioOutParam; diff --git a/src/audio_core/sdl_audio.h b/src/audio_core/sdl_audio.h index 4bd16cbf..ae5e7276 100644 --- a/src/audio_core/sdl_audio.h +++ b/src/audio_core/sdl_audio.h @@ -14,7 +14,6 @@ public: SDLAudio() = default; virtual ~SDLAudio() = default; - int AudioInit(); int AudioOutOpen(int type, u32 samples_num, u32 freq, Libraries::AudioOut::OrbisAudioOutParam format); s32 AudioOutOutput(s32 handle, const void* ptr); diff --git a/src/common/io_file.cpp b/src/common/io_file.cpp index fda3353e..71c40a16 100644 --- a/src/common/io_file.cpp +++ b/src/common/io_file.cpp @@ -183,9 +183,8 @@ void IOFile::Open(const fs::path& path, FileAccessMode mode, FileType type, File #endif if (!IsOpen()) { - const auto ec = std::error_code{errno, std::generic_category()}; - LOG_ERROR(Common_Filesystem, "Failed to open the file at path={}, ec_message={}", - PathToUTF8String(file_path), ec.message()); + LOG_ERROR(Common_Filesystem, "Failed to open the file at path={}", + PathToUTF8String(file_path)); } } diff --git a/src/common/path_util.cpp b/src/common/path_util.cpp index 7210f212..293ee1b7 100644 --- a/src/common/path_util.cpp +++ b/src/common/path_util.cpp @@ -1,10 +1,7 @@ // SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later -#include -#include #include - #include "common/logging/log.h" #include "common/path_util.h" diff --git a/src/core/address_space.cpp b/src/core/address_space.cpp index 420ed59a..79a6a6f4 100644 --- a/src/core/address_space.cpp +++ b/src/core/address_space.cpp @@ -10,6 +10,7 @@ #ifdef _WIN32 #include #else +#include #include #endif @@ -215,25 +216,96 @@ enum PosixPageProtection { struct AddressSpace::Impl { Impl() { - UNREACHABLE(); + // Allocate virtual address placeholder for our address space. + void* hint_address = reinterpret_cast(SYSTEM_MANAGED_MIN); + virtual_size = SystemSize + UserSize; + virtual_base = reinterpret_cast( + mmap(reinterpret_cast(hint_address), virtual_size, PROT_READ | PROT_WRITE, + MAP_PRIVATE | MAP_ANONYMOUS | MAP_NORESERVE, -1, 0)); + if (virtual_base == MAP_FAILED) { + LOG_CRITICAL(Kernel_Vmm, "mmap failed: {}", strerror(errno)); + throw std::bad_alloc{}; + } + madvise(virtual_base, virtual_size, MADV_HUGEPAGE); + + backing_fd = memfd_create("BackingDmem", 0); + if (backing_fd < 0) { + LOG_CRITICAL(Kernel_Vmm, "memfd_create failed: {}", strerror(errno)); + throw std::bad_alloc{}; + } + + // Defined to extend the file with zeros + int ret = ftruncate(backing_fd, BackingSize); + if (ret != 0) { + LOG_CRITICAL(Kernel_Vmm, "ftruncate failed with {}, are you out-of-memory?", + strerror(errno)); + throw std::bad_alloc{}; + } + + // Map backing dmem handle. + backing_base = static_cast( + mmap(nullptr, BackingSize, PROT_READ | PROT_WRITE, MAP_SHARED, backing_fd, 0)); + if (backing_base == MAP_FAILED) { + LOG_CRITICAL(Kernel_Vmm, "mmap failed: {}", strerror(errno)); + throw std::bad_alloc{}; + } + + const VAddr start_addr = reinterpret_cast(virtual_base); + m_free_regions.insert({start_addr, start_addr + virtual_size}); } void* Map(VAddr virtual_addr, PAddr phys_addr, size_t size, PosixPageProtection prot) { - UNREACHABLE(); - return nullptr; + m_free_regions.subtract({virtual_addr, virtual_addr + size}); + const int fd = phys_addr != -1 ? backing_fd : -1; + const int host_offset = phys_addr != -1 ? phys_addr : 0; + const int flag = phys_addr != -1 ? MAP_SHARED : (MAP_ANONYMOUS | MAP_PRIVATE); + void* ret = mmap(reinterpret_cast(virtual_addr), size, prot, MAP_FIXED | flag, fd, + host_offset); + ASSERT_MSG(ret != MAP_FAILED, "mmap failed: {}", strerror(errno)); + return ret; } void Unmap(VAddr virtual_addr, PAddr phys_addr, size_t size) { - UNREACHABLE(); + // Check to see if we are adjacent to any regions. + auto start_address = virtual_addr; + auto end_address = start_address + size; + auto it = m_free_regions.find({start_address - 1, end_address + 1}); + + // If we are, join with them, ensuring we stay in bounds. + if (it != m_free_regions.end()) { + start_address = std::min(start_address, it->lower()); + end_address = std::max(end_address, it->upper()); + } + + // Free the relevant region. + m_free_regions.insert({start_address, end_address}); + + // Return the adjusted pointers. + void* ret = mmap(reinterpret_cast(start_address), end_address - start_address, + PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED, -1, 0); + ASSERT_MSG(ret != MAP_FAILED, "mmap failed: {}", strerror(errno)); } void Protect(VAddr virtual_addr, size_t size, bool read, bool write, bool execute) { - UNREACHABLE(); + int flags = PROT_NONE; + if (read) { + flags |= PROT_READ; + } + if (write) { + flags |= PROT_WRITE; + } + if (execute) { + flags |= PROT_EXEC; + } + int ret = mprotect(reinterpret_cast(virtual_addr), size, flags); + ASSERT_MSG(ret == 0, "mprotect failed: {}", strerror(errno)); } + int backing_fd; u8* backing_base{}; u8* virtual_base{}; size_t virtual_size{}; + boost::icl::interval_set m_free_regions; }; #endif diff --git a/src/core/file_format/pkg.cpp b/src/core/file_format/pkg.cpp index 5150e128..6d5fb0d4 100644 --- a/src/core/file_format/pkg.cpp +++ b/src/core/file_format/pkg.cpp @@ -1,11 +1,10 @@ // SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later -#include #include #include "common/io_file.h" -#include "pkg.h" -#include "pkg_type.h" +#include "core/file_format/pkg.h" +#include "core/file_format/pkg_type.h" static void DecompressPFSC(std::span compressed_data, std::span decompressed_data) { diff --git a/src/core/file_format/pkg.h b/src/core/file_format/pkg.h index f77a7804..3fef6c1c 100644 --- a/src/core/file_format/pkg.h +++ b/src/core/file_format/pkg.h @@ -4,7 +4,6 @@ #pragma once #include -#include #include #include #include diff --git a/src/core/file_format/psf.cpp b/src/core/file_format/psf.cpp index 4a7f6215..dd9da71a 100644 --- a/src/core/file_format/psf.cpp +++ b/src/core/file_format/psf.cpp @@ -2,11 +2,8 @@ // SPDX-License-Identifier: GPL-2.0-or-later #include -#include -#include - #include "common/io_file.h" -#include "psf.h" +#include "core/file_format/psf.h" PSF::PSF() = default; diff --git a/src/core/libraries/audio/audioout.cpp b/src/core/libraries/audio/audioout.cpp index 993970c6..0207eaff 100644 --- a/src/core/libraries/audio/audioout.cpp +++ b/src/core/libraries/audio/audioout.cpp @@ -192,9 +192,8 @@ int PS4_SYSV_ABI sceAudioOutGetSystemState() { int PS4_SYSV_ABI sceAudioOutInit() { audio = std::make_unique(); - u32 result = audio->AudioInit() == 0 ? ORBIS_OK : ORBIS_AUDIO_OUT_ERROR_NOT_INIT; - LOG_INFO(Lib_AudioOut, "AudioInit returned {}", result); - return result; + LOG_INFO(Lib_AudioOut, "called"); + return ORBIS_OK; } int PS4_SYSV_ABI sceAudioOutInitIpmiGetSession() { diff --git a/src/core/libraries/kernel/thread_management.cpp b/src/core/libraries/kernel/thread_management.cpp index 218a743a..63e80caa 100644 --- a/src/core/libraries/kernel/thread_management.cpp +++ b/src/core/libraries/kernel/thread_management.cpp @@ -393,6 +393,8 @@ void* createMutex(void* addr) { if (addr == nullptr || *static_cast(addr) != nullptr) { return addr; } + static std::mutex mutex; + std::scoped_lock lk{mutex}; auto vaddr = reinterpret_cast(addr); std::string name = fmt::format("mutex{:#x}", vaddr); @@ -464,7 +466,7 @@ int PS4_SYSV_ABI scePthreadMutexattrInit(ScePthreadMutexattr* attr) { int result = pthread_mutexattr_init(&(*attr)->pth_mutex_attr); - result = (result == 0 ? scePthreadMutexattrSettype(attr, 1) : result); + result = (result == 0 ? scePthreadMutexattrSettype(attr, 2) : result); result = (result == 0 ? scePthreadMutexattrSetprotocol(attr, 0) : result); switch (result) { @@ -1165,6 +1167,10 @@ int PS4_SYSV_ABI posix_pthread_create_name_np(ScePthread* thread, const ScePthre return result; } +int PS4_SYSV_ABI scePthreadOnce(int* once_control, void (*init_routine)(void)) { + return pthread_once(reinterpret_cast(once_control), init_routine); +} + void pthreadSymbolsRegister(Core::Loader::SymbolsResolver* sym) { LIB_FUNCTION("4+h9EzwKF4I", "libkernel", 1, "libkernel", 1, 1, scePthreadAttrSetschedpolicy); LIB_FUNCTION("-Wreprtu0Qs", "libkernel", 1, "libkernel", 1, 1, scePthreadAttrSetdetachstate); @@ -1191,6 +1197,7 @@ void pthreadSymbolsRegister(Core::Loader::SymbolsResolver* sym) { LIB_FUNCTION("6UgtwV+0zb4", "libkernel", 1, "libkernel", 1, 1, scePthreadCreate); LIB_FUNCTION("T72hz6ffq08", "libkernel", 1, "libkernel", 1, 1, scePthreadYield); LIB_FUNCTION("-quPa4SEJUw", "libkernel", 1, "libkernel", 1, 1, scePthreadAttrGetstack); + LIB_FUNCTION("14bOACANTBo", "libkernel", 1, "libkernel", 1, 1, scePthreadOnce); // mutex calls LIB_FUNCTION("cmo1RIYva9o", "libkernel", 1, "libkernel", 1, 1, scePthreadMutexInit); diff --git a/src/core/libraries/kernel/thread_management.h b/src/core/libraries/kernel/thread_management.h index a97def16..c8357e68 100644 --- a/src/core/libraries/kernel/thread_management.h +++ b/src/core/libraries/kernel/thread_management.h @@ -27,7 +27,7 @@ struct PthreadMutexattrInternal; struct PthreadCondInternal; struct PthreadCondAttrInternal; struct PthreadRwInternal; -struct PthreadRwLockAttrInernal; +struct PthreadRwLockAttrInternal; using SceKernelSchedParam = ::sched_param; using ScePthread = PthreadInternal*; @@ -37,7 +37,7 @@ using ScePthreadMutexattr = PthreadMutexattrInternal*; using ScePthreadCond = PthreadCondInternal*; using ScePthreadCondattr = PthreadCondAttrInternal*; using OrbisPthreadRwlock = PthreadRwInternal*; -using OrbisPthreadRwlockattr = PthreadRwLockAttrInernal*; +using OrbisPthreadRwlockattr = PthreadRwLockAttrInternal*; using pthreadEntryFunc = PS4_SYSV_ABI void* (*)(void*); @@ -86,7 +86,7 @@ struct PthreadCondAttrInternal { pthread_condattr_t cond_attr; }; -struct PthreadRwLockAttrInernal { +struct PthreadRwLockAttrInternal { u8 reserved[64]; pthread_rwlockattr_t attr_rwlock; int type; diff --git a/src/core/libraries/kernel/threads/kernel_threads_rwlock.cpp b/src/core/libraries/kernel/threads/kernel_threads_rwlock.cpp index c8bf3724..a092d712 100644 --- a/src/core/libraries/kernel/threads/kernel_threads_rwlock.cpp +++ b/src/core/libraries/kernel/threads/kernel_threads_rwlock.cpp @@ -121,7 +121,7 @@ int PS4_SYSV_ABI posix_pthread_rwlockattr_gettype_np() { } int PS4_SYSV_ABI posix_pthread_rwlockattr_init(OrbisPthreadRwlockattr* attr) { - *attr = new PthreadRwLockAttrInernal{}; + *attr = new PthreadRwLockAttrInternal{}; int result = pthread_rwlockattr_init(&(*attr)->attr_rwlock); if (result != 0) { LOG_ERROR(Kernel_Pthread, "posix_pthread_rwlockattr_init: error = {}", result); @@ -161,7 +161,7 @@ int PS4_SYSV_ABI scePthreadRwlockattrGettype() { } int PS4_SYSV_ABI scePthreadRwlockattrInit(OrbisPthreadRwlockattr* attr) { - *attr = new PthreadRwLockAttrInernal{}; + *attr = new PthreadRwLockAttrInternal{}; int result = pthread_rwlockattr_init(&(*attr)->attr_rwlock); if (result != 0) { LOG_ERROR(Kernel_Pthread, "scePthreadRwlockattrInit: error = {}", result); diff --git a/src/core/tls.cpp b/src/core/tls.cpp index 15147788..a6eb36fa 100644 --- a/src/core/tls.cpp +++ b/src/core/tls.cpp @@ -8,6 +8,8 @@ #ifdef _WIN32 #include +#else +#include #endif namespace Core { @@ -53,9 +55,83 @@ Tcb* GetTcbBase() { return reinterpret_cast(TlsGetValue(slot)); } -void PatchTLS(u64 segment_addr, u64 segment_size, Xbyak::CodeGenerator& c) { - using namespace Xbyak::util; +static void AllocTcbKey() { + slot = TlsAlloc(); +} +static void PatchFsAccess(u8* code, const TLSPattern& tls_pattern, Xbyak::CodeGenerator& c) { + using namespace Xbyak::util; + const auto total_size = tls_pattern.pattern_size + tls_pattern.imm_size; + + // Replace mov instruction with near jump to the trampoline. + static constexpr u32 NearJmpSize = 5; + auto patch = Xbyak::CodeGenerator(total_size, code); + patch.jmp(c.getCurr(), Xbyak::CodeGenerator::LabelType::T_NEAR); + patch.nop(total_size - NearJmpSize); + + // Write the trampoline. + // The following logic is based on the wine implementation of TlsGetValue + // https://github.com/wine-mirror/wine/blob/a27b9551/dlls/kernelbase/thread.c#L719 + static constexpr u32 TlsSlotsOffset = 0x1480; + static constexpr u32 TlsExpansionSlotsOffset = 0x1780; + static constexpr u32 TlsMinimumAvailable = 64; + const u32 teb_offset = slot < TlsMinimumAvailable ? TlsSlotsOffset : TlsExpansionSlotsOffset; + const u32 tls_index = slot < TlsMinimumAvailable ? slot : slot - TlsMinimumAvailable; + + const auto target_reg = Xbyak::Reg64(tls_pattern.target_reg); + c.mov(target_reg, teb_offset); + c.putSeg(gs); + c.mov(target_reg, ptr[target_reg]); // Load the pointer to the table of tls slots. + c.mov(target_reg, + qword[target_reg + tls_index * sizeof(LPVOID)]); // Load the pointer to our buffer. + c.jmp(code + total_size); // Return to the instruction right after the mov. +} + +#else + +static pthread_key_t slot = 0; + +void SetTcbBase(void* image_address) { + ASSERT(pthread_setspecific(slot, image_address) == 0); +} + +Tcb* GetTcbBase() { + return reinterpret_cast(pthread_getspecific(slot)); +} + +static void AllocTcbKey() { + slot = pthread_key_create(&slot, nullptr); +} + +static void PatchFsAccess(u8* code, const TLSPattern& tls_pattern, Xbyak::CodeGenerator& c) { + using namespace Xbyak::util; + const auto total_size = tls_pattern.pattern_size + tls_pattern.imm_size; + + // Replace mov instruction with near jump to the trampoline. + static constexpr u32 NearJmpSize = 5; + auto patch = Xbyak::CodeGenerator(total_size, code); + patch.jmp(c.getCurr(), Xbyak::CodeGenerator::LabelType::T_NEAR); + patch.nop(total_size - NearJmpSize); + + // Write the trampoline. + // The following logic is based on the glibc implementation of pthread_getspecific + // https://github.com/bminor/glibc/blob/29807a27/nptl/pthread_getspecific.c#L23 + static constexpr u32 PthreadKeySecondLevelSize = 32; + static constexpr u32 SpecificFirstBlockOffset = 0x308; + static constexpr u32 SelfInTcbheadOffset = 16; + static constexpr u32 PthreadKeyDataSize = 16; + ASSERT(slot < PthreadKeySecondLevelSize); + + const auto target_reg = Xbyak::Reg64(tls_pattern.target_reg); + c.putSeg(fs); + c.mov(target_reg, qword[SelfInTcbheadOffset]); // Load self member pointer of tcbhead_t. + c.add(target_reg, SpecificFirstBlockOffset + sizeof(uintptr_t) + slot * PthreadKeyDataSize); + c.jmp(code + total_size); // Return to the instruction right after the mov. +} + +#endif + +void PatchTLS(u64 segment_addr, u64 segment_size, Xbyak::CodeGenerator& c) { u8* code = reinterpret_cast(segment_addr); auto remaining_size = segment_size; @@ -89,7 +165,7 @@ void PatchTLS(u64 segment_addr, u64 segment_size, Xbyak::CodeGenerator& c) { // Allocate slot in the process if not done already. if (slot == 0) { - slot = TlsAlloc(); + AllocTcbKey(); } // Replace bogus instruction prefix with nops if it exists. @@ -98,30 +174,8 @@ void PatchTLS(u64 segment_addr, u64 segment_size, Xbyak::CodeGenerator& c) { patch.nop(BadPrefix.size()); } - // Replace mov instruction with near jump to the trampoline. - static constexpr u32 NearJmpSize = 5; - auto patch = Xbyak::CodeGenerator(total_size, code); - patch.jmp(c.getCurr(), Xbyak::CodeGenerator::LabelType::T_NEAR); - patch.nop(total_size - NearJmpSize); - - // Write the trampoline. - // The following logic is based on the wine implementation of TlsGetValue - // https://github.com/wine-mirror/wine/blob/a27b9551/dlls/kernelbase/thread.c#L719 - static constexpr u32 TlsSlotsOffset = 0x1480; - static constexpr u32 TlsExpansionSlotsOffset = 0x1780; - static constexpr u32 TlsMinimumAvailable = 64; - const u32 teb_offset = - slot < TlsMinimumAvailable ? TlsSlotsOffset : TlsExpansionSlotsOffset; - const u32 tls_index = slot < TlsMinimumAvailable ? slot : slot - TlsMinimumAvailable; - - const auto target_reg = Xbyak::Reg64(tls_pattern.target_reg); - c.mov(target_reg, teb_offset); - c.putSeg(gs); - c.mov(target_reg, ptr[target_reg]); // Load the pointer to the table of tls slots. - c.mov( - target_reg, - qword[target_reg + tls_index * sizeof(LPVOID)]); // Load the pointer to our buffer. - c.jmp(code + total_size); // Return to the instruction right after the mov. + // Patch access to FS register to a trampoline. + PatchFsAccess(code, tls_pattern, c); // Move ahead in module. code += total_size - 1; @@ -133,20 +187,4 @@ void PatchTLS(u64 segment_addr, u64 segment_size, Xbyak::CodeGenerator& c) { } } -#else - -void SetTcbBase(void* image_address) { - UNREACHABLE_MSG("Thread local storage is unimplemented on posix platforms!"); -} - -Tcb* GetTcbBase() { - UNREACHABLE_MSG("Thread local storage is unimplemented on posix platforms!"); -} - -void PatchTLS(u64 segment_addr, u64 segment_size, Xbyak::CodeGenerator& c) { - UNREACHABLE_MSG("Thread local storage is unimplemented on posix platforms!"); -} - -#endif - } // namespace Core diff --git a/src/emulator.cpp b/src/emulator.cpp index c5facd19..b887685b 100644 --- a/src/emulator.cpp +++ b/src/emulator.cpp @@ -40,10 +40,6 @@ Emulator::Emulator() : window{WindowWidth, WindowHeight, controller} { Common::Log::Initialize(); Common::Log::Start(); - // Start discord integration - discord_rpc.init(); - discord_rpc.update(Discord::RPCStatus::Idling, ""); - // Initialize kernel and library facilities. Libraries::Kernel::init_pthreads(); Libraries::InitHLELibs(&linker->GetHLESymbols()); @@ -52,7 +48,6 @@ Emulator::Emulator() : window{WindowWidth, WindowHeight, controller} { Emulator::~Emulator() { const auto config_dir = Common::FS::GetUserPath(Common::FS::PathType::UserDir); Config::save(config_dir / "config.toml"); - discord_rpc.stop(); } void Emulator::Run(const std::filesystem::path& file) { @@ -116,7 +111,7 @@ void Emulator::Run(const std::filesystem::path& file) { std::jthread([this](std::stop_token stop_token) { linker->Execute(); }); // Begin main window loop until the application exits - static constexpr std::chrono::microseconds FlipPeriod{100000}; + static constexpr std::chrono::microseconds FlipPeriod{10}; while (window.isOpen()) { window.waitEvent(); @@ -138,4 +133,4 @@ void Emulator::LoadSystemModules(const std::filesystem::path& file) { } } -} // namespace Core \ No newline at end of file +} // namespace Core diff --git a/src/emulator.h b/src/emulator.h index 7364af8c..36faaad3 100644 --- a/src/emulator.h +++ b/src/emulator.h @@ -7,7 +7,6 @@ #include #include -#include "common/discord.h" #include "core/linker.h" #include "input/controller.h" #include "sdl_window.h" @@ -23,10 +22,9 @@ public: private: void LoadSystemModules(const std::filesystem::path& file); - Discord::RPC discord_rpc; Input::GameController* controller = Common::Singleton::Instance(); Core::Linker* linker = Common::Singleton::Instance(); Frontend::WindowSDL window; }; -} // namespace Core \ No newline at end of file +} // namespace Core diff --git a/src/sdl_window.cpp b/src/sdl_window.cpp index 255946fc..ce9ff729 100644 --- a/src/sdl_window.cpp +++ b/src/sdl_window.cpp @@ -19,6 +19,7 @@ WindowSDL::WindowSDL(s32 width_, s32 height_, Input::GameController* controller_ if (SDL_Init(SDL_INIT_VIDEO) < 0) { UNREACHABLE_MSG("Failed to initialize SDL video subsystem: {}", SDL_GetError()); } + SDL_InitSubSystem(SDL_INIT_AUDIO); const std::string title = "shadPS4 v" + std::string(Common::VERSION); SDL_PropertiesID props = SDL_CreateProperties(); diff --git a/src/video_core/amdgpu/liverpool.h b/src/video_core/amdgpu/liverpool.h index 22b59f74..0a427c91 100644 --- a/src/video_core/amdgpu/liverpool.h +++ b/src/video_core/amdgpu/liverpool.h @@ -695,7 +695,7 @@ struct Liverpool { NumberFormat NumFormat() const { // There is a small difference between T# and CB number types, account for it. return info.number_type == AmdGpu::NumberFormat::SnormNz ? AmdGpu::NumberFormat::Srgb - : info.number_type; + : info.number_type.Value(); } }; diff --git a/src/video_core/amdgpu/resource.h b/src/video_core/amdgpu/resource.h index ba2231b0..64721b62 100644 --- a/src/video_core/amdgpu/resource.h +++ b/src/video_core/amdgpu/resource.h @@ -32,7 +32,7 @@ struct Buffer { }; u32 GetStride() const noexcept { - return stride == 0 ? 1U : stride; + return stride == 0 ? 1U : stride.Value(); } u32 GetStrideElements(u32 element_size) const noexcept { From 080ec3e23ebd8d1b9bf762e127cf998f11d85b0a Mon Sep 17 00:00:00 2001 From: raziel1000 Date: Fri, 14 Jun 2024 01:37:26 -0600 Subject: [PATCH 2/2] Added LibPngDec (tested with Metal Slug 3, Risk of Rain, Deadbolt and Nidhogg) --- CMakeLists.txt | 5 + src/common/logging/filter.cpp | 1 + src/common/logging/types.h | 1 + .../libraries/kernel/thread_management.cpp | 19 +- src/core/libraries/kernel/time_management.cpp | 53 +++++- src/core/libraries/kernel/time_management.h | 19 ++ src/core/libraries/libpng/pngdec.cpp | 169 ++++++++++++++++++ src/core/libraries/libpng/pngdec.h | 79 ++++++++ src/core/libraries/libs.cpp | 2 + 9 files changed, 336 insertions(+), 12 deletions(-) create mode 100644 src/core/libraries/libpng/pngdec.cpp create mode 100644 src/core/libraries/libpng/pngdec.h diff --git a/CMakeLists.txt b/CMakeLists.txt index a9f47acc..7ee2dcb3 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -190,6 +190,10 @@ set(PAD_LIB src/core/libraries/pad/pad.cpp src/core/libraries/pad/pad.h ) +set(PNG_LIB src/core/libraries/libpng/pngdec.cpp + src/core/libraries/libpng/pngdec.h +) + set(NP_LIBS src/core/libraries/np_manager/np_manager.cpp src/core/libraries/np_manager/np_manager.h src/core/libraries/np_score/np_score.cpp @@ -290,6 +294,7 @@ set(CORE src/core/aerolib/stubs.cpp ${PAD_LIB} ${VIDEOOUT_LIB} ${NP_LIBS} + ${PNG_LIB} ${MISC_LIBS} src/core/linker.cpp src/core/linker.h diff --git a/src/common/logging/filter.cpp b/src/common/logging/filter.cpp index 1e49561c..cda1b020 100644 --- a/src/common/logging/filter.cpp +++ b/src/common/logging/filter.cpp @@ -104,6 +104,7 @@ bool ParseFilterRule(Filter& instance, Iterator begin, Iterator end) { SUB(Lib, AppContent) \ SUB(Lib, Rtc) \ SUB(Lib, DiscMap) \ + SUB(Lib, Png) \ CLS(Frontend) \ CLS(Render) \ SUB(Render, Vulkan) \ diff --git a/src/common/logging/types.h b/src/common/logging/types.h index af52df88..3dcfab12 100644 --- a/src/common/logging/types.h +++ b/src/common/logging/types.h @@ -71,6 +71,7 @@ enum class Class : u8 { Lib_AppContent, ///< The LibSceAppContent implementation. Lib_Rtc, ///< The LibSceRtc implementation. Lib_DiscMap, ///< The LibSceDiscMap implementation. + Lib_Png, ///< The LibScePng implementation. Frontend, ///< Emulator UI Render, ///< Video Core Render_Vulkan, ///< Vulkan backend diff --git a/src/core/libraries/kernel/thread_management.cpp b/src/core/libraries/kernel/thread_management.cpp index 63e80caa..ce83f5d3 100644 --- a/src/core/libraries/kernel/thread_management.cpp +++ b/src/core/libraries/kernel/thread_management.cpp @@ -679,7 +679,7 @@ int PS4_SYSV_ABI scePthreadCondTimedwait(ScePthreadCond* cond, ScePthreadMutex* time.tv_nsec = ((usec % 1000000) * 1000); int result = pthread_cond_timedwait(&(*cond)->cond, &(*mutex)->pth_mutex, &time); - LOG_INFO(Kernel_Pthread, "scePthreadCondTimedwait, result={}", result); + // LOG_INFO(Kernel_Pthread, "scePthreadCondTimedwait, result={}", result); switch (result) { case 0: @@ -1018,7 +1018,7 @@ int PS4_SYSV_ABI scePthreadCondSignal(ScePthreadCond* cond) { int result = pthread_cond_signal(&(*cond)->cond); - LOG_INFO(Kernel_Pthread, "scePthreadCondSignal, result={}", result); + // LOG_INFO(Kernel_Pthread, "scePthreadCondSignal, result={}", result); switch (result) { case 0: @@ -1170,7 +1170,19 @@ int PS4_SYSV_ABI posix_pthread_create_name_np(ScePthread* thread, const ScePthre int PS4_SYSV_ABI scePthreadOnce(int* once_control, void (*init_routine)(void)) { return pthread_once(reinterpret_cast(once_control), init_routine); } +int PS4_SYSV_ABI posix_pthread_create(ScePthread* thread, const ScePthreadAttr* attr, + pthreadEntryFunc start_routine, void* arg) { + LOG_INFO(Kernel_Pthread, "posix pthread_create redirect to scePthreadCreate"); + int result = scePthreadCreate(thread, attr, start_routine, arg, ""); + if (result != 0) { + int rt = result > SCE_KERNEL_ERROR_UNKNOWN && result <= SCE_KERNEL_ERROR_ESTOP + ? result + -SCE_KERNEL_ERROR_UNKNOWN + : POSIX_EOTHER; + return rt; + } + return result; +} void pthreadSymbolsRegister(Core::Loader::SymbolsResolver* sym) { LIB_FUNCTION("4+h9EzwKF4I", "libkernel", 1, "libkernel", 1, 1, scePthreadAttrSetschedpolicy); LIB_FUNCTION("-Wreprtu0Qs", "libkernel", 1, "libkernel", 1, 1, scePthreadAttrSetdetachstate); @@ -1192,7 +1204,8 @@ void pthreadSymbolsRegister(Core::Loader::SymbolsResolver* sym) { LIB_FUNCTION("x1X76arYMxU", "libkernel", 1, "libkernel", 1, 1, scePthreadAttrGet); LIB_FUNCTION("UTXzJbWhhTE", "libkernel", 1, "libkernel", 1, 1, scePthreadAttrSetstacksize); LIB_FUNCTION("vNe1w4diLCs", "libkernel", 1, "libkernel", 1, 1, __tls_get_addr); - + LIB_FUNCTION("OxhIB8LB-PQ", "libkernel", 1, "libkernel", 1, 1, posix_pthread_create); + LIB_FUNCTION("OxhIB8LB-PQ", "libScePosix", 1, "libkernel", 1, 1, posix_pthread_create); LIB_FUNCTION("bt3CTBKmGyI", "libkernel", 1, "libkernel", 1, 1, scePthreadSetaffinity); LIB_FUNCTION("6UgtwV+0zb4", "libkernel", 1, "libkernel", 1, 1, scePthreadCreate); LIB_FUNCTION("T72hz6ffq08", "libkernel", 1, "libkernel", 1, 1, scePthreadYield); diff --git a/src/core/libraries/kernel/time_management.cpp b/src/core/libraries/kernel/time_management.cpp index a4362e28..c32e8be8 100644 --- a/src/core/libraries/kernel/time_management.cpp +++ b/src/core/libraries/kernel/time_management.cpp @@ -63,9 +63,7 @@ int PS4_SYSV_ABI sceKernelUsleep(u32 microseconds) { } int PS4_SYSV_ABI posix_usleep(u32 microseconds) { - ASSERT(microseconds >= 1000); - std::this_thread::sleep_for(std::chrono::microseconds(microseconds)); - return 0; + return sceKernelUsleep(microseconds); } u32 PS4_SYSV_ABI sceKernelSleep(u32 seconds) { @@ -79,11 +77,15 @@ int PS4_SYSV_ABI sceKernelClockGettime(s32 clock_id, OrbisKernelTimespec* tp) { } clockid_t pclock_id = CLOCK_REALTIME; switch (clock_id) { - case 0: + case ORBIS_CLOCK_REALTIME: + case ORBIS_CLOCK_REALTIME_PRECISE: + case ORBIS_CLOCK_REALTIME_FAST: pclock_id = CLOCK_REALTIME; break; - case 13: - case 4: + case ORBIS_CLOCK_SECOND: + case ORBIS_CLOCK_MONOTONIC: + case ORBIS_CLOCK_MONOTONIC_PRECISE: + case ORBIS_CLOCK_MONOTONIC_FAST: pclock_id = CLOCK_MONOTONIC; break; default: @@ -100,7 +102,7 @@ int PS4_SYSV_ABI sceKernelClockGettime(s32 clock_id, OrbisKernelTimespec* tp) { return SCE_KERNEL_ERROR_EINVAL; } -int PS4_SYSV_ABI clock_gettime(s32 clock_id, OrbisKernelTimespec* time) { +int PS4_SYSV_ABI posix_clock_gettime(s32 clock_id, OrbisKernelTimespec* time) { int result = sceKernelClockGettime(clock_id, time); if (result < 0) { UNREACHABLE(); // TODO return posix error code @@ -151,6 +153,37 @@ int PS4_SYSV_ABI gettimeofday(OrbisKernelTimeval* tp, OrbisKernelTimezone* tz) { return sceKernelGettimeofday(tp); } +int PS4_SYSV_ABI posix_clock_getres(u32 clock_id, OrbisKernelTimespec* res) { + if (res == nullptr) { + return SCE_KERNEL_ERROR_EFAULT; + } + clockid_t pclock_id = CLOCK_REALTIME; + switch (clock_id) { + case ORBIS_CLOCK_REALTIME: + case ORBIS_CLOCK_REALTIME_PRECISE: + case ORBIS_CLOCK_REALTIME_FAST: + pclock_id = CLOCK_REALTIME; + break; + case ORBIS_CLOCK_SECOND: + case ORBIS_CLOCK_MONOTONIC: + case ORBIS_CLOCK_MONOTONIC_PRECISE: + case ORBIS_CLOCK_MONOTONIC_FAST: + pclock_id = CLOCK_MONOTONIC; + break; + default: + UNREACHABLE(); + } + + timespec t{}; + int result = clock_getres(pclock_id, &t); + res->tv_sec = t.tv_sec; + res->tv_nsec = t.tv_nsec; + if (result == 0) { + return SCE_OK; + } + return SCE_KERNEL_ERROR_EINVAL; +} + void timeSymbolsRegister(Core::Loader::SymbolsResolver* sym) { clock = std::make_unique(); initial_ptc = clock->GetUptime(); @@ -163,6 +196,7 @@ void timeSymbolsRegister(Core::Loader::SymbolsResolver* sym) { LIB_FUNCTION("ejekcaNQNq0", "libkernel", 1, "libkernel", 1, 1, sceKernelGettimeofday); LIB_FUNCTION("n88vx3C5nW8", "libkernel", 1, "libkernel", 1, 1, gettimeofday); LIB_FUNCTION("n88vx3C5nW8", "libScePosix", 1, "libkernel", 1, 1, gettimeofday); + LIB_FUNCTION("QvsZxomvUHs", "libkernel", 1, "libkernel", 1, 1, sceKernelNanosleep); LIB_FUNCTION("1jfXLRVzisc", "libkernel", 1, "libkernel", 1, 1, sceKernelUsleep); LIB_FUNCTION("QcteRwbsnV0", "libScePosix", 1, "libkernel", 1, 1, posix_usleep); LIB_FUNCTION("-ZR+hG7aDHw", "libkernel", 1, "libkernel", 1, 1, sceKernelSleep); @@ -170,8 +204,9 @@ void timeSymbolsRegister(Core::Loader::SymbolsResolver* sym) { LIB_FUNCTION("yS8U2TGCe1A", "libkernel", 1, "libkernel", 1, 1, posix_nanosleep); LIB_FUNCTION("yS8U2TGCe1A", "libScePosix", 1, "libkernel", 1, 1, posix_nanosleep); LIB_FUNCTION("QBi7HCK03hw", "libkernel", 1, "libkernel", 1, 1, sceKernelClockGettime); - LIB_FUNCTION("lLMT9vJAck0", "libkernel", 1, "libkernel", 1, 1, clock_gettime); - LIB_FUNCTION("lLMT9vJAck0", "libScePosix", 1, "libkernel", 1, 1, clock_gettime); + LIB_FUNCTION("lLMT9vJAck0", "libkernel", 1, "libkernel", 1, 1, posix_clock_gettime); + LIB_FUNCTION("lLMT9vJAck0", "libScePosix", 1, "libkernel", 1, 1, posix_clock_gettime); + LIB_FUNCTION("smIj7eqzZE8", "libScePosix", 1, "libkernel", 1, 1, posix_clock_getres); } } // namespace Libraries::Kernel diff --git a/src/core/libraries/kernel/time_management.h b/src/core/libraries/kernel/time_management.h index 64689bf6..a28f8c13 100644 --- a/src/core/libraries/kernel/time_management.h +++ b/src/core/libraries/kernel/time_management.h @@ -26,6 +26,25 @@ struct OrbisKernelTimespec { s64 tv_nsec; }; +constexpr int ORBIS_CLOCK_REALTIME = 0; +constexpr int ORBIS_CLOCK_VIRTUAL = 1; +constexpr int ORBIS_CLOCK_PROF = 2; +constexpr int ORBIS_CLOCK_MONOTONIC = 4; +constexpr int ORBIS_CLOCK_UPTIME = 5; +constexpr int ORBIS_CLOCK_UPTIME_PRECISE = 7; +constexpr int ORBIS_CLOCK_UPTIME_FAST = 8; +constexpr int ORBIS_CLOCK_REALTIME_PRECISE = 9; +constexpr int ORBIS_CLOCK_REALTIME_FAST = 10; +constexpr int ORBIS_CLOCK_MONOTONIC_PRECISE = 11; +constexpr int ORBIS_CLOCK_MONOTONIC_FAST = 12; +constexpr int ORBIS_CLOCK_SECOND = 13; +constexpr int ORBIS_CLOCK_THREAD_CPUTIME_ID = 14; +constexpr int ORBIS_CLOCK_PROCTIME = 15; +constexpr int ORBIS_CLOCK_EXT_NETWORK = 16; +constexpr int ORBIS_CLOCK_EXT_DEBUG_NETWORK = 17; +constexpr int ORBIS_CLOCK_EXT_AD_NETWORK = 18; +constexpr int ORBIS_CLOCK_EXT_RAW_NETWORK = 19; + u64 PS4_SYSV_ABI sceKernelGetTscFrequency(); u64 PS4_SYSV_ABI sceKernelGetProcessTime(); u64 PS4_SYSV_ABI sceKernelGetProcessTimeCounter(); diff --git a/src/core/libraries/libpng/pngdec.cpp b/src/core/libraries/libpng/pngdec.cpp new file mode 100644 index 00000000..3a5d1ba7 --- /dev/null +++ b/src/core/libraries/libpng/pngdec.cpp @@ -0,0 +1,169 @@ +// 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/libs.h" +#include "externals/stb_image.h" +#include "pngdec.h" + +namespace Libraries::PngDec { + +void setImageInfoParams(OrbisPngDecImageInfo* imageInfo, int width, int height, int channels, + bool isInterlaced, bool isTransparent) { + if (imageInfo != nullptr) { + imageInfo->imageWidth = width; + imageInfo->imageHeight = height; + imageInfo->bitDepth = 8; // always 8? + switch (channels) { // clut missing + case 1: + imageInfo->colorSpace = OrbisPngDecColorSpace::ORBIS_PNG_DEC_COLOR_SPACE_GRAYSCALE; + break; + case 2: + imageInfo->colorSpace = + OrbisPngDecColorSpace::ORBIS_PNG_DEC_COLOR_SPACE_GRAYSCALE_ALPHA; + break; + case 3: + imageInfo->colorSpace = OrbisPngDecColorSpace::ORBIS_PNG_DEC_COLOR_SPACE_RGB; + break; + case 4: + imageInfo->colorSpace = OrbisPngDecColorSpace::ORBIS_PNG_DEC_COLOR_SPACE_RGBA; + break; + default: + imageInfo->colorSpace = OrbisPngDecColorSpace::ORBIS_PNG_DEC_COLOR_SPACE_RGB; + break; + } + imageInfo->imageFlag = 0; + if (isInterlaced) { + imageInfo->imageFlag |= ORBIS_PNG_DEC_IMAGE_FLAG_ADAM7_INTERLACE; + } + if (isTransparent) { + imageInfo->imageFlag |= ORBIS_PNG_DEC_IMAGE_FLAG_TRNS_CHUNK_EXIST; + } + } +} + +bool checktRNS(const u8* png_raw, int size) { + for (int i = 30; i < size - 4; i += 4) { + if (std::memcmp(png_raw + i, "tRNS", 4) == 0) { + return true; + } + } + return false; +} + +s32 PS4_SYSV_ABI scePngDecCreate(const OrbisPngDecCreateParam* param, void* memoryAddress, + u32 memorySize, OrbisPngDecHandle* handle) { + if (param == nullptr || param->attribute > 1) { + LOG_ERROR(Lib_Png, "Invalid param!"); + return ORBIS_PNG_DEC_ERROR_INVALID_PARAM; + } + if (memoryAddress == nullptr) { + LOG_ERROR(Lib_Png, "Invalid memory address!"); + return ORBIS_PNG_DEC_ERROR_INVALID_ADDR; + } + if (param->maxImageWidth - 1 > 1000000) { + LOG_ERROR(Lib_Png, "Invalid size! width = {}", param->maxImageWidth); + return ORBIS_PNG_DEC_ERROR_INVALID_SIZE; + } + const OrbisPngDecCreateParam* nextParam = param + 1; + int ret = (8 << (reinterpret_cast(nextParam) & 0x1f)) * + (param->maxImageWidth + 0x47U & 0xfffffff8) + + 0xd000; + *handle = reinterpret_cast(ret); + return ORBIS_OK; +} + +s32 PS4_SYSV_ABI scePngDecDecode(OrbisPngDecHandle handle, const OrbisPngDecDecodeParam* param, + OrbisPngDecImageInfo* imageInfo) { + if (handle == nullptr) { + LOG_ERROR(Lib_Png, "invalid handle!"); + return ORBIS_PNG_DEC_ERROR_INVALID_HANDLE; + } + if (param == nullptr) { + LOG_ERROR(Lib_Png, "Invalid param!"); + return ORBIS_PNG_DEC_ERROR_INVALID_PARAM; + } + if (param->pngMemAddr == nullptr || param->pngMemAddr == nullptr) { + LOG_ERROR(Lib_Png, "invalid image address!"); + return ORBIS_PNG_DEC_ERROR_INVALID_ADDR; + } + + int width, height, channels; + const u8* png_raw = (const u8*)param->pngMemAddr; + u8* img = stbi_load_from_memory(png_raw, param->pngMemSize, &width, &height, &channels, + STBI_rgb_alpha); // STBI_rgb_alpha? + if (!img) { + LOG_ERROR(Lib_Png, "Decoding failed!"); + return ORBIS_PNG_DEC_ERROR_DECODE_ERROR; + } + bool isInterlaced = (png_raw[28] == 1); + bool isTransparent = checktRNS(png_raw, param->pngMemSize); + setImageInfoParams(imageInfo, width, height, channels, isInterlaced, isTransparent); + u8* imageBuffer = (u8*)(param->imageMemAddr); + memcpy(imageBuffer, img, width * height * 4); // copy/pass decoded data + stbi_image_free(img); + return 0; +} + +s32 PS4_SYSV_ABI scePngDecDecodeWithInputControl() { + LOG_ERROR(Lib_Png, "(STUBBED)called"); + return ORBIS_OK; +} + +s32 PS4_SYSV_ABI scePngDecDelete(OrbisPngDecHandle handle) { + handle = nullptr; // ? + LOG_ERROR(Lib_Png, "(STUBBED)called"); + return ORBIS_OK; +} + +s32 PS4_SYSV_ABI scePngDecParseHeader(const OrbisPngDecParseParam* param, + OrbisPngDecImageInfo* imageInfo) { + if (param == nullptr) { + LOG_ERROR(Lib_Png, "Invalid param!"); + return ORBIS_PNG_DEC_ERROR_INVALID_PARAM; + } + int width, height, channels; + const u8* png_raw = (const u8*)(param->pngMemAddr); + int img = stbi_info_from_memory(png_raw, param->pngMemSize, &width, &height, &channels); + if (img == 0) { + LOG_ERROR(Lib_Png, "Decoding failed!"); + return ORBIS_PNG_DEC_ERROR_DECODE_ERROR; + } + bool isInterlaced = (png_raw[28] == 1); + bool isTransparent = checktRNS(png_raw, param->pngMemSize); + setImageInfoParams(imageInfo, width, height, channels, isInterlaced, isTransparent); + return ORBIS_OK; +} + +s32 PS4_SYSV_ABI scePngDecQueryMemorySize(const OrbisPngDecCreateParam* param) { + if (param == nullptr) { + LOG_ERROR(Lib_Png, "Invalid param!"); + return ORBIS_PNG_DEC_ERROR_INVALID_PARAM; + } + if (param->attribute > 1) { + LOG_ERROR(Lib_Png, "Invalid attribute! attribute = {}", param->attribute); + return ORBIS_PNG_DEC_ERROR_INVALID_ADDR; + } + if (param->maxImageWidth - 1 > 1000000) { + LOG_ERROR(Lib_Png, "Invalid size! width = {}", param->maxImageWidth); + return ORBIS_PNG_DEC_ERROR_INVALID_SIZE; + } + int ret = + (8 << ((u8)param->attribute & 0x1f)) * (param->maxImageWidth + 0x47U & 0xfffffff8) + 0xd090; + return ret; +} + +void RegisterlibScePngDec(Core::Loader::SymbolsResolver* sym) { + LIB_FUNCTION("m0uW+8pFyaw", "libScePngDec", 1, "libScePngDec", 1, 1, scePngDecCreate); + LIB_FUNCTION("WC216DD3El4", "libScePngDec", 1, "libScePngDec", 1, 1, scePngDecDecode); + LIB_FUNCTION("cJ--1xAbj-I", "libScePngDec", 1, "libScePngDec", 1, 1, + scePngDecDecodeWithInputControl); + LIB_FUNCTION("QbD+eENEwo8", "libScePngDec", 1, "libScePngDec", 1, 1, scePngDecDelete); + LIB_FUNCTION("U6h4e5JRPaQ", "libScePngDec", 1, "libScePngDec", 1, 1, scePngDecParseHeader); + LIB_FUNCTION("-6srIGbLTIU", "libScePngDec", 1, "libScePngDec", 1, 1, scePngDecQueryMemorySize); + LIB_FUNCTION("cJ--1xAbj-I", "libScePngDec_jvm", 1, "libScePngDec", 1, 1, + scePngDecDecodeWithInputControl); +}; + +} // namespace Libraries::PngDec \ No newline at end of file diff --git a/src/core/libraries/libpng/pngdec.h b/src/core/libraries/libpng/pngdec.h new file mode 100644 index 00000000..35034a19 --- /dev/null +++ b/src/core/libraries/libpng/pngdec.h @@ -0,0 +1,79 @@ +// 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::PngDec { + +constexpr int ORBIS_PNG_DEC_ERROR_INVALID_ADDR = 0x80690001; +constexpr int ORBIS_PNG_DEC_ERROR_INVALID_SIZE = 0x80690002; +constexpr int ORBIS_PNG_DEC_ERROR_INVALID_PARAM = 0x80690003; +constexpr int ORBIS_PNG_DEC_ERROR_INVALID_HANDLE = 0x80690004; +constexpr int ORBIS_PNG_DEC_ERROR_INVALID_WORK_MEMORY = 0x80690005; +constexpr int ORBIS_PNG_DEC_ERROR_INVALID_DATA = 0x80690010; +constexpr int ORBIS_PNG_DEC_ERROR_UNSUPPORT_DATA = 0x80690011; +constexpr int ORBIS_PNG_DEC_ERROR_DECODE_ERROR = 0x80690012; +constexpr int ORBIS_PNG_DEC_ERROR_FATAL = 0x80690020; + +typedef struct OrbisPngDecParseParam { + const void* pngMemAddr; + u32 pngMemSize; + u32 reserved; +} OrbisPngDecParseParam; + +typedef struct OrbisPngDecImageInfo { + u32 imageWidth; + u32 imageHeight; + u16 colorSpace; + u16 bitDepth; + u32 imageFlag; +} OrbisPngDecImageInfo; + +typedef enum OrbisPngDecColorSpace { + ORBIS_PNG_DEC_COLOR_SPACE_GRAYSCALE = 2, + ORBIS_PNG_DEC_COLOR_SPACE_RGB, + ORBIS_PNG_DEC_COLOR_SPACE_CLUT, + ORBIS_PNG_DEC_COLOR_SPACE_GRAYSCALE_ALPHA = 18, + ORBIS_PNG_DEC_COLOR_SPACE_RGBA +} ScePngDecColorSpace; + +typedef enum OrbisPngDecImageFlag { + ORBIS_PNG_DEC_IMAGE_FLAG_ADAM7_INTERLACE = 1, + ORBIS_PNG_DEC_IMAGE_FLAG_TRNS_CHUNK_EXIST = 2 +} OrbisPngDecImageFlag; + +typedef struct OrbisPngDecCreateParam { + u32 thisSize; + u32 attribute; + u32 maxImageWidth; +} OrbisPngDecCreateParam; + +typedef void* OrbisPngDecHandle; + +typedef struct OrbisPngDecDecodeParam { + const void* pngMemAddr; + void* imageMemAddr; + u32 pngMemSize; + u32 imageMemSize; + u16 pixelFormat; + u16 alphaValue; + u32 imagePitch; +} OrbisPngDecDecodeParam; + +s32 PS4_SYSV_ABI scePngDecCreate(const OrbisPngDecCreateParam* param, void* memoryAddress, + u32 memorySize, OrbisPngDecHandle* handle); +s32 PS4_SYSV_ABI scePngDecDecode(OrbisPngDecHandle handle, const OrbisPngDecDecodeParam* param, + OrbisPngDecImageInfo* imageInfo); +s32 PS4_SYSV_ABI scePngDecDecodeWithInputControl(); +s32 PS4_SYSV_ABI scePngDecDelete(OrbisPngDecHandle handle); +s32 PS4_SYSV_ABI scePngDecParseHeader(const OrbisPngDecParseParam* param, + OrbisPngDecImageInfo* imageInfo); +s32 PS4_SYSV_ABI scePngDecQueryMemorySize(const OrbisPngDecCreateParam* param); + +void RegisterlibScePngDec(Core::Loader::SymbolsResolver* sym); +} // namespace Libraries::PngDec \ No newline at end of file diff --git a/src/core/libraries/libs.cpp b/src/core/libraries/libs.cpp index 97de991a..932943ad 100644 --- a/src/core/libraries/libs.cpp +++ b/src/core/libraries/libs.cpp @@ -30,6 +30,7 @@ #include "core/libraries/system/systemservice.h" #include "core/libraries/system/userservice.h" #include "core/libraries/videoout/video_out.h" +#include "src/core/libraries/libpng/pngdec.h" namespace Libraries { @@ -65,6 +66,7 @@ void InitHLELibs(Core::Loader::SymbolsResolver* sym) { Libraries::AppContent::RegisterlibSceAppContent(sym); Libraries::Rtc::RegisterlibSceRtc(sym); Libraries::DiscMap::RegisterlibSceDiscMap(sym); + Libraries::PngDec::RegisterlibScePngDec(sym); } } // namespace Libraries