diff --git a/CMakeLists.txt b/CMakeLists.txt index 55f1172f2..c4f639bdd 100755 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -354,6 +354,11 @@ set(PNG_LIB src/core/libraries/libpng/pngdec.cpp src/core/libraries/libpng/pngdec.h ) +set(JPEG_LIB src/core/libraries/jpeg/jpeg_error.h + src/core/libraries/jpeg/jpegenc.cpp + src/core/libraries/jpeg/jpegenc.h +) + set(PLAYGO_LIB src/core/libraries/playgo/playgo.cpp src/core/libraries/playgo/playgo.h src/core/libraries/playgo/playgo_types.h @@ -536,6 +541,7 @@ set(CORE src/core/aerolib/stubs.cpp ${VIDEOOUT_LIB} ${NP_LIBS} ${PNG_LIB} + ${JPEG_LIB} ${PLAYGO_LIB} ${RANDOM_LIB} ${USBD_LIB} diff --git a/src/common/alignment.h b/src/common/alignment.h index 8480fae26..3fb961c63 100644 --- a/src/common/alignment.h +++ b/src/common/alignment.h @@ -22,6 +22,12 @@ template return static_cast(value - value % size); } +template + requires std::is_integral_v +[[nodiscard]] constexpr bool IsAligned(T value, std::size_t alignment) { + return (value & (alignment - 1)) == 0; +} + template requires std::is_integral_v [[nodiscard]] constexpr bool Is16KBAligned(T value) { diff --git a/src/common/logging/filter.cpp b/src/common/logging/filter.cpp index fc9fa0557..5f44658f0 100644 --- a/src/common/logging/filter.cpp +++ b/src/common/logging/filter.cpp @@ -105,6 +105,7 @@ bool ParseFilterRule(Filter& instance, Iterator begin, Iterator end) { SUB(Lib, Rtc) \ SUB(Lib, DiscMap) \ SUB(Lib, Png) \ + SUB(Lib, Jpeg) \ SUB(Lib, PlayGo) \ SUB(Lib, Random) \ SUB(Lib, Usbd) \ diff --git a/src/common/logging/types.h b/src/common/logging/types.h index 1422c3926..a373e8f1b 100644 --- a/src/common/logging/types.h +++ b/src/common/logging/types.h @@ -72,6 +72,7 @@ enum class Class : u8 { Lib_Rtc, ///< The LibSceRtc implementation. Lib_DiscMap, ///< The LibSceDiscMap implementation. Lib_Png, ///< The LibScePng implementation. + Lib_Jpeg, ///< The LibSceJpeg implementation. Lib_PlayGo, ///< The LibScePlayGo implementation. Lib_Random, ///< The libSceRandom implementation. Lib_Usbd, ///< The LibSceUsbd implementation. diff --git a/src/core/libraries/jpeg/jpeg_error.h b/src/core/libraries/jpeg/jpeg_error.h new file mode 100644 index 000000000..c1525db16 --- /dev/null +++ b/src/core/libraries/jpeg/jpeg_error.h @@ -0,0 +1,9 @@ +// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +constexpr int ORBIS_JPEG_ENC_ERROR_INVALID_ADDR = 0x80650101; +constexpr int ORBIS_JPEG_ENC_ERROR_INVALID_SIZE = 0x80650102; +constexpr int ORBIS_JPEG_ENC_ERROR_INVALID_ATTR = 0x80650103; +constexpr int ORBIS_JPEG_ENC_ERROR_INVALID_HANDLE = 0x80650104; diff --git a/src/core/libraries/jpeg/jpegenc.cpp b/src/core/libraries/jpeg/jpegenc.cpp new file mode 100644 index 000000000..00fafd6c2 --- /dev/null +++ b/src/core/libraries/jpeg/jpegenc.cpp @@ -0,0 +1,104 @@ +// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#include "common/alignment.h" +#include "common/assert.h" +#include "common/logging/log.h" +#include "core/libraries/error_codes.h" +#include "core/libraries/libs.h" +#include "jpeg_error.h" +#include "jpegenc.h" + +namespace Libraries::JpegEnc { + +constexpr s32 ORBIS_JPEG_ENC_MINIMUM_MEMORY_SIZE = 0x800; + +static bool IsJpegEncHandleValid(OrbisJpegEncHandle handle) { + return handle && Common::IsAligned(reinterpret_cast(handle), 0x20) && + handle->handle == handle; +} + +s32 PS4_SYSV_ABI sceJpegEncCreate(const OrbisJpegEncCreateParam* param, void* memory, + const u32 memory_size, OrbisJpegEncHandle* handle) { + if (!param || !memory || !handle) { + LOG_ERROR(Lib_Jpeg, "Invalid address"); + return ORBIS_JPEG_ENC_ERROR_INVALID_ADDR; + } + if (param->size != sizeof(OrbisJpegEncCreateParam) || + memory_size < ORBIS_JPEG_ENC_MINIMUM_MEMORY_SIZE) { + LOG_ERROR(Lib_Jpeg, "Invalid size"); + return ORBIS_JPEG_ENC_ERROR_INVALID_SIZE; + } + if (param->attr != 0) { + LOG_ERROR(Lib_Jpeg, "Invalid attribute"); + return ORBIS_JPEG_ENC_ERROR_INVALID_ATTR; + } + + auto* handle_internal = reinterpret_cast( + Common::AlignUp(reinterpret_cast(memory), 0x20)); + handle_internal->handle = handle_internal; + handle_internal->handle_size = sizeof(OrbisJpegEncHandleInternal*); + *handle = handle_internal; + + return ORBIS_OK; +} + +s32 PS4_SYSV_ABI sceJpegEncDelete(OrbisJpegEncHandle handle) { + if (!IsJpegEncHandleValid(handle)) { + LOG_ERROR(Lib_Jpeg, "Invalid handle"); + return ORBIS_JPEG_ENC_ERROR_INVALID_HANDLE; + } + + handle->handle = nullptr; + return ORBIS_OK; +} + +s32 PS4_SYSV_ABI sceJpegEncEncode(OrbisJpegEncHandle handle, const OrbisJpegEncEncodeParam* param, + OrbisJpegEncOutputInfo* output_info) { + if (!IsJpegEncHandleValid(handle)) { + LOG_ERROR(Lib_Jpeg, "Invalid handle"); + return ORBIS_JPEG_ENC_ERROR_INVALID_HANDLE; + } + if (!param || !param->image || !param->jpeg) { + LOG_ERROR(Lib_Jpeg, "Invalid address"); + return ORBIS_JPEG_ENC_ERROR_INVALID_ADDR; + } + if (param->image_size == 0 || param->jpeg_size == 0) { + LOG_ERROR(Lib_Jpeg, "Invalid size"); + return ORBIS_JPEG_ENC_ERROR_INVALID_SIZE; + } + + LOG_ERROR(Lib_Jpeg, "(STUBBED) called"); + + if (output_info) { + output_info->size = param->jpeg_size; + output_info->height = param->image_height; + } + return ORBIS_OK; +} + +s32 PS4_SYSV_ABI sceJpegEncQueryMemorySize(const OrbisJpegEncCreateParam* param) { + if (!param) { + LOG_ERROR(Lib_Jpeg, "Invalid address"); + return ORBIS_JPEG_ENC_ERROR_INVALID_ADDR; + } + if (param->size != sizeof(OrbisJpegEncCreateParam)) { + LOG_ERROR(Lib_Jpeg, "Invalid size"); + return ORBIS_JPEG_ENC_ERROR_INVALID_SIZE; + } + if (param->attr != 0) { + LOG_ERROR(Lib_Jpeg, "Invalid attribute"); + return ORBIS_JPEG_ENC_ERROR_INVALID_ATTR; + } + return ORBIS_JPEG_ENC_MINIMUM_MEMORY_SIZE; +} + +void RegisterlibSceJpegEnc(Core::Loader::SymbolsResolver* sym) { + LIB_FUNCTION("K+rocojkr-I", "libSceJpegEnc", 1, "libSceJpegEnc", 1, 1, sceJpegEncCreate); + LIB_FUNCTION("j1LyMdaM+C0", "libSceJpegEnc", 1, "libSceJpegEnc", 1, 1, sceJpegEncDelete); + LIB_FUNCTION("QbrU0cUghEM", "libSceJpegEnc", 1, "libSceJpegEnc", 1, 1, sceJpegEncEncode); + LIB_FUNCTION("o6ZgXfFdWXQ", "libSceJpegEnc", 1, "libSceJpegEnc", 1, 1, + sceJpegEncQueryMemorySize); +}; + +} // namespace Libraries::JpegEnc diff --git a/src/core/libraries/jpeg/jpegenc.h b/src/core/libraries/jpeg/jpegenc.h new file mode 100644 index 000000000..2371b7d3b --- /dev/null +++ b/src/core/libraries/jpeg/jpegenc.h @@ -0,0 +1,59 @@ +// 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::JpegEnc { + +struct OrbisJpegEncHandleInternal { + OrbisJpegEncHandleInternal* handle; + u32 handle_size; +}; +static_assert(sizeof(OrbisJpegEncHandleInternal) == 0x10); + +typedef OrbisJpegEncHandleInternal* OrbisJpegEncHandle; + +struct OrbisJpegEncCreateParam { + u32 size; + u32 attr; +}; +static_assert(sizeof(OrbisJpegEncCreateParam) == 0x8); + +struct OrbisJpegEncEncodeParam { + void* image; + void* jpeg; + u32 image_size; + u32 jpeg_size; + u32 image_width; + u32 image_height; + u32 image_pitch; + u16 pixel_format; + u16 encode_mode; + u16 color_space; + u8 sampling_type; + u8 compression_ratio; + s32 restart_interval; +}; +static_assert(sizeof(OrbisJpegEncEncodeParam) == 0x30); + +struct OrbisJpegEncOutputInfo { + u32 size; + u32 height; +}; +static_assert(sizeof(OrbisJpegEncOutputInfo) == 0x8); + +s32 PS4_SYSV_ABI sceJpegEncCreate(const OrbisJpegEncCreateParam* param, void* memory, + u32 memory_size, OrbisJpegEncHandle* handle); +s32 PS4_SYSV_ABI sceJpegEncDelete(OrbisJpegEncHandle handle); +s32 PS4_SYSV_ABI sceJpegEncEncode(OrbisJpegEncHandle handle, const OrbisJpegEncEncodeParam* param, + OrbisJpegEncOutputInfo* output_info); +s32 PS4_SYSV_ABI sceJpegEncQueryMemorySize(const OrbisJpegEncCreateParam* param); + +void RegisterlibSceJpegEnc(Core::Loader::SymbolsResolver* sym); +} // namespace Libraries::JpegEnc diff --git a/src/emulator.cpp b/src/emulator.cpp index 27291707d..a01eb816b 100644 --- a/src/emulator.cpp +++ b/src/emulator.cpp @@ -29,6 +29,7 @@ #include "core/file_sys/fs.h" #include "core/libraries/disc_map/disc_map.h" #include "core/libraries/fiber/fiber.h" +#include "core/libraries/jpeg/jpegenc.h" #include "core/libraries/libc_internal/libc_internal.h" #include "core/libraries/libs.h" #include "core/libraries/ngs2/ngs2.h" @@ -278,7 +279,7 @@ void Emulator::LoadSystemModules(const std::filesystem::path& file, std::string {"libSceLibcInternal.sprx", &Libraries::LibcInternal::RegisterlibSceLibcInternal}, {"libSceDiscMap.sprx", &Libraries::DiscMap::RegisterlibSceDiscMap}, {"libSceRtc.sprx", &Libraries::Rtc::RegisterlibSceRtc}, - {"libSceJpegEnc.sprx", nullptr}, + {"libSceJpegEnc.sprx", &Libraries::JpegEnc::RegisterlibSceJpegEnc}, {"libSceCesCs.sprx", nullptr}}}; std::vector found_modules;