diff --git a/.gitmodules b/.gitmodules index 3284ecce5..14f7520f8 100644 --- a/.gitmodules +++ b/.gitmodules @@ -51,10 +51,10 @@ url = https://github.com/zyantific/zydis.git [submodule "externals/sirit"] path = externals/sirit - url = https://github.com/raphaelthegreat/sirit + url = https://github.com/raphaelthegreat/sirit.git [submodule "externals/xxhash"] path = externals/xxhash url = https://github.com/Cyan4973/xxHash.git [submodule "externals/tracy"] path = externals/tracy - url = https://github.com/shadps4-emu/tracy + url = https://github.com/shadps4-emu/tracy.git diff --git a/.reuse/dep5 b/.reuse/dep5 index 9ac78f7ac..b5ca5ee8a 100644 --- a/.reuse/dep5 +++ b/.reuse/dep5 @@ -3,17 +3,27 @@ Comment: It is best to use this file to record copyright information about generated, binary and third party files Files: CMakeSettings.json - scripts/ps4_names.txt - documents/changelog.txt - documents/readme.txt - documents/Screenshots/screenshot.png .github/shadps4.desktop .github/shadps4.png .gitmodules - src/images/shadps4.ico + documents/changelog.txt + documents/readme.txt + documents/Screenshots/screenshot.png + documents/Screenshots/Sonic Mania.png + documents/Screenshots/Undertale.png + documents/Screenshots/We are DOOMED.png + externals/stb_image.h + externals/tracy/* + scripts/ps4_names.txt src/images/controller_icon.png src/images/exit_icon.png src/images/file_icon.png + src/images/flag_china.png + src/images/flag_eu.png + src/images/flag_jp.png + src/images/flag_unk.png + src/images/flag_us.png + src/images/flag_world.png src/images/folder_icon.png src/images/grid_icon.png src/images/iconsize_icon.png @@ -24,16 +34,9 @@ Files: CMakeSettings.json src/images/refresh_icon.png src/images/settings_icon.png src/images/stop_icon.png + src/images/shadps4.ico src/images/themes_icon.png - src/images/flag_jp.png - src/images/flag_eu.png - src/images/flag_us.png - src/images/flag_china.png - src/images/flag_world.png - src/images/flag_unk.png - src/shadps4.rc src/shadps4.qrc - externals/stb_image.h - externals/tracy/* + src/shadps4.rc Copyright: shadPS4 Emulator Project License: GPL-2.0-or-later diff --git a/CMakeLists.txt b/CMakeLists.txt index 027645d0a..d85e4da7c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -10,7 +10,7 @@ if (NOT CMAKE_BUILD_TYPE) set(CMAKE_BUILD_TYPE Release) endif() -project(shadps4) +project(shadPS4) option(ENABLE_QT_GUI "Enable the Qt GUI. If not selected then the emulator uses a minimal SDL-based UI instead" OFF) @@ -192,6 +192,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 @@ -292,6 +296,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/README.md b/README.md index c93a3b44d..4e5cd02c0 100644 --- a/README.md +++ b/README.md @@ -27,10 +27,18 @@ SPDX-License-Identifier: GPL-2.0-or-later -

-
-
-
+

+ + + + + + + + + + + # shadPS4 diff --git a/documents/Screenshots/Sonic Mania.png b/documents/Screenshots/Sonic Mania.png new file mode 100644 index 000000000..38d064f97 Binary files /dev/null and b/documents/Screenshots/Sonic Mania.png differ diff --git a/documents/Screenshots/Undertale.png b/documents/Screenshots/Undertale.png new file mode 100644 index 000000000..c3e7745d0 Binary files /dev/null and b/documents/Screenshots/Undertale.png differ diff --git a/documents/Screenshots/We are DOOMED.png b/documents/Screenshots/We are DOOMED.png new file mode 100644 index 000000000..757160e5b Binary files /dev/null and b/documents/Screenshots/We are DOOMED.png differ diff --git a/externals/glslang b/externals/glslang index 73eccd4b6..a92c61f84 160000 --- a/externals/glslang +++ b/externals/glslang @@ -1 +1 @@ -Subproject commit 73eccd4b67985d344578cade8958214cee0a3f6e +Subproject commit a92c61f8456fa9731c0b000a2c6fc52a740c2be7 diff --git a/externals/toml11 b/externals/toml11 index 85faca9cb..b389bbc4e 160000 --- a/externals/toml11 +++ b/externals/toml11 @@ -1 +1 @@ -Subproject commit 85faca9cbe8d76324ff38c1801be44c63e12d5be +Subproject commit b389bbc4ebf90fa2fe7651de3046fb19f661ba3c diff --git a/externals/vulkan-headers b/externals/vulkan-headers index d192041a2..05fe2cc91 160000 --- a/externals/vulkan-headers +++ b/externals/vulkan-headers @@ -1 +1 @@ -Subproject commit d192041a2fc9c9fd8ae67d8ae3f32c5511541f04 +Subproject commit 05fe2cc910a68c9ba5dac07db46ef78573acee72 diff --git a/externals/xbyak b/externals/xbyak index 80477f635..aabb091ae 160000 --- a/externals/xbyak +++ b/externals/xbyak @@ -1 +1 @@ -Subproject commit 80477f635345e8f13efc512d84b01b94cad92cd9 +Subproject commit aabb091ae37068498751fd58202a9854408ecb0e diff --git a/externals/xxhash b/externals/xxhash index ac3a25da3..b0adcc541 160000 --- a/externals/xxhash +++ b/externals/xxhash @@ -1 +1 @@ -Subproject commit ac3a25da3d957d9ef3e4114d9f8332d34ce83a46 +Subproject commit b0adcc54188c3130b1793e7b19c62eb1e669f7df diff --git a/externals/zydis b/externals/zydis index fd3e9a6cc..5a68f639e 160000 --- a/externals/zydis +++ b/externals/zydis @@ -1 +1 @@ -Subproject commit fd3e9a6cc8bdcc617b531feda186699e51664f76 +Subproject commit 5a68f639e4f01604cc7bfc8d313f583a8137e3d3 diff --git a/src/common/logging/filter.cpp b/src/common/logging/filter.cpp index 1e49561c8..cda1b0205 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 af52df884..3dcfab127 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 afe50c9e5..c1fd28df9 100644 --- a/src/core/libraries/kernel/thread_management.cpp +++ b/src/core/libraries/kernel/thread_management.cpp @@ -687,7 +687,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: @@ -1026,7 +1026,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: @@ -1240,7 +1240,19 @@ int PS4_SYSV_ABI scePthreadSetschedparam(ScePthread thread, int policy, 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("lZzFeSxPl08", "libScePosix", 1, "libkernel", 1, 1, posix_pthread_setcancelstate); LIB_FUNCTION("0TyVk4MSLt0", "libScePosix", 1, "libkernel", 1, 1, posix_pthread_cond_init); @@ -1270,7 +1282,8 @@ void pthreadSymbolsRegister(Core::Loader::SymbolsResolver* sym) { LIB_FUNCTION("oIRFTjoILbg", "libkernel", 1, "libkernel", 1, 1, scePthreadSetschedparam); 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 eaf2c535f..63f27e78b 100644 --- a/src/core/libraries/kernel/time_management.cpp +++ b/src/core/libraries/kernel/time_management.cpp @@ -63,13 +63,7 @@ int PS4_SYSV_ABI sceKernelUsleep(u32 microseconds) { } int PS4_SYSV_ABI posix_usleep(u32 microseconds) { -#ifdef _WIN64 - ASSERT(microseconds >= 1000 || microseconds == 0); - std::this_thread::sleep_for(std::chrono::microseconds(microseconds)); - return 0; -#else - return usleep(microseconds); -#endif + return sceKernelUsleep(microseconds); } u32 PS4_SYSV_ABI sceKernelSleep(u32 seconds) { @@ -83,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: @@ -104,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 @@ -175,6 +173,37 @@ s32 PS4_SYSV_ABI sceKernelGettimezone(OrbisKernelTimezone* tz) { return ORBIS_OK; } +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(); @@ -187,6 +216,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", "libkernel", 1, "libkernel", 1, 1, posix_usleep); LIB_FUNCTION("QcteRwbsnV0", "libScePosix", 1, "libkernel", 1, 1, posix_usleep); @@ -195,9 +225,10 @@ 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("kOcnerypnQA", "libkernel", 1, "libkernel", 1, 1, sceKernelGettimezone); + 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 64689bf67..a28f8c133 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 000000000..3a5d1ba71 --- /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 000000000..35034a196 --- /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 97de991ab..932943ade 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